Troubleshooting
在开发阶段,logging让你决定和展示有利于解决问题关于应用程序的状态的信息。
通过logging的展示的信息对于Debugging很重要但是这是不够的,但是
应该知道错误发生在哪里。当面对这无法预期的错误时,错误
定位成为了一个拯救者。知道了正确的工具和技术使你能迅速的解决问题。
栈追踪分析:
为了观察栈,你将安装一个bug在hello-jni实例应用程序中将引发程序
崩溃。使用Eclipse,打开着hello-jni.c的源文件。修改本地函数的
内容如下:
static jstring func1( JNIEnv* env )
{
/* BUG BEGIN */
env = 0;
/* BUG END */
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return func1(env);
}
通过设置JNIEnv的接口指针的值为0,你将触发这个崩溃。现在建立
和运行这个应用程序。当应用程序开始,点击Call本地方法来触发这
本地的功能。这应用程序崩溃,和一个栈的几率被展示在logcat中
如下:
带有崩溃信号的开始行指示这栈的调用。#00的开始行是崩溃发生的
。接下的一行,#01,是上一个函数的调用,等等。在这PC的后面这
数子是代码的地址。正如在栈记录所看到的,这本地代码的崩溃在地址
000003c处,和上一个函数调用时stringFromJNI本地函数。这个000003c
地址本身可能不会告诉你太多,但是使用正确的工具这个地址能够
被用来发现真正的文件盒crash发生的行。Android NDK带有ndk-stack
工具能够把栈记录到真正文件的名字和行号。在命令行,进入项目根目录
,使用
adb locat|ndk-stack -sym 0bj/local/armabi
这ndk-stack工具将翻译栈,如下。地址得到翻译到jni/hello-jni.c在
源文件33行。这些信息使错误定位更加容易。通过简单放置一个断点在
地址上你能够阻止应用程序和监听应用程序的状态。
JNI的扩展检测:
默认情况下,JNI函数做非常少的错误检测。错误经常导致程序崩溃。Andoid
提供一个扩展的检测模式对于JNI调用,如CheckJNI。当开启下,JavaVM
和JNIENV接口指针转到了函数表来执行一个扩展水平的错误检测在调用
真正的实现前。CheckJNI能够侦测接下的问题:
设法分配一个负数长度的数组
Bad或NULL指针被传递给JNI函数
当传递给类名时,语法错误
当在critical部分是,JNI调用
错误的参数当传递到NEWDirectByeBuffer
当一个异常发生时JNI调用
JNIEnv接口指针被用作错误线程
Field类型和set<Type>Fiel函数不搭配
函数类型和Call<Type>Method函数不搭配
DeleteGlobalRef/DeleteLocalRef调用有错误引用类型
错误的释放模式被传递到Release<Type>ArrayElement函数
不兼容的错误类型返回从本地方法
传递到一个JNI调用无效的UTF-8序列。
默认情况下,在模拟器上CheckJNI模式开启的,但是并不在常用的
Andoid设备上,由于它在系统性能的影响。
开启ChckJNI:
在一个regular设备上,使用命令行,你能够开启CheckJNI模式通过
使用:adb shell setprop debug.checkjni 1
这并不影响着运行的应用程序但是任何应用程序开启向导使
CheckJni开启。CheckJNI状态被展示在logcat中,如下:
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
jintArray javaArray = (*env)->NewIntArray(env, -1);
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
创建了一个负长度的整形数组。建立和运行应用程序在模拟器上。当
应用程序开启,点击Call本地按钮来触发本地方法。如下,CheckJNI将
展示一个警告信息在logcat和终止执行。
在开发阶段,logging让你决定和展示有利于解决问题关于应用程序的状态的信息。
通过logging的展示的信息对于Debugging很重要但是这是不够的,但是
应该知道错误发生在哪里。当面对这无法预期的错误时,错误
定位成为了一个拯救者。知道了正确的工具和技术使你能迅速的解决问题。
栈追踪分析:
为了观察栈,你将安装一个bug在hello-jni实例应用程序中将引发程序
崩溃。使用Eclipse,打开着hello-jni.c的源文件。修改本地函数的
内容如下:
static jstring func1( JNIEnv* env )
{
/* BUG BEGIN */
env = 0;
/* BUG END */
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return func1(env);
}
通过设置JNIEnv的接口指针的值为0,你将触发这个崩溃。现在建立
和运行这个应用程序。当应用程序开始,点击Call本地方法来触发这
本地的功能。这应用程序崩溃,和一个栈的几率被展示在logcat中
如下:
带有崩溃信号的开始行指示这栈的调用。#00的开始行是崩溃发生的
。接下的一行,#01,是上一个函数的调用,等等。在这PC的后面这
数子是代码的地址。正如在栈记录所看到的,这本地代码的崩溃在地址
000003c处,和上一个函数调用时stringFromJNI本地函数。这个000003c
地址本身可能不会告诉你太多,但是使用正确的工具这个地址能够
被用来发现真正的文件盒crash发生的行。Android NDK带有ndk-stack
工具能够把栈记录到真正文件的名字和行号。在命令行,进入项目根目录
,使用
adb locat|ndk-stack -sym 0bj/local/armabi
这ndk-stack工具将翻译栈,如下。地址得到翻译到jni/hello-jni.c在
源文件33行。这些信息使错误定位更加容易。通过简单放置一个断点在
地址上你能够阻止应用程序和监听应用程序的状态。
JNI的扩展检测:
默认情况下,JNI函数做非常少的错误检测。错误经常导致程序崩溃。Andoid
提供一个扩展的检测模式对于JNI调用,如CheckJNI。当开启下,JavaVM
和JNIENV接口指针转到了函数表来执行一个扩展水平的错误检测在调用
真正的实现前。CheckJNI能够侦测接下的问题:
设法分配一个负数长度的数组
Bad或NULL指针被传递给JNI函数
当传递给类名时,语法错误
当在critical部分是,JNI调用
错误的参数当传递到NEWDirectByeBuffer
当一个异常发生时JNI调用
JNIEnv接口指针被用作错误线程
Field类型和set<Type>Fiel函数不搭配
函数类型和Call<Type>Method函数不搭配
DeleteGlobalRef/DeleteLocalRef调用有错误引用类型
错误的释放模式被传递到Release<Type>ArrayElement函数
不兼容的错误类型返回从本地方法
传递到一个JNI调用无效的UTF-8序列。
默认情况下,在模拟器上CheckJNI模式开启的,但是并不在常用的
Andoid设备上,由于它在系统性能的影响。
开启ChckJNI:
在一个regular设备上,使用命令行,你能够开启CheckJNI模式通过
使用:adb shell setprop debug.checkjni 1
这并不影响着运行的应用程序但是任何应用程序开启向导使
CheckJni开启。CheckJNI状态被展示在logcat中,如下:
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
jintArray javaArray = (*env)->NewIntArray(env, -1);
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
创建了一个负长度的整形数组。建立和运行应用程序在模拟器上。当
应用程序开启,点击Call本地按钮来触发本地方法。如下,CheckJNI将
展示一个警告信息在logcat和终止执行。