Android ANR 無響應(yīng)原理解讀

和你一起終身學(xué) 習(xí),這里是程序員Android
經(jīng)典好文推薦,通過閱讀本文,您將收獲以下知識(shí)點(diǎn):
一 概述ANR (Application Not responding),是指應(yīng)用程序未響應(yīng),Android 系統(tǒng)對(duì)于一些事件需要在一定的時(shí)間范圍內(nèi)完成,如果超過預(yù)定時(shí)間能未能得到有效響應(yīng)或者響應(yīng)時(shí)間過長(zhǎng),都會(huì)造成 ANR。一般地,這時(shí)往往會(huì)彈出一個(gè)提示框,告知用戶當(dāng)前 xxx 未響應(yīng),用戶可選擇繼續(xù)等待或者Force Close。
那么哪些場(chǎng)景會(huì)造成 ANR 呢?
-
Service Timeout:前臺(tái)服務(wù)在 20s 內(nèi)未執(zhí)行完成
-
BroadcastQueue Timeout:前臺(tái)廣播在 10s 內(nèi)未執(zhí)行完成
-
ContentProvider Timeout:內(nèi)容提供者,超時(shí) 10s
-
InputDispatching Timeout:輸入事件分發(fā)超時(shí) 5s,包括按鍵和觸摸事件
觸發(fā) ANR 的過程可分為三個(gè)步驟:埋炸彈,拆炸彈,引爆炸彈
二 ServiceService Timeout 是位于 ”ActivityManager” 線程中的 AMS.MainHandler 收到 SERVICE_TIMEOUT_MSG 消息時(shí)觸發(fā)。
對(duì)于 Service 有兩類:
-
對(duì)于前臺(tái)服務(wù),則超時(shí)為 SERVICE_TIMEOUT = 20s
-
對(duì)于后臺(tái)服務(wù),則超時(shí)為 SERVICE_BACKGROUND_TIMEOUT = 200s
由變量 ProcessRecord.execServicesFg 來決定是否前臺(tái)啟動(dòng)
2.1 埋炸彈
文章Android四大組件系列4 Service啟動(dòng)流程詳細(xì)介紹了 Service 的啟動(dòng)流程。其中在 Service 進(jìn)程 attach 到 system_server 進(jìn)程的過程中會(huì)調(diào)用 realStartServiceLocked() 方法來埋下炸彈。
2.1.1 ActiveServices.realStartServiceLocked
ActiveServices.java
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
......
//發(fā)送delay消息(SERVICE_TIMEOUT_MSG)
bumpServiceExecutingLocked(r, execInFg, "create");
try {
......
//最終執(zhí)行服務(wù)的onCreate()方法
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(
r.serviceInfo.applicationInfo),
app.repProcState);
} catch (DeadObjectException e) {
......
} finally {
......
}
......
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
2.1.2 ActiveServices.bumpServiceExecutingLocked
ActiveServices.java
private final void bumpServiceExecutingLocked(ServiceRecord r,
boolean fg, String why) {
......
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;
//當(dāng)超時(shí)后仍沒有remove該SERVICE_TIMEOUT_MSG消息,則執(zhí)行service Timeout流程
mAm.mHandler.sendMessageDelayed(msg,
proc.execServicesFg ? (now+SERVICE_TIMEOUT) :
(now+ SERVICE_BACKGROUND_TIMEOUT));
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
該方法的主要工作是發(fā)送 delay 消息 (SERVICE_TIMEOUT_MSG)。炸彈已埋下,我們并不希望炸彈被引爆,那么就需要在炸彈爆炸之前拆除炸彈。
2.2 拆炸彈
在 system_server 進(jìn)程 ActiveServices.realStartServiceLocked() 調(diào)用的過程會(huì)埋下一顆炸彈,超時(shí)沒有啟動(dòng)完成則會(huì)爆炸。那么什么時(shí)候會(huì)拆除這顆炸彈的引線呢?我們來看經(jīng)過 Binder 等進(jìn)程間通信層層調(diào)用進(jìn)入目標(biāo)進(jìn)程的主線程 handleCreateService() 函數(shù)。
2.2.1 ActivityThread.handleCreateService
ActivityThread.java
private void handleCreateService(CreateServiceData data) {
......
java.lang.ClassLoader cl = packageInfo.getClassLoader();
Service service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
......
try {
//創(chuàng)建ContextImpl對(duì)象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
//創(chuàng)建Application對(duì)象
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
//調(diào)用服務(wù)onCreate()方法
service.onCreate();
mServices.put(data.token, service);
//拆除炸彈引線
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (Exception e) {
......
}
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
在這個(gè)過程會(huì)創(chuàng)建目標(biāo)服務(wù)對(duì)象,并回調(diào)其 onCreate() 方法,緊接著再次經(jīng)過 IPC 調(diào)用回到 system_server 來執(zhí)行 serviceDoneExecuting。
2.2.2 ActiveServices.serviceDoneExecutingLocked
ActiveServices.java
private void serviceDoneExecutingLocked(ServiceRecord r,
boolean inDestroying, boolean finishing) {
......
if (r.executeNesting <= 0) {
if (r.app != null) {
r.app.execServicesFg = false;
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
//當(dāng)前服務(wù)所在進(jìn)程中沒有正在執(zhí)行的service
mAm.mHandler.removeMessages(
ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
......
}
......
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
該方法的主要工作是當(dāng) service 啟動(dòng)完成,則移除服務(wù)超時(shí)消息 SERVICE_TIMEOUT_MSG。
2.3 引爆炸彈
前面介紹了埋炸彈和拆炸彈的過程,如果在炸彈倒計(jì)時(shí)結(jié)束之前成功拆卸炸彈,那么就沒有爆炸的機(jī)會(huì),但是世事難料,總有些極端情況下無法即時(shí)拆除炸彈,導(dǎo)致炸彈爆炸,其結(jié)果就是 App 發(fā)生 ANR。接下來,分析下炸彈爆炸的現(xiàn)場(chǎng)。
在 system_server 進(jìn)程中有一個(gè) Handler 線程,名叫 ”ActivityManager”。當(dāng)?shù)褂?jì)時(shí)結(jié)束便會(huì)向該 Handler 線程發(fā)送一條消息 SERVICE_TIMEOUT_MSG。
2.3.1 MainHandler.handleMessage
ActivityManagerService.java ::MainHandler
final class MainHandler extends Handler {
......
public void handleMessage(Message msg) {
switch (msg.what) {
case SERVICE_TIMEOUT_MSG: {
......
mServices.serviceTimeout((ProcessRecord)msg.obj);
} break;
......
}
......
}
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
2.3.2 ActiveServices.serviceTimeout
ActiveServices.java
void serviceTimeout(ProcessRecord proc) {
String anrMessage = null;
synchronized(mAm) {
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.shortName;
}
}
if (anrMessage != null) {
//當(dāng)存在timeout的service,則執(zhí)行appNotResponding
proc.appNotResponding(null, null, null, null, false, anrMessage);
}
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
其中 anrMessage 的內(nèi)容為 ”executing service [發(fā)送超時(shí) serviceRecord 信息]”。
三 BroadcastReceiverBroadcastReceiver Timeout 是位于 ”ActivityManager” 線程中的 BroadcastQueue.BroadcastHandler 收到 BROADCAST_TIMEOUT_MSG 消息時(shí)觸發(fā)。
對(duì)于廣播隊(duì)列在 AMS 中有兩個(gè):mFgBroadcastQueue 隊(duì)列和 mBgBroadcastQueue 隊(duì)列:
-
對(duì)于前臺(tái)廣播,則超時(shí)為 BROADCAST_FG_TIMEOUT = 10s
-
對(duì)于后臺(tái)廣播,則超時(shí)為 BROADCAST_BG_TIMEOUT = 60s
3.1 埋炸彈
我們之前已經(jīng)分析過廣播的注冊(cè)和發(fā)送流程,通過調(diào)用 processNextBroadcast 來處理廣播。其流程為先處理并行廣播,再處理當(dāng)前有序廣播,最后獲取并處理下條有序廣播。
3.1.1 processNextBroadcast
final void processNextBroadcast(boolean fromMsg) {
synchronized (mService) {
processNextBroadcastLocked(fromMsg, false);
}
}
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
......
//part 2: 處理當(dāng)前有序廣播
do {
final long now = SystemClock.uptimeMillis();
r = mDispatcher.getNextBroadcastLocked(now);
......
//獲取所有該廣播所有的接收者
int numReceivers =
(r.receivers != null) ? r.receivers.size() : 0;
if (mService.mProcessesReady && !r.timeoutExempt &&
r.dispatchTime > 0) {
long now = SystemClock.uptimeMillis();
if ((numReceivers > 0) &&
(now > r.dispatchTime + (2*mConstants.TIMEOUT*numReceivers))) {
//當(dāng)廣播處理時(shí)間超時(shí),則強(qiáng)制結(jié)束這條廣播
broadcastTimeoutLocked(false);
......
}
}
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) {
if (r.resultTo != null) {
//處理廣播消息消息
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);
r.resultTo = null;
}
//拆炸彈
cancelBroadcastTimeoutLocked();
}
} while (r == null);
......
//part 3: 獲取下條有序廣播
r.receiverTime = SystemClock.uptimeMillis();
if (!mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
//埋炸彈
setBroadcastTimeoutLocked(timeoutTime);
}
......
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
對(duì)于廣播超時(shí)處理時(shí)機(jī):
1.首先在 part3 的過程中 setBroadcastTimeoutLocked(timeoutTime) 設(shè)置超時(shí)廣播消息
2.然后在 part2 根據(jù)廣播處理情況來處理:
-
當(dāng)廣播接收者等待時(shí)間過長(zhǎng),則調(diào)用 broadcastTimeoutLocked(false)
-
當(dāng)執(zhí)行完廣播,則調(diào)用 cancelBroadcastTimeoutLocked
3.1.2 setBroadcastTimeoutLocked
final void setBroadcastTimeoutLocked(long timeoutTime) {
if (!mPendingBroadcastTimeoutMessage) {
Message msg =
mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
mHandler.sendMessageAtTime(msg, timeoutTime);
mPendingBroadcastTimeoutMessage = true;
}
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
設(shè)置定時(shí)廣播 BROADCAST_TIMEOUT_MSG,即當(dāng)前往后推 mTimeout 時(shí)間廣播還沒處理完畢,則進(jìn)入廣播超時(shí)流程。
3.2 拆炸彈
broadcast 跟 service 超時(shí)機(jī)制大體上相同,但有一個(gè)非常隱蔽的技能點(diǎn),那就是通過靜態(tài)注冊(cè)的廣播超時(shí)會(huì)受 SharedPreferences 的影響。
3.2.1 sendFinished
關(guān)于廣播是否考慮 SP 的情況取決于如下代碼:
BroadcastReceiver.PendingResult.finish
public final void finish() {
if (mType == TYPE_COMPONENT) {
final IActivityManager mgr = ActivityManager.getService();
if (QueuedWork.hasPendingWork()) {
//當(dāng)SP有未同步到磁盤的工作,則需等待其完成,才告知系統(tǒng)已完成該廣播
QueuedWork.queue(new Runnable() {
@Override public void run() {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast after work to component " + mToken);
sendFinished(mgr);
}
}, false);
} else {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to component " + mToken);
sendFinished(mgr);
}
} else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to " + mToken);
final IActivityManager mgr = ActivityManager.getService();
sendFinished(mgr);
}
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
可見,只有 XML 靜態(tài)注冊(cè)的廣播超時(shí)檢測(cè)過程會(huì)考慮是否有 SP 尚未完成,動(dòng)態(tài)廣播并不受其影響。
3.2.2 cancelBroadcastTimeoutLocked
final void cancelBroadcastTimeoutLocked() {
if (mPendingBroadcastTimeoutMessage) {
mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
mPendingBroadcastTimeoutMessage = false;
}
}
-
1
-
2
-
3
-
4
-
5
-
6
移除廣播超時(shí)消息 BROADCAST_TIMEOUT_MSG。
3.3 引爆炸彈
3.3.1 BroadcastHandler.handleMessage
BroadcastQueue.java ::BroadcastHandler
private final class BroadcastHandler extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
if (DEBUG_BROADCAST) Slog.v(
TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["
+ mQueueName + "]");
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
}
}
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
3.3.2 broadcastTimeoutLocked
BroadcastQueue.java
final void broadcastTimeoutLocked(boolean fromMsg) {
if (fromMsg) {//fromMsg = true
mPendingBroadcastTimeoutMessage = false;
}
if (mDispatcher.isEmpty() || mDispatcher.getActiveBroadcastLocked()
== null) {
return;
}
long now = SystemClock.uptimeMillis();
BroadcastRecord r = mDispatcher.getActiveBroadcastLocked();
if (fromMsg) {
//當(dāng)系統(tǒng)還沒有準(zhǔn)備就緒時(shí),廣播處理流程中不存在廣播超時(shí)
if (!mService.mProcessesReady) {
return;
}
......
long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
if (timeoutTime > now) {
//如果當(dāng)前正在執(zhí)行的receiver沒有超時(shí),則重新設(shè)置廣播超時(shí)
setBroadcastTimeoutLocked(timeoutTime);
return;
}
}
if (r.state == BroadcastRecord.WAITING_SERVICES) {
//廣播已經(jīng)處理完成,但需要等待已啟動(dòng)service執(zhí)行完成。當(dāng)?shù)却銐驎r(shí)間,則處理下一條廣播。
r.curComponent = null;
r.state = BroadcastRecord.IDLE;
processNextBroadcast(false);
return;
}
r.receiverTime = now;
if (!debugging) {
r.anrCount++;//當(dāng)前BroadcastRecord的anr次數(shù)執(zhí)行加1操作
}
Object curReceiver;
if (r.nextReceiver > 0) {
curReceiver = r.receivers.get(r.nextReceiver-1);
r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT;
} else {
curReceiver = r.curReceiver;
}
//查詢App進(jìn)程
if (curReceiver != null && curReceiver instanceof BroadcastFilter) {
BroadcastFilter bf = (BroadcastFilter)curReceiver;
if (bf.receiverList.pid != 0
&& bf.receiverList.pid != ActivityManagerService.MY_PID) {
synchronized (mService.mPidsSelfLocked) {
app = mService.mPidsSelfLocked.get(
bf.receiverList.pid);
}
}
} else {
app = r.curApp;
}
if (app != null) {
anrMessage = "Broadcast of " + r.intent.toString();
}
if (mPendingBroadcast == r) {
mPendingBroadcast = null;
}
//繼續(xù)移動(dòng)到下一個(gè)廣播接收者
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
if (!debugging && anrMessage != null) {
mHandler.post(new AppNotResponding(app, anrMessage));
}
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
3.3.3 AppNotResponding
BroadcastQueue.java
private final class AppNotResponding implements Runnable {
private final ProcessRecord mApp;
private final String mAnnotation;
public AppNotResponding(ProcessRecord app, String annotation) {
mApp = app;
mAnnotation = annotation;
}
@Override
public void run() {
// 進(jìn)入ANR處理流程
mApp.appNotResponding(null, null, null, null, false, mAnnotation);
}
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
ContentProvider Timeout 是位于 ”ActivityManager” 線程中的 AMS.MainHandler 收到 CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG 消息時(shí)觸發(fā)。
ContentProvider 超時(shí)為 CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10s。這個(gè)跟前面的 Service 和 BroadcastQueue 完全不同,由 Provider 進(jìn)程啟動(dòng)過程相關(guān)。
4.1 埋炸彈
我們之前詳細(xì)介紹了 Provider 啟動(dòng)流程。埋炸彈的過程其實(shí)是在進(jìn)程創(chuàng)建的過程,進(jìn)程創(chuàng)建后會(huì)調(diào)用 attachApplicationLocked() 進(jìn)入 system_server 進(jìn)程。
4.1.1 AMS.attachApplicationLocked
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
ProcessRecord app;
long startTime = SystemClock.uptimeMillis();
long bindApplicationTimeMillis;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid); // 根據(jù)pid獲取ProcessRecord
}
}
......
//系統(tǒng)處于ready狀態(tài)或者該app為FLAG_PERSISTENT進(jìn)程則為true
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
List<ProviderInfo> providers = normalMode ?
generateApplicationProvidersLocked(app) : null;
//app進(jìn)程存在正在啟動(dòng)中的provider
// 則超時(shí)10s后發(fā)送CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息
if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
Message msg = mHandler.obtainMessage(
CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
}
......
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
4.2 拆炸彈
當(dāng) provider 成功 publish 之后,便會(huì)拆除該炸彈。
4.2.1 AMS.publishContentProviders
public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
......
synchronized (this) {
final ProcessRecord r = getRecordForAppLocked(caller);
final int N = providers.size();
for (int i = 0; i < N; i++) {
ContentProviderHolder src = providers.get(i);
......
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
if (dst != null) {
ComponentName comp =
new ComponentName(dst.info.packageName, dst.info.name);
//將該provider添加到mProviderMap
mProviderMap.putProviderByClass(comp, dst);
String names[] = dst.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
mProviderMap.putProviderByName(names[j], dst);
}
int launchingCount = mLaunchingProviders.size();
int j;
boolean wasInLaunchingProviders = false;
for (j = 0; j < launchingCount; j++) {
if (mLaunchingProviders.get(j) == dst) {
//將該provider移除mLaunchingProviders隊(duì)列
mLaunchingProviders.remove(j);
wasInLaunchingProviders = true;
j--;
launchingCount--;
}
}
//成功pubish則移除該消息
if (wasInLaunchingProviders) {
mHandler.removeMessages(
CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
}
synchronized (dst) {
dst.provider = src.provider;
dst.proc = r;
//喚醒客戶端的wait等待方法
dst.notifyAll();
}
......
}
}
}
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
4.3 引爆炸彈
在 system_server 進(jìn)程中有一個(gè) Handler 線程, 名 叫”ActivityManager”。當(dāng)?shù)褂?jì)時(shí)結(jié)束便會(huì)向該 Handler 線程發(fā)送 一條信息 CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG
4.3.1 MainHandler.handleMessage
ActivityManagerService.java ::MainHandler
final class MainHandler extends Handler {
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;
......
}
......
}
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
4.3.2 AMS.processContentProviderPublishTimedOutLocked
private final void processContentProviderPublishTimedOutLocked(
ProcessRecord app) {
cleanupAppInLaunchingProvidersLocked(app, true);
mProcessList.removeProcessLocked(app, false, true,
"timeout publishing content providers");
}
-
1
-
2
-
3
-
4
-
5
-
6
4.3.3 AMS.cleanupAppInLaunchingProvidersLocked
boolean cleanupAppInLaunchingProvidersLocked(
ProcessRecord app, boolean alwaysBad) {
boolean restart = false;
for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
ContentProviderRecord cpr = mLaunchingProviders.get(i);
if (cpr.launchingApp == app) {
if (!alwaysBad && !app.bad && cpr.hasConnectionOrHandle()) {
restart = true;
} else {
//移除死亡的provider
removeDyingProviderLocked(app, cpr, true);
}
}
}
return restart;
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
removeDyingProviderLocked() 的功能跟進(jìn)程的存活息息相關(guān)
-
對(duì)于 stable 類型的 provider (即 conn.stableCount > 0),則會(huì)殺掉所有跟該 provider 建立 stable 連接的非persistent 進(jìn)程
-
對(duì)于 unstable 類的 provider (即 conn.unstableCount > 0),并不會(huì)導(dǎo)致 client 進(jìn)程被級(jí)聯(lián)所殺
4.3.4 ProcessList.removeProcessLocked
boolean removeProcessLocked(ProcessRecord app,
boolean callerWillRestart, boolean allowRestart, String reason) {
final String name = app.processName;
final int uid = app.uid;
......
//移除mProcessNames中的相應(yīng)對(duì)象
removeProcessNameLocked(name, uid);
mService.mAtmInternal.clearHeavyWeightProcessIfEquals(
app.getWindowProcessController());
boolean needRestart = false;
if ((app.pid > 0 && app.pid != ActivityManagerService.MY_PID) ||
(app.pid == 0 && app.pendingStart)) {
int pid = app.pid;
if (pid > 0) {
......
}
boolean willRestart = false;
if (app.isPersistent() && !app.isolated) {
if (!callerWillRestart) {
willRestart = true;
} else {
needRestart = true;
}
}
app.kill(reason, true);//殺進(jìn)程
mService.handleAppDiedLocked(app, willRestart, allowRestart);
if (willRestart) {
removeLruProcessLocked(app);
mService.addAppLocked(app.info, null, false, null /* ABI override */);
}
} else {
mRemovedProcesses.add(app);
}
return needRestart;
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
當(dāng)出現(xiàn) ANR 時(shí),都是調(diào)用到 AMS.appNotResponding() 方法,詳細(xì)過程見文章理解Android ANR的信息收集過程. 當(dāng)然這里介紹的 provider 例外。
5.1 Timeout時(shí)長(zhǎng)
-
對(duì)于前臺(tái)服務(wù),則超時(shí)為 SERVICE_TIMEOUT = 20s
-
對(duì)于后臺(tái)服務(wù),則超時(shí)為 SERVICE_BACKGROUND_TIMEOUT = 200s
-
對(duì)于前臺(tái)廣播,則超時(shí)為 BROADCAST_FG_TIMEOUT = 10s
-
對(duì)于后臺(tái)廣播,則超時(shí)為 BROADCAST_BG_TIMEOUT = 60s
-
ContentProvider 超時(shí)為 CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10s
5.2 超時(shí)檢測(cè)
Service 超時(shí)檢測(cè)機(jī)制:
-
超過一定時(shí)間沒有執(zhí)行完相應(yīng)操作來觸發(fā)移除延時(shí)消息,則會(huì)觸發(fā) anr
BroadcastReceiver 超時(shí)檢測(cè)機(jī)制:
-
有序廣播的總執(zhí)行時(shí)間超過 2* receiver 個(gè)數(shù) * timeout 時(shí)長(zhǎng),則會(huì)觸發(fā) anr
-
有序廣播的某一個(gè) receiver 執(zhí)行過程超過 timeout 時(shí)長(zhǎng),則會(huì)觸發(fā) anr
另外:
-
對(duì)于 Service,Broadcast,Input 發(fā)生 ANR 之后,最終都會(huì)調(diào)用 AMS.appNotResponding
-
對(duì)于 provider,在其進(jìn)程啟動(dòng)時(shí) publish 過程可能會(huì)出現(xiàn) ANR,則會(huì)直接殺進(jìn)程以及清理相應(yīng)信息,而不會(huì)彈出 ANR 的對(duì)話框。appNotRespondingViaProvider() 過程會(huì)走 appNotResponding(),這個(gè)就不介紹了,很少使用,由用戶自定義超時(shí)時(shí)間.
原文鏈接:
https://blog.csdn.net/liuwg1226/article/details/11383483
至此,本篇已結(jié)束。轉(zhuǎn)載網(wǎng)絡(luò)的文章,小編覺得很優(yōu)秀,歡迎點(diǎn)擊閱讀原文,支持原創(chuàng)作者,如有侵權(quán),懇請(qǐng)聯(lián)系小編刪除,歡迎您的建議與指正。同時(shí)期待您的關(guān)注,感謝您的閱讀,謝謝!
點(diǎn)個(gè)在看,方便您使用時(shí)快速查找!
