一、ANR出現(xiàn)原因
Android 系統(tǒng)中熏兄, ActivityManagerService( 簡稱 AMS)和WindowManagerService( 簡 稱 WMS)會檢測App的響應時間品洛,如果App在特定時間無法相應屏幕觸摸或鍵盤輸入時間,或者特定事件沒有處理完畢摩桶,就會出現(xiàn) ANR桥状。
1、以下四個條件都可以造成 ANR 發(fā)生:
-
InputDispatching Timeout
:5 秒內(nèi)無法響應屏幕觸摸事件或鍵盤輸入事件 -
BroadcastQueue Timeout
:在執(zhí)行前臺廣播(BroadcastReceiver)的 onReceive()函數(shù)時 10 秒沒有處理完成硝清,后臺為 60 秒辅斟。 -
Service Timeout
:前臺服務 20 秒內(nèi),后臺服務在 200 秒內(nèi)沒有執(zhí)行完畢芦拿。 -
ContentProvider Timeout
:ContentProvider 的 publish 在 10s 內(nèi)沒進行完士飒。
二、Service ANR 源碼分析
1蔗崎、Service 造成的 e Service Timeout
Service Timeout 是位于 ActivityManager
線程中的 AMS.MainHandler
收到 SERVICE_TIMEOUT_MSG
消息時觸發(fā)变汪。
2、發(fā)送延時消息
Service 進程 attach 到 system_server 進程的過程中會調(diào)用realStartServiceLocked
蚁趁,緊接著mAm.mHandler.sendMessageAtTime() 來發(fā)送一個延時消息裙盾,延時的時常是定義好的,如前臺 Service 的 20 秒他嫡。ActivityManager 線程中的 AMS.MainHandler 收到 SERVICE_TIMEOUT_MSG 消息時會觸發(fā)番官。
- Service 是在AMS 中交給 ActiveServices 進行管理的。
調(diào)用 ActiveServices.realStartServiceLocked
方法
IApplicationThread thread; //ActivityThread 的內(nèi)部類
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException {
...
//發(fā)送 delay 消息(SERVICE_TIMEOUT_MSG
bumpServiceExecutingLocked(r, execInFg, "create");
try {
if (LOG_SERVICE_START_STOP) {
...
//最終執(zhí)行服務的 onCreate()方法
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
r.postNotification();
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app, "Died when creating service");
throw e;
} finally {
..
}
...
}
- 發(fā)送延時消息
ActiveServices.java
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
...
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0) {
r.executeFg = fg;
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
}
if (r.app != null) {
r.app.executingServices.add(r);
r.app.execServicesFg |= fg;
if (timeoutNeeded && r.app.executingServices.size() == 1) {
scheduleServiceTimeoutLocked(r.app);
}
}
} else if (r.app != null && fg && !r.app.execServicesFg) {
r.app.execServicesFg = true;
if (timeoutNeeded) {
scheduleServiceTimeoutLocked(r.app);
}
}
r.executeFg |= fg;
r.executeNesting++;
r.executingStart = now;
}
static final int SERVICE_TIMEOUT = 20*1000; //前臺服務 20 秒內(nèi)
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10; //后臺服務在 200 秒
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
}
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
//發(fā)送延時消息
//當超時后仍沒有 remove 該SERVICE_TIMEOUT_MSG 消息钢属,則執(zhí)行 service Timeout 流程
mAm.mHandler.sendMessageDelayed(msg,
proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}
進入 ActivityManagerService#MainHandler
處理消息
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
final MainHandler mHandler;
final ActiveServices mServices;
final class MainHandler extends Handler {
public MainHandler(Looper looper) {
super(looper, null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case GC_BACKGROUND_PROCESSES_MSG: {
synchronized (ActivityManagerService.this) {
performAppGcsIfAppropriateLocked();
}
} break;
case SERVICE_TIMEOUT_MSG: { //處理 service 的超時時間 ANR
mServices.serviceTimeout((ProcessRecord)msg.obj);
} break;
...
}
}
}
進入ActiveServices#serviceTimeout
進行處理
void serviceTimeout(ProcessRecord proc) {
String anrMessage = null;
synchronized(mAm) {
if (proc.isDebugging()) {
// The app's being debugged, ignore timeout.
return;
}
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
}
final long now = SystemClock.uptimeMillis();
final long maxTime = now -
(proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
ServiceRecord timeout = null;
long nextTime = 0;
for (int i=proc.executingServices.size()-1; i>=0; i--) {
ServiceRecord sr = proc.executingServices.valueAt(i);
if (sr.executingStart < maxTime) {
timeout = sr;
break;
}
if (sr.executingStart > nextTime) {
nextTime = sr.executingStart;
}
}
if (timeout != null && mAm.mProcessList.mLruProcesses.contains(proc)) {
Slog.w(TAG, "Timeout executing service: " + timeout);
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 1024);
pw.println(timeout);
timeout.dump(pw, " ");
pw.close();
mLastAnrDump = sw.toString();
mAm.mHandler.removeCallbacks(mLastAnrDumpClearer);
mAm.mHandler.postDelayed(mLastAnrDumpClearer, LAST_ANR_LIFETIME_DURATION_MSECS);
//異常 消息
anrMessage = "executing service " + timeout.shortInstanceName;
} else {
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg
? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT));
}
}
if (anrMessage != null) {
//處理 NAR
mAm.mAnrHelper.appNotResponding(proc, anrMessage);
}
}
無論是四大組件或者進程等只要發(fā)生ANR徘熔,最終都會調(diào)用 AMS.appNotResponding()
方法。
class AnrHelper {
//保存 ANR 信息
private final ArrayList<AnrRecord> mAnrRecords = new ArrayList<>();
private final AtomicBoolean mRunning = new AtomicBoolean(false);
void appNotResponding(ProcessRecord anrProcess, String annotation) {
appNotResponding(anrProcess, null /* activityShortComponentName */, null /* aInfo */,
null /* parentShortComponentName */, null /* parentProcess */,
false /* aboveSystem */, annotation);
}
void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
synchronized (mAnrRecords) {
mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
parentShortComponentName, parentProcess, aboveSystem, annotation));
}
startAnrConsumerIfNeeded();
}
private void startAnrConsumerIfNeeded() {
if (mRunning.compareAndSet(false, true)) {
new AnrConsumerThread().start();
}
}
//執(zhí)行 ANR 的線程
private class AnrConsumerThread extends Thread {
AnrConsumerThread() {
super("AnrConsumer");
}
private AnrRecord next() {
synchronized (mAnrRecords) {
return mAnrRecords.isEmpty() ? null : mAnrRecords.remove(0);
}
}
@Override
public void run() {
AnrRecord r;
while ((r = next()) != null) {
final long startTime = SystemClock.uptimeMillis();
// If there are many ANR at the same time, the latency may be larger. If the latency
// is too large, the stack trace might not be meaningful.
final long reportLatency = startTime - r.mTimestamp;
final boolean onlyDumpSelf = reportLatency > EXPIRED_REPORT_TIME_MS;
r.appNotResponding(onlyDumpSelf);
final long endTime = SystemClock.uptimeMillis();
Slog.d(TAG, "Completed ANR of " + r.mApp.processName + " in "
+ (endTime - startTime) + "ms, latency " + reportLatency
+ (onlyDumpSelf ? "ms (expired, only dump ANR app)" : "ms"));
}
mRunning.set(false);
synchronized (mAnrRecords) {
// The race should be unlikely to happen. Just to make sure we don't miss.
if (!mAnrRecords.isEmpty()) {
startAnrConsumerIfNeeded();
}
}
}
}
//存儲 ANR 信息類
private static class AnrRecord {
final ProcessRecord mApp;
final String mActivityShortComponentName;
final String mParentShortComponentName;
final String mAnnotation;
final ApplicationInfo mAppInfo;
final WindowProcessController mParentProcess;
final boolean mAboveSystem;
final long mTimestamp = SystemClock.uptimeMillis();
AnrRecord(ProcessRecord anrProcess, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
mApp = anrProcess;
mActivityShortComponentName = activityShortComponentName;
mParentShortComponentName = parentShortComponentName;
mAnnotation = annotation;
mAppInfo = aInfo;
mParentProcess = parentProcess;
mAboveSystem = aboveSystem;
}
void appNotResponding(boolean onlyDumpSelf) {
mApp.appNotResponding(mActivityShortComponentName, mAppInfo,
mParentShortComponentName, mParentProcess, mAboveSystem, mAnnotation,
onlyDumpSelf);
}
}
}
- 進入目標進程的主線程創(chuàng)建 Service
進入 ActivityThread#ApplicationThread#scheduleCreateService
的方法淆党。
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
//發(fā)送 CREATE_SERVICE 消息
sendMessage(H.CREATE_SERVICE, s);
}
調(diào)用 ActivityThread#H
類發(fā)送消息
class H extends Handler {
public void handleMessage(Message msg)
switch (msg.what) {
case CREATE_SERVICE:
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
("serviceCreate: " + String.valueOf(msg.obj)));
}
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
}
private void handleCreateService(CreateServiceData data) {
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
//創(chuàng)建 ContextImpl 對象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
//創(chuàng)建 Application 對象
Application app = packageInfo.makeApplication(false, mInstrumentation);
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
// Service resources must be initialized with the same loaders as the application
// context.
context.getResources().addLoaders(
app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
context.setOuterContext(service);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
//調(diào)用服務 onCreate()方法
service.onCreate();
mServices.put(data.token, service);
try {
//取消 AMS.MainHandler 的延時消息
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
這個方法中會創(chuàng)建目標服務對象酷师,以及回調(diào)常用的 Service 的 onCreate() 方法,緊接著通過 serviceDoneExecuting() 回到 system_server
執(zhí)行取消 AMS.MainHandler
的延時消息
3染乌、回到 system_server 進程執(zhí)行取消 AMS.MainHandler 的延時消息山孔。
進入ActivityManagerService#serviceDoneExecuting
方法
final ActiveServices mServices;
public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
throw new IllegalArgumentException("Invalid service token");
}
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
}
調(diào)用 ActiveServices#serviceDoneExecutingLocked
方法
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
boolean inDestroying = mDestroyingServices.contains(r);
if (r != null) {
if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
r.callStart = true;
switch (res) {
case Service.START_STICKY_COMPATIBILITY:
case Service.START_STICKY: {
// We are done with the associated start arguments.
r.findDeliveredStart(startId, false, true);
// Don't stop if killed.
r.stopIfKilled = false;
break;
}
case Service.START_NOT_STICKY: {
// We are done with the associated start arguments.
r.findDeliveredStart(startId, false, true);
if (r.getLastStartId() == startId) {
r.stopIfKilled = true;
}
break;
}
case Service.START_REDELIVER_INTENT: {
ServiceRecord.StartItem si = r.findDeliveredStart(startId, false, false);
if (si != null) {
si.deliveryCount = 0;
si.doneExecutingCount++;
// Don't stop if killed.
r.stopIfKilled = true;
}
break;
}
case Service.START_TASK_REMOVED_COMPLETE: {
r.findDeliveredStart(startId, true, true);
break;
}
default:
throw new IllegalArgumentException(
"Unknown service start result: " + res);
}
if (res == Service.START_STICKY_COMPATIBILITY) {
r.callStart = false;
}
} else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
if (!inDestroying) {
if (r.app != null) {
Slog.w(TAG, "Service done with onDestroy, but not inDestroying: "
+ r + ", app=" + r.app);
}
} else if (r.executeNesting != 1) {
Slog.w(TAG, "Service done with onDestroy, but executeNesting="
+ r.executeNesting + ": " + r);
// Fake it to keep from ANR due to orphaned entry.
r.executeNesting = 1;
}
}
final long origId = Binder.clearCallingIdentity();
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
Binder.restoreCallingIdentity(origId);
} else {
Slog.w(TAG, "Done executing unknown service from pid "
+ Binder.getCallingPid());
}
}
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "<<< DONE EXECUTING " + r
+ ": nesting=" + r.executeNesting
+ ", inDestroying=" + inDestroying + ", app=" + r.app);
else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
"<<< DONE EXECUTING " + r.shortInstanceName);
r.executeNesting--;
if (r.executeNesting <= 0) {
if (r.app != null) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"Nesting at 0 of " + r.shortInstanceName);
r.app.execServicesFg = false;
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
"No more executingServices of " + r.shortInstanceName);
//移除當前服務所在進程中沒有正在執(zhí)行的 service
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
} else if (r.executeFg) {
// Need to re-evaluate whether the app still needs to be in the foreground.
for (int i=r.app.executingServices.size()-1; i>=0; i--) {
if (r.app.executingServices.valueAt(i).executeFg) {
r.app.execServicesFg = true;
break;
}
}
}
if (inDestroying) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"doneExecuting remove destroying " + r);
mDestroyingServices.remove(r);
r.bindings.clear();
}
mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
}
r.executeFg = false;
if (r.tracker != null) {
final int memFactor = mAm.mProcessStats.getMemFactorLocked();
final long now = SystemClock.uptimeMillis();
r.tracker.setExecuting(false, memFactor, now);
r.tracker.setForeground(false, memFactor, now);
if (finishing) {
r.tracker.clearCurrentOwner(r, false);
r.tracker = null;
}
}
if (finishing) {
if (r.app != null && !r.app.isPersistent()) {
r.app.stopService(r);
r.app.updateBoundClientUids();
if (r.whitelistManager) {
updateWhitelistManagerLocked(r.app);
}
}
r.setProcess(null);
}
}
}
此方法中 Service 邏輯處理完成則移除之前延時的消息SERVICE_TIMEOUT_MSG 。如果沒有執(zhí)行完畢不調(diào)用這個方法,則超時后會發(fā)出 SERVICE_TIMEOUT_MSG 來告知ANR 發(fā)生。