android原生态音乐播放器中文歌曲乱码问题——没落的MIPS

基于android4.2,主要出现在mips架构,arm架构上没有此现象。

猜测与MediaScanner有关,一直跟代码,跟啊跟,跟啊跟。跟到frameworks/base/media/jni/android_media_MediaScanner.cpp文件的handleStringTag函数,它的实现如下:

119     virtual status_t handleStringTag(const char* name, const char* value)
120     {
121         ALOGE("handleStringTag: name(%s) and value(%s)", name, value);
122         jstring nameStr, valueStr;
123         if ((nameStr = mEnv->NewStringUTF(name)) == NULL) {
124             mEnv->ExceptionClear();
125             return NO_MEMORY;
126         }
127 
128         // Check if the value is valid UTF-8 string and replace
129         // any un-printable characters with '?' when it's not.
130         char *cleaned = NULL;
131         if (utf8_length(value) == -1) {
132             cleaned = strdup(value);
133             char *chp = cleaned;
134             char ch;
135             while ((ch = *chp)) {
136                 if (ch & 0x80) {
137                     *chp = '?';
138                 }   
139                 ALOGE("handleStringTag: value(%x)",ch);
140                 chp++;
141             }   
142             value = cleaned;
143         }   
144         valueStr = mEnv->NewStringUTF(value);
145         free(cleaned);
146         if (valueStr == NULL) {
147             mEnv->DeleteLocalRef(nameStr);
148             mEnv->ExceptionClear();
149             return NO_MEMORY;
150         }   
151         
152         mEnv->CallVoidMethod(
153             mClient, mHandleStringTagMethodID, nameStr, valueStr);
154             
155         mEnv->DeleteLocalRef(nameStr);
156         mEnv->DeleteLocalRef(valueStr);
157         return checkAndClearExceptionFromCallback(mEnv, "handleStringTag");
158     }   

看131行,就是utf8_length()这个函数调用返回-1,才导致歌曲的名字都设置成了“?”。其实已经测试过了,arm架构返回的值不等于-1.

那就看下函数utf8_length()的实现,找到在frameworks/native/libs/utils/Unicode.cpp中:

364 ssize_t utf8_length(const char *src)
365 {
366     const char *cur = src;
367     size_t ret = 0;
368     while (*cur != '\0') {
369         const char first_char = *cur++;
370         if ((first_char & 0x80) == 0) { // ASCII
371             ret += 1;
372             continue;
373         }
374         // (UTF-8's character must not be like 10xxxxxx,
375         //  but 110xxxxx, 1110xxxx, ... or 1111110x)
376         if ((first_char & 0x40) == 0) {
377             return -1;
378         }   
379         
380         int32_t mask, to_ignore_mask;
381         size_t num_to_read = 0;
382         char32_t utf32 = 0;
383         for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80;
384              num_to_read < 5 && (first_char & mask);
385              num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
386             if ((*cur & 0xC0) != 0x80) { // must be 10xxxxxx 
387                 return -1;
388             }   
389             // 0x3F == 00111111
390             utf32 = (utf32 << 6) + (*cur++ & 0x3F);
391         }   
392         // "first_char" must be (110xxxxx - 11110xxx)
393         if (num_to_read == 5) {
394             return -1;
395         }   
396         to_ignore_mask |= mask;
397         utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1));
398         if (utf32 > kUnicodeMaxCodepoint) {
399             return -1;
400         }   
401         
402         ret += num_to_read;
403     }   
404     return ret;
405 }   
看起来像是判断utf-8的格式,返回-1的地方有多个,测试了一下是在399行返回的,utf32的值大于kUnicodeMaxCodepoint,kUnicodeMaxCodepoint的定义如下:

static const char32_t kUnicodeMaxCodepoint        = 0x0010FFFF;
打印了一下(~to_ingnore_mask)、first_char和num_to_read的16进制的值,发现first_char的高位全是F,这个非常不正常。first_char的定义在369行:

 const char first_char = *cur++;

一个正常的char类型的高位不是F的,为何有这样的结果?慢慢分析后发现first_char与mask以及to_ingnore_mask这两个变量运算过,它们的类型是int32_t,类型不一样就涉及到类型转换。原来,在char类型扩展到32位时,高位要补0。在arm架构里,char类型的默认扩展是无符号扩展,而在mips是有符号扩展,所以高位全补了1,导致运算出来的utf32的高位全是F,所以它的值大于kUnicodeMaxCodepoint。

如何解决?其实很简单,把first_char声明为无符号类型就可以了:

const unsigned char *first_char = *cur++;

其实这个是google程序员写程序时没注意到的细微的地方,但是在goldfish上跑明显有中文歌曲乱码的bug存在,在这种情况下也把源码发布,这个就有点说不过去。结合之前TraceView Issue 这篇文章,可以看出android在支持mips架构时已经不想花太多的精力。不过市场上的android设备跑mips的确实不多。君正不知道还有没有搞mips的soc!mips注定要没落吗!?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值