Android 5.0 Usb除錯攔截分析及修改
當我們除錯安卓機器時,第一次插上usb線,會彈出一個授權的對話方塊,(前提是打開了usb除錯功能)點選確認,才會允許除錯.
如果我們想機器預設就可以除錯該怎麼做呢?
如果我們想動態攔截,需要使用者輸入帳號密碼,才確認是否可以除錯,該怎麼做呢?或者只是單純的想改變這個不好看的UI,又該怎麼做呢?
分析的原始碼基於android 5.0.2_r1
前面所說的情況1,想在預設情況下就允許usb除錯,需要修改原始碼下的/build/core/main.mk檔案,然後重新編譯,刷機,具體請看: http://blog.csdn.net/fanmengke_im/article/details/28389439?utm_source=tuicool&utm_medium=referral
至於後面的那一種,就是我要說的重點,需要去看一看android原始碼,然後做一些適當的修改.首先,我們要找到關於usb的原始碼,主要在/frameworks/base/services/java/目錄下,也就是這幾個檔案: UsbDebuggingManager.java UsbDeviceManager.java UsbHostManager.java UsbService.java UsbSettingsManager.java
其中涉及到的一些資原始檔在/frameworks/base/core/res/res/目錄下
尋找入口點 原始碼與資原始檔都在這了,從哪入手,我也是一頭霧水,還好,只有5個java檔案,去讀一讀,看看有什麼收穫. 你會發現,在UsbDebuggingmanager類中,你會發現有這樣的幾個方法:
startConfirmation(String key, String fingerprints)
startConfirmationActivity(ComponentName componentName, String key, String fingerprints)
startConfirmationService(ComponentName componentName, String key, String fingerprints) 1 2 3 4 5 6 7 會不會就是這些方法彈出了對話方塊呢?繼續追蹤,發現startConfirmationActivity()和startConfirmationService()都是在startConfirmation()方法中呼叫的,現在我們來看下startConfirmation()方法:
首先通過資原始檔拿到一個String型別的nameString,然後通過unflattenFromString()方法,傳入nameString得到一個ComponentName物件,那麼nameString到底是什麼呢?
在/frameworks/base/core/res/res/values/config.xml 檔案中,我們看到:
原來ConponentName就是: 包名為com.android.systemui 元件為com.android.systemui.usb.UsbDebuggingActivity的類
彈窗UI在這修改
哦哦,原來我們彈出的授權對話方塊就是systemui app中的一個activity,如果你只是單純的想改變這個UI,你現在只要到/frameworks/base/packages/SystemUI/usb/目錄下,找到UsbDebuggingActivity這個類,修改它的佈局檔案即可.等會再來看下這個類,做了哪些事情.
繼續回到上面的分析,你會發現startConfirmation()方法在一個Handler被呼叫,什麼情況下會出發這個Handler呢?原來,UsbDebuggingManager實現了Runnable,在run()方法中開啟了一個LocalSocket,去讀取底層的usb資訊,做出響應的操作.至於該執行緒的開啟,也在Handler中,只要你呼叫了setAdbEnabled(),如果引數為true,就開啟該執行緒.
現在我們只要看看在哪個地方例項化了UsbDebuggingManager類,呼叫了setAdbEnabled()方法.
追蹤發現在UsbDeviceManager中,它的構造方法中初始化了UsbDebuggingManager類.
可以看到會通過SystemProperties讀取ro.adb.secure 和 vold.decrypt的值,這兩個值,我請教了做rom的同事,說這些值是在編譯的時候修改的,主要來區分user,eng版本,這兩個值主要就是來進行是否進行usb認證機制的.
然後就初始化了UsbDeviceManager類,在看看呼叫mDebuggingManager.setAdbEnabled(mAdbEnabled)的地方.
也是在UsbDeviceManager的Handler中呼叫的,它註冊啦一個開機廣播,每次開機就會觸發它.程式碼只截取了一小部分…
當然,還有幾個地方呼叫了setAdbEnabled()方法,比如在這個Handler初始化的時候,我就沒有追蹤了,如果你有興趣,可以去除錯下~
接下來,繼續往上追蹤,看看UsbDeviceManager在哪被例項化了.它是通過UsbService的構造方法來例項化的.
在UsbService這個類中,它是繼承自IUsbManager.Stub類的,也就是IUsbManager.aidl這個檔案,它在/frameworks/base/core/java/android/hardware/usb/資料夾下,這個介面是@hide的,因為外部不可以引用,檔案內容如下:
// 只摘錄了IUsbManager中的幾個方法 /** @hide */ interface IUsbManager{
/* Allow USB debugging from the attached host. If alwaysAllow is true, add the * the public key to list of host keys that the user has approved. */ void allowUsbDebugging(boolean alwaysAllow, String publicKey);
/* Deny USB debugging from the attached host */ void denyUsbDebugging();
/* Clear public keys installed for secure USB debugging */ void clearUsbDebuggingKeys(); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 看方法名就大致能猜出來該方法的作用,允許授權,拒絕授權,清除授權.
在看看UsbService在哪被例項化?在UsbService中有一個Lifecycle靜態內部類,繼承自SystemService,在onStart()方法中,例項化了UsbService類.
那是在何處呼叫了Lifecycle類呢?通過查詢發現,原來是在SystemService這個類呼叫的.
對於SystemService類,我也不是很瞭解,具體的相關資訊可以去查詢.SystemService是android系統一個很重要的服務,它是由zytote來初始化的,然後會啟動android系統的一些必要服務和支援元件,地位相當重要.直接看看程式碼吧.
private void run() { // If a device's clock is before 1970 (before 0), a lot of // APIs crash dealing with negative numbers, notably // java.io.File#setLastModified, so instead we fake it and // hope that time from cell towers or NTP fixes it shortly. if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) { Slog.w(TAG, "System clock is before 1970; setting to 1970."); SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME); }
// Here we go! Slog.i(TAG, "Entered the Android system server!"); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
// In case the runtime switched since last boot (such as when // the old runtime was removed in an OTA), set the system // property so that it is in sync. We can't do this in // libnativehelper's JniInvocation::Init code where we already // had to fallback to a different runtime because it is // running as root and we need to be the system user to set // the property. http://b/11463182 SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
// Enable the sampling profiler. if (SamplingProfilerIntegration.isEnabled()) { SamplingProfilerIntegration.start(); mProfilerSnapshotTimer = new Timer(); mProfilerSnapshotTimer.schedule(new TimerTask() { @Override public void run() { SamplingProfilerIntegration.writeSnapshot("system_server", null); } }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL); }
// Mmmmmm... more memory! VMRuntime.getRuntime().clearGrowthLimit();
// The system server has to run all of the time, so it needs to be // as efficient as possible with its memory usage. VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
// Some devices rely on runtime fingerprint generation, so make sure // we've defined it before booting further. Build.ensureFingerprintProperty();
// Within the system server, it is an error to access Environment paths without // explicitly specifying a user. Environment.setUserRequired(true);
// Ensure binder calls into the system always run at foreground priority. BinderInternal.disableBackgroundScheduling(true);
// Prepare the main looper thread (this thread). android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_FOREGROUND); android.os.Process.setCanSelfBackground(false); Looper.prepareMainLooper();
// Initialize native services. System.loadLibrary("android_servers"); nativeInit();
// Check whether we failed to shut down last time we tried. // This call may not return. performPendingShutdown();
// Initialize the system context. createSystemContext();
// Create the system service manager. mSystemServiceManager = new SystemServiceManager(mSystemContext); LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Start services. try { startBootstrapServices(); startCoreServices(); startOtherServices(); } catch (Throwable ex) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting system services", ex); throw ex; }
// For debug builds, log event loop stalls to dropbox for analysis. if (StrictMode.conditionallyEnableDebugLogging()) { Slog.i(TAG, "Enabled StrictMode for system server main thread."); }
// Loop forever. Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 可以看到初始化很多東西,建立Context,載入android_servers,初始化主執行緒…最後呼叫了startBootstrapServices(),startCoreServices(),startOtherServices()方法,在這個方法中,啟動了Lifecycle服務.
這樣的話,整體流程就串起來了. 1.首先android系統啟動,初始化了SystemServer 2.在由SystemServer去啟動UsbService$Lifecycle服務,然後例項化UsbService 3.在由UsbService初始化了UsbHostManager和UsbDeviceManager. 4.然後UsbDeviceManager通過讀取ro.adb.secure和vold.decrypt的值,來判定是否開啟除錯攔截流程(也就是初始化UsbDebuggingManager) 5.如果初始化UsbDebuggingManager,它會一直監聽LocalSocketAddress(“adbd”, LocalSocketAddress.Namespace.RESERVED)這個埠,判斷是否彈出授權視窗
分析彈出授權的UI視窗
也就是UsbDebuggingActivity類,繼承自AlertActivity,我們主要看一些確認和取消的事件.
通過ServiceManager得到一個IBinder物件,然後通過IBinder得到一個IUsbManager物件,這個就是前面所說的aidl介面,UsbService實現了IUsbManager介面,呼叫allowUsbDebugging()和denyUsbDebugging(),同意授權和不同意授權.
那我們在回過頭來,看一看IUsbManager介面中的allowUsbDebugging()和denyUsbDebugging()的實現. 在UsbService中:
其實呼叫的是UsbDeviceManager中的方法:
最終發現原來呼叫的是UsbDebuggingManager中的方法:
最終,找到了原來所有的操作還是在它的UsbDebuggingHandler中,如果授權成功了,會向檔案中寫入這個key和相關資訊,然後通過上面所說的Socket寫入一條”OK”這樣的資訊.如果取消授權,會通過Socket寫入一條”NO”這樣的資訊.到此,整個流程就走完了.
至於Socket的另一端,暫時沒有去尋找它,據個人估計,可能與驅動方面有關.(咱待研究)
定製除錯攔截 1.如果你只是想改動彈出的UI,只需要修改UsbDebuggingActivity的佈局檔案就可以了.
2.如該想改動相關邏輯,就需要在UsbDebuggingManager類中改動,是否彈窗,或者根本不想用systemui裡面的Activity,都可以在這裡面進行改動. 不過上層如果想要授權的話,需要呼叫IUsbManager的授權和取消授權方法. 如果獲取不到該類或者它的實現類UsbService(好像是因為IUsbManager是@hide,我沒有試過),建議你仿照IUsbManager.adil檔案,上下層都去實現其中的幾個重要方法,就可以拿來用了.
3.如果你根本想不攔截除錯授權的話,就需要在main.mk檔案中做一些相應的修改了,具體的話,可以去網上搜一下.
4.當然,如果你修改UsbDeviceManager類的,在初始化的時候給它再加一個判斷條件的話,也可以顯示自由攔截功能.
暫時就研究到這了,因為公司需要定製這東西,等需求有變化了,可能需要在做研究,到時候在補充吧~
相關文章: android4.4 debug除錯授權攔截(替換掉 允許USB除錯嗎? UI) Android 如何開啟與關閉adb 的認證機制(google adb secure) (adb RSA 指紋認證) Android 下的usb框架及功能點 Android裝置adb授權的原理 --------------------- 作者:zhou_lee 來源:CSDN 原文:https://blog.csdn.net/u012301841/article/details/53200172 版權宣告:本文為博主原創文章,轉載請附上博文連結!