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
附下图说明service的启动过程
*每个进程binder线程数是16个
这里的args发送的是service的flag
service超时未响应时,发送消息去做下一步操作
停止服务并弹出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 }
版权声明:本文为loveseal518原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。