您的位置:首页 > 其它

JNI WARNING: illegal start byte

2015-05-20 14:57 204 查看
在尝试将一个C的字符串转到java的字串符时,出错了,提示有非法字符。感觉非常奇怪,输入的数据确定为 utf-8 格式无误,不应该会出现非法的字符呀。查看LOG 发现非法的开始字符是 0xf0 ,感觉这个更奇怪了,因为根据utf-8的定义(http://baike.baidu.com/link?url=yrMBL7jXDhKy_LCUBL5QTZgx2Io2fCqRtp0mPBTjn-ArsSnQSWPFow89OaxkS_eSuhLpMsLoOs6HegDPp_kfIa)这个开始字符是合法的。

05-20 06:13:12.103: W/dalvikvm(1210): JNI WARNING: illegal start byte 0xf0

05-20 06:13:12.103: W/dalvikvm(1210): string: '测试客户端邮件大师?????? 发自我的iPad'

05-20 06:13:12.103: W/dalvikvm(1210): in Lcom/tec/mail/core/NativeInterface;.stringFromJNI (I)Ljava/lang/String; (NewStringUTF)

05-20 06:13:12.103: I/dalvikvm(1210): "main" prio=5 tid=1 NATIVE

05-20 06:13:12.103: I/dalvikvm(1210): | group="main" sCount=0 dsCount=0 obj=0xb6054c38 self=0x8e4ee48

05-20 06:13:12.103: I/dalvikvm(1210): | sysTid=1210 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-2145907712

05-20 06:13:12.103: I/dalvikvm(1210): at com.tec.mail.core.NativeInterface.stringFromJNI(Native Method)

05-20 06:13:12.103: I/dalvikvm(1210): at com.tec.mail.MainActivity$1.onClick(MainActivity.java:27)

05-20 06:13:12.103: I/dalvikvm(1210): at android.view.View.performClick(View.java:2485)

05-20 06:13:12.103: I/dalvikvm(1210): at android.view.View$PerformClick.run(View.java:9080)

05-20 06:13:12.103: I/dalvikvm(1210): at android.os.Handler.handleCallback(Handler.java:587)

05-20 06:13:12.103: I/dalvikvm(1210): at android.os.Handler.dispatchMessage(Handler.java:92)

05-20 06:13:12.103: I/dalvikvm(1210): at android.os.Looper.loop(Looper.java:130)

05-20 06:13:12.103: I/dalvikvm(1210): at android.app.ActivityThread.main(ActivityThread.java:3683)

05-20 06:13:12.103: I/dalvikvm(1210): at java.lang.reflect.Method.invokeNative(Native Method)

05-20 06:13:12.103: I/dalvikvm(1210): at java.lang.reflect.Method.invoke(Method.java:507)

05-20 06:13:12.103: I/dalvikvm(1210): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)

05-20 06:13:12.103: I/dalvikvm(1210): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)

05-20 06:13:12.103: I/dalvikvm(1210): at dalvik.system.NativeStart.main(Native Method)

05-20 06:13:12.103: E/dalvikvm(1210): VM aborting

(百度一下你就知道)导出这一错误是在android中chechjni.c里面的函数 checkUtfString;这个函数会对字符串进行检查,不符合它的标准就回出错。

源码如下:

/*

* Verify that "bytes" points to valid "modified UTF-8" data.

*/

static void checkUtfString(JNIEnv* env, const char* bytes, bool nullOk,

const char* func)

{

const char* origBytes = bytes;

if (bytes == NULL) {

if (!nullOk) {

LOGW("JNI WARNING: unexpectedly null UTF string/n");

goto fail;

}

return;

}

while (*bytes != '/0') {

u1 utf8 = *(bytes++);

// Switch on the high four bits.

switch (utf8 >> 4) {

case 0x00:

case 0x01:

case 0x02:

case 0x03:

case 0x04:

case 0x05:

case 0x06:

case 0x07: {

// Bit pattern 0xxx. No need for any extra bytes.

break;

}

case 0x08:

case 0x09:

case 0x0a:

case 0x0b:

case 0x0f: {

/*

* Bit pattern 10xx or 1111, which are illegal start bytes.

* Note: 1111 is valid for normal UTF-8, but not the

* modified UTF-8 used here.

*/

LOGW("JNI WARNING: illegal start byte 0x%x/n", utf8);

goto fail;

}

case 0x0e: {

// Bit pattern 1110, so there are two additional bytes.

utf8 = *(bytes++);

if ((utf8 & 0xc0) != 0x80) {

LOGW("JNI WARNING: illegal continuation byte 0x%x/n", utf8);

goto fail;

}

// Fall through to take care of the final byte.

}

case 0x0c:

case 0x0d: {

// Bit pattern 110x, so there is one additional byte.

utf8 = *(bytes++);

if ((utf8 & 0xc0) != 0x80) {

LOGW("JNI WARNING: illegal continuation byte 0x%x/n", utf8);

goto fail;

}

break;

}

}

}

return;

fail:

LOGW(" string: '%s'/n", origBytes);

showLocation(dvmGetCurrentJNIMethod(), func);

abortMaybe();

}

根据提示:Note: 1111 is valid for normal utf-8, but not the modified utf-8 used here.

原来是Google的utf-8是经过修改过的,对一些utf-8字符不兼容。虽然0xf0是合法的utf-8字符,但是修改后utf-8不使用这个字符

相关知识:

是否进行checkjni检查是由ro.kernel.android.checkjni决定。

在eng版本中ro.kernel.android.checkjni=1.而在user版本不做检查

解决方案:

一:
http://blog.csdn.net/livingpark/article/details/6050478
解决方法是使用字符串之前进行转换,使字符串符合要求,以下函数是一种方案,根据checkUtfString函数改写。

int char2UTF(char* cp)

{

char* bytes;

bytes = cp;

while (*bytes != '/0')

{

unsigned char utf8 = *(bytes++);

// Switch on the high four bits.

switch (utf8 >> 4) {

case 0x00:

case 0x01:

case 0x02:

case 0x03:

case 0x04:

case 0x05:

case 0x06:

case 0x07: {

// Bit pattern 0xxx. No need for any extra bytes.

break;

}

case 0x08:

case 0x09:

case 0x0a:

case 0x0b:

case 0x0f: {

/*

* Bit pattern 10xx or 1111, which are illegal start bytes.

* Note: 1111 is valid for normal UTF-8, but not the

* modified UTF-8 used here.

*/

LOGW("JNI WARNING: illegal start byte 0x%x/n", utf8);

*((unsigned char *)(bytes-1)) = 0x3f;

break;

}

case 0x0e: {

// Bit pattern 1110, so there are two additional bytes.

utf8 = *(bytes++);

if ((utf8 & 0xc0) != 0x80) {

LOGW("JNI WARNING: illegal continuation byte 0x%x/n", utf8);

*((unsigned char *)(bytes-1)) = 0x80;

}

// Fall through to take care of the final byte.

}

case 0x0c:

case 0x0d: {

// Bit pattern 110x, so there is one additional byte.

utf8 = *(bytes++);

if ((utf8 & 0xc0) != 0x80) {

LOGW("JNI WARNING: illegal continuation byte 0x%x/n", utf8);

*((unsigned char *)(bytes-1)) = 0x80;

}

break;

}

}

}

return 0;

}

二:调用java层String的构造函数

jstring StringC2JUTF(JNIEnv* env, CString src){

int lenght = src.GetLength();

jbyteArray byteContent = env->NewByteArray(lenght * sizeof(jbyte));

env->SetByteArrayRegion(byteContent, 0, (jsize)lenght, (jbyte *)LPCSTR(src));

jclass clsString = env->FindClass("java/lang/String");

jmethodID consID = env->GetMethodID(clsString, "<init>", "([BLjava/lang/String;)V");

jobject obj = env->NewObject(clsString, consID, byteContent, env->NewStringUTF("utf-8"));

return (jstring)obj;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐