1. 程式人生 > >Android apk執行時錯誤java.lang.NoSuchMethodError: com.google.gson.GsonBuilder.setLenient

Android apk執行時錯誤java.lang.NoSuchMethodError: com.google.gson.GsonBuilder.setLenient

最近在Hisi3751V500上移植一個新的專案,在執行gitv牌照方apk的時候提示java.lang.NoSuchMethodError: com.google.gson.GsonBuilder.setLenient

06-03 17:44:28.966 I/dalvikvm( 3617): Could not find method com.google.gson.GsonBuilder.setLenient, referenced from method com.gitv.tv.launcher.utils.RetrofitFactory.create
06-03 17:44:28.966
W/dalvikvm( 3617): VFY: unable to resolve virtual method 39078: Lcom/google/gson/GsonBuilder;.setLenient ()Lcom/google/gson/GsonBuilder; 06-03 17:44:28.966 D/dalvikvm( 3617): VFY: replacing opcode 0x6e at 0x0007 06-03 17:44:28.970 D/AndroidRuntime( 3617): Shutting down VM 06-03 17:44:28.970 W/dalvikvm( 3617): threadid=1: thread exiting with uncaught exception (group=0x41724ba8
) 06-03 17:44:28.976 E/AndroidRuntime( 3617): FATAL EXCEPTION: main 06-03 17:44:28.976 E/AndroidRuntime( 3617): Process: com.gitv.tv.launcher, PID: 3617 06-03 17:44:28.976 E/AndroidRuntime( 3617): java.lang.NoSuchMethodError: com.google.gson.GsonBuilder.setLenient 06-03 17:44:28.976 E/AndroidRuntime( 3617): at com
.gitv.tv.launcher.utils.RetrofitFactory.create(RetrofitFactory.java:68) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at com.gitv.tv.launcher.utils.RetrofitFactory.create(RetrofitFactory.java:36) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at com.gitv.tv.launcher.data.DataManager.getIP(DataManager.java:708) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at com.gitv.tv.launcher.service.task.SettingTask.getIP(SettingTask.java:105) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at com.gitv.tv.launcher.service.task.SettingTask.init(SettingTask.java:69) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at com.gitv.tv.launcher.application.GitvLauncherApplication.init(GitvLauncherApplication.java:91) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at com.gitv.tv.launcher.application.GitvLauncherApplication.onCreate(GitvLauncherApplication.java:60) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1007) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4366) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at android.app.ActivityThread.access$1500(ActivityThread.java:135) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at android.os.Handler.dispatchMessage(Handler.java:102) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at android.os.Looper.loop(Looper.java:136) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at android.app.ActivityThread.main(ActivityThread.java:5039) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at java.lang.reflect.Method.invokeNative(Native Method) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at java.lang.reflect.Method.invoke(Method.java:515) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:736) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:552) 06-03 17:44:28.976 E/AndroidRuntime( 3617): at dalvik.system.NativeStart.main(Native Method) 06-03 17:44:28.978 W/ActivityManager( 2022): Force finishing activity com.gitv.tv.launcher/.activity.GitvInterfaceActivity

考慮到這個apk在Hisi3798M,AmlogicS905,Amlogic8726MX上面能正常執行,於是把apk進行反編譯,發現apk存在classes.dex及classes2.dex,並且classes.dex裡面存在com.google.gson.GsonBuilder.setLenient這個方法,第一反應是Hisi3751V500上面對apk分包機制支援不夠,導致方法未載入上,但是折騰了一兩天也證明不了分包機制的問題。於是把著重點放到了apk安裝的日誌上面:

`06-06 15:24:17.467 D/dalvikvm( 5507): DexOpt: not verifying/optimizing 'Lcom/google/gson/GsonBuilder;': multiple definitions`

注意到系統提示multiple definitions,證明GsonBuilder這個classes類跟系統某個classes類版本衝突,因此在系統的ext.jar包匯入一個包含GsonBuilder的setLenient方法的google gson的gson-2.6.2.jar包,方法是在$SDK根目錄/frameworks/opt/ 目錄下新建一個gson的目錄,然後把gson-2.6.2.jar包放入到gson目錄,寫一個Android.mk檔案,然後再gson目錄下mm編譯。Android.mk檔案內容:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := gson
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := gson:gson-2.6.2.jar

include $(BUILD_MULTI_PREBUILT)

然後進入到$SDK根目錄/frameworks/base/目錄,修改系統Android.mk目錄,修改內容如下:

# ====  the library  =========================================
include $(CLEAR_VARS)

LOCAL_SRC_FILES := $(ext_src_files)

LOCAL_NO_STANDARD_LIBRARIES := true
LOCAL_JAVA_LIBRARIES := core
LOCAL_JAVA_RESOURCE_DIRS := $(ext_res_dirs)
#以下這行是新增內容
LOCAL_STATIC_JAVA_LIBRARIES := gson
#以上這行是新增內容
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := ext

LOCAL_DX_FLAGS := --core-library

修改完成後,在$SDK根目錄/frameworks/base/目錄進行mm編譯,編譯OK後,替換ext.jar包,已經修正了這個gson的錯誤。
但是此時apk又報其他錯誤,正是由於這個錯誤,讓我對於之前gson的版本衝突的判斷產生了懷疑:

06-06 18:20:29.795 E/AndroidRuntime( 3060): FATAL EXCEPTION: pool-3-thread-1
06-06 18:20:29.795 E/AndroidRuntime( 3060): Process: com.gitv.tv.launcher, PID: 3060
06-06 18:20:29.795 E/AndroidRuntime( 3060): java.lang.NoSuchMethodError: no static or non-static method "Lcom/facebook/imagepipeline/nativecode/WebpTranscoder;.nativeTranscodeWebpToJpeg(Ljava/io/InputStream;Ljava/io/OutputStream;I)V"
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at java.lang.Runtime.nativeLoad(Native Method)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at java.lang.Runtime.doLoad(Runtime.java:421)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at java.lang.Runtime.loadLibrary(Runtime.java:362)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at java.lang.System.loadLibrary(System.java:526)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at com.facebook.common.soloader.SoLoaderShim$DefaultHandler.loadLibrary(SoLoaderShim.java:32)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at com.facebook.common.soloader.SoLoaderShim.loadLibrary(SoLoaderShim.java:56)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at com.facebook.imagepipeline.nativecode.ImagePipelineNativeLoader.load(ImagePipelineNativeLoader.java:48)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at com.facebook.imagepipeline.memory.NativeMemoryChunk.<clinit>(NativeMemoryChunk.java:36)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at com.facebook.imagepipeline.memory.NativeMemoryChunkPool.alloc(NativeMemoryChunkPool.java:60)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at com.facebook.imagepipeline.memory.NativeMemoryChunkPool.alloc(NativeMemoryChunkPool.java:22)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at com.facebook.imagepipeline.memory.BasePool.get(BasePool.java:260)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at com.facebook.imagepipeline.memory.NativePooledByteBufferOutputStream.<init>(NativePooledByteBufferOutputStream.java:53)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at com.facebook.imagepipeline.memory.NativePooledByteBufferFactory.newByteBuffer(NativePooledByteBufferFactory.java:100)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at com.facebook.imagepipeline.memory.NativePooledByteBufferFactory.newByteBuffer(NativePooledByteBufferFactory.java:28)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at com.facebook.imagepipeline.cache.BufferedDiskCache.readFromDiskCache(BufferedDiskCache.java:341)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at com.facebook.imagepipeline.cache.BufferedDiskCache.access$400(BufferedDiskCache.java:38)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at com.facebook.imagepipeline.cache.BufferedDiskCache$2.call(BufferedDiskCache.java:185)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at com.facebook.imagepipeline.cache.BufferedDiskCache$2.call(BufferedDiskCache.java:168)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at bolts.Task$4.run(Task.java:357)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
06-06 18:20:29.795 E/AndroidRuntime( 3060):     at java.lang.Thread.run(Thread.java:841)
06-06 18:20:29.801 W/ActivityManager( 2042):   Force finishing activity com.gitv.tv.launcher/.activity.PlayActivity

以為是跟gson同樣的錯誤,然後按照gson匯入facebook的imagepipeline包發現又報facebook的common類未找到錯誤,繼續匯入,發現又有新的錯誤,此時又回到了起點,以為是Multidex分包的問題,折騰了好久,然後發現系統裡面某一個so庫跟facebook的libimagepipeline.so重名,編譯的時候gitv的牌照方apk的so庫被覆蓋掉了,替換回gitv的libimagepipeline.so庫,一切正常,OK終於搞定了這個問題。

在除錯的時候其實也仔細看了上面報錯的log,提示com.facebook.imagepipeline.nativecode.ImagePipelineNativeLoader.load錯誤,當時第一反應是so庫被覆蓋了,然後一股腦把gitv的so全部匯入到系統/system/lib/目錄,結果悲劇的是系統宕機了(⊙﹏⊙)!,估計是某一個so庫覆蓋了系統的一個很重要的so導致系統宕機了。勝利的曙光又被這次宕機拖延了好久,直到後來發現pm安裝這個apk系統不會報錯,然後再參考上面的log,這次只替換了gitv的一個so庫,libimagepipeline.so,終於結束了這幾天蛋疼的除錯之旅。。。

最終結論,這幾天折騰的根源是兩個問題導致的:
1. gson版本跟系統某一個apk的gson版本不一致,並且系統這個gson庫不包含GsonBuilder的setLenient方法
2. gitv apk的libimagepipeline.so庫跟系統某一個apk的so庫衝突,在loadlibrary的時候報錯,導致gitv閃退