Android 上の JNI で SIGSEGV (セグメンテーション違反) をキャッチし、スタック トレースを取得するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/1083154

質問

引越し中 プロジェクト 新しい Android ネイティブ開発キット (つまり、JNI)、現在起こっていることの代わりに (またはその前に) 優れたクラッシュ レポート ダイアログを表示するために、SIGSEGV が発生した場合 (おそらく SIGILL、SIGABRT、SIGFPE も) をキャッチしたいと思います。プロセスが即座に無礼に終了し、おそらく OS によるプロセスの再起動が試みられます。(編集: JVM/Dalvik VM はシグナルをキャッチし、スタック トレースやその他の有用な情報をログに記録します。私はユーザーにその情報を実際に電子メールで送信するオプションを提供したいだけです。)

状況は次のとおりです。私が書いたわけではない大量の C コードが、このアプリケーションのほとんどの作業 (すべてのゲーム ロジック) を実行します。また、他の多くのプラットフォームで十分にテストされていますが、私の Android 移植版では、それはガベージであり、ネイティブ コードでクラッシュを引き起こすため、現在 Android ログに表示されるクラッシュ ダンプ (ネイティブと Java の両方) が必要です (Android 以外の状況では stderr になると思います)。C コードと Java コードの両方を自由に変更できますが、コールバック (JNI に出入りする両方) の数は約 40 で、小さな差分には明らかにボーナス ポイントがあります。

J2SE のシグナル チェーン ライブラリである libjsig.so について聞いたことがあります。そのようなシグナル ハンドラーを Android に安全にインストールできれば、私の質問の引っ掛かり部分は解決するでしょうが、Android/Dalvik にはそのようなライブラリがありません。 。

役に立ちましたか?

解決

編集: Jelly Bean 以降では、スタック トレースを取得できません。 READ_LOGS 去って行った. :-(

実際に、あまり変わったことをせずにシグナル ハンドラーを動作させることができ、それを使用したコードをリリースしました。ご覧のとおりです。 github 上で (編集:過去のリリースへのリンク。それ以来、クラッシュ ハンドラーを削除しました)。その方法は次のとおりです。

  1. 使用 sigaction() シグナルをキャッチし、古いハンドラーを保存します。(アンドロイド.c:570)
  2. 時間が経つと、セグメンテーション違反が発生します。
  3. シグナル ハンドラーで、最後にもう一度 JNI を呼び出してから、古いハンドラーを呼び出します。(アンドロイド.c:528)
  4. その JNI 呼び出しで、有用なデバッグ情報をログに記録し、次の呼び出しを行います。 startActivity() 独自のプロセス内に存在する必要があるとフラグが立てられているアクティビティに対して。(SGTPuzzles.java:962, AndroidManifest.xml:28)
  5. Java から戻って古いハンドラーを呼び出すと、Android フレームワークは次のハンドラーに接続します。 debuggerd 適切なネイティブ トレースをログに記録すると、プロセスが終了します。(デバッガ.c, debuggerd.c)
  6. その間、クラッシュ処理アクティビティが開始されます。実際には、ステップ 5 が完了するまで待機できるように PID を渡す必要があります。私はこれをしません。ここでは、ユーザーに謝罪し、ログを送信してもよいか尋ねます。その場合は、出力を収集します。 logcat -d -v threadtime そして、 ACTION_SEND 受信者、件名、本文が入力された状態。ユーザーは送信を押す必要があります。(クラッシュハンドラー.java, SGTPuzzles.java:462, 文字列.xml:41
  7. 気をつけて logcat 失敗するか、数秒以上かかります。私が遭遇したデバイス、T-Mobile Pulse / Huawei U8220 では、logcat がすぐに T (トレースされた) 状態になり、ハングします。(クラッシュハンドラー.java:70, 文字列.xml:51)

Android 以外の状況では、一部が異なります。独自のネイティブ トレースを収集する必要があります。を参照してください。 この他の質問, 、持っている libc の種類に応じて。そのトレースをダンプし、別のクラッシュ ハンドラー プロセスを起動し、プラットフォームに適した方法で電子メールを送信する必要がありますが、一般的なアプローチはまだ機能すると思います。

他のヒント

私は少し遅れてんだけど、私は正確に同じニーズを持っていた、と私はをJNIコード内部の一般的なクラッシュ(SEGVSIBGUSなど)を引くことで、それに対処するための小さなライブラリを開発しましたの、および定期的なjava.lang.Error例外をすることによって、それらを交換してください。クライアントは、Android> = 4.1.1上で実行されている場合のボーナスは、スタックトレースがクラッシュ(フルネイティブ・スタック・トレースを含む擬似トレース)の> のバックトレース解決のの最ものから回復することを可能にする必要があります。 (コードは真新しく、成功と失敗を報告してください)。

https://github.com/xroche/coffeecatchする

詳細情報 (コードは BSD 2条項ライセンス

コントロールは、Javaコードに戻される前に

私の限られた経験(非アンドロイド)では、JNIコードでSIGSEGVは、一般的にJVMがクラッシュします。私は漠然と、あなたがSIGSEGVをキャッチ、しかしAFAICRはあなたがそうすることができることを期待することはできませんすることができますいくつかの非Sun JVMの話を聞い思い出します。

プロセスの継続的な動作は正式に定義されていないとして、

あなたはSIGSEGV(またはSIGFPEまたはSIGILL)の後にはほとんどを行うことができますが、((2)はsigactionを参照)ハンドラCでそれらをキャッチしようとすることができます。

scroll top