暂停任务、转至 Console(控制台)并输入命令“thread 1”和“go”。
| thread 1 |
现在我们可以设置断点并对其进行调试。
5 同时进行 Java 和 C/C++ 调试
5.1 观察从 Java 到原生的所有调用追踪
有时候,我们希望观察从 Java 到原生的所有调用追踪。 要实现这一点,我们需要使用前面介绍的两种 Java 和 C/C++ 调试技巧。
- 使用脚本 start_system_server.sh 或 start_app.sh,使 system_process 和应用进入无限循环模式。
- 使用 DDMS 连接至 system_process 或应用。
- 输入“go”命令,使 system_process 或应用退出无限循环。
- 使用您感兴趣的原生函数来切换 C/C++ 断点。
- 输入“loop”命令,使原生函数进入无限循环模式。
- 开始运行。
- 现在转至安卓调试工具,停止线程,并检查每个线程的调用堆栈。 分别找到调用原生函数的线程,以及处于无线循环模式中的线程。
然后合并 Java 调用追踪和 C/C++ 调用追踪,并查看从 Java 到原生的整个调用追踪。
在下面的实例中,调用追踪为:
Java: WindowManagerService$Session.add-> SurfaceSession.init()->C/C++: SurfaceSession_init()->android::SurfaceFlinger::createConnection()
system_process_1234 [C/C++ Remote Application]
app_process [cores: 0,1]
Thread [52] 10969 [core: 1] (Suspended : Container)
Thread [51] 10968 [core: 1] (Suspended : Container)
Thread [50] 10556 [core: 1] (Suspended : Container)
Thread [49] 10547 [core: 1] (Suspended : Container)
android::SurfaceFlinger::createConnection() at SurfaceFlinger.cpp:174 0x8643b728
android::SurfaceComposerClient::onFirstRef() at SurfaceComposerClient.cpp:170 0x81f248b9
android::RefBase::incStrong() at RefBase.cpp:304 0x8051e128
sp() at RefBase.h:353 0x808711f3
SurfaceSession_init() at android_view_Surface.cpp:109 0x808711f3
dvmPlatformInvoke() at Call386ABI.S:133 0x8302be8f
dvmCallJNIMethod_virtualNoRef() at Jni.c:1,849 0x8307505b
dvmCheckCallJNIMethod_virtualNoRef() at CheckJni.c:158 0x83052741
dvmInterpretDbg() at InterpC-portdbg.c:4,354 0x8304083d
dvmInterpret() at Interp.c:1,335 0x83036521
<...more frames...>
<==
system_process [Android Application]
DalvikVM[localhost:8600]
Thread [<1> main] (Running)
Thread [<50> Binder Thread #10] (Running)
Thread [<49> Binder Thread #9] (Running)
Thread [<47> Binder Thread #8] (Running)
Thread [<44> Binder Thread #7] (Suspended)
SurfaceSession.init() line: not available [native method]
SurfaceSession.() line: 29
WindowManagerService$Session.windowAddedLocked() line: 5774
WindowManagerService$WindowState.attach() line: 6107
WindowManagerService.addWindow(WindowManagerService$Session, IWindow, WindowManager$LayoutParams, int, Rect, InputChannel) line: 1914
WindowManagerService$Session.add(IWindow, WindowManager$LayoutParams, int, Rect, InputChannel) line: 5664
WindowManagerService$Session(IWindowSession$Stub).onTransact(int, Parcel, Parcel, int) line: 68
WindowManagerService$Session.onTransact(int, Parcel, Parcel, int) line: 5636
WindowManagerService$Session(Binder).execTransact(int, int, int, int) line: 320
NativeStart.run() line: not available [native method]5. 观察 IPC 调用追踪
安卓系统进程间通信 (IPC) 通过 Binder 来实施。 一个任务调用一个函数,另外一项任务也能调用此函数,并通过执行任务获得结果。 有时候,我们希望观察 IPC 调用中不同任务之间的所有调用追踪。 幸运的是,binder IPC 具备同步功能。 也就是说,如果被调用者(callee)任务没有完成,则调用者(caller)任务不会返回。 所以,如果我们在被调用者任务中部署一个无限循环,调用者任务将在调用 IPC 时被阻止。 通过这种方式,我们能够观察被调用者和调用者任务的调用追踪。
要观察这两个任务,我们需要分别为每个任务启动一个 gdbserver/gdb 会话。 您可以通过调试工具 TCP 端口 1235 设置另外一个 C/C++ 项目 system_process_2 和另外一个调试配置。
- 按照 5.1 中的步骤操作,使用调试配置 system_process_1234 连接第一个任务。
- 按照相同的步骤,使用调试配置 system_process_1235 连接第二个任务。
注: 您需要修改 start_app.sh 以便将调试工具监听端口从 1234 指定为 1235,并使用 adb 向设备转发本地端口 1235。
- 使被调用者任务进入无限循环