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