1.Create Android Studio Project
(1)新建一个Empty Activity工程:TestNDK
(2)在工程的主Activity中加入对.so的引用.这步很关键,将System loadLibrary放入主Activity,是让程序启动后立刻加载.so,否则后面调试时,会有些麻烦
static {
// Load native library to invoke chreographerCallback().
System.loadLibrary("DebugNDK");
}
public native String stringFromJNI();
(3)使用javah生成相应的.h文件
在Android Studio的Terminal窗口中输入:
cd app\src\main\java #进入工程的app\src\main\java目录
javah stable.testndk.MainActivity #生成.h文件,stable.testndk是包名,MainActivity是native函数所在的类名
接下来就可以编译NDK了,NDK编译完再回来
(4)将NDK编译出的libs目录下的文件copy到app\libs目录下,如下:
app\libs\armeabi\
gdb.setup
gdbserver
libDebugNDK.so
app\libs\armeabi-v7a\
gdb.setup
gdbserver
libDebugNDK.so
app\libs\mips\
gdb.setup
gdbserver
libDebugNDK.so
app\libs\x86\
gdb.setup
gdbserver
libDebugNDK.so
(5)修改app\build.gradle,在android下加入如下代码,告知jniLibs所在目录
sourceSets {
main() {
jniLibs.srcDirs = [‘libs‘]
}
}
(6)rebuild工程,可以通过Build->Build APK来生成APK,然后用7Zip看一下里面是将.so打包进去了.
接下来进入第三步调试NDK
2.NDK程序的编译
(1)以 android-ndk-r10b\samples\hello-jni为模板,建立自己的NDK程序(DebugNDK).
自己的程序需要修改Android.mk文件,增加工程及代码文件,这里将所有的hello-jni更改为DebugNDK.
修改DebugNDK.c中的jni对外接口函数名,修改为上面使用javah到处的.h中的相应函数(Java_stable_testndk_MainActivity_stringFromJNI).
(2)编译.so
在windows命令行下,进入工程目录(TestNDK目录),输入如下命令:
ndk-build NDK_DEBUG=1 #注意事先要将ndk-build所在目录设置到系统环境变量中
之后开始编译,最终在工程目录下会生成libs和obj两个目录,其中libs目录下的是发布到硬件的.so, obj下是用于调试的,后面会用到.
好了到此可以回到 上面个 Create Android Studio Project 的第4步了.
3.NDK调试
服务器端配置
(1)在手机上运行TestNDK程序
(2)将编译NDK程序时生成的gdbserver pull到手机(我是放到/data/data/stable.testndk.
gdbserver在app\libs\x86\下,可以将其放到手机 /data/data/stable.testndk/lib 下
在windows命令行下,执行:
adb push .\app\libs\x86\gdbserver /data/data/stable.testndk/lib/
(3)在手机上启动gdbserver并attach你想调试的进程,并指定监听调试命令的端口(此端口是手机上的端口)
在windows命令行下,执行:
adb shell #进入手机
cd /data/data/stable.testndk/lib
ps | grep stable.testndk #查看要调试进程的PID
gdbserver :1818 --attach 19906 #:1818是端口号,19906 是进程ID
此时,终端终端上会显示:
Attached; pid = 19906
Listening on port 1818
台式机端配置
(1)使用adb做端口映射,将pc机上的端口定向到手机上gdbserver监听的端口
adb forward tcp:1818 tcp:1818 #端口映射,将pc机的1818端口映射到手机的1818端口
(2)将设备上的app_process32拉到台式机,用于gdb调试.
adb pull /system/bin/app_process32 ./
(3)使用android-ndk-r10b\toolchains下的gdb客户端去连接gdbserver,gdb的类型要选择针对手机平台的,由于我使用的手机是x86 PC模拟器,因此要选择:
android-ndk-r10b\toolchains\x86-4.8\prebuilt\windows-x86_64\bin\i686-linux-android-gdb.exe
并且gdb版本要和gdbserver一致。(可以通过--version来确认)
在windows命令行下,执行如下命令,app_process32_path 表示app_process32所在目录。
android-ndk-r10b\toolchains\x86-4.8\prebuilt\windows-x86_64\bin\i686-linux-android-gdb.exe {app_process32_path}\app_process32
上面的命令执行完后,便进入gdb命令模式了(命令行前有(gdb)),然后执行:
target remote :1818 #连接本地的:1234端口,此端口已经和手机的1234端口做好映射。
set solib-search-path {solibpath} #加载所有的动态连接库,solibpath的路径位置可以参考:NDK编译输出文件 gdb.setup 中的"set solib-search-path XXX"的目录,但注意要使用绝对目录.
#我的是set solib-search-path D:/Android/android-ndk-r10b/samples/TestNDK/obj/local/x86
然后用info shared命令查看是否libDebugNDK.so的符号库已经加载,我的显示的是:
0xaabd92e0 0xaabd93c8 Yes D:\Android\android-ndk-r10b\samples\TestNDK\obj\local\x86\libDebugNDK.so #如果符号库未加载则在Yes后有个(*).
(4)设置断点,开始调试
在gdb模式,执行:
b Java_stable_testndk_MainActivity_stringFromJNI #设置断点
c #运行
然后在函数调用时,断点就可以停住了! Over!