1. 程式人生 > >Android 5.0 Usb除錯攔截分析及修改

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  版權宣告:本文為博主原創文章,轉載請附上博文連結!