Android如何完全调试framework层代码

1 之前写过一篇文章:《Android实现开机调试system_process》

2 google的eclipse插件ADT的已经能够很方便的调试Android的apk了,但是调试的时候应用程序已经进入Activity。

3 如果我们想了解一下Activity的启动过程,只有看代码+看log输出了吗?本文可以告诉你:NO!

4 相信大家比较感兴趣的都是代码,这里先把代码再放出来

ZygoteInit.java


  public static List<String> readCommandOutput(String command)  {

     Runtime rt =Runtime.getRuntime();

     java.lang.Processproc;

     try {

       proc =rt.exec(command);

       

       if (proc.waitFor() != 0) {

          return null;

       }

       LinkedList<String>list = new LinkedList<String>();      

       InputStreamReader ir = new InputStreamReader(proc.getInputStream());

       BufferedReader in = new BufferedReader(ir);       

       String line = null;      

       while ((line = in.readLine()) != null) {

          list.add(line);

       }      

       return list;

     } catch (InterruptedException e) {

       e.printStackTrace();

     } catch (IOException e) {

       e.printStackTrace();

     }

     return null;

  }

 

  public static String getPackageName(){

     String strPid =Integer.toString(android.os.Process.myPid());

     String cmd = "ps";

     

     List<String>result = readCommandOutput(cmd);

     if(result == null){

       return "";

     }

     

     for(String info:result){

       if(info.contains(strPid)){

          int index = info.lastIndexOf(" ");

          if(index >=0){

            StringsubStr = info.substring(index+1);

            Log.i(TAG,subStr);

            return subStr;

          }

       }

     }

     return "";

  }  

 

  public static boolean needDebug(String packageName){

     String debugProcess = android.os.SystemProperties.get("persist.sys.debug");    

     Log.i(TAG,debugProcess);

 

     if(debugProcess.equals(packageName)){

       return true;

     }

     return false;

  }  

  

    public static void main(Stringargv[]) {

         

        try {

            // Start profiling the zygote initialization.

           SamplingProfilerIntegration.start();

 

            registerZygoteSocket();

           EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,

               SystemClock.uptimeMillis());

            preload();

           EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,

               SystemClock.uptimeMillis());

 

            // Finish profiling the zygote initialization.

           SamplingProfilerIntegration.writeZygoteSnapshot();

 

            // Do an initial gc to cleanup after startup

            gc();

 

            // If requested, start system server directlyfrom Zygote

            if (argv.length != 2) {

                throw new RuntimeException(argv[0] + USAGE_STRING);

           }

 

            if (argv[1].equals("start-system-server")) {

                startSystemServer();

           } else if (!argv[1].equals("")) {

                throw new RuntimeException(argv[0] + USAGE_STRING);

           }

 

           Log.i(TAG, "Accepting command socket connections");

 

            if (ZYGOTE_FORK_MODE) {

                runForkMode();

           } else {

                runSelectLoopMode();

           }

 

            closeServerSocket();

       } catch (MethodAndArgsCaller caller) {

         String packageName = getPackageName();

         if(needDebug(packageName)){

           android.ddm.DdmHandleAppName.setAppName(packageName,UserHandle.myUserId());

           android.os.Debug.waitForDebugger();

           }         

         caller.run();

       } catch (RuntimeException ex) {

           Log.e(TAG, "Zygote died with exception", ex);

            closeServerSocket();

            throw ex;

        }

    }




5 如果有兴趣,继续往下看!


6 readCommandOutput:用于执行命令并获取命令的输出


7 getPackageName()有于获取当前进程的包名

    这里默认进程名称即为包名

    获取ps的输出

    然后通过pid找到本程序所在的输出行。

   提取出本程序所在的输出行包名


8 needDebug()用于判断当前进程是否需要调试,原理是这样的:

    使用者通过setprop persist.sys.debug 包名来设置包的名称

    needDebug获取 persist.sys.debug

    再与本进程的包名进行比较,以判断是否要调试


9 接下来的动作就和《Android实现开机调试system_process》一样了:

    设置App在DDM中的名称:

android.ddm.DdmHandleAppName.setAppName(packageName,UserHandle.myUserId());

    等待调试器来连接:

android.os.Debug.waitForDebugger();


10 接下来重新编译和烧录,mmm...,一个漫长的过程,但是结果将会证明一确都是值得的。


11 接下来,创建一个伪工程,修改Manifest中的package为需要调试的程序包名


12 再在工程中将需要调试的framework层代码引进来


13 接下来,adb shell连接到android,进行命令行


14 执行命令:

setprop persist.sys.debug 包名


15 在需要调试的代码上设置断点


16 接下来,启动应用程序,注意,是直接启动程序,而不是通过eclipse启动调试!


17 enjoy it!


18 (完)

 

你可能感兴趣的:(java,android,framework,adt)