关于APP应用无响应的处理

时间:2025-01-25 07:41:53

什么是ANR
ANR,是“Application Not Responding”的缩写,即“应用程序无响应”。在Android中,ActivityManagerService(简称AMS)和WindowManagerService(简称WMS)会监测应用程序的响应时间,如果应用程序主线程(即UI线程)在超时时间内对输入事件没有处理完毕,或者对特定操作没有执行完毕,就会出现ANR。对于输入事件没有处理完毕产生的ANR,Android会显示一个对话框,提示用户当前应用程序没有响应,
用户可以选择继续等待或者关闭这个应用程序(也就是杀掉这个应用程序的进程)。 
    
产生ANR的原因     
ANR的产生需要同时满足三个条件:

主线程:只有应用程序进程的主线程响应超时才会产生ANR;

超时时间:产生ANR的上下文不同,超时时间也会不同,但只要在这个时间上限内没有响应就会ANR;

输入事件/特定操作:输入事件是指按键、触屏等设备输入事件,特定操作是指BroadcastReceiver和Service的生命周期中的各个函数,产生ANR的上下文不同,导致ANR的原因也会不同; 
其实很多情况下产生ANR,是系统卡顿导致的手机超时,app程序等待超时。如果需要找到根本原因,一般非常困难,但是我们可以考虑一些规避的方法。

手机一般发生anr都会跑到frameworks/base / services/core/java/com/android/server/am/函数中,一般anr有几种表现形式,一个是静默ANR,现象是手机应用一直停在
一个界面,类似假死状态,另外一种情况是有弹出对话框,显示应用程序无反应,但是有些程序发现的anr一个是后台进程,对用户体验不太好,可以做一些优化。

//sw 20180305 add background and blacklist process anr killed
 import ; 

//#ifdef 1
//,20180523,third party app directly kill app
import ;
import ;
//#endif


 //#ifdef 1
        //james,20180523,third party app directly kill app
        boolean isThirdPartyProcess = isThirdPartyProcess(app);
        if ((crashTime != null && now < crashTime + ProcessList.MIN_CRASH_INTERVAL) || isThirdPartyProcess) {
        //#endif
            // The process crashed again very quickly. If it was a bound foreground service, let's
            // try to restart again in a while, otherwise the process loses!
            (TAG, "Process " +
                    + " has crashed too many times: killing!");
            (EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
                    , , );
            (app);
            //#ifdef 1
            //james,20180523,third party app directly kill app
            if (! || isThirdPartyProcess) {
            //#endif
            
          // We don't want to start this process again until the user
                // explicitly does so...  but for persistent process, we really
                // need to keep it running.  If a persistent process is actually
                // repeatedly crashing, then badness for everyone.
                (EventLogTags.AM_PROC_BAD, , ,
                        );
                if (!) {
                    // XXX We don't have a way to mark isolated processes
                    // as bad, since they don't have a peristent identity.
                    (, ,
                            new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
                    (, );
                }
                = true;
                = true;
                // Don't let services in this process be restarted and potentially
                // annoy the user repeatedly.  Unless it is persistent, since those
                // processes run critical code.
                (app, false, tryAgain, "crash");
                ();
                //#ifdef 1
                //james,20180523,third party app directly kill app
                if (!showBackground || isThirdPartyProcess) {
                //#endif
                    return false;
                }    
            
   //sw 20180305 add background and blacklist process anr killed
    public void forceStopPackageAndDisableComponent(final ArrayList<String> pkgList) {
        final String PACKAGE_NAME = "";
        final String CLASS_NAME = "";
        final String ACTION_KILL_DIABLE_APP = "action_kill_diable_app";
        final String KEY_KILL_DIABLE_APP = "key_kill_diable_app";
        
        Intent intent = new Intent();
        (ACTION_KILL_DIABLE_APP);
        (PACKAGE_NAME, CLASS_NAME);
        (KEY_KILL_DIABLE_APP, pkgList);
        (intent);
    }


public final static List<String> PROCEE_WHITE_LIST = new ArrayList<String>() {
    {
        add("");
    }
};

    final boolean isWhiteListprocess(ProcessRecord app) {
        String packageName = ;
        (TAG, "james--packageName="+packageName);
        for (int i = 0; i < PROCEE_WHITE_LIST.size(); i++) {
            String whiteListpacakgeName = PROCEE_WHITE_LIST.get(i);
            (TAG, "james--whiteListpacakgeName="+whiteListpacakgeName);
            if ((packageName)) {
                return true;
            }
        }
        return false;
    }


    final boolean isNeedKillBackgrondprocess(ProcessRecord app) {
        boolean showforeground = ;

        String packageName = ;
        (TAG, "james--packageName="+packageName);
        (TAG, "james--foregroundActivities="+);

        if (app != null && > 0 && != MY_PID && !showforeground ) {
            if (isWhiteListprocess(app)) {
                return false;
            } else {
                ("james--kill background and balcklist anr process", true);
                ArrayList<String> pkgList = new ArrayList<String>();
                ();
                forceStopPackageAndDisableComponent(pkgList);
                
                (TAG, "james--app is killed="+);
                return true;
            }
        }
        return false;
    }
    boolean isThirdPartyProcess(ProcessRecord app)
    {
         String packageName = ;
         try {
           PackageInfo packageInfo = ().getPackageInfo(packageName, 0); 
           if (( & ApplicationInfo.FLAG_SYSTEM) <= 0) { 
                return true;

            } 
        } catch (NameNotFoundException e) {
        
        }

        return false;
    }

    
    final void appNotResponding(ProcessRecord app, ActivityRecord activity,
            ActivityRecord parent, boolean aboveSystem, final String annotation) {
        ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
        SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);

        boolean isSetupWardComplete = (
                (), .USER_SETUP_COMPLETE, 0) != 0;
        //isSetupWardComplete=true;
        ("james", "isSetupWardComplete="+isSetupWardComplete);
        if (!isSetupWardComplete) {

            // #ifdef LAVA_EDIT
            // james.2017-3-14,directly kill app(exception system_server).
            if (app != null && > 0 && != MY_PID) {
                ("kill before setupward", true);
            }
            // #endif

            (TAG, "can't report anr info before setupward complete");
            return;
        } else {

            //sw 20180305 add background and blacklist process anr killed
            /*
            if (isNeedKillBackgrondprocess(app)) {
                return;
            }*/
        }

        if ( != null) {
            try {
                // 0 == continue, -1 = kill process immediately
                int res = (
                        , , annotation);
                if (res < 0 && != MY_PID) {
                    ("anr", true);
                }
            } catch (RemoteException e) {
                = null;
                ().setActivityController(null);
            }
        }

        long anrTime = ();
        if (ActivityManagerService.MONITOR_CPU_USAGE) {
            ();
        }

        // Unless configured otherwise, swallow ANRs in background processes & kill the process.
        boolean showBackground = ((),
                .ANR_SHOW_BACKGROUND, 0) != 0;
        /// M: ANR Debug Mechanism
        if ((mService, app, activity, parent, aboveSystem,
                annotation, showBackground))
            return;
        boolean isSilentANR;

        synchronized (mService) {
            // () can block for a long time, so ignore ANRs while shutting down.
            if () {
                (TAG, "During shutdown skipping ANR: " + app + " " + annotation);
                return;
            } else if () {
                (TAG, "Skipping duplicate ANR: " + app + " " + annotation);
                return;
            } else if () {
                (TAG, "Crashing app skipping ANR: " + app + " " + annotation);
                return;
            } else if () {
                (TAG, "App already killed by AM skipping ANR: " + app + " " + annotation);
                return;
            } else if () {
                (TAG, "Skipping died app ANR: " + app + " " + annotation);
                return;
            }

            // In case we come through here for the same app before completing
            // this one, mark as anring now so we will bail out.
            = true;

            // Log the ANR to the event log.
            (EventLogTags.AM_ANR, , ,
                    , , annotation);

            // Dump thread traces as quickly as we can, starting with "interesting" processes.
            ();

            // Don't dump other PIDs if it's a background ANR
            isSilentANR = !showBackground && !isInterestingForBackgroundTraces(app);
            if (!isSilentANR) {
                int parentPid = ;
                if (parent != null && != null && > 0) {
                    parentPid = ;
                }
                if (parentPid != ) (parentPid);

                if (MY_PID != && MY_PID != parentPid) (MY_PID);

                for (int i = () - 1; i >= 0; i--) {
                    ProcessRecord r = (i);
                    if (r != null && != null) {
                        int pid = ;
                        if (pid > 0 && pid != && pid != parentPid && pid != MY_PID) {
                            if () {
                                (pid);
                                if (DEBUG_ANR) (TAG, "Adding persistent proc: " + r);
                            } else if () {
                                (pid);
                                if (DEBUG_ANR) (TAG, "Adding likely IME: " + r);
                            } else {
                                (pid, );
                                if (DEBUG_ANR) (TAG, "Adding ANR proc: " + r);
                            }
                        }
                    }
                }
            }
        }

        // Log the ANR to the main log.
        StringBuilder info = new StringBuilder();
        (0);
        ("ANR in ").append();
        if (activity != null && != null) {
            (" (").append().append(")");
        }
        ("\n");
        ("PID: ").append().append("\n");
        if (annotation != null) {
            ("Reason: ").append(annotation).append("\n");
        }
        if (parent != null && parent != activity) {
            ("Parent: ").append().append("\n");
        }

        ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);

        // don't dump native PIDs for background ANRs unless it is the process of interest
        String[] nativeProcs = null;
        if (isSilentANR) {
            for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) {
                if (NATIVE_STACKS_OF_INTEREST[i].equals()) {
                    nativeProcs = new String[] { };
                    break;
                }
            }
        } else {
            nativeProcs = NATIVE_STACKS_OF_INTEREST;
        }

        int[] pids = nativeProcs == null ? null : (nativeProcs);
        ArrayList<Integer> nativePids = null;

        if (pids != null) {
            nativePids = new ArrayList<Integer>();
            for (int i : pids) {
                (i);
            }
        }

        // For background ANRs, don't pass the ProcessCpuTracker to
        // avoid spending 1/2 second collecting stats to rank lastPids.
        File tracesFile = (
                true, firstPids,
                (isSilentANR) ? null : processCpuTracker,
                (isSilentANR) ? null : lastPids,
                nativePids);

        String cpuInfo = null;
        if (ActivityManagerService.MONITOR_CPU_USAGE) {
            ();
            synchronized () {
                cpuInfo = (anrTime);
            }
            (());
            (cpuInfo);
        }

        ((anrTime));

        (TAG, ());
        if (tracesFile == null) {
            // There is no trace file, so dump (only) the alleged culprit's threads to the log
            (, Process.SIGNAL_QUIT);
        }

        ("anr", app, , activity, parent, annotation,
                cpuInfo, tracesFile, null);

        if ( != null) {
            try {
                // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
                int res = (
                        , , ());
                if (res != 0) {
                    if (res < 0 && != MY_PID) {
                        ("anr", true);
                    } else {
                        synchronized (mService) {
                            (app);
                        }
                    }
                    return;
                }
            } catch (RemoteException e) {
                = null;
                ().setActivityController(null);
            }
        }

        synchronized (mService) {
            (, );

            if (isSilentANR) {
                ("bg anr", true);
                return;
            }

            // Set the app's notResponding state, and look up the errorReportReceiver
            makeAppNotRespondingLocked(app,
                    activity != null ? : null,
                    annotation != null ? "ANR " + annotation : "ANR",
                    ());

            // Bring up the infamous App Not Responding dialog
            Message msg = ();
            HashMap<String, Object> map = new HashMap<String, Object>();
            = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
            = map;
            msg.arg1 = aboveSystem ? 1 : 0;
            ("app", app);
            if (activity != null) {
                ("activity", activity);
            }

            (msg);
        }
    }

    private void makeAppNotRespondingLocked(ProcessRecord app,
            String activity, String shortMsg, String longMsg) {
        = true;
        = generateProcessError(app,
                .NOT_RESPONDING,
                activity, shortMsg, longMsg, null);
        startAppProblemLocked(app);
        ();
    }

    void handleShowAnrUi(Message msg) {
        Dialog d = null;
        synchronized (mService) {
            HashMap<String, Object> data = (HashMap<String, Object>) ;
            ProcessRecord proc = (ProcessRecord)("app");
            if (proc != null && != null) {
                (TAG, "App already has anr dialog: " + proc);
                (mContext, .ACTION_APP_ANR,
                        AppNotRespondingDialog.ALREADY_SHOWING);
                return;
            }

            //,20180523,third party app directly kill app
            boolean isThirdPartyProcess = isThirdPartyProcess(proc);
            //#endif
            Intent intent = new Intent("");
            if (!) {
                (Intent.FLAG_RECEIVER_REGISTERED_ONLY
                        | Intent.FLAG_RECEIVER_FOREGROUND);
            }
            (null, null, intent,
                    null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                    null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);

            boolean showBackground = ((),
                    .ANR_SHOW_BACKGROUND, 0) != 0;
            //#ifdef 1
            //,20180523,third party app directly kill app
            if (!isThirdPartyProcess && (() || showBackground)) {
            //#endif         

2:vendor/mediatek/proprietary/frameworks/base / services/core/java/com/mediatek/server/anr/

     synchronized (mService) {
                (TAG, "appNotResponding-got this lock: " + app + " "
                        + annotation + ",shuttingDown: " + shuttingDown + ",notResponding: "
                        + notResponding + ",crashing: " + crashing);
                // () can block for a long time,
                // so ignore ANRs while shutting down.
                if(shuttingDown || notResponding || crashing){
                     //#ifdef 1
                    //james,20180712,if notResponding = ture,force kill app process
                    if(notResponding)
                    {
                        isSilentANR = !showBackground && !()
                            && pid != mAmsPid;
                        if (isSilentANR) {
                            (app, new Object[] { "bg anr", true });
                            return true;
                        }
                        // Bring up the infamous App Not Responding dialog
                        Message msg = ();
                        HashMap<String, Object> map = new HashMap<String, Object>();
                        = (int) (mAMS);
                        = map;
                        msg.arg1 = aboveSystem ? 1 : 0;
                        ("app", app);
                        if (activity != null) {
                            ("activity", activity);
                        }

                        Handler mUiHandler = (Handler) (mService);
                        (msg);
            
                        
                    }
                    //#endif

                    
这个其实只是规避,改善用户体验,其实没有从根本上解决ANR。

相关文章