web-dev-qa-db-ja.com

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

私は プロジェクト を新しいAndroid Native Development Kit(すなわちJNI)に移動しているので、SIGSEGVが発生した場合はそれをキャッチしたい(おそらくSIGILL、 SIGABRT、SIGFPE)現在発生していることの代わりに(またはその前に)Niceクラッシュレポートダイアログを表示するために:プロセスの即時の不意の死、および場合によってはOSによる再起動の試み。編集: JVM/Dalvik VMはシグナルをキャッチし、スタックトレースおよびその他の有用な情報を記録します。ユーザーにその情報を実際にメールで送信するオプションを提供したいだけです。)

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

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

89
Chris Boyle

Edit:_READ_LOGS_がなくなったため、Jelly Bean以降ではスタックトレースを取得できません。 。 :-(

私は実際に、あまりにもエキゾチックなことを何もせずに機能するシグナルハンドラを取得し、それを使用してコードをリリースしました。 ongithub それ以降のクラッシュハンドラ)。方法は次のとおりです。

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

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

79
Chris Boyle

少し遅れましたが、まったく同じニーズがあり、一般的なクラッシュ(SEGVSIBGUSなど)をキャッチすることで、それに対処する小さなライブラリを開発しました。内部JNIコード、およびそれらを通常のJava.lang.Errorexceptions。ボーナス、クライアントがAndroid> = 4.1.1、スタックトレースは、クラッシュ(完全なネイティブスタックトレースを含む擬似トレース)の解決済みbacktraceを埋め込みます。悪質なクラッシュ(たとえば、アロケータを破損した場合)からは回復しませんが、少なくともmostから回復できるはずです。 (成功と失敗を報告してください、コードは新しいです)

詳細は https://github.com/xroche/coffeecatch (code isBSD 2-Clauses license

14
xroche

FWIW、 Google Breakpad Androidで正常に動作します。移植作業を行い、Firefox Mobileの一部として出荷しています。クライアント側でスタックトレースを提供しないため、少しセットアップが必要です)。

6
Ted Mielczarek

私の限られた経験(Android以外)で、JNIコードのSIGSEGVは通常、Javaコードに制御が戻る前にJVMをクラッシュさせます。Sun以外のJVMについて聞いたことを漠然と思い出しますSIGSEGVをキャッチしますが、AFAICRを使用すると期待できません。

プロセスの進行中の動作は公式に定義されていないため、SIGSEGV(またはSIGFPEまたはSIGILL)ハンドラーの後ではほとんど実行できませんが、Cでそれらをキャッチしようとすることができます(sigaction(2)を参照)。

5
mas90