如果您有 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工具来抓进程内的流程。或者是traceview与Simpleperf。
-
如果你想确认最全面的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;
-