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.
官方指導
示例
- 敲命令
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 | 轉載請註明作者出處