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.
官方指導
示例
- 敲命令
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