android ANR原始碼分析 --- 之一
概述:
ANR(ApplicationNot responding),是指應用程式未響應,Android系統對於一些事件需要在一定的時間範圍內完成,如果超過預定時間
能未能得到有效響應或者響應時間過長,都會造成ANR。一般地,這時往往會彈出一個提示框,告知使用者當前xxx未響應,使用者可選擇
繼續等待或者Force Close。
那麼哪些場景會造成ANR呢?
1,Service Timeout:服務在20s內未執行完成;
2,BroadcastQueueTimeout:比如前臺廣播在10s內執行完成
3,ContentProviderTimeout:內容提供者執行超時
4,inputDispatchingTimeout: 輸入事件分發超時5s,包括按鍵分發事件的超時。
1, Service Timeout
ServiceTimeout觸發時機,簡單說就是AMS中的mHandler收到SERVICE_TIMEOUT_MSG訊息時觸發。
在service啟動時,最後會呼叫system_server程序中的ActiveServices的attachApplicationLocked方法,然後呼叫realStartServiceLocked方法完成服務的啟動。
整個過程主要分為3個部分:
1,在啟動service之前傳送SERVICE_TIMEOUT_MSG 訊息;
2,如果service順利啟動,則刪除SERVICE_TIMEOUT_MSG 訊息;
3,如果SERVICE_TIMEOUT_MSG 未刪除,時間到後就會發生ANR。
1.1 傳送訊息
ActiveServices的realStartServiceLocked方法在呼叫service的OnCreate方法之前就會發送訊息,呼叫流程圖如下,
realStartServiceLocked方法呼叫如下,
bumpServiceExecutingLocked(r, execInFg, "create");//傳送訊息 ••• app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState); //呼叫service的OnCreate方法
在bumpServiceExecutingLocked方法中回撥用scheduleServiceTimeoutLocked方法傳送SERVICE_TIMEOUT_MSG 訊息。
scheduleServiceTimeoutLocked方法如下,
long now = SystemClock.uptimeMillis();
Message msg = mAm.mHandler.obtainMessage(ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
首先獲取系統的當前時間,然後利用AMS的mHandler變數構造SERVICE_TIMEOUT_MSG訊息,最後呼叫AMS的mHandler變數的sendMessageAtTime方法傳送訊息。
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;
因此, 對於前臺服務,則超時為SERVICE_TIMEOUT,即timeout=20s;
對於後臺服務,則超時為SERVICE_BACKGROUND_TIMEOUT,即timeout=200s;
1.2 刪除訊息
在比較多的地方會刪除訊息,
比如,在realStartServiceLocked方法中
app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
呼叫service的OnCreate方法時程序掛掉之後會呼叫serviceDoneExecutingLocked方法刪除訊息。
catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app);
throw e;
} finally {
if (!created) {
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
或者在sendServiceArgsLocked方法中,啟動service丟擲異常也會呼叫serviceDoneExecutingLocked方法刪除訊息。
if (caughtException != null) {
// Keep nesting count correct
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
此處會呼叫ActivityThread的內部類ApplicationThread的scheduleCreateService方法,最後會呼叫handleCreateService方法。
ActivityThread的handleCreateService方法主要邏輯如下,
1,載入service 物件,
LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
2,呼叫service的onCreate方法,
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault());
service.onCreate();
mServices.put(data.token, service);
3,成功呼叫service的onCreate方法之後,跨程序呼叫AMS的serviceDoneExecuting方法刪除訊息。
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
AMS的serviceDoneExecuting方法如下,
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
直接呼叫ActiveServices的serviceDoneExecutingLocked方法.
由此可見,刪除SERVICE_TIMEOUT_MSG 訊息一般通過ActiveServices的serviceDoneExecutingLocked方法。
serviceDoneExecutingLocked方法邏輯如下,
if (r.app.executingServices.size() == 0) {
if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
"No more executingServices of " + r.shortName);
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
如果當前服務所在程序中沒有正在執行的service,就刪除SERVICE_TIMEOUT_MSG訊息。
1.3 處理訊息
AMS中內部類MainHandler的handleMessage方法對SERVICE_TIMEOUT_MSG訊息處理如下,
mServices.serviceTimeout((ProcessRecord)msg.obj);
呼叫ActiveServices的serviceTimeout方法進行處理,
serviceTimeout方法邏輯如下,
if (anrMessage != null) {
mAm.appNotResponding(proc, null, null, false, anrMessage);
}
呼叫AMS的appNotResponding方法統一處理。處理過程後面詳細論述。
其中, anrMessage 字串為 executing service [傳送超時serviceRecord資訊]