Linux环境下android平台调试native代码, 从java debug 到C++ (NDK DEBUG)

时间:2024-03-27 21:12:02

研究了两天,今天终于成功,拿来分享,其中还有些东西知其然却不知其所以然,在以后的学习中再慢慢研究吧。如果你还不了解android NDK开发,可以参考我的另外一篇文章(http://blog.csdn.net/dfqin/article/details/6290095

现在的android工程,常会将一些核心代码用C++实现,原因各异,防止反编译、运行效率、老代码重用等等,这些不是重点,重点是当我们在java代码中通过JNI调用C++代码,程序crash了,而C++方面却检查不到错误原因,如果不从通过从JAVA代码debug,一路跟到C++代码,很难重现程序挂掉的原因。于是native code debug的问题就出现了。理论上android native是基于linux的,调试不是难事,早有开源的gdb可以在linux下调试,现在的问题是程序是运行在设备上,而且是从java代码跟踪到C++代码,这个就有点复杂了,android官方从NDK4r开始支持了native debug,但没有找到官方文档和例子,在网上也找了不少文章,看到了几种方法实现,自己调试了几天,最终实现了其中一种最友好的调试方法,记录在此分享,其它的几种方法有时间再继续测试。

另外,在此提一下,很多时候你并不需要调试跟踪到C++,通过程序输出的错误地址,反找.so包可以定位到程序出错到C++程序的那个文件第几行,可以通过NDK提供的一个小工具arm-eabi-addr2line来实现,方法可以参考(http://www.codexperiments.com/android/2010/08/tips-tricks-debugging-android-ndk-stack-traces/)。

我之前说过,有多种调试的方法(最终还是基于gdb),有通过gdb直接调试的,有通过cgdb的,还有基于eclipse IDE进行可视化调试的,有在Linux系统上的,还有在Windows系统上的,我实现的是在虚拟机安装Linux(Ubuntu)系统通过Eclipse进行调试,其它的方法如果成功了,有机会再补上来吧。我的平台:VMware下安装的Ubuntu系统,Eclipse 3.6.2,android sdk 2.2/2.3.1,NDK5r,CDT7.0,Sequoyah2.0。NDK6r也可以,但是没法用sequoyah插件(sequoyah的一个bug,因为ndk内部目录调整,它找不到对应的文件)。

首先,建议是下载一个全新的Eclipse(原文作者建议),至少是3.6以上的版本,我的是3.62,一个同事装的是3.7,这个本来不是必须的,但它需要的一个插件要求对应的Eclipse版本是3.6以上的,所以对于我的实现方法,它是必须的。在这里用到两个插件:CDT和Sequoyah,CDT是必须的,support在eclipse上进行C++开发。Sequoyah可以不要,但装上了会方便很多(帮你生成.mk文件,自动编译生成.so文件),我的实现主要是基于这篇文章(http://www.eclipse.org/sequoyah/documentation/native_debug.php),大家如果看不懂我写的,可以直接参考原文,还有其它参考的网站,到最后我也会列出来。搭建linux平台和安装Eclipse,配置android开发环境,我就不讲了,现在是在假设你已有一个Linux系统,且可以在eclipse上跑出android程序Hello Android World上进行的。

1.安装CDT插件,我安装的是CDT7.0,更高的版本应该也可以。如果你下载的Eclipse已经集成了CDT,可以跳过这步。我选择的是先下载到本地在安装的,里面有很多子包可以不装,我选择的是sequoya依赖的那些包(见原文中有图),当然全装了绝对没有坏处,地址(http://www.eclipse.org/cdt/)。

2.安装Sequoyah插件,我安装的是2.0版本,而且我测试的通过URL直接安装连接不上,也是下载安装的。地址(http://www.eclipse.org/sequoyah/downloads/)。

3.把你的android sdk下的adb和ndk下面的ndk-gdb添加到系统路径中(这样你在终端输入abd或ndk-gdb时才能识别这个命令)。

4.建一个普通的android工程。界面上只有一个button,点击后改变button的text显示的内容。

Linux环境下android平台调试native代码, 从java debug 到C++ (NDK DEBUG)

5.修改它的配置文件Debuggable为true。

Linux环境下android平台调试native代码, 从java debug 到C++ (NDK DEBUG)

6.指定NDK目录。Window->Preferences->Android->Native Development。

Linux环境下android平台调试native代码, 从java debug 到C++ (NDK DEBUG)

7.通过sequoyah生成jni目录,android.mk文件和一个空的C++文件,如果你没安装sequoyah,可以自己创建(参考http://blog.csdn.net/dfqin/article/details/6290095)。通过sequoyah生成jni目录等的方法为:右击工程->android Tools->add Native support...

Linux环境下android平台调试native代码, 从java debug 到C++ (NDK DEBUG)

8.实现native代码。native代码的方法是根据包名加方法名生成的,你可以直接在生成的cpp文件中写,如果不会写 ,也可以通过javah生成头文件,然后把头文件中的代码粘贴过来。(参考http://blog.csdn.net/dfqin/article/details/6290095)。

Linux环境下android平台调试native代码, 从java debug 到C++ (NDK DEBUG)

9.现在已经完成了一个包含JNI调用的android工程,先测试一下程序运行是否正确。如果安装了sequoyah插件,编译工程时会自动生成.so文件。

10.如果程序没有问题,就在java代码JNI调用的地方打个断点,同时也在C++代码中被调用的方法内打个断点,关键时刻到来了!

Linux环境下android平台调试native代码, 从java debug 到C++ (NDK DEBUG)

11.右键你的工程->debug as->android application,程序运行到断点处暂停(我的代码中,程序运行成功后,我点模拟器界面中的button,断点才会hit)。此时到了正常java调试的状态,保持这个状态,下面要配置C++调试环境了。

Linux环境下android平台调试native代码, 从java debug 到C++ (NDK DEBUG)

12. 找到你的NDK目录下的ndk-gdb文件,编辑内容,把最后一行“$GDBCLIENT -x `native_path $GDBSETUP`”注释掉并保存。在终端下面进入android工程目录,输入“ndk-gdb”并回车,此时终端应该没有什么输出,但它会在你的工程目录(app->obj->local->armeabi)下生成app_process和gdb.setup等几个文件。

13.右键你的工程->debug as->debug configurations...,在新窗口中选中“C/C++ Application ”,点击上面图标菜单“new launch configuration”,创建一个新的C++配置文件。选中自己创建的配置文件,它的name可以用默认的,在main选项卡,“C/C++ Application:"指定你工程目录下的app_process文件, "Build configuration"选 Use Active, 下面选“Disable auto build",点击下面的“select other...",在弹出的选项卡里勾选”use configuration specific setting",选中下面的Standard Create Process Launcher确定。

Linux环境下android平台调试native代码, 从java debug 到C++ (NDK DEBUG)

Linux环境下android平台调试native代码, 从java debug 到C++ (NDK DEBUG)

14. 选中Debugger选项卡,“Debugger:"选gdbserver, 下面的"GDB debugger" 选你NDK 目录下的arm-linux-androideabi-gdb(), 把你工程目录下的gdb.setup文件改成gdb2.setpu,并打开编辑,把最后一行“target remote :5039”删掉。 "GDB command file:"选你工程目录下的那个gdb2.setup文件(改名的原因应该是怕下次执行ndk-gdb时生成新的文件,把它覆盖掉)。

Linux环境下android平台调试native代码, 从java debug 到C++ (NDK DEBUG)

15.点击"Connection“子选项卡,选“TCP”,localhost, 5039.这个5039不能改成别的,因为在ndk-gdb里面写死了,硬编码害死人啊,我就是因为这个端口号改了,怎么也无法成功。接下来点"Apply",先应用了,然后点"Debug",这时你会看到Eclipse的Console中输出已经启动了gdb, 回到你的java程序断点处,按F6,此时程序就会跟进C++代码,当然你的C++代码要提前打好断点。

Linux环境下android平台调试native代码, 从java debug 到C++ (NDK DEBUG)

Linux环境下android平台调试native代码, 从java debug 到C++ (NDK DEBUG)

16.如果下次重新打开工程,想进行调试,只需要(1)debug程序在JAVA代码断点处停止。(2)在终端下进入工程目录,运行ndk-gdb。(3)点debug图标后面的小三角,选你之前创建的C++配置文件或者debug as ->debug configuration找到你的配置文件点debug。

OK,至此结束,转载请声明出处。