NDK技巧
- 加快ndk-build编译速度
NDK编译时加上-j参数,如:
1
ndk-build -j4 # -j4,让make最多允许4个编译命令同时执行
测试后编译速度至少可以提高一倍
native崩溃分析
定位crash错误位置
首先我们要先把Logcat里的show only selected application选项改成No Filters, 这时就能看到系统打印出的DEBUG信息. 在DEBUG信息里找到backtrace, 这段就是系统给出的造成崩溃的信息, 但仅仅给出了是哪个函数, 而没有准确给出是那一行代码造成的崩溃. 记下#00 pc 00013122(红框3)这个信息, 这个信息就是用来定位崩溃代码的地址
1 | 12-27 10:45:41.580 6189-6761/com.wodekouwei.demo E/HwDecodeWrapper: dequeueOutputBuffer = -1 |
想要准确定位崩溃代码的地址的话我们就需要用到ndk工具包里的adrr2line这个工具了 首先先找到这个工具, linux系统这个工具在如下位置
1 | /home/gavinandre/Documents/Android/android-sdk-linux/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-addr2line |
在该目录下做个软链接后就能在任何目录使用这个命令了
1 | sudo ln -s arm-linux-androideabi-addr2line /usr/local/bin/addr2line |
找到造成崩溃的so文件地址, 在app目录下搜索so文件
1 | find . -name "liboarp-lib.so" ✘ |
可以看到android studio编译后生成了许多so文件, 以我的经验正确的so文件一般是这个文件:./srsrtmpplayer/build/intermediates/transforms/mergeJniLibs/debug/0/lib/armeabi-v7a/liboarp-lib.so
然后就可以使用addrline命令了, 格式是addr2line -e 文件位置 崩溃地址
:
1 | addr2line -e ./srsrtmpplayer/build/intermediates/transforms/mergeJniLibs/debug/0/lib/armeabi-v7a/liboarp-lib.so 000ccb4c |
如果so文件正确的话会打印如下信息,oar_player_gl_thread.c就是崩溃的cpp文件, 152, 然后检查下定位出来的位置是否在DEBUG信息里给出的函数里
1 | oar_player_gl_thread.c:152 |
如果so文件错误的话会打印问号或者一个不对的位置, 这时就要换so文件多尝试了
C回调JAVA
c中返回一个字符串
1
(*env)->NewStringUTF(env,"Huazi 华仔");
c中返回一个数组
1
2
3
4
5
6
7
8
9
10.....................
int i = 0;
jintArray array;
array =(*env)->NewIntArray(env,8);
for(;i<8;i++)
// 赋值成 0 ~ 7
(*env)->SetObjectArrayElement(env,array,i,i);
}
return array;c中使用调用传入的参数是数组array 是传入的数组
1
2
3
4
5
6
7
8
9.........
int sum =0, i;
int len = (*env)->GetArrayLength(env,array);
jint *element =(*env)->GetIntArrayElement(env,array,0);
for(i=0;i<len;i++)
{
sum+= *(element+i);
}
return sum;c中调用java中类的方法 没有参数 只有返回值String
1
2
3
4
5
6
7//()Ljava/lang/String;" 表示参数为空 返回值是String类型
JNIEXPORT jstring JNICALLJava_com_huazi_Demo_getCallBack(JNIENV env,jobject object){
jmethodID mid;
jclass cls =(*env)->FindClass(env,"com/huazi/Demo"); //后面是包名+类名
mid =(*env)->GetMethodID(env,cls,"TestMethod","()Ljava/lang/String;");//TestMethod java中的方法名
jstring msg =(*env)->CallObjectMethod(env,object,mid); //object 注意下是jni传过来的jobject
return msg;c中调用java中类的静态方法 没有参数 只有返回值String
1
2
3
4
5
6
7
8//@"()Ljava/lang/String;" 表示参数为空 返回值是String类型
JNIEXPORT jstring JNICALLJava_com_huazi_Demo_getCallBack(JNIENV env,jobject object){
jmethodID mid;
jclass cls =(*env)->FindClass(env,"com/huazi/Demo"); //后面是包名+类名
mid =(*env)->GeStatictMethodID(env,cls,"TestMethod","()Ljava/lang/String;");// TestMethod java中的方法名
jstring msg =(*env)->CallStaticObjectMethod(env,cls,mid); //object 注意下是jni传过来的jobject
return msg;
}