說到ANR前域,首先提出以下三個(gè)問題
- ANR是什么
- ANR什么時(shí)候出現(xiàn)
- ANR發(fā)生的原理
帶著這三個(gè)問題我們進(jìn)入本次的話題
ANR是什么
ANR全稱Application Not Response,應(yīng)用無響應(yīng)韵吨。指的是一定時(shí)間內(nèi)處理某一事件超過一定時(shí)間就會(huì)彈出應(yīng)用無響應(yīng)的彈框匿垄,用于用戶可以強(qiáng)制結(jié)束進(jìn)程。
ANR什么時(shí)候出現(xiàn)
- InputDispatch響應(yīng)時(shí)間超過5秒
- BroadCastReceiver 前臺(tái)響應(yīng)時(shí)間超過10秒归粉,后臺(tái)響應(yīng)時(shí)間超過60秒
- Service 前臺(tái)響應(yīng)時(shí)間超過20秒椿疗,后臺(tái)響應(yīng)時(shí)間超過200秒
- ContentProvider響應(yīng)時(shí)間超過10秒
ANR發(fā)生的原理
針對(duì)上面4種情況接下來一一分析:
1. InputDispatch ANR
Android底層接收處理觸摸事件主要依賴
InputReader.cpp和InputDispatcher.cpp兩大類。這里先簡單介紹下這兩個(gè)類
首先來看InputReader.cpp
/frameworks/native/services/inputflinger/InputReader.cpp
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
Vector<InputDeviceInfo> inputDevices;
{ // acquire lock
...代碼省略...
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
...代碼省略...
// Flush queued events out to the listener.
// This must happen outside of the lock because the listener could potentially call
// back into the InputReader's methods, such as getScanCodeState, or become blocked
// on another thread similarly waiting to acquire the InputReader lock thereby
// resulting in a deadlock. This situation is actually quite plausible because the
// listener is actually the input dispatcher, which calls into the window manager,
// which occasionally calls into the input reader.
mQueuedListener->flush();
}
本身做loop循環(huán)糠悼,然后通過EventHub#getEvents方法獲取指定事件届榄,然后生成事件,加入到隊(duì)列倔喂,通知喚醒InputDispatcher(此處詳情不再展開)
然后介紹InputDispatcher.cpp
/frameworks/native/services/inputflinger/InputDispatcher.cpp
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce(); //【見小節(jié)1.2】
return true;
}
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
} // release lock
// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
與InputReader類似铝条,自身開啟一個(gè)Loop循環(huán),然后當(dāng)隊(duì)列不為空時(shí)席噩,開始執(zhí)行dispatchOnceInnerLocked-> dispatchKeyLocked-> findFocusedWindowTargetsLocked-> handleTargetsNotReadyLocked.
接下來我們重點(diǎn)關(guān)注下handleTargetsNotReadyLocked方法
int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
const EventEntry* entry,
const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
nsecs_t* nextWakeupTime, const char* reason) {
...代碼省略...
nsecs_t timeout;
if (windowHandle != NULL) {
timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
} else if (applicationHandle != NULL) {
timeout = applicationHandle->getDispatchingTimeout(
DEFAULT_INPUT_DISPATCHING_TIMEOUT);
} else {
timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT;
}
...代碼省略...
if (currentTime >= mInputTargetWaitTimeoutTime) {
onANRLocked(currentTime, applicationHandle, windowHandle,
entry->eventTime, mInputTargetWaitStartTime, reason);
// Force poll loop to wake up immediately on next iteration once we get the
// ANR response back from the policy.
*nextWakeupTime = LONG_LONG_MIN;
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;
}
}
從中我們可以看到兩點(diǎn):
- DEFAULT_INPUT_DISPATCHING_TIMEOUT這個(gè)值為5秒
- currentTime >= mInputTargetWaitTimeoutTime 代表超過5秒的時(shí)候就要處理相應(yīng)的事件了
即onANRLocked方法(看名字就是ANR的處理了)
然后會(huì)執(zhí)行doNotifyANRLockedInterruptible方法
void InputDispatcher::doNotifyANRLockedInterruptible(
CommandEntry* commandEntry) {
mLock.unlock();
nsecs_t newTimeout = mPolicy->notifyANR(
commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle,
commandEntry->reason);
mLock.lock();
resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
commandEntry->inputWindowHandle != NULL
? commandEntry->inputWindowHandle->getInputChannel() : NULL);
}
接下來會(huì)執(zhí)行mPolicy的notifyANR方法班缰。
此處的mPolicy便是com_android_server_input_InputManagerService
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
看這名字感覺已經(jīng)快到Java層了,我們慢慢往下看:
nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<InputWindowHandle>& inputWindowHandle, const std::string& reason) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyANR");
#endif
ATRACE_CALL();
JNIEnv* env = jniEnv();
jobject inputApplicationHandleObj =
getInputApplicationHandleObjLocalRef(env, inputApplicationHandle);
jobject inputWindowHandleObj =
getInputWindowHandleObjLocalRef(env, inputWindowHandle);
jstring reasonObj = env->NewStringUTF(reason.c_str());
jlong newTimeout = env->CallLongMethod(mServiceObj,
gServiceClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj,
reasonObj);
if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
newTimeout = 0; // abort dispatch
} else {
assert(newTimeout >= 0);
}
env->DeleteLocalRef(reasonObj);
env->DeleteLocalRef(inputWindowHandleObj);
env->DeleteLocalRef(inputApplicationHandleObj);
return newTimeout;
}
關(guān)鍵代碼為 env->CallLongMethod 悼枢。 此處正是C++ 層調(diào)用Java代碼也就是執(zhí)行了gServiceClassInfo的notifyANR方法鲁捏,此處的gServiceClassInfo便是InputManagerService。那么我們繼續(xù)往Java層看:
private long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason) {
return mWindowManagerCallbacks.notifyANR(
inputApplicationHandle, inputWindowHandle, reason);
}
這里的處理邏輯很簡單,執(zhí)行了mWindowManagerCallbacks的notifyANR方法给梅,InputMonitor實(shí)現(xiàn)了WindowManagerCallbacks假丧,所以這里便進(jìn)入了InputMonitor類:
@Override
public long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason) {
...代碼省略...
if (appWindowToken != null && appWindowToken.appToken != null) {
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
...代碼省略...
} else if (windowState != null) {
try {
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
long timeout = ActivityManager.getService().inputDispatchingTimedOut(
windowState.mSession.mPid, aboveSystem, reason);
if (timeout >= 0) {
// The activity manager declined to abort dispatching.
// Wait a bit longer and timeout again later.
return timeout * 1000000L; // nanoseconds
}
} catch (RemoteException ex) {
}
}
return 0; // abort dispatching
}
當(dāng)WindowState不為空的時(shí)候執(zhí)行ActivityManager.getService().inputDispatchingTimedOut方法即ActivityManagerService#inputDispatchingTimedOut。(這里的WindowState即代表一個(gè)真正的 窗口动羽。,此處不做展開)包帚。
@Override
public long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
+ android.Manifest.permission.FILTER_EVENTS);
}
ProcessRecord proc;
long timeout;
synchronized (this) {
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(pid);
}
timeout = getInputDispatchingTimeoutLocked(proc);
}
if (inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
return -1;
}
return timeout;
}
然后繼續(xù)執(zhí)行inputDispatchingTimedOut方法
public boolean inputDispatchingTimedOut(final ProcessRecord proc,
final ActivityRecord activity, final ActivityRecord parent,
final boolean aboveSystem, String reason) {
...代碼省略...
if (proc != null) {
synchronized (this) {
if (proc.debugging) {
//當(dāng)程序Debug的情況下,不彈出ANR窗口
return false;
}
if (proc.instr != null) {
//當(dāng)前進(jìn)程為子進(jìn)程的時(shí)候运吓,直接kill掉子進(jìn)程渴邦,不彈出ANR窗口
Bundle info = new Bundle();
info.putString("shortMsg", "keyDispatchingTimedOut");
info.putString("longMsg", annotation);
finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
return true;
}
}
mHandler.post(new Runnable() {
@Override
public void run() {
mAppErrors.appNotResponding(proc, activity, parent, aboveSystem, annotation);
}
});
}
return true;
}
執(zhí)行mAppErrors.appNotResponding方法:
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
ActivityRecord parent, boolean aboveSystem, final String annotation) {
...代碼省略...
synchronized (mService) {
mService.mBatteryStatsService.noteProcessAnr(app.processName, app.uid);
if (isSilentANR) {
app.kill("bg anr", true);
return;
}
// Set the app's notResponding state, and look up the errorReportReceiver
makeAppNotRespondingLocked(app,
activity != null ? activity.shortComponentName : null,
annotation != null ? "ANR " + annotation : "ANR",
info.toString());
// Bring up the infamous App Not Responding dialog
Message msg = Message.obtain();
msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
msg.obj = new AppNotRespondingDialog.Data(app, activity, aboveSystem);
mService.mUiHandler.sendMessage(msg);
}
}
這段代碼非常長,直接省略部分代碼拘哨,看最后谋梭,通過UIHandler發(fā)送了一個(gè)SHOW_NOT_RESPONDING_UI_MSG通知。我們找到初始化這個(gè)UIHandler的地方看看他的dispatchMessage 吧
final class UiHandler extends Handler {
public UiHandler() {
super(com.android.server.UiThread.get().getLooper(), null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW_ERROR_UI_MSG: {
mAppErrors.handleShowAppErrorUi(msg);
ensureBootCompleted();
} break;
case SHOW_NOT_RESPONDING_UI_MSG: {
mAppErrors.handleShowAnrUi(msg);
ensureBootCompleted();
} break;
...代碼省略...
}
}
看SHOW_NOT_RESPONDING_UI_MSG是執(zhí)行了mAppErrors.handleShowAnrUi方法:
void handleShowAnrUi(Message msg) {
Dialog dialogToShow = null;
synchronized (mService) {
... 代碼省略...
if (mService.canShowErrorDialogs() || showBackground) {
dialogToShow = new AppNotRespondingDialog(mService, mContext, data);
proc.anrDialog = dialogToShow;
} else {
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
AppNotRespondingDialog.CANT_SHOW);
// Just kill the app if there is no dialog to be shown.
mService.killAppAtUsersRequest(proc, null);
}
}
// If we've created a crash dialog, show it without the lock held
if (dialogToShow != null) {
dialogToShow.show();
}
}
終于到了最后一步了倦青,這里的dialogToShow正是我們非常熟悉的ANR提示窗口了瓮床,最終就會(huì)彈出ANR窗口。下面給出對(duì)應(yīng)的時(shí)序圖:
2. BroadCastReceiver ANR
同樣的我們從BroadcastReceiver啟動(dòng)源頭開始sendBroadcast說起,調(diào)用這個(gè)方法的時(shí)候會(huì)調(diào)用到ContextWrapper的sendBroadcast方法:
@Override
public void sendBroadcast(Intent intent) {
mBase.sendBroadcast(intent);
}
然后會(huì)執(zhí)行mBase的sendBroadcast方法,那么這個(gè)mBase是什么呢产镐,這就要從Activity啟動(dòng)流程開始說起隘庄,本文篇幅有限直接進(jìn)入ActivityThread#performLaunchActivity()方法:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...代碼省略...
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...代碼省略...
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to start activity " + component
+ ": " + e.toString(), e);
}
}
return activity;
}
這里Activity會(huì)執(zhí)行attach方法將appContext傳入然后執(zhí)行attachBaseContent將appContent賦值給mBase。而此處的appContext就是ContextImpl癣亚。那么就進(jìn)入ContextImp看下:
@Override
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
處理也是非常簡單丑掺,直接調(diào)起了ActivityManagerService的broadcastIntent方法:
public final int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
intent = verifyBroadcastLocked(intent);
final ProcessRecord callerApp = getRecordForAppLocked(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
int res = broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, appOp, bOptions, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
然后調(diào)用broadcastIntentLocked,這里的代碼過長就不再展示述雾,然后是調(diào)用了BroadcastQueue#scheduleBroadcastsLocked方法:
public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) {
return;
}
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
我們可以看到它是通過Handler發(fā)送了一條消息:
private final class BroadcastHandler extends Handler {
public BroadcastHandler(Looper looper) {
super(looper, null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
if (DEBUG_BROADCAST) Slog.v(
TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
}
}
}
final void processNextBroadcast(boolean fromMsg) {
synchronized (mService) {
processNextBroadcastLocked(fromMsg, false);
}
}
跟到消息處理里面街州,然后執(zhí)行processNextBroadcast->processNextBroadcastLocked方法:
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
// Keep track of when this receiver started, and make sure there
// is a timeout message pending to kill it if need be.
r.receiverTime = SystemClock.uptimeMillis();
if (! mPendingBroadcastTimeoutMessage) {
//mPendingBroadcastTimeoutMessage這個(gè)參數(shù)只有在已經(jīng)發(fā)送了延時(shí)消息的時(shí)候才會(huì)設(shè)置成true目的是為了防止重新發(fā)送延時(shí)消息。這個(gè)延時(shí)時(shí)間點(diǎn)正式超時(shí)時(shí)間
long timeoutTime = r.receiverTime + mTimeoutPeriod;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Submitting BROADCAST_TIMEOUT_MSG ["
+ mQueueName + "] for " + r + " at " + timeoutTime);
setBroadcastTimeoutLocked(timeoutTime);
}
}
這里面我們可以看下mTimeoutPeriod,因?yàn)檠訒r(shí)消息發(fā)送的時(shí)候是將當(dāng)前時(shí)間+mTimeoutPeriod這個(gè)時(shí)間的玻孟。搜了一下發(fā)現(xiàn)是在初始化對(duì)象的時(shí)候?qū)⒅祩魅氲?
BroadcastQueue(ActivityManagerService service, Handler handler,
String name, long timeoutPeriod, boolean allowDelayBehindServices) {
mService = service;
mHandler = new BroadcastHandler(handler.getLooper());
mQueueName = name;
mTimeoutPeriod = timeoutPeriod;
mDelayBehindServices = allowDelayBehindServices;
}
再去看下什么時(shí)候初始化:
mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
"foreground", BROADCAST_FG_TIMEOUT, false);
mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
"background", BROADCAST_BG_TIMEOUT, true);
發(fā)現(xiàn)有兩種類型的廣播隊(duì)列初始化菇肃,一種是前臺(tái)的,一種是后臺(tái)的
// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_FG_TIMEOUT = 10*1000;
static final int BROADCAST_BG_TIMEOUT = 60*1000;
前臺(tái)廣播對(duì)應(yīng)的超時(shí)時(shí)間是10s,后臺(tái)廣播對(duì)應(yīng)的超時(shí)時(shí)間是60s取募,然后一旦延時(shí)消息執(zhí)行的時(shí)候會(huì)調(diào)用下面的方法:
final void broadcastTimeoutLocked(boolean fromMsg) {
if (fromMsg) {
//從延時(shí)消息過來的時(shí)候琐谤,將這個(gè)值設(shè)置為false,解鎖操作
mPendingBroadcastTimeoutMessage = false;
}
if (mOrderedBroadcasts.size() == 0) {
//當(dāng)前廣播已經(jīng)處理完了玩敏,那么就不需要彈出ANR了
return;
}
...代碼省略...
if (app != null) {
anrMessage = "Broadcast of " + r.intent.toString();
}
if (mPendingBroadcast == r) {
mPendingBroadcast = null;
}
// Move on to the next receiver.
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
if (!debugging && anrMessage != null) {
// Post the ANR to the handler since we do not want to process ANRs while
// potentially holding our lock.
mHandler.post(new AppNotResponding(app, anrMessage));
}
}
當(dāng)當(dāng)前不屬于debug狀態(tài)斗忌,并且ANR信息不為空的時(shí)候調(diào)用 mHandler.post(new AppNotResponding(app, anrMessage));,這個(gè)方法是不是很熟悉旺聚,就跟前面手勢(shì)事件超時(shí)最后調(diào)用的地方一致會(huì)執(zhí)行mAppErrors.appNotResponding操作织阳,最終彈出ANR窗口,這里給出對(duì)應(yīng)的流程圖:
3. Service ANR
ServiceANR原理與BroadcastReceiver類似砰粹,那么也從源頭開始說起吧:
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
類似的啟動(dòng)方式糕篇,然后跳到ContextImpl中:
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service
+ " without permission " + cn.getClassName());
} else if (cn.getPackageName().equals("!!")) {
throw new SecurityException(
"Unable to start service " + service
+ ": " + cn.getClassName());
} else if (cn.getPackageName().equals("?")) {
throw new IllegalStateException(
"Not allowed to start service " + service + ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
也是一樣最終會(huì)進(jìn)入ActivityManagerService中startService
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
ActivityManagerService最終會(huì)調(diào)用ActiveServices的startServiceLocked->startServiceInnerLocked:
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
}
r.callStart = false;
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
}
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
..代碼省略...
return r.name;
}
然后就是執(zhí)行bringUpServiceLocked方法,此方法里面會(huì)真正開始啟動(dòng)service术吝,也就是會(huì)執(zhí)行realStartServiceLocked方法:
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
...代碼省略...
//此處處理方式與BroadcastReceiver相似,都是先獲取當(dāng)前時(shí)間饭入,然后加上超時(shí)所需要的時(shí)間就是最后的超時(shí)時(shí)間
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
//這個(gè)地方會(huì)先發(fā)送一個(gè)超時(shí)消息
bumpServiceExecutingLocked(r, execInFg, "create");
...代碼省略...
try {
...代碼省略...
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//app.thread就是ApplicationThread,就是ActivityThread的子類
//然后scheduleCreateService就會(huì)執(zhí)行Service的onCreate方法
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app);
throw e;
} finally {
...代碼省略...
}
...代碼省略...
}
在調(diào)用Service的onCreate方法前會(huì)先調(diào)用bumpServiceExecutingLocked發(fā)送超時(shí)消息
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
...代碼省略...
if (r.executeNesting == 0) {
...代碼省略...
} else if (r.app != null && fg && !r.app.execServicesFg) {
r.app.execServicesFg = true;
if (timeoutNeeded) {
scheduleServiceTimeoutLocked(r.app);
}
}
...代碼省略...
}
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;
mAm.mHandler.sendMessageDelayed(msg,
proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}
// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000;
// How long we wait for a service to finish executing.
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
在scheduleServiceTimeoutLocked方法中會(huì)先判斷Service是到底是屬于前臺(tái)Service還是后臺(tái)Service肛真,前臺(tái)Service超時(shí)時(shí)間是20s,后臺(tái)Service超時(shí)時(shí)間是200s.
發(fā)送超時(shí)消息以后谐丢,會(huì)在ActivityManagerService里面接收到此消息,會(huì)執(zhí)行ActiveServices的serviceTimeout方法:
void serviceTimeout(ProcessRecord proc) {
...代碼省略...
if (anrMessage != null) {
mAm.mAppErrors.appNotResponding(proc, null, null, false, anrMessage);
}
}
最后無一例外都會(huì)調(diào)用AppErrors的appNotResponding方法蚓让,后續(xù)就不在跟進(jìn)了乾忱。此處給出時(shí)序圖:
4. ContentProvider ANR
ContentProvider啟動(dòng)的流程就有點(diǎn)不太一致了,它的入口是ActivityThread的main方法(這也是整個(gè)APP啟動(dòng)的入口):
public static void main(String[] args) {
...代碼省略...
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
...代碼省略...
}
ContentProvider就從thread.attach方法開始的:
private void attach(boolean system, long startSeq) {
...代碼省略
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...代碼省略...
}
這里也是交給了ActivityManagerService來處理历极,調(diào)用了attachApplication方法:
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}
接著就會(huì)執(zhí)行attachApplicationLocked方法:
@GuardedBy("this")
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...代碼省略...
if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
}
...代碼省略...
return true;
}
// How long we wait for an attached process to publish its content providers
// before we decide it must be hung.
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
這里會(huì)發(fā)送CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG的延時(shí)消息窄瘟,延時(shí)時(shí)間為CONTENT_PROVIDER_PUBLISH_TIMEOUT即10秒。然后延時(shí)消息里面會(huì)執(zhí)行processContentProviderPublishTimedOutLocked方法:
@GuardedBy("this")
boolean removeProcessLocked(ProcessRecord app,
boolean callerWillRestart, boolean allowRestart, String reason) {
...代碼省略...
boolean needRestart = false;
if ((app.pid > 0 && app.pid != MY_PID) || (app.pid == 0 && app.pendingStart)) {
...代碼省略...
app.kill(reason, true);
handleAppDiedLocked(app, willRestart, allowRestart);
if (willRestart) {
removeLruProcessLocked(app);
addAppLocked(app.info, null, false, null /* ABI override */);
}
} else {
mRemovedProcesses.add(app);
}
return needRestart;
}
與其他三種情況不一樣的是趟卸,ContentProvider在超時(shí)的時(shí)候并不會(huì)彈出ANR的Dialog蹄葱,而是直接干掉了進(jìn)程,下面給出ContentProvider超時(shí)的時(shí)序圖:
從上面四種ANR流程可以看出一個(gè)共同點(diǎn)衰腌,那就是不管以何種方式出現(xiàn)超時(shí)處理,都需要經(jīng)過AMS觅赊,由此也可以看出AMS作為一個(gè)核心類的重要性