非原生 ROM 的 Crash 問題通用排查方法

日常 Crash 治理過程中,經常會遇到一些比較難排查的問題,比如,Crash 堆棧信息中出現了一些本不應該出現的函數,這些函數其實是手機廠商修改了 Google 的原生 ROM,自己添加進去的。本文介紹了一種定位和排查非原生 ROM 的 Crash 問題的通用方法。

問題的提出

日常清理 Crash 時,遇到一些空指針異常的問題,每天不多,但是日積月累,數量并不少,堆棧信息如下:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
	at android.os.Message.toStringLite(Message.java:507)
	at android.os.Looper.loop(Looper.java:221)
	at android.app.ActivityThread.main(ActivityThread.java:5809)
	at java.lang.reflect.Method.invoke(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:372)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1113)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:879)

翻看 android.os.Message 的源代碼,并沒有 toStringLite() 這個函數,顯然,這是手機廠商修改了原生 ROM,自己加上的。如何跟進此類適配性問題呢?

思考

此類 ROM 相關問題無法修復,只能從 App 的代碼調用端進行適配,類似 H5 頁面適配各種瀏覽器一樣。所以,主要問題在于找出非原生 ROM 的執行邏輯,從而想辦法避免 Crash。那么,如何發掘里面的執行邏輯呢?

探索

初步考慮,通過 ClassLoader 動態導出具體的 class 類,代碼如下:

public class Demo {
    public static void main(String[] args) {
        try {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            InputStream inputStream = classLoader.getResourceAsStream("java/util/List.class");
            FileOutputStream fileOutputStream = new FileOutputStream("List.class");
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) > 0) {
                fileOutputStream.write(buffer, 0, length);
            }
            fileOutputStream.close();
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

這種方法對 Java 是適用的,但是在 Android 中并不適用。

通用方法

既然動態方法不行,考慮靜態方法,畢竟在手機 ROM 中,必然有對應的文件。

步驟一

首先,通過 Crash 平臺的附加信息,找到手機的型號、版本「型號:OPPO R9tm,版本:5.1」,找一臺同型號、同版本的手機「美團真機平臺,上面的手機種類繁多」,連上 adb

步驟二

把 boot.oat 文件從手機 pull 下來,boot.oat 包含啟動相關的代碼,可理解為里面有優化過的 framework.jar 文件,對應 SDK 的 android.jar 文件,文件較大,有 85M 左右。

[[email protected]: ] ~/Desktop $ adb -s 172.18.92.198:44429 pull /system/framework/arm64/boot.oat .
/system/framework/arm64/boot.oat: 1 file pulled. 0.4 MB/s (85477748 bytes in 229.612s)
[[email protected]: ] ~/Desktop $ ls -l boot.oat 
-rw-r--r--  1 leidiqiu  staff  85477748 May  8 16:17 boot.oat

步驟三

下載 oat2dex.jar 工具,并將 oat 文件轉換成 dex 文件,會生成 odex、dex 兩個文件夾。

[[email protected]: ] ~/Desktop $ java -jar ~/libs/oat2dex.jar boot boot.oat 
05-08 16:23:27:465 Output raw dex: /Users/leidiqiu/Desktop/odex/core-libart.dex
05-08 16:23:27:466 Output raw dex: /Users/leidiqiu/Desktop/odex/conscrypt.dex
05-08 16:23:27:467 Output raw dex: /Users/leidiqiu/Desktop/odex/okhttp.dex
05-08 16:23:27:467 Output raw dex: /Users/leidiqiu/Desktop/odex/core-junit.dex
05-08 16:23:27:469 Output raw dex: /Users/leidiqiu/Desktop/odex/bouncycastle.dex
05-08 16:23:27:472 Output raw dex: /Users/leidiqiu/Desktop/odex/ext.dex
05-08 16:23:27:488 Output raw dex: /Users/leidiqiu/Desktop/odex/framework.dex
05-08 16:23:27:503 Output raw dex: /Users/leidiqiu/Desktop/odex/framework-classes2.dex
05-08 16:23:27:511 Output raw dex: /Users/leidiqiu/Desktop/odex/telephony-common.dex
05-08 16:23:27:512 Output raw dex: /Users/leidiqiu/Desktop/odex/voip-common.dex
05-08 16:23:27:516 Output raw dex: /Users/leidiqiu/Desktop/odex/ims-common.dex
05-08 16:23:27:516 Output raw dex: /Users/leidiqiu/Desktop/odex/mms-common.dex
05-08 16:23:27:517 Output raw dex: /Users/leidiqiu/Desktop/odex/android.policy.dex
05-08 16:23:27:523 Output raw dex: /Users/leidiqiu/Desktop/odex/apache-xml.dex
05-08 16:23:27:529 Output raw dex: /Users/leidiqiu/Desktop/odex/oppo-framework.dex
05-08 16:23:27:530 Output raw dex: /Users/leidiqiu/Desktop/odex/mediatek-common.dex
05-08 16:23:27:531 Output raw dex: /Users/leidiqiu/Desktop/odex/mediatek-framework.dex
05-08 16:23:27:532 Output raw dex: /Users/leidiqiu/Desktop/odex/mediatek-telephony-common.dex
05-08 16:23:27:786 De-optimizing /system/framework/core-libart.jar
05-08 16:23:30:094 Output to /Users/leidiqiu/Desktop/dex/core-libart.dex
05-08 16:23:30:094 De-optimizing /system/framework/conscrypt.jar
05-08 16:23:30:208 Output to /Users/leidiqiu/Desktop/dex/conscrypt.dex
05-08 16:23:30:208 De-optimizing /system/framework/okhttp.jar
05-08 16:23:30:356 Output to /Users/leidiqiu/Desktop/dex/okhttp.dex
05-08 16:23:30:356 De-optimizing /system/framework/core-junit.jar
05-08 16:23:30:371 Output to /Users/leidiqiu/Desktop/dex/core-junit.dex
05-08 16:23:30:371 De-optimizing /system/framework/bouncycastle.jar
05-08 16:23:30:928 Output to /Users/leidiqiu/Desktop/dex/bouncycastle.dex
05-08 16:23:30:928 De-optimizing /system/framework/ext.jar
05-08 16:23:31:483 Output to /Users/leidiqiu/Desktop/dex/ext.dex
05-08 16:23:31:483 De-optimizing /system/framework/framework.jar
05-08 16:23:36:301 Output to /Users/leidiqiu/Desktop/dex/framework.dex
05-08 16:23:36:301 De-optimizing /system/framework/framework.jar:classes2.dex
05-08 16:23:38:611 Output to /Users/leidiqiu/Desktop/dex/framework-classes2.dex
05-08 16:23:38:611 De-optimizing /system/framework/telephony-common.jar
05-08 16:23:40:395 Output to /Users/leidiqiu/Desktop/dex/telephony-common.dex
05-08 16:23:40:395 De-optimizing /system/framework/voip-common.jar
05-08 16:23:40:440 Output to /Users/leidiqiu/Desktop/dex/voip-common.dex
05-08 16:23:40:440 De-optimizing /system/framework/ims-common.jar
05-08 16:23:40:625 Output to /Users/leidiqiu/Desktop/dex/ims-common.dex
05-08 16:23:40:625 De-optimizing /system/framework/mms-common.jar
05-08 16:23:40:626 Output to /Users/leidiqiu/Desktop/dex/mms-common.dex
05-08 16:23:40:626 De-optimizing /system/framework/android.policy.jar
05-08 16:23:40:764 Output to /Users/leidiqiu/Desktop/dex/android.policy.dex
05-08 16:23:40:764 De-optimizing /system/framework/apache-xml.jar
05-08 16:23:41:178 Output to /Users/leidiqiu/Desktop/dex/apache-xml.dex
05-08 16:23:41:178 De-optimizing /system/framework/oppo-framework.jar
05-08 16:23:41:613 Output to /Users/leidiqiu/Desktop/dex/oppo-framework.dex
05-08 16:23:41:613 De-optimizing /system/framework/mediatek-common.jar
05-08 16:23:41:660 Output to /Users/leidiqiu/Desktop/dex/mediatek-common.dex
05-08 16:23:41:660 De-optimizing /system/framework/mediatek-framework.jar
05-08 16:23:41:889 Output to /Users/leidiqiu/Desktop/dex/mediatek-framework.dex
05-08 16:23:41:889 De-optimizing /system/framework/mediatek-telephony-common.jar
05-08 16:23:41:891 Output to /Users/leidiqiu/Desktop/dex/mediatek-telephony-common.dex

步驟四

查看 dex 文件夾,發現有 framework.dex 文件。

[[email protected]: ] ~/Desktop $ cd dex/
[[email protected]: ] ~/Desktop/dex $ ls
android.policy.dex            ext.dex                       mediatek-telephony-common.dex
apache-xml.dex                framework-classes2.dex        mms-common.dex
bouncycastle.dex              framework.dex                 okhttp.dex
conscrypt.dex                 ims-common.dex                oppo-framework.dex
core-junit.dex                mediatek-common.dex           telephony-common.dex
core-libart.dex               mediatek-framework.dex        voip-common.dex

步驟五

下載 dex2jar-2.0.zip 工具,將 dex 轉成 jar,并用 JD-GUI 打開,JD-GUI 下載地址: http://java-decompiler.github.io/。

[[email protected]: ] ~/Desktop/dex $ dex2jar.sh framework.dex 
dex2jar framework.dex -> ./framework-dex2jar.jar
Detail Error Information in File ./framework-error.zip
Please report this file to http://code.google.com/p/dex2jar/issues/entry if possible.
[[email protected]: ] ~/Desktop/dex $ open framework-dex2jar.jar -a JD-GUI.app

步驟六

通過 JD-GUI 查看,終于找到了 Message 類,里面確實有 toStringLite() 方法。

非原生 ROM 的 Crash 問題通用排查方法

原文 

http://xgfe.github.io/2019/06/17/leidiqiu/resolve-non-google-rom-crash/

本站部分文章源于互聯網,本著傳播知識、有益學習和研究的目的進行的轉載,為網友免費提供。如有著作權人或出版方提出異議,本站將立即刪除。如果您對文章轉載有任何疑問請告之我們,以便我們及時糾正。

PS:推薦一個微信公眾號: askHarries 或者qq群:474807195,里面會分享一些資深架構師錄制的視頻錄像:有Spring,MyBatis,Netty源碼分析,高并發、高性能、分布式、微服務架構的原理,JVM性能優化這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多

轉載請注明原文出處:Harries Blog? » 非原生 ROM 的 Crash 問題通用排查方法

贊 (0)
分享到:更多 ()

評論 0

  • 昵稱 (必填)
  • 郵箱 (必填)
  • 網址
2013平特肖公式