Android ANR(超时未响应) 触发的原理(基于Android 9/10)

ANR的触发场景

1.前台应用启动服务(startservice)

2.后台应用启动服务

3.前台广播10秒(android.content.intent#Flag_receiver_***)

4.后台广播60秒

5.CP

6.输入事件

*以上时间数据基于android 10(不同的api会有差异)

* targetSdkVersion 8.0以后才有前台ANR

*检测ANR的机制:消息机制,looper循环去检测

android 源码中的 超时时间定义:

常见service触发机制:

*handleThread处理耗时操作容易导致ANR

Android ANR(超时未响应) 触发的原理(基于Android 9/10)_第1张图片

附下图说明service的启动过程

Android ANR(超时未响应) 触发的原理(基于Android 9/10)_第2张图片

*每个进程binder线程数是16个 

 Android ANR(超时未响应) 触发的原理(基于Android 9/10)_第3张图片

 Android ANR(超时未响应) 触发的原理(基于Android 9/10)_第4张图片

这里的args发送的是service的flag

 Android ANR(超时未响应) 触发的原理(基于Android 9/10)_第5张图片

service超时未响应时,发送消息去做下一步操作

Android ANR(超时未响应) 触发的原理(基于Android 9/10)_第6张图片

停止服务并弹出anr提示 

ANR的显示

ANR提示dialog的源码在AppErrorDialog文件中,从android10开始 AppNotRespondingDialog分成了独立的文件。

*Android 11 中新增了 ANRhelper

 ​
9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java



​/frameworks/base/services/core/java/com/android/server/am/AppErrors.java

793    void handleShowAppErrorUi(Message msg) {
794        AppErrorDialog.Data data = (AppErrorDialog.Data) msg.obj;
795        boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
796                Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
797
798        AppErrorDialog dialogToShow = null;
799        final String packageName;
800        final int userId;
801        synchronized (mService) {
802            final ProcessRecord proc = data.proc;
803            final AppErrorResult res = data.result;
804            if (proc == null) {
805                Slog.e(TAG, "handleShowAppErrorUi: proc is null");
806                return;
807            }
808            packageName = proc.info.packageName;
809            userId = proc.userId;
810            if (proc.crashDialog != null) {
811                Slog.e(TAG, "App already has crash dialog: " + proc);
812                if (res != null) {
813                    res.set(AppErrorDialog.ALREADY_SHOWING);
814                }
815                return;
816            }
817            boolean isBackground = (UserHandle.getAppId(proc.uid)
818                    >= Process.FIRST_APPLICATION_UID
819                    && proc.pid != MY_PID);
820            for (int profileId : mService.mUserController.getCurrentProfileIds()) {
821                isBackground &= (userId != profileId);
822            }
823            if (isBackground && !showBackground) {
824                Slog.w(TAG, "Skipping crash dialog of " + proc + ": background");
825                if (res != null) {
826                    res.set(AppErrorDialog.BACKGROUND_USER);
827                }
828                return;
829            }
830            final boolean showFirstCrash = Settings.Global.getInt(
831                    mContext.getContentResolver(),
832                    Settings.Global.SHOW_FIRST_CRASH_DIALOG, 0) != 0;
833            final boolean showFirstCrashDevOption = Settings.Secure.getIntForUser(
834                    mContext.getContentResolver(),
835                    Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
836                    0,
837                    mService.mUserController.getCurrentUserId()) != 0;
838            final boolean crashSilenced = mAppsNotReportingCrashes != null &&
839                    mAppsNotReportingCrashes.contains(proc.info.packageName);
840            if ((mService.canShowErrorDialogs() || showBackground) && !crashSilenced
841                    && (showFirstCrash || showFirstCrashDevOption || data.repeating)) {
842                proc.crashDialog = dialogToShow = new AppErrorDialog(mContext, mService, data);
843            } else {
844                // The device is asleep, so just pretend that the user
845                // saw a crash dialog and hit "force quit".
846                if (res != null) {
847                    res.set(AppErrorDialog.CANT_SHOW);
848                }
849            }
850        }
851        // If we've created a crash dialog, show it without the lock held
852        if (dialogToShow != null) {
853            Slog.i(TAG, "Showing crash dialog for package " + packageName + " u" + userId);
854            dialogToShow.show();
855        }
856    }

你可能感兴趣的:(android,android)