如何在真实设备上调试Android原生代码

5
我遇到了一些与Android媒体后端(主要是Stagefrightplayer)相关的问题,我想了解为什么它会抛出这些错误。这些错误通常是设备特定的,因此在模拟器上进行调试是不够的。
例如:
I/AwesomePlayer(  147): mConnectingDataSource->connect() returned -1004
V/MediaPlayerService(  147): [332] notify (0x272830, 100, 1, -1004)
E/MediaPlayer(24881): error (1, -1004)
E/MediaPlayer(24881): Error (1,-1004)
W/PlayerListener(24881): Received error: what = 1, extra = -1004

示例 2:

E/MediaPlayer(  941): error (1, -2147483648)

我也让播放器完全崩溃并输出了一个traces.txt。

有没有办法像调试Java代码一样调试发生的情况?谢谢。


这是来自C++用户空间代码的内容,与内核无关。请参阅git://android.git.kernel.org/platform/frameworks/base.git/media/jni/android_media_MediaPlayer.cpp和类似的内容。 - Christopher Orr
谢谢。但仍然有一个问题:可以调试这个问题吗?例如,使用远程GDB会话? - neu242
7个回答

9

你可以做很多事情。

如果你认为错误在框架本身中,那么获取源代码并挖掘 http://source.android.com/

否则,Android最好的调试器是DDMS,它可以与模拟器一起使用,也可以与实际设备一起使用。http://developer.android.com/guide/developing/tools/ddms.html

通过adb(http://developer.android.com/guide/developing/tools/adb.html)进行dumpstate还会为您提供设备上正在发生的完整快照,但是很难获得错误发生的确切时间点。

虽然这仍然无法像GDB一样提供源级别的调试,或者我不确定您通常调试Java代码的方式。

如果您真的指的是内核作为内核,那么您现在并不真正处于Android中,而更多地处于Linux世界中,但我认为您不需要走那么远。

如果您遇到特定的Android应用程序(不是开源且不是您自己的应用程序)出现问题,恐怕您就没什么办法了。
对于MediaPlayer部分,Eclair版本的文件位于https://android.googlesource.com/platform/frameworks/base/+/eclair-release/media/java/android/media/MediaPlayer.java,但无法找到您所放置的具体错误消息。

2

虽然这并不是直接回答你的问题,但这些信息可能对你有用。

根据您收到的-1004错误代码,您尝试流式传输时发生了I/O错误。至于-2147483648错误代码,我无法提供太多帮助。您需要查看媒体播放器的所有日志输出,以查看为什么会得到该代码,因为它没有定义。我曾经遇到过解码器在视频编码方面出现问题而导致此错误。

引用自:/frameworks/base/include/media/stagefright/MediaErrors.h

MEDIA_ERROR_BASE = -1000,

ERROR_ALREADY_CONNECTED = MEDIA_ERROR_BASE,
ERROR_NOT_CONNECTED     = MEDIA_ERROR_BASE - 1,
ERROR_UNKNOWN_HOST      = MEDIA_ERROR_BASE - 2,
ERROR_CANNOT_CONNECT    = MEDIA_ERROR_BASE - 3,
ERROR_IO                = MEDIA_ERROR_BASE - 4,
ERROR_CONNECTION_LOST   = MEDIA_ERROR_BASE - 5,
ERROR_MALFORMED         = MEDIA_ERROR_BASE - 7,
ERROR_OUT_OF_RANGE      = MEDIA_ERROR_BASE - 8,
ERROR_BUFFER_TOO_SMALL  = MEDIA_ERROR_BASE - 9,
ERROR_UNSUPPORTED       = MEDIA_ERROR_BASE - 10,
ERROR_END_OF_STREAM     = MEDIA_ERROR_BASE - 11,

2
即使您无法在内核级别上进行调试,将难以理解的错误号追踪到正确的头文件(和描述性定义)仍然可能很有用。
-1004 表示 ERROR_IO,可以在 MediaErrors.h 中找到:
https://android.googlesource.com/platform/frameworks/base/+/eclair-release/include/media/stagefright/MediaErrors.h#32 -2147483648 可能是 UNKNOWN_ERROR,可以在 Errors.h 中找到:
https://android.googlesource.com/platform/frameworks/base/+/eclair-release/include/utils/Errors.h#49 正如您在 Errors.h 中所看到的那样,它包括 errno.h,其中包含内核级别错误代码,/kernel/include/asm-generic/errno.h。
例如,如果connect()返回错误代码-110,你就会知道这是超时引起的,因为它被定义为:
#define ETIMEDOUT       110     /* Connection timed out */

2

远程调试(目标机上的gdbserver +主机上的gdb)可用于在实际硬件上运行C/C++用户空间代码。它提供了所有“通常”的选项,如断点、回溯、查看/设置变量、跟踪点。

有关详细信息,请查看Android构建系统的“gdbclient”shell函数,预构建eabi gdb和可能的DDD或其他前端。Eclipse也应该可以。


1
尽管Android确实支持远程GDB会话,但对于内核代码来说这可能无法正常工作。最好的选择是使用JTAG连接进行停止模式调试。由于停止模式调试有效地暂停了CPU的执行,您可能会发现这会导致看门狗定时器出现问题。
另外,将跟踪插入内核代码可能更容易一些。

谢谢,但是...将跟踪插入我的Java代码如何帮助调试内核代码?请耐心等待,我很无知 :p - neu242

1
你可以用几种不同的方法来实现这一点。首先,您需要找出要调试的服务是Java框架服务(例如system_server)还是纯本机应用程序(例如surfaceflinger)。
如果它是纯本机服务,请查看调试Android平台本机应用程序文章。
如果该服务是托管在system_server进程中的Java代码,请查看调试Android Java框架服务文章。
如果您想调试的代码是通过JNI隐式加载到Java服务中的本机库,请查看调试Android框架本机库文章。

0

除非你想在汇编级别调试,否则你可能需要自己构建一个启用了调试和调试符号的内核。我认为大多数小型设备中的内核默认情况下都会避免这样做,因为它会使内核变得更大。此时,你可以启用内核调试器...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接