• 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 | 转载请注明作者出处
  • 相关阅读:
    第二章 数据类型、变量、和运算符
    第一章
    ActiveMQ点对点的发送和接收
    初探设计模式(1)——工厂模式
    IDEA使用switch传入String编译不通过
    MyBatis日期转换报错
    HTML页面传值问题
    maven配置本地仓库
    Maven的下载及安装
    PHP实现获得一段时间内所在的所有周的时间
  • 原文地址:https://www.cnblogs.com/houser0323/p/15086982.html
Copyright © 2020-2023  润新知