大概
Android的ANR主要有兩種方式:
1. 通過(guò)handler的延遲機(jī)制觸發(fā)ANR
2. Input事件觸發(fā)ANR
Service踢俄、BroadcastReceiver聂宾、ContentProvider都是通過(guò)Hander機(jī)制觸發(fā)ANR。
ANR的發(fā)生的場(chǎng)景有:
- service timeout:前臺(tái)服務(wù)在20s未執(zhí)行完虚倒,后臺(tái)服務(wù)200s未執(zhí)行完美侦。
- BroadcastQueue timeout:前臺(tái)廣播在10s未執(zhí)行完,后臺(tái)廣播在60s未執(zhí)行完魂奥。
- ContentProvider timeout: ContentProvider在發(fā)布時(shí)超過(guò)10s未執(zhí)行完菠剩。
- InputDispatching Timeout:輸入分發(fā)事件超過(guò)5s未執(zhí)行完。
ANR的過(guò)程總體就是:裝炸彈耻煤、拆炸彈具壮、引爆炸彈
1. Service Timeout
在文章startService啟動(dòng)流程可以知道Service的生命周期和啟動(dòng)流程。
裝彈
在ActiveServices.realStartServiceLocked()
方法中開(kāi)始真正執(zhí)行Service的生命周期方法哈蝇,并開(kāi)始裝炸彈的開(kāi)始嘴办。
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
// handle發(fā)送延遲消息,如果在規(guī)定時(shí)間還沒(méi)有被取消买鸽,則證明方法執(zhí)行時(shí)間長(zhǎng),則拋ANR異常贯被。
bumpServiceExecutingLocked(r, execInFg, "create");
//...
try {
//調(diào)用Service對(duì)應(yīng)onCreate()方法
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
} catch (DeadObjectException e) {
mAm.appDiedLocked(app, "Died when creating service");
throw e;
} finally {
//...
}
}
// 通過(guò)Handler發(fā)送延遲時(shí)間眼五,到時(shí)間內(nèi)沒(méi)被取消則拋ANR異常
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
....
// 發(fā)送Handler
scheduleServiceTimeoutLocked(r.app);
}
// 發(fā)送延遲消息
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;
//當(dāng)超時(shí)后仍沒(méi)有remove該SERVICE_TIMEOUT_MSG消息妆艘,則執(zhí)行service Timeout流程
mAm.mHandler.sendMessageDelayed(msg,
proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}
static final int SERVICE_TIMEOUT = 20 * 1000;
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
在執(zhí)行生命周期的方法前會(huì)通過(guò)bumpServiceExecutingLocked()
方法進(jìn)行裝炸彈,通過(guò)Handler機(jī)制發(fā)送一個(gè)標(biāo)志為SERVICE_TIMEOUT_MSG
的延遲消息看幼,如果是前臺(tái)則20s,是后臺(tái)則200s執(zhí)行批旺。
拆彈
在執(zhí)行完Service的生命周期方法后就會(huì)執(zhí)行拆彈,比如onCreate()
方法在Application.handleCreateService()
執(zhí)行完畢:
private class ApplicationThread extends IApplicationThread.Stub {
// 創(chuàng)建對(duì)應(yīng)的Service并執(zhí)行onCreate()方法
private void handleCreateService(CreateServiceData data) {
try {
....
// 調(diào)用service.attach綁定資源文件
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
// 調(diào)用 service.onCreate()方法
service.onCreate();
try {
// onCreate()執(zhí)行完成诵姜,拆彈過(guò)程汽煮,最終調(diào)用到ActiveServices.serviceDoneExecutingLocked方法
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
//...
}
}
// AMS
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);
}
}
// ActiveServices
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing) {
//...
// 取消SERVICE_TIMEOUT_MSG消息,拆出炸彈
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
//...
}
如果在生命周期方法內(nèi)執(zhí)行完棚唆,會(huì)回調(diào)AMS的方法暇赤,解除SERVICE_TIMEOUT_MSG
延遲發(fā)送的消息。
引爆彈
如果Service方法在規(guī)定時(shí)間內(nèi)沒(méi)有執(zhí)行完成宵凌,則會(huì)執(zhí)行AMS.MainHandler
的SERVICE_TIMEOUT_MSG
類型的消息:
// AMS
final class MainHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SERVICE_TIMEOUT_MSG: {
mServices.serviceTimeout((ProcessRecord) msg.obj);
}
break;
}
}
}
// ActiveServices
void serviceTimeout(ProcessRecord proc) {
// 如果超時(shí)鞋囊,調(diào)用appNotResponding()方法
if (anrMessage != null) {
mAm.mAnrHelper.appNotResponding(proc, anrMessage);
}
}
如果超時(shí)則會(huì)觸發(fā)ANR,調(diào)用mAm.mAnrHelper.appNotResponding()
方法。
2. BroadcastReceiver Timeout
裝彈
在文章廣播的注冊(cè)瞎惫、發(fā)送原理流程可以了解溜腐,發(fā)送廣播后調(diào)用之行對(duì)應(yīng)的廣播接收器的方法,對(duì)應(yīng)的方法在BroadcastQueue.processNextBroadcast()
:
public final class BroadcastQueue {
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
// 處理當(dāng)前有序廣播
do {
// 獲取BroadcastRecord
final long now = SystemClock.uptimeMillis();
r = mDispatcher.getNextBroadcastLocked(now);
//當(dāng)廣播處理時(shí)間超時(shí)瓜喇,則強(qiáng)制結(jié)束這條廣播
if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) {
if ((numReceivers > 0) &&
(now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {
broadcastTimeoutLocked(false); // forcibly finish this broadcast
forceReceive = true;
r.state = BroadcastRecord.IDLE;
}
}
//...
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) {
if (r.resultTo != null) {
//...
//處理廣播消息消息,調(diào)用到onReceive()
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);
//...
}
//拆炸彈
cancelBroadcastTimeoutLocked();
r = null;
looped = true;
continue;
}
//..
} while (r == null);
//獲取下一個(gè)receiver的index
int recIdx = r.nextReceiver++;
if (!mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mTimeoutPeriod;
//裝炸彈乘寒,設(shè)置廣播超時(shí)時(shí)間望众,發(fā)送BROADCAST_TIMEOUT_MSG
setBroadcastTimeoutLocked(timeoutTime);
}
//...
}
// 裝彈
final void setBroadcastTimeoutLocked(long timeoutTime) {
if (!mPendingBroadcastTimeoutMessage) {
Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
mHandler.sendMessageAtTime(msg, timeoutTime);
mPendingBroadcastTimeoutMessage = true;
}
}
}
通過(guò)setBroadcastTimeoutLocked()
方法進(jìn)行裝彈。
拆彈
通過(guò)上面的processNextBroadcastLocked()
方法可知肃续,調(diào)用cancelBroadcastTimeoutLocked()
進(jìn)行拆彈黍檩。
// 拆彈
final void cancelBroadcastTimeoutLocked() {
if (mPendingBroadcastTimeoutMessage) {
mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
mPendingBroadcastTimeoutMessage = false;
}
}
引爆彈
通過(guò)BroadcastHandler
的BROADCAST_TIMEOUT_MSG
類型的消息的執(zhí)行,進(jìn)行引爆炸彈始锚。
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
// 調(diào)用broadcastTimeoutLocked()方法
broadcastTimeoutLocked(true);
}
}
break;
}
}
final void broadcastTimeoutLocked(boolean fromMsg) {
...
// 如果超時(shí)刽酱,調(diào)用AMS.mAnrHelper.appNotResponding
if (!debugging && anrMessage != null) {
mService.mAnrHelper.appNotResponding(app, anrMessage);
}
}
最后也是調(diào)用AMS.mAnrHelper.appNotResponding()
方法
3. ContentProvider Timeout
裝彈
ContentProvider的注冊(cè)在啟動(dòng)進(jìn)程的時(shí)候就開(kāi)始執(zhí)行,在注冊(cè)的過(guò)程中會(huì)向AMS綁定Application瞧捌,如果有ContentProvider就裝彈棵里,方法在AMS.attachApplicationLocked()
方法中:
// AMS
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
//...
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
// 裝彈
Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg,
ContentResolver.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS);
}
}
public static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS = 10 * 1000;
在綁定Application時(shí),會(huì)判斷是否有ContentProvider時(shí)會(huì)裝炸彈進(jìn)行一個(gè)CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG
消息的延遲發(fā)送姐呐。
拆彈
在AT.installContentProviders()
安裝完后會(huì)調(diào)用AMS.publishContentProviders()
方法進(jìn)行拆彈殿怜。
public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
...
// 拆彈,移除CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息
mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r)
}
引爆彈
如果消息沒(méi)被移除則引爆炸彈,CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG
的handler在AMS.MainHandler
中曙砂,
public void handleMessage(Message msg) {
switch (msg.what) {
case CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG: {
ProcessRecord app = (ProcessRecord) msg.obj;
synchronized (ActivityManagerService.this) {
processContentProviderPublishTimedOutLocked(app);
}
}
break;
}
}
private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
//移除死亡的provider
cleanupAppInLaunchingProvidersLocked(app, true);
//移除mProcessNames中的相應(yīng)對(duì)象
mProcessList.removeProcessLocked(app, false, true,
ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
ApplicationExitInfo.SUBREASON_UNKNOWN,
"timeout publishing content providers");
}
4. InputDispatching Timeout
InputReader
不斷的從EventHub
中監(jiān)聽(tīng)是否有Input事件头谜,InputReader把事件分發(fā)給InputDispatcher
。
InputDispatcher調(diào)用dispatchOnce()
方法開(kāi)始把事件分發(fā)給對(duì)應(yīng)的View,就從InputDispatcher的分發(fā)開(kāi)始監(jiān)控ANR鸠澈,InputDispatcher的ANR區(qū)間是查找窗口findFocusedWindowTargetsLocked()
方法到resetANRTimeoutsLocked()
重置方法柱告。
void InputDispatcher::dispatchOnce() {
...
// 調(diào)用dispatchOnceInnerLocked進(jìn)行分析
dispatchOnceInnerLocked(&nextWakeupTime);
}
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t*nextWakeupTime) {
nsecs_t currentTime = now();
// ...
// 重置標(biāo)記
resetANRTimeoutsLocked();
switch (mPendingEvent -> type) {
case EventEntry::TYPE_KEY: {
...
// key類型
done = dispatchKeyLocked(currentTime, typedEntry, & dropReason, nextWakeupTime);
break;
}
case EventEntry::TYPE_MOTION: {
...
done = dispatchMotionLocked(currentTime, typedEntry,
& dropReason, nextWakeupTime);
break;
}
default:
ALOG_ASSERT(false);
break;
}
}
void InputDispatcher::resetANRTimeoutsLocked() {
// 將mInputTargetWaitCause設(shè)置為INPUT_TARGET_WAIT_CAUSE_NONE
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
mInputTargetWaitApplicationToken.clear();
}
在分發(fā)之前會(huì)調(diào)用resetANRTimeoutsLocked()
方法截驮,重置mInputTargetWaitCause標(biāo)記為:INPUT_TARGET_WAIT_CAUSE_NONE
。接著根據(jù)下發(fā)的類型际度,尋找對(duì)應(yīng)的窗口葵袭,比如KEY類型,則調(diào)用dispatchKeyLocked()
方法乖菱。
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry*entry,
DropReason*dropReason, nsecs_t*nextWakeupTime) {
// 尋找目標(biāo)窗口
int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
// 給目標(biāo)窗口分發(fā)事件
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
const EventEntry*entry, std::vector<InputTarget>&inputTargets, nsecs_t*nextWakeupTime) {
...
// 檢查窗口不能input的原因
reason = checkWindowReadyForMoreInputLocked(currentTime,
focusedWindowHandle, entry, "focused");
if (!reason.empty()) {
// 調(diào)用handleTargetsNotReadyLocked()方法
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
focusedApplicationHandle, focusedWindowHandle, nextWakeupTime, reason.c_str());
goto Unresponsive;
}
...
return injectionResult;
}
int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,const EventEntry*entry,const sp<InputApplicationHandle>&applicationHandle,const sp<InputWindowHandle>&windowHandle,
nsecs_t*nextWakeupTime, const char*reason) {
// 在resetANRTimeoutsLocked方法中坡锡,mInputTargetWaitCause為INPUT_TARGET_WAIT_CAUSE_NONE
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
// DEFAULT_INPUT_DISPATCHING_TIMEOUT為5s
nsecs_t timeout;
if (windowHandle != nullptr) {
timeout = windowHandle -> getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
} else if (applicationHandle != nullptr) {
timeout = applicationHandle -> getDispatchingTimeout(
DEFAULT_INPUT_DISPATCHING_TIMEOUT);
} else {
timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT;
}
// 要等到下次調(diào)用resetANRTimeoutsLocked時(shí)才能進(jìn)
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
// 當(dāng)前時(shí)間加上5s
mInputTargetWaitTimeoutTime = currentTime + timeout;
mInputTargetWaitTimeoutExpired = false;
mInputTargetWaitApplicationToken.clear();
}
if (mInputTargetWaitTimeoutExpired) {
return INPUT_EVENT_INJECTION_TIMED_OUT;
}
if (currentTime >= mInputTargetWaitTimeoutTime) {
// 當(dāng)前時(shí)間超過(guò)設(shè)定的5s,后執(zhí)行onANRLocked()的ANR方法
onANRLocked(currentTime, applicationHandle, windowHandle,
entry -> eventTime, mInputTargetWaitStartTime, reason);
return INPUT_EVENT_INJECTION_PENDING;
} else {
// Force poll loop to wake up when timeout is due.
if (mInputTargetWaitTimeoutTime < *nextWakeupTime){
*nextWakeupTime = mInputTargetWaitTimeoutTime;
}
return INPUT_EVENT_INJECTION_PENDING;
}
}
在分發(fā)一次事件時(shí)窒所,會(huì)調(diào)用resetANRTimeoutsLocked
將標(biāo)記為INPUT_TARGET_WAIT_CAUSE_NONE
,所以第一次事件會(huì)設(shè)置一個(gè)5s后的超時(shí)時(shí)間鹉勒,并把標(biāo)記設(shè)置為INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
,如果下次事件來(lái)臨時(shí)當(dāng)前的時(shí)間超過(guò)上次設(shè)置的5s時(shí)間就會(huì)調(diào)用onANRLocked()
方法產(chǎn)生ANR墩新。
void InputDispatcher::onANRLocked(
nsecs_t currentTime, const sp<InputApplicationHandle>&applicationHandle,
const sp<InputWindowHandle>&windowHandle,
nsecs_t eventTime, nsecs_t waitStartTime, const char*reason) {
float dispatchLatency = (currentTime - eventTime) * 0.000001f;
float waitDuration = (currentTime - waitStartTime) * 0.000001f;
// 收集ANR現(xiàn)場(chǎng)信息
time_t t = time(nullptr);
struct tm tm;
localtime_r( & t, &tm);
char timestr[ 64];
strftime(timestr, sizeof(timestr), "%F %T", & tm);
mLastANRState.clear();
mLastANRState += INDENT "ANR:\n";
mLastANRState += StringPrintf(INDENT2"Time: %s\n", timestr);
mLastANRState += StringPrintf(INDENT2"Window: %s\n",
getApplicationWindowLabel(applicationHandle, windowHandle).c_str());
mLastANRState += StringPrintf(INDENT2"DispatchLatency: %0.1fms\n", dispatchLatency);
mLastANRState += StringPrintf(INDENT2"WaitDuration: %0.1fms\n", waitDuration);
mLastANRState += StringPrintf(INDENT2"Reason: %s\n", reason);
//dump信息
dumpDispatchStateLocked(mLastANRState);
//將ANR命令加入commandQueue
CommandEntry * commandEntry = postCommandLocked(
& InputDispatcher::doNotifyANRLockedInterruptible);
commandEntry -> inputApplicationHandle = applicationHandle;
commandEntry -> inputChannel = windowHandle != nullptr ?
getInputChannelLocked(windowHandle -> getToken()) : nullptr;
commandEntry -> reason = reason;
}
在下次執(zhí)行InputDispatcher.dispatchOnce
時(shí)會(huì)先執(zhí)行commandQueue的隊(duì)列命令贸弥,這里把InputDispatcher::doNotifyANRLockedInterruptible
放入到了隊(duì)列。
void InputDispatcher::doNotifyANRLockedInterruptible(CommandEntry*commandEntry) {
mLock.unlock();
//mPolicy是指NativeInputManager
nsecs_t newTimeout = mPolicy -> notifyANR(
commandEntry -> inputApplicationHandle,
commandEntry -> inputChannel ? commandEntry -> inputChannel -> getToken() : nullptr,
commandEntry -> reason);
mLock.lock();
resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
commandEntry -> inputChannel);
}
mPolicy -> notifyANR
通過(guò)JNI最終調(diào)用到InputManagerService.notifyANR()
方法:
// InputManagerService
private long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
String reason) {
return mWindowManagerCallbacks.notifyANR(inputApplicationHandle,
token, reason);
}
這里的mWindowManagerCallbacks
是InputManagerCallback對(duì)象
//InputManagerCallback
public long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
String reason) {
final long startTime = SystemClock.uptimeMillis();
try {
return notifyANRInner(inputApplicationHandle, token, reason);
} finally {
}
}
private long notifyANRInner(InputApplicationHandle inputApplicationHandle, IBinder token,
String reason) {
...
// 調(diào)用AMS的inputDispatchingTimedOut()方法
long timeout = mService.mAmInternal.inputDispatchingTimedOut(windowPid, aboveSystem,
reason);
return 0; // abort dispatching
}
最終調(diào)用到AMS.inputDispatchingTimedOut()
方法
// AMS
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission " + FILTER_EVENTS);
}
ProcessRecord proc;
long timeout;
synchronized (this) {
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(pid);
}
timeout = proc != null ? proc.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
}
// 調(diào)用inputDispatchingTimedOut
if (inputDispatchingTimedOut(proc, null, null, null, null, aboveSystem, reason)) {
return -1;
}
return timeout;
}
boolean inputDispatchingTimedOut(ProcessRecord proc, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem, String reason) {
// 調(diào)用appNotResponding方法
mAnrHelper.appNotResponding(proc, activityShortComponentName, aInfo,
parentShortComponentName, parentProcess, aboveSystem, annotation);
return true;
}
還是執(zhí)行appNotResponding()
方法海渊。