AndroidキャプチャRuntimeException,ANR,Native信号異常
よく知られているように、安卓端には3つの崩壊があり、アプリケーションが崩壊します.
この3つの異常をキャプチャする方法についてお話しします
RuntimExceptionのキャプチャ
/**
*
*
java (Runtime-Exception)
*
Uncaught , , UncaughtExceptionHandler, ,
uncaughtException 。 handler , handler。
, handler, :
MyCrashHandler myCrashHandler = new MyCrashHandler();
Thread.setDefaultUncaughtExceptionHandler(myCrashHandler);
handler, JavaCrashHandler, myUncaughtExceptionToDo 。
*/
public class JavaCrashHandler implements UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread thread, final Throwable throwable) {
//
String stackTraceInfo = getStackTraceInfo(throwable);
myUncaughtExceptionToDo();
}
/**
*
*/
public void myUncaughtExceptionToDo() {
// //
}
/**
*
Exception
*
Exception , , , Bug。
printStackTrace , printStackTrace ,
, 。
*/
public static String getStackTraceInfo(final Throwable throwable) {
String trace = "";
try {
Writer writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
throwable.printStackTrace(pw);
trace = writer.toString();
pw.close();
} catch (Exception e) {
return "";
}
return trace;
}
}
キャプチャANR
ANRはキャプチャできませんが、後でメッセージを受け取って、必要な操作をすることができます.
/**
* ANR , ANR , ANR
*
*
onReceive()
if (intent.getAction().equals(ACTION_ANR)) {
// do you want to do
}
*
* @author aaa
*
*/
public class ANRCacheHelper {
private static MyReceiver myReceiver;
public static void registerANRReceiver(Context context){
myReceiver = new MyReceiver();
context.registerReceiver(myReceiver, new IntentFilter(ACTION_ANR));
}
public static void unregisterANRReceiver(Context context){
if (myReceiver == null) {
return;
}
context.unregisterReceiver(myReceiver);
}
private static final String ACTION_ANR = "android.intent.action.ANR";
private static class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_ANR)) {
// to do
}
}
}
}
キャプチャNative信号異常
NativeCacheHandler.java
package com.wtest.wlib.android.catchs;
import android.util.Log;
/**
* native
* @author aaa
*
*/
public class NativeCacheHandler {
static {
// Android.mk
// libs/armeabi/libwlibcatchs.so ,
System.loadLibrary("wlibcatchs");
}
/**
* Native
*/
public void registerNativeCacheHandler(){
nativeRegisterHandler();
}
/**
* native ,
*/
public void onNativeCrashed() {
Log.d("wtest", " , ");
// new RuntimeException("crashed here (native trace should follow after the Java trace)").printStackTrace();
// startActivity(new Intent(this, MainActivity.class));
}
/**
* !!!
* , ,
*
*/
@Deprecated
public void makeError() {
nativeMakeError();
}
private native int nativeRegisterHandler();
private native boolean nativeMakeError();
}
NativeCacheHandler.cpp
/**
# 。
# 。
# , # 。
, 。
*/
// #include
#include // jni java c ,
#include // C
#include // signal.h , 。
//#include "NativeActivity.hpp"
#include // JNI log
// : , , C 、 、 。
#ifdef MIKMOD // #ifdef ,
// #include "mikmod_build.h"
#endif // #endif #ifdef
#define DO_TRY // #define
#define DO_CATCH(loc)
#define CATCH_SIGNALS
extern "C" // C++ C , C++ extern “C” 。 , C 。 C++ C 。
{
#ifdef CATCH_SIGNALS
static struct sigaction old_sa[NSIG];
/**
JNIEnv :
NewObject: Java
NewString: Java String
NewArray: Type
GetField: Type
SetField: Type
GetStaticField: Type static
SetStaticField: Type static
CallMethod: Type
CallStaticMethod: Type static
, jni.h 。
*/
static JNIEnv *g_sigEnv; // JNIEnv // JNIEnv Java , JNIEnv* , Java 。
// , Java , Java , Java 。JNIEnv JNI Java 。
static jobject g_sigObj; // native static , obj native
// native static , obj native class (static , class )
static jmethodID g_sigNativeCrashed;
// ,
void android_sigaction(int signal, siginfo_t *info, void *reserved)
{
// java
g_sigEnv->CallVoidMethod(g_sigObj, g_sigNativeCrashed);
old_sa[signal].sa_handler(signal);
}
#endif
static jshortArray g_audioSamples;
// Android VM(Virtual Machine) System.loadLibrary() , C JNI_OnLoad() 。
// JNI_OnLoad() ,Android (No JNI_OnLoad found)
// 13:53:12.204: D/dalvikvm(361): No JNI_OnLoad found in /data/data/com.conowen.helloworld/lib/libHelloWorld.so 0x44edea98, skipping init
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNIEnv *env = NULL;
/*JavaVM::GetEnv jint (*GetEnv)(JavaVM*, void**, jint);
* GetEnv() Jni ,
* Dalvik Multi-threading 。 JNI_OnLoad() ,
* JNI Env , vm->GetEnv
*
*/
// JNI Env
if (jvm->GetEnv((void **)&env, JNI_VERSION_1_2))
return JNI_ERR;
jclass cls = env->FindClass("com/wtest/wlib/android/catchs/NativeCacheHandler");
#ifdef CATCH_SIGNALS
g_sigEnv = env;
g_sigNativeCrashed = env->GetMethodID(cls, "onNativeCrashed", "()V");
#endif
return JNI_VERSION_1_2;
}
JNIEXPORT jint JNICALL
Java_com_wtest_wlib_android_catchs_NativeCacheHandler_nativeRegisterHandler(JNIEnv *env, jobject this_)
{
#ifdef CATCH_SIGNALS
// Try to catch crashes...
g_sigObj = env->NewGlobalRef(this_); // 。 NewGlobalRef 。
struct sigaction handler; // struct ( java javabean)
memset( // c ,void *memset(void *buffer, int c, int count); buffer count c
&handler, // 1: 。
0, // 2: 。 int , 。
sizeof( //
struct sigaction)); // 3: 。
// // sigaction 、 、 。
// struct sigaction {
// void (*sa_handler)(int); // signum , SIG_DFL ,SIG_IGN , 。 。
// void (*sa_sigaction)(int, siginfo_t *, void *); // sa_flags SA_SIGINFO ,sa_sigaction signum 。
// sigset_t sa_mask; // 。
// int sa_flags; // , 0 or , SA_RESETHAND,SA_ONSTACK | SA_SIGINFO。
// void (*sa_restorer)(void); // , 。
// }
//
handler.sa_sigaction = android_sigaction;
// 。
// SA_RESTART: syscall 。
// SA_NOCLDSTOP: SIGCHLD 。
// SA_NOCLDWAIT: SIGCHLD , 。
// SA_NODEFER: , 。
// SA_RESETHAND: 。
// SA_SIGINFO: sa_sigaction sa_handler 。
handler.sa_flags = SA_RESETHAND;
//
// 1 , SIGKILL SIGSTOP , , 。
// 2 sigaction , , , 。
// 3 act , , NULL。
#define CATCHSIG(X) sigaction(X, &handler, &old_sa[X])
CATCHSIG(SIGILL); // 4
CATCHSIG(SIGABRT); // 6 abort
CATCHSIG(SIGBUS); // 7
CATCHSIG(SIGFPE); // 8
CATCHSIG(SIGSEGV); // 11 ( )
CATCHSIG(SIGSTKFLT);// 16
CATCHSIG(SIGPIPE); // 13
#endif
}
JNIEXPORT jboolean JNICALL
Java_com_wtest_wlib_android_catchs_NativeCacheHandler_nativeMakeError()
{
// 11
char *ptr = NULL; // NULL, , 0
*ptr = '!'; // ERROR HERE! // , 0 ,
}
}