JNI WARNING: illegal start byte

在尝试将一个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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值