前兩篇在這里:
最近遇到的問題是,
java.io.IOException: FAT Full
StackOverflow的結果:
http://stackoverflow.com/questions/18906055/what-causes-jobb-tool-to-throw-fat-full-ioexception
提問者自己解釋了原因, 原因是obb超過512M就出錯了. 但是FAT16最大可以支持2G, 這個是jobb的bug.
同時作者提供了jobb修復的代碼和bin:
https://github.com/monkey0506/jobbifier/tree/master/jObbifier/bin (由於不懂Java/eclipse,花了點時間才編譯打包出來)
最后關於在native下 mount一直報錯的問題(AOBB_STATE_ERROR_INTERNAL, AOBB_STATE_ERROR_COULD_NOT_MOUNT)
logcat沒有任何輸出, 同時網上也沒有任何解決方法可以解決我這里遇到的問題.
最后改用在java端mount, 竟然毫無錯誤的成功了...表示很無語. What's wrong with the NDK team? why mounting obb in native fails but in Java end succeeds?
另外, 網上可以找到關於native API code里的問題 https://code.google.com/p/android/issues/detail?id=41983
AStorageManager::getMountedObbPath
https://github.com/android/platform_frameworks_base/blob/master/native/android/storage_manager.cpp
155 const char* getMountedObbPath(const char* filename) { 156 String16 filename16(filename); 157 String16 path16; 158 if (mMountService->getMountedObbPath(filename16, path16)) { 159 return String8(path16).string(); //WTF? return a temp object's buffer? 160 } else { 161 return NULL; 162 } 163 }
由於沒有看String8的實現, 但是單從表面上看, 返回一個local temp object的buffer, 應該是有問題的, 除非buffer是malloc的,但貌似文檔又沒有說要free之類的(或者是mountService內部的也可以). 而實際中我也遇到返回亂碼的情況.
這個問題有人提出很久了, 但是一直沒有人去改..
雖然obb的mount都是異步的, 但java的回調是同步的, 而且回調只有在開始了消息循環以后才會被調用. 而native的callback確定是在另外一個線程調用的,難道也要等到消息循環開始以后才可以? 即便是這樣, 這種坑也應該在文檔里面說清楚,或者給個native sample吧..現在只有java的obb sample.
感覺native API上對obb的支持有很多坑還沒有發現. 這部分決定先用java了.
更新06/05/2014
native代碼是這樣的:
1 Callback(const char* filename, const SYSTEM::int32_t state, void* callbackdata ) 2 { 3 Android_App* app = (Android_App*)data; 4 if( state == AOBB_STATE_MOUNTED ) 5 { 6 int isMounted = AStorageManager_isObbMounted(app->storage, filename); 7 assert( isMounted != 0 ); 8 9 const char* mntPath = AStorageManager_getMountedObbPath(app->storage, filename); 10 11 //save persistent path data - current NDK returns tmp string that may even corrupted right after AStorageManager_getMountedObbPath() return 12 //https://code.google.com/p/android/issues/detail?id=41983 13 static char mountPath[PATH_MAX]; 14 app->storageRoot = strcpy(mountPath, mntPath); 15 append(mountPath, "/data"); 16 17 LOGI("OBB mounted: %s", filename); 18 pthread_cond_broadcast(&app->cond); 19 } 20 else if( state == AOBB_STATE_UNMOUNTED ) 21 { 22 LOGI("OBB unmounted: %s", filename); 23 } 24 else if( state != AOBB_STATE_ERROR_NOT_MOUNTED) 25 { 26 LOGE("VCAndroid_ObbCallbackFunc: %d", state); 27 if( app != null ) 28 pthread_cond_broadcast(&app->cond); 29 } 30 } 31 32 33 mountOBB() 34 { 35 AStorageManager_mountObb( Callback ); 36 pthread_cond_wait(&app->cond, &app->mutex); 37 38 } 39 40 41 //Main thread entry for activity create, called by NactiveActivity.java 42 NativeActivity_onCreate() 43 { 44 ... 45 mountOBB(); 46 createthread: android_main(); //this is pseudo code 47 return; 48 }
調用java的native代碼是這樣:
//pseudo codes: mountOBB() { call Java code to mount } bool isOBBMounted() { query Java code whether mount ready } NativeActivity_onCreate(...) { ... mountOBB(); create thread: android_main(); } android_main() { while ((ident= ALooper_pollAll(...)) >= 0 ) { if( isOBBMounted() ) continue_app(); } }
最后嘗試把native代碼也全放在android_main()線程里,而且等窗口創建好, 像用Java代碼那樣循環查詢, 還是失敗...
還有, 測試的時候還發現, 某些設備push OBB以后app讀取不出來, 最后發現是沒有使用新的標准路徑,
有的設備上/sdcard/Android/obb/com.XXX.XXX/ 是無法訪問的. 要使用sdk/tools/monnitor查看mount的真正路徑,然后方進去
比如三星的Galaxy S4, 更新到4.4.2的系統, 直接adb push到/sdcard/Android/obb/XXX/main.1.XXX.obb就沒有問題,
而Galaxy Note 10 2014新版雖然系統版本是4.3, 但是就有這個問題, push以后, 應用程序找不到該文件.
不過這個是調試的時候才有的問題. 真正發布的時候, 我們不需要知道真實路徑, app會拿到系統給的路徑, 然后下載obb放到該文件夾下. 調試的時候因為是手動上傳的包, 可能路徑不對.
目前在各種設備上測試確定Java的mount沒有出現過問題.
現在為了方便測試, 會優先讀取/sdcard/main.1.XXX.obb 這樣測試的時候obb直接放到sd卡里面就好了,一般測試的時候都是這么做吧.
但是還是不確定新的安卓系統對於非app私有的數據是否有讀取權限限制, 應該沒有, 不過最好先看文檔確認下.
因為Android4.4 KitKat已經沒有外部寫權限了(我覺得這樣更安全,本來是個好事,但是應該一開始就這么搞,現在突然這么搞會出現軟件兼容性問題), 不知道外部讀會不會有問題, 現在測過一兩個4.4的設備還沒有發現問題.