AndroidキャプチャRuntimeException,ANR,Native信号異常

10820 ワード

三大崩壊
よく知られているように、安卓端には3つの崩壊があり、アプリケーションが崩壊します.
  • RuntimeException
  • java端の運転時異常.例えば、空のポインタなど、発生時に適用がクラッシュする.

  • ANR
  • アンドロイドはユーザー体験のために設けられた保護メカニズムであり、アプリケーションがメインスレッドで時間のかかる操作を行うと、長時間応答が発生せず、ユーザーに待ち続けるかどうかを尋ねる選択ボックスが発生し、ユーザーが閉じるかを選択しないか、または長時間選択しないと、アプリケーションが閉鎖される.

  • Native信号異常
  • 我々のコードがサードパーティのsoパケットにインポートされると、c/c++コードのいくつかの問題によりnative信号が発生し、アプリケーションが直接崩壊し、大量のアセンブリのスタック情報を報告する.


  • この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    ,             
        }
    
    }