海神プラットフォームCrashモニタリングSDK(Android)開発経験総括
海神プラットフォームは私たちが自主的に開発したモバイル端末の品質監視プラットフォームであり、昨年7月から現在まで、Crash監視、ANR監視、ネットワーク監視、カスタムエラーなどの機能を続々とオンライン化しており、現在、社内の10以上のアプリ(AndroidとiOS平台を区別しない)にアクセスしている.本文は主にAndroid端がCrash監視SDKを開発する過程におけるいくつかの実践と経験を分かち合う.皆さんの収穫を願っています.
一、Java層異常捕獲
システムにはフックが用意されています.カスタムのUncaughtExceptionHandlerを設定することで、クラッシュが発生したときに現場情報を取得できます.なお、このフックは単一のプロセスに対して、マルチプロセスのAPPでどのプロセスを監視するかは、どのプロセスにExceptionHandlerを一度設定する必要があります.
ExceptionHandlerを設定する前に、getメソッドで前のExceptionHandlerを保存し、今回のクラッシュ情報を消費した後、クラッシュを前のExceptionHandlerに渡す必要があります.このような目的は、複数のモニタリングSDKが併存する場合、各モニタリングSDKがクラッシュを検出し、システムのデフォルトの異常処理は直接プロセスを終了することである.なぜこのインタフェースはJavaレイヤのすべてのクラッシュをキャプチャできるのですか?詳細については、次の記事を参照してください.
二、スタックデータソース 2.1 Throwableでは、 という情報を取得できます. 2.2メインスレッドのスタック情報: 2.3現在のスレッドのスタック情報: 2.4すべてのスレッドのスタック情報:
三、スタック情報処理
一般に、各StackTraceElementインスタンスは、関数呼び出しに対応する.異常ログを出力する方法printStackTrace、Fabric、テンセントBuglyなどのサードパーティのCrashモニタリングツールは、配列StackTraceElement[]を文字列結合で文字列形式に変換し、保存、報告、または表示します.以下の異常ログスタイルはよく知られていますか?
そう、これはFabricで見た異常な詳細です.どうやってつなぎ合わせたのでしょうか?データはすべてuncaughtExceptionコールバックインタフェースの入力Throwable eから来ている.このうち「Fatal Exception:」の後の情報は、e自体のclassName、Message、StackTraceでつづられている.その後の「Caused by」データブロックの情報は、e.getCause()のclassName、Message、StackTraceによってつづられる.このように推す.ここで注意しなければならないのは、スタックの情報の長さが最も長く、Cause異常チェーンが最も多く、オンライン環境では不確定であり、Fabricが与えた経験値は: 3.1各Throwableのスタック長、Fabricは1024バイトに制限される. 3.2 Throwableのスタックごとに隣接する行に重複がある可能性があり、1つの重さを行うことができ、Fabricは最大10行連続の重複に制限されている. 3.3異常チェーン全体に長さ制限が必要であり、Fabric制限は最長8層である.
四、報告のタイミングについて
クラッシュが発生した場合、最初にしなければならないのは現場データを保存し、リアルタイムでアップロードすることです.リアルタイムでアップロードする方法FabricはExecutorServiceとFuture.getからなる非同期ブロック方式によって実現される.保存アップロードなどの論理操作を直接しないのはなぜですか?ブロックポイントは、Androidシステムに限定されており、メインスレッドが同期するネットワークリクエスト操作(同期とは、ネットワークリクエストの結果が返されるまで待つこと)を行うと、システムがエラーを報告します.
非同期発リクエストに変更すると、アップロード結果がわかりません.クラッシュ時刻の同期アップロードに加えて,問題が最大限に記録され発見されることを確保するために,その後の補完論理と補完タイミングを考慮する必要がある.
五、崩壊率について
我々がよく使用するクラッシュ指標は,デバイス/ユーザクラッシュ率,セッションクラッシュ率の前者がクラッシュの影響力を反映し,後者がクラッシュの発生確率を反映することである.デバイスまたはユーザーのクラッシュ率は理解しやすいが、APP側はできるだけデバイスの一意な識別の一意性を保証すればよい.「セッション」はどのように理解され、定義されますか?「セッション」を使用して、ユーザーの使用を説明し、定義したいと考えています.Fabricの定義は次のとおりです.
Sessionとは、アプリがフロントに入る時刻が前回バックグラウンドに退いた時刻から30秒以上離れているということで、新しいセッションの始まりと考えられます.
詳細は、Fabric:session定義がありますが、コード上でどのように実現すればいいですか?Androidシステムはアプリのフロントバックグラウンド切り替えイベントを知るために明確なフックを提供していないため、複数の条件を総合して自分で判断する必要がある.ここでは海神Crash SDKの実践について簡単に説明します.要点は以下の通りです.1)APPグローバルのActivity LifecycleCallbackに基づいてページライフサイクルの傍受を行い、「OnStopped」イベントが発生した場合、現在のAPPがフロントアプリケーションであるかどうかを判断し、そうでなければ、今APPがバックグラウンドに退くと判断し、タイムスタンプをメモする.「OnStarted」イベントが発生した場合、次の2つのイベントの時間差が30秒を超えるかどうかを計算します.アプリがフロントアプリかどうかをどう判断するか、ネット上の資料が多いので、ここでは説明しません. 2)新しいセッションを生成する条件は3つある:1つは1)のフロントバックグラウンド切り替え;二つ目はAPPのコールドスタートです.三つ目は出産プロセスが崩壊したことだ.サブプロセスがクラッシュしたときにセッションIdをアクティブに更新するのはなぜですか?理由は,1つのセッションの間に最大1回のクラッシュ異常しか発生しないと考えられるからである.サブプロセスがクラッシュした場合、APPは通常終了せず、ページ切り替えが起こらない可能性があります.したがって,セッションIdをアクティブに更新する必要がある.
六、混同について
混同されたAPPの場合、そのクラッシュスタックの情報も混同されることが多く、位置決めと分析を容易にするために、いくつかの補助作業が必要です.1)パッケージ化によって混同APKが生成されるたびに、Mappingファイルを保存して監視バックグラウンドにアップロードする必要がある. 2)海神プラットフォームの現在のマーキング方法は、appName+versioncodeの組み合わせを使用してMappingファイルをマーキングすることです.このようなタグの粒度がまだ十分ではないと感じたら、Crashが発生したときにこのタグIdを一緒にアップロードして、バックエンドが対応するMappingファイルに正確に一致するように、毎回のパッケージ動作をタグすることができます. 3)Android原生の反混同ツールパッケージはretrace.jarであり,監視バックグラウンドで各報告のクラッシュをリアルタイムで解析するために使用される場合,それを改造する必要がある.retraceの原理は,Mappingファイルをテキスト解析とオブジェクトインスタンス化することであり,このプロセスは比較的時間がかかる.海神プラットフォームの実践は、Mappingオブジェクトのインスタンスをメモリキャッシュすることですが、メモリの漏洩やメモリの過剰使用を防ぐために、定期的に自動的に回収するロジックが追加されています.現在、崩壊した反混同には1ミリ秒程度かかります.
七、ANRの捕獲方法
ANRのフルスペルはApplication Not Respondingであり,プログラムに応答がない.アプリがある場合、ユーザーの操作に敏感に応答できない場合、ANRのダイアログボックスがポップアップされます.ユーザーに与える体験的なダメージは、クラッシュに次ぐものです.ANRが発生した原因は、携帯電話自体のCPUやメモリなどの資源状況が悪化したり、緊張したりする原因が多い一方、APPには時間のかかる操作や瞬時のメモリ消費が大きすぎるという欠陥がある.ANRを捕獲する関連案はネット上の資料が多く、紙面の原因に限られており、ここでは海神の実践を直接話している.海神はFileObserverとWatchDogの2つの方式を採用している.このうちFileObserverはAndroid 5.0以前のシステム(すなわちlevel 21未満のシステム)に用いられていたが、WatchDogの1つのスキームのみを採用することもできる.FileObserver方式で/data/anr/traces.txtに書き込み完了のイベントが発生した場合、携帯電話にANRが発生したに違いない.ここでは2つの点に注意してください.1)書き込み操作が完了したイベントは、システムが連続して複数回発行され、重複応答と処理を避けるために相応の論理を追加する必要がある. 2)traces.txtファイルの解析は一般的に数秒から十数秒で、比較的時間がかかる.また、traces.txtファイルには、ANRが発生したプロセスが必ずしもファイルの先頭に記録されていない複数のプロセスの情報が記録される可能性があります.WatchDogスキームを使用して監視した結果、APPにUIブロックが発生し、必ずしもANRが発生するとは限らず、二次検査が必要であることしか説明できません.チェックの仕方は、携帯電話のシステムにエラーが発生するのを待つプロセスであり、エラータイプはNOT_RESPONDING(値は2).コード実装は、
また、ANRフレームが現れるたびにNative層がsignalをSIGNALとして発行するという案も試してみてください.QUIT(値3)の信号イベント.
八、ANRの現場情報
前節ではANRイベントの発生をどのように偵察するか、この節では現場に関する情報をどのように取得するかについて説明しました.ANRの現場情報はいくつかの場所から入手できます. 1)traces.txt; 2)ProcessErrorStateInfoの例. )その時点で刻み込まれたスタック情報は,第2節を参照して取得する.3つの長所と短所の比較: データソース
提供可能なコンテンツ
メリットとデメリット
traces.txt
ANR時間、ANRプロセス、UIマスタースレッドを含むすべてのスレッドのスタック、およびNative呼び出しスタック
利点:スタックデータの正確な欠点:解析に時間がかかり、リアルタイムアップロードに適していない
ProcessErrorStateInfo
ANRプロセス、shortMsg:ANRが発生した位置;longMsg:ANRの位置、短い原因、CPU、メモリ等の占有状況が発生
利点:明確なANR原因と問題コードの行を提供することができる;ミリ秒レベルの取得;欠点:スタック情報がありません;
当時刻み込まれたスタック情報
メインスレッドのJavaレイヤスタック、その他のスレッドのJavaレイヤスタック
利点:データミリ秒レベル取得;欠点:ANR発生の本当の時刻を知ることができなくて、ただ近似します
海神SDKは現在,ProcessErrorStateInfoとANRが出現したときのスタック情報を統合し,ANRのリアルタイムアップロードを実現している.以上が今回まとめたすべての内容で、疑問があれば私談を歓迎します.
一、Java層異常捕獲
システムにはフックが用意されています.カスタムのUncaughtExceptionHandlerを設定することで、クラッシュが発生したときに現場情報を取得できます.なお、このフックは単一のプロセスに対して、マルチプロセスのAPPでどのプロセスを監視するかは、どのプロセスにExceptionHandlerを一度設定する必要があります.
// Thread.java
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh)
public interface UncaughtExceptionHandler {
/**
* Method invoked when the given thread terminates due to the
* given uncaught exception.
* Any exception thrown by this method will be ignored by the
* Java Virtual Machine.
* @param t the thread
* @param e the exception
*/
void uncaughtException(Thread t, Throwable e);
}
ExceptionHandlerを設定する前に、getメソッドで前のExceptionHandlerを保存し、今回のクラッシュ情報を消費した後、クラッシュを前のExceptionHandlerに渡す必要があります.このような目的は、複数のモニタリングSDKが併存する場合、各モニタリングSDKがクラッシュを検出し、システムのデフォルトの異常処理は直接プロセスを終了することである.なぜこのインタフェースはJavaレイヤのすべてのクラッシュをキャプチャできるのですか?詳細については、次の記事を参照してください.
二、スタックデータソース
Throwable ex
1) :ex.getClass().getName(); // "java.lang.ArithmeticException"
2) :ex.getLocalizedMessage(); // "divide by zero"
3) :ex.getStackTrace();// StackTraceElement[]
4) :ex.getCause(); // Throwable , Throwable,
Looper.getMainLooper().getThread().getStackTrace();
Thread.currentThread().getStackTrace();
// Thread.getAllStackTraces();
public static Map getAllStackTraces()
三、スタック情報処理
public final class StackTraceElement implements java.io.Serializable {
// Normally initialized by VM (public constructor added in 1.5)
private String declaringClass;
private String methodName;
private String fileName;
private int lineNumber;
一般に、各StackTraceElementインスタンスは、関数呼び出しに対応する.異常ログを出力する方法printStackTrace、Fabric、テンセントBuglyなどのサードパーティのCrashモニタリングツールは、配列StackTraceElement[]を文字列結合で文字列形式に変換し、保存、報告、または表示します.以下の異常ログスタイルはよく知られていますか?
Fatal Exception:xxxThrowable:xxxMessage
at xxxStackTraceElement11
at xxxStackTraceElement12
at xxx1......
Caused by xxxCauseThrowable:xxxCauseMessage
at xxxStackTraceElement21
at xxxStackTraceElement22
at xxx2......
Caused by xxxCauseCauseThrowable:xxxCauseCauseMessage
at xxxStackTraceElement31
at xxxStackTraceElement32
at xxx3......
そう、これはFabricで見た異常な詳細です.どうやってつなぎ合わせたのでしょうか?データはすべてuncaughtExceptionコールバックインタフェースの入力Throwable eから来ている.このうち「Fatal Exception:」の後の情報は、e自体のclassName、Message、StackTraceでつづられている.その後の「Caused by」データブロックの情報は、e.getCause()のclassName、Message、StackTraceによってつづられる.このように推す.ここで注意しなければならないのは、スタックの情報の長さが最も長く、Cause異常チェーンが最も多く、オンライン環境では不確定であり、Fabricが与えた経験値は:
四、報告のタイミングについて
クラッシュが発生した場合、最初にしなければならないのは現場データを保存し、リアルタイムでアップロードすることです.リアルタイムでアップロードする方法FabricはExecutorServiceとFuture.getからなる非同期ブロック方式によって実現される.保存アップロードなどの論理操作を直接しないのはなぜですか?ブロックポイントは、Androidシステムに限定されており、メインスレッドが同期するネットワークリクエスト操作(同期とは、ネットワークリクエストの結果が返されるまで待つこと)を行うと、システムがエラーを報告します.
android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1460)
非同期発リクエストに変更すると、アップロード結果がわかりません.クラッシュ時刻の同期アップロードに加えて,問題が最大限に記録され発見されることを確保するために,その後の補完論理と補完タイミングを考慮する必要がある.
五、崩壊率について
我々がよく使用するクラッシュ指標は,デバイス/ユーザクラッシュ率,セッションクラッシュ率の前者がクラッシュの影響力を反映し,後者がクラッシュの発生確率を反映することである.デバイスまたはユーザーのクラッシュ率は理解しやすいが、APP側はできるだけデバイスの一意な識別の一意性を保証すればよい.「セッション」はどのように理解され、定義されますか?「セッション」を使用して、ユーザーの使用を説明し、定義したいと考えています.Fabricの定義は次のとおりです.
Sessionとは、アプリがフロントに入る時刻が前回バックグラウンドに退いた時刻から30秒以上離れているということで、新しいセッションの始まりと考えられます.
詳細は、Fabric:session定義がありますが、コード上でどのように実現すればいいですか?Androidシステムはアプリのフロントバックグラウンド切り替えイベントを知るために明確なフックを提供していないため、複数の条件を総合して自分で判断する必要がある.ここでは海神Crash SDKの実践について簡単に説明します.要点は以下の通りです.
六、混同について
混同されたAPPの場合、そのクラッシュスタックの情報も混同されることが多く、位置決めと分析を容易にするために、いくつかの補助作業が必要です.
七、ANRの捕獲方法
ANRのフルスペルはApplication Not Respondingであり,プログラムに応答がない.アプリがある場合、ユーザーの操作に敏感に応答できない場合、ANRのダイアログボックスがポップアップされます.ユーザーに与える体験的なダメージは、クラッシュに次ぐものです.ANRが発生した原因は、携帯電話自体のCPUやメモリなどの資源状況が悪化したり、緊張したりする原因が多い一方、APPには時間のかかる操作や瞬時のメモリ消費が大きすぎるという欠陥がある.ANRを捕獲する関連案はネット上の資料が多く、紙面の原因に限られており、ここでは海神の実践を直接話している.海神はFileObserverとWatchDogの2つの方式を採用している.このうちFileObserverはAndroid 5.0以前のシステム(すなわちlevel 21未満のシステム)に用いられていたが、WatchDogの1つのスキームのみを採用することもできる.FileObserver方式で/data/anr/traces.txtに書き込み完了のイベントが発生した場合、携帯電話にANRが発生したに違いない.ここでは2つの点に注意してください.
public static ActivityManager.ProcessErrorStateInfo getProcessInANRState(Context context,int totalCounts) {
if (context == null) {
return null;
}
Log.i(TAG,"start find process which in ANR");
ActivityManager activityManager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (activityManager == null) {
return null;
}
ActivityManager.ProcessErrorStateInfo errorStateInfo;
int i = 0;
do {
List processErrorStateInfoList = activityManager.getProcessesInErrorState();
if (processErrorStateInfoList != null && !processErrorStateInfoList.isEmpty()) {
for (Object process : processErrorStateInfoList) {
errorStateInfo = (ActivityManager.ProcessErrorStateInfo) process;
if (errorStateInfo.condition == 2) {
LJCLog.i("the anr process found!");
return errorStateInfo;
}
}
}
ThreadUtils.sleep(500L);
} while (i++ <= totalCounts);
LJCLog.i("not found process which in ANR!");
return null;
}
また、ANRフレームが現れるたびにNative層がsignalをSIGNALとして発行するという案も試してみてください.QUIT(値3)の信号イベント.
八、ANRの現場情報
前節ではANRイベントの発生をどのように偵察するか、この節では現場に関する情報をどのように取得するかについて説明しました.ANRの現場情報はいくつかの場所から入手できます.
提供可能なコンテンツ
メリットとデメリット
traces.txt
ANR時間、ANRプロセス、UIマスタースレッドを含むすべてのスレッドのスタック、およびNative呼び出しスタック
利点:スタックデータの正確な欠点:解析に時間がかかり、リアルタイムアップロードに適していない
ProcessErrorStateInfo
ANRプロセス、shortMsg:ANRが発生した位置;longMsg:ANRの位置、短い原因、CPU、メモリ等の占有状況が発生
利点:明確なANR原因と問題コードの行を提供することができる;ミリ秒レベルの取得;欠点:スタック情報がありません;
当時刻み込まれたスタック情報
メインスレッドのJavaレイヤスタック、その他のスレッドのJavaレイヤスタック
利点:データミリ秒レベル取得;欠点:ANR発生の本当の時刻を知ることができなくて、ただ近似します
海神SDKは現在,ProcessErrorStateInfoとANRが出現したときのスタック情報を統合し,ANRのリアルタイムアップロードを実現している.以上が今回まとめたすべての内容で、疑問があれば私談を歓迎します.