跳转至

am trace-ipc 分析

一、使用

官网介绍

链接:Slow rendering

如果您有 binder 事务,则可以使用以下 adb 命令捕获其调用堆栈:

$ adb shell am trace-ipc start
     use the app - scroll/animate ...
    $ adb shell am trace-ipc stop --dump-file /data/local/tmp/ipc-trace.txt
    $ adb pull /data/local/tmp/ipc-trace.txt

命令提示

:/ # am
Activity manager (activity) commands:
  trace-ipc [start|stop] [--dump-file <FILE>]
      Trace IPC transactions.
      start: start tracing IPC transactions.
      stop: stop tracing IPC transactions and dump the results to file.
      --dump-file <FILE>: Specify the file the trace should be dumped to.

小结

1、抓所有进程的java层面的binder调用栈,只抓发起端的线程栈,也就是堆栈的最上一句总是

Trace: java.lang.Throwable
android.os.BinderProxy.transact(BinderProxy.java:509)

2、抓的是一段时间start↔stop,没有类似logcat的缓存

3、主要用于在java层面上

  • 确认谁(进程)调用了某个binder服务
  • 确认操作过程中发生了哪些ipc动作

需要注意的是,此处局限于java层,局限于ipc。

  • 如果你的目的是确认最全面(进程内+进程外)的代码流程,则还需要cpu-profiler工具来抓进程内的流程。或者是traceviewSimpleperf

  • 如果你想确认最全面的ipc流程,目前native的ipc记录工具还有待发掘。

下面分析源码实现。

二、源码分析

代码基于android11。am命令的实现见debug:am、cmd命令

书接上文,

ActivityManagerShellCommand#onCommand

frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand

 176     @Override
 177     public int onCommand(String cmd) {      
 183             switch (cmd) {
 184                 case "start":
 185                 case "start-activity":
 186                     return runStartActivity(pw);
......
 203                 case "trace-ipc":
 204                     return runTraceIpc(pw);
......

走到204行

ActivityManagerShellCommand#runTraceIpc

frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand

 754     int runTraceIpc(PrintWriter pw) throws RemoteException { 
 755         String op = getNextArgRequired();
 756         if (op.equals("start")) {
 757             return runTraceIpcStart(pw);
 758         } else if (op.equals("stop")) {
 759             return runTraceIpcStop(pw);
 760         } else {
 761             getErrPrintWriter().println("Error: unknown trace ipc command '" + op + "'");

757行start,759行stop。先看start

am trace-ipc start

ActivityManagerShellCommand#runTraceIpcStart

frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand

 168     ActivityManagerShellCommand(ActivityManagerService service, boolean dumping) {
 169         mInterface = service;     
----------------------------------------------------------------------------------
 766     int runTraceIpcStart(PrintWriter pw) throws RemoteException {                      
 767         pw.println("Starting IPC tracing.");
 768         pw.flush();
 769         mInterface.startBinderTracking();
 770         return 0;
 771     }

769行,mInterface是ams,见构造函数169行。继续跟

ActivityManagerService.java#startBinderTracking

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

18843     public boolean startBinderTracking() throws RemoteException {
18844         synchronized (this) {
18845             mBinderTransactionTrackingEnabled = true;
18846             // TODO: hijacking SET_ACTIVITY_WATCHER, but should be changed to its own
18847             // permission (same as profileControl).
18848             if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
18849                     != PackageManager.PERMISSION_GRANTED) {
18850                 throw new SecurityException("Requires permission "
18851                         + android.Manifest.permission.SET_ACTIVITY_WATCHER);
18852             }
18853 
18854             for (int i = 0; i < mProcessList.mLruProcesses.size(); i++) {
18855                 ProcessRecord process = mProcessList.mLruProcesses.get(i);
18856                 if (!processSanityChecksLocked(process)) {
18857                     continue;
18858                 }
18859                 try {
18860                     process.thread.startBinderTracking();
18861                 } catch (RemoteException e) {

18848-18852鉴权。

18854行for循环,将系统的java进程都开启binderTracking,重点就是18860行。

下面进入java进程的ActivityThread中跟踪

ActivityThread.java$ApplicationThread#startBinderTracking

frameworks/base/core/java/android/app/ActivityThread.java

 947     private class ApplicationThread extends IApplicationThread.Stub {
1688         @Override
1689         public void startBinderTracking() {                                             
1690             sendMessage(H.START_BINDER_TRACKING, null);
1691         }     
--------------------------------------------------------------------------
1803     class H extends Handler {
1907         public void handleMessage(Message msg) {
2042                 case START_BINDER_TRACKING:                                             
2043                     handleStartBinderTracking();
2044                     break;
--------------------------------------------------------------------------
3842     private void handleStartBinderTracking() {
3843         Binder.enableTracing();                                                         
3844     }

Binder.java#enableTracing

frameworks/base/core/java/android/os/Binder.java

 138     /**
 139      * Enable Binder IPC tracing.
 140      *
 141      * @hide
 142      */
 143     public static void enableTracing() {
 144         sTracingEnabled = true;                                                         
 145     }
-------------------------------------------------------------------
 161     public static boolean isTracingEnabled() {
 162         return sTracingEnabled;
 163     }

144行,将标志位置true。作用是在每次java世界发起binder调用的时候,来通过这个参数判断是否要抓trace。

BinderProxy.java#transact

frameworks/base/core/java/android/os/BinderProxy.java

495     public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
517         final boolean tracingEnabled = Binder.isTracingEnabled();
518         if (tracingEnabled) {
519             final Throwable tr = new Throwable();
520             Binder.getTransactionTracker().addTrace(tr);
521             StackTraceElement stackTraceElement = tr.getStackTrace()[1];
522             Trace.traceBegin(Trace.TRACE_TAG_ALWAYS,
523                     stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName());
524         }
526         // Make sure the listener won't change while processing a transaction.
527         final Binder.ProxyTransactListener transactListener = sTransactListener;
530         if (transactListener != null) {
531             final int origWorkSourceUid = Binder.getCallingWorkSourceUid();
532             session = transactListener.onTransactStarted(this, code, flags);
540         }
549         try {
550             return transactNative(code, data, reply, flags);
551         } finally {
554             if (transactListener != null) {
555                 transactListener.onTransactEnded(session);
556             }
558             if (tracingEnabled) {
559                 Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);

519、520行抓调用栈放到TransactionTracker里存放

522和559是抓systrace,抓出来类似长这样,有详细的类名方法名:

评论