1. 程式人生 > 其它 >debug:am set-debug-app命令的實現

debug:am set-debug-app命令的實現

debug:am set-debug-app命令的實現

目錄

一、原始碼分析

程式碼基於android11。am命令的實現見debug:am、cmd命令。書接上文,

1.1、命令列引數設定

ActivityManagerShellCommand#onCommand

frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand.java

 176     @Override
 177     public int onCommand(String cmd) {      
 183             switch (cmd) {
 184                 case "start":
 185                 case "start-activity":
 186                     return runStartActivity(pw);
......
 209                 case "set-debug-app":                                                   
 210                     return runSetDebugApp(pw);
 213                 case "clear-debug-app":
 214                     return runClearDebugApp(pw);

209行設定debug,對應的214行去掉debug

ActivityManagerShellCommand#runSetDebugApp

frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand.java

 980     int runSetDebugApp(PrintWriter pw) throws RemoteException {
 981         boolean wait = false;
 982         boolean persistent = false;
 983 
 984         String opt;
 985         while ((opt=getNextOption()) != null) {
 986             if (opt.equals("-w")) {
 987                 wait = true;
 988             } else if (opt.equals("--persistent")) {
 989                 persistent = true;
 990             } else {                                                                   
 991                 getErrPrintWriter().println("Error: Unknown option: " + opt);
 992                 return -1;
 993             }
 994         }
 995 
 996         String pkg = getNextArgRequired();
 997         mInterface.setDebugApp(pkg, wait, persistent);
 998         return 0;
 999     }
-------------------------------------------------------------------------
1008     int runClearDebugApp(PrintWriter pw) throws RemoteException {
1009         mInterface.setDebugApp(null, false, true);
1010         return 0;
1011     }

runSetDebugApp僅記錄了倆引數,-w--persistent。分別代表:下次等待app啟動、總是等待app啟動

997行,實現與之前分析的am命令一樣,轉到ams處理

1009行,去掉debug。呼叫同樣的方法,只是入參不一致。繼續跟蹤

ActivityManagerService.java#setDebugApp

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

 8391     public void setDebugApp(String packageName, boolean waitForDebugger,
 8392             boolean persistent) {
 8393         enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
 8394                 "setDebugApp()");
 8396         long ident = Binder.clearCallingIdentity();
 8397         try {
 8401             if (persistent) {
 8402                 final ContentResolver resolver = mContext.getContentResolver();
 8403                 Settings.Global.putString(
 8404                     resolver, Settings.Global.DEBUG_APP,
 8405                     packageName);
 8406                 Settings.Global.putInt(
 8407                     resolver, Settings.Global.WAIT_FOR_DEBUGGER,
 8408                     waitForDebugger ? 1 : 0);
 8409             }
 8410 
 8411             synchronized (this) {
 8412                 if (!persistent) {
 8413                     mOrigDebugApp = mDebugApp;
 8414                     mOrigWaitForDebugger = mWaitForDebugger;
 8415                 }
 8416                 mDebugApp = packageName;
 8417                 mWaitForDebugger = waitForDebugger;
 8418                 mDebugTransient = !persistent;
 8419                 if (packageName != null) {
 8420                     forceStopPackageLocked(packageName, -1, false, false, true, true,
 8421                             false, UserHandle.USER_ALL, "set debug app");

命令的設定僅有三點內容:settings資料庫、全域性變數、停止app程序

引數的組合有點亂,使用時一般-w --persistent一起用,這樣每次app啟動都會等待AS的debug了。

1.2、Setting中的debug設定

需要注意的是,上小節設定的資料庫僅僅是為了同步資訊。。。,除此之外沒有任何用處

沒有人監聽這個資料庫,只是在設定裡檢查該值,決定設定裡開發者選項的UI,如何顯示。

另外說下設定裡的實現,如何設定debug app 和debugger的,答案:同命令行一樣呼叫介面ActivityManagerService.java#setDebugApp

WaitForDebuggerPreferenceController.java#writeDebuggerAppOptions

packages/apps/Settings/src/com/android/settings/development/WaitForDebuggerPreferenceController.java

103     private void writeDebuggerAppOptions(String packageName, boolean waitForDebugger,
104             boolean persistent) {
105         try {
106             getActivityManagerService().setDebugApp(packageName, waitForDebugger, persistent);

所以對流程有影響的是AMS裡的幾個全域性變數。看下面

1.3、進入等待

ActivityManagerService.java#attachApplicationLocked

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

 5011     private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
 5012             int pid, int callingUid, long startSeq) {
 5144         try {
 5145             int testMode = ApplicationThreadConstants.DEBUG_OFF;
 5146             if (mDebugApp != null && mDebugApp.equals(processName)) {
 5147                 testMode = mWaitForDebugger
 5148                     ? ApplicationThreadConstants.DEBUG_WAIT
 5149                     : ApplicationThreadConstants.DEBUG_ON;
 5150                 app.setDebugging(true);
 5151                 if (mDebugTransient) {
 5152                     mDebugApp = mOrigDebugApp;
 5153                     mWaitForDebugger = mOrigWaitForDebugger;
 ......
 5318                 thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
 5319                         null, null, null, testMode,

假設當前是-w --persistent,5147行,testMode為DEBUG_WAIT

5150給ProcessRecord設定標誌位mDebugging = ture

5318行,binder呼叫到app程序bindApplication階段

ActivityThread.java$ApplicationThread#bindApplication

frameworks/base/core/java/android/app/ActivityThread.java

         private class ApplicationThread extends IApplicationThread.Stub {    
1036         public final void bindApplication(String processName, ApplicationInfo appInfo, 
1040                 IUiAutomationConnection instrumentationUiConnection, int debugMode,
1074             AppBindData data = new AppBindData();
1082             data.debugMode = debugMode;
1094             sendMessage(H.BIND_APPLICATION, data);

1094行,轉到主執行緒

ActivityThread.java#handleBindApplication

frameworks/base/core/java/android/app/ActivityThread.java

1907         public void handleMessage(Message msg) {
1909             switch (msg.what) {
1910                 case BIND_APPLICATION:
1911                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
1912                     AppBindData data = (AppBindData)msg.obj;
1913                     handleBindApplication(data);
------------------------------------------------------------------
6500         if (data.debugMode != ApplicationThreadConstants.DEBUG_OFF) {
6501             // XXX should have option to change the port.
6502             Debug.changeDebugPort(8100);
6503             if (data.debugMode == ApplicationThreadConstants.DEBUG_WAIT) {
6504                 Slog.w(TAG, "Application " + data.info.getPackageName()
6505                       + " is waiting for the debugger on port 8100...");
6506 
6507                 IActivityManager mgr = ActivityManager.getService();
6508                 try {
6509                     mgr.showWaitingForDebugger(mAppThread, true);
6510                 } catch (RemoteException ex) {
6511                     throw ex.rethrowFromSystemServer();
6512                 }
6513 
6514                 Debug.waitForDebugger();
6515 
6516                 try {
6517                     mgr.showWaitingForDebugger(mAppThread, false);
6518                 } catch (RemoteException ex) {
6519                     throw ex.rethrowFromSystemServer();
6520                 }
6521 
6522             } else {
6523                 Slog.w(TAG, "Application " + data.info.getPackageName()
6524                       + " can be debugged on port 8100...");

有兩種debug連結方式,一是6514行DEBUG_WAIT,二是通過6502行設定的埠。我們一般通過第一種。

二、使用

命令提示

generic_x86_64:/ # am
Activity manager (activity) commands:
  set-debug-app [-w] [--persistent] <PACKAGE>
      Set application <PACKAGE> to debug.  Options are:
      -w: wait for debugger when application starts
      --persistent: retain this value
  clear-debug-app
      Clear the previously set-debug-app.

官方指導

見連結Debug your app

示例

  • 敲命令
generic_x86_64:/ # am set-debug-app -w --persistent com.example.myapplication
  • 然後點選啟動app。此時會出現彈窗等待AS上的操作
  • AS上Attach Debugger to Android Process

    在AndroidStudio中的操作路徑為Attach Debugger to Android Process --> 選擇連結裝置上的程序。如下圖

選中我們的程序,點ok就好了。如果有正確斷點,則程式碼會走到斷點處。

三、總結

1、設定開發者選項和命令列實現完全一致

2、等待debugger的點在Activity冷啟動bindeApplication階段。

我們知道,app程序啟動後經歷初始化-->attach到AMS,然後才是AMS回來bindeApplication階段。所以之前的程式碼流程用這個工具是斷點不到的,可以自己動手,將Debug.waitForDebugger();放在你希望的地方。
比如斷點除錯SystemServer時可以這樣寫

frameworks/base/services/java/com/android/server/SystemServer.java

 413     public static void main(String[] args) {
 414         boolean bootDebug = "1".equals(SystemProperties.get("persist.boot.debug"));
 415         if(bootDebug){
 416             android.ddm.DdmHandleAppName.setAppName("system_process",
 417                     UserHandle.myUserId());
 418             android.os.Debug.waitForDebugger();                                         
 419         }
 420         new SystemServer().run();
 421     }

3、關於AS除錯app的其他資料,可以看官網Debug your app

作者:秋城 | 部落格:https://www.cnblogs.com/houser0323 | 轉載請註明作者出處