安卓* 系统级 Java*/C++ 代码调试(四)

2014-11-24 01:34:11 · 作者: · 浏览: 4
安卓服务 C/C++ 调试工具

暂停任务、转至 Console(控制台)并输入命令“thread 1”和“go”。

thread 1
[Switching to thread 1 (Thread 1561)]
#0 0x08049663 in main (argc=1, argv=0xbf9a3d64) at external/mtpd/mtpd.c:155
155 {
go
android service in dead loop, trying to restore...done

现在我们可以设置断点并对其进行调试。

5 同时进行 Java 和 C/C++ 调试

5.1 观察从 Java 到原生的所有调用追踪

有时候,我们希望观察从 Java 到原生的所有调用追踪。 要实现这一点,我们需要使用前面介绍的两种 Java 和 C/C++ 调试技巧。

  1. 使用脚本 start_system_server.sh 或 start_app.sh,使 system_process 和应用进入无限循环模式。
  2. 使用 DDMS 连接至 system_process 或应用。
  3. 输入“go”命令,使 system_process 或应用退出无限循环。
  4. 使用您感兴趣的原生函数来切换 C/C++ 断点。
  5. 输入“loop”命令,使原生函数进入无限循环模式。
  6. 开始运行。
  7. 现在转至安卓调试工具,停止线程,并检查每个线程的调用堆栈。 分别找到调用原生函数的线程,以及处于无线循环模式中的线程。

    然后合并 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 和另外一个调试配置。

    1. 按照 5.1 中的步骤操作,使用调试配置 system_process_1234 连接第一个任务。
    2. 按照相同的步骤,使用调试配置 system_process_1235 连接第二个任务。

      注: 您需要修改 start_app.sh 以便将调试工具监听端口从 1234 指定为 1235,并使用 adb 向设备转发本地端口 1235。

      1. 使被调用者任务进入无限循环