什么是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。