四 、ContentProvider Timeout
4.1 attachApplicationLocked
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
long startTime = SystemClock.uptimeMillis();
long bindApplicationTimeMillis;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
if (app != null && (app.startUid != callingUid || app.startSeq != startSeq)) {
String processName = null;
final ProcessRecord pending = mProcessList.mPendingStarts.get(startSeq);
if (pending != null) {
processName = pending.processName;
}
final String msg = "attachApplicationLocked process:" + processName
+ " startSeq:" + startSeq
+ " pid:" + pid
+ " belongs to another existing app:" + app.processName
+ " startSeq:" + app.startSeq;
Slog.wtf(TAG, msg);
// SafetyNet logging for b/131105245.
EventLog.writeEvent(0x534e4554, "131105245", app.startUid, msg);
// If there is already an app occupying that pid that hasn't been cleaned up
cleanUpApplicationRecordLocked(app, false, false, -1,
true /*replacingPid*/);
mPidsSelfLocked.remove(app);
app = null;
}
} else {
app = null;
}
// It's possible that process called attachApplication before we got a chance to
// update the internal state.
if (app == null && startSeq > 0) {
final ProcessRecord pending = mProcessList.mPendingStarts.get(startSeq);
if (pending != null && pending.startUid == callingUid && pending.startSeq == startSeq
&& mProcessList.handleProcessStartedLocked(pending, pid, pending
.isUsingWrapper(),
startSeq, true)) {
app = pending;
}
}
if (app == null) {
Slog.w(TAG, "No pending application record for pid " + pid
+ " (IApplicationThread " + thread + "); dropping process");
EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
if (pid > 0 && pid != MY_PID) {
killProcessQuiet(pid);
//TODO: killProcessGroup(app.info.uid, pid);
} else {
try {
thread.scheduleExit();
} catch (Exception e) {
// Ignore exceptions.
}
}
return false;
}
// If this application record is still attached to a previous
// process, clean it up now.
if (app.thread != null) {
handleAppDiedLocked(app, true, true);
}
// Tell the process all about itself.
if (DEBUG_ALL) Slog.v(
TAG, "Binding process pid " + pid + " to record " + app);
final String processName = app.processName;
try {
AppDeathRecipient adr = new AppDeathRecipient(
app, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
} catch (RemoteException e) {
app.resetPackageList(mProcessStats);
mProcessList.startProcessLocked(app,
new HostingRecord("link fail", processName));
return false;
}
EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
app.setCurrentSchedulingGroup(app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT);
app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, 0, false);
app.hasShownUi = false;
app.setDebugging(false);
app.cached = false;
app.killedByAm = false;
app.killed = false;
// We carefully use the same state that PackageManager uses for
// filtering, since we use this flag to decide if we need to install
// providers when user is unlocked later
app.unlocked = StorageManager.isUserKeyUnlocked(app.userId);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
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, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
}
checkTime(startTime, "attachApplicationLocked: before bindApplication");
if (!normalMode) {
Slog.i(TAG, "Launching preboot mode app: " + app);
}
......
}
上面代码快看两个关键信息:Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG); 这个message 是在10s后执行。
EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);会再event log中生成,关键字:am_proc_bound.
4.2 publishContentProviders
public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
if (providers == null) {
return;
}
enforceNotIsolatedCaller("publishContentProviders");
synchronized (this) {
final ProcessRecord r = getRecordForAppLocked(caller);//获取进程
/// M: Fix NullPointerException @{
if (DEBUG_MU && r != null) {
Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
}
/// M: Fix NullPointerException @}
if (r == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when publishing content providers");
}
final long origId = Binder.clearCallingIdentity();
//providers是系统在开机启动的时候,会对所有包含contentprovide的扫描收集的集合。
final int N = providers.size();
for (int i = 0; i < N; i++) {
ContentProviderHolder src = providers.get(i);
if (src == null || src.info == null || src.provider == null) {
continue;
}
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
/// M: Fix NullPointerException @{
if (DEBUG_MU && dst != null) {
Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
}
/// M: Fix NullPointerException @}
if (dst != null) {//当找到对应的contentprovide的时候
ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
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();//保存已经启动的provider集合。
int j;
boolean wasInLaunchingProviders = false;
//如果已经启动provide 等于我们所要求的。wasInLaunchingProviders=true。移除CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG
for (j = 0; j < launchingCount; j++) {
if (mLaunchingProviders.get(j) == dst) {
mLaunchingProviders.remove(j);
wasInLaunchingProviders = true;
j--;
launchingCount--;
}
}
if (wasInLaunchingProviders) {
mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
}
// Make sure the package is associated with the process.
// XXX We shouldn't need to do this, since we have added the package
// when we generated the providers in generateApplicationProvidersLocked().
// But for some reason in some cases we get here with the package no longer
// added... for now just patch it in to make things happy.
r.addPackage(dst.info.applicationInfo.packageName,
dst.info.applicationInfo.longVersionCode, mProcessStats);
synchronized (dst) {
dst.provider = src.provider;
dst.setProcess(r);
dst.notifyAll();
}
updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
src.info.authority);
}
}
Binder.restoreCallingIdentity(origId);
}
}
在这个函数中我们移除 mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
4.3 CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG
case CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG: {
ProcessRecord app = (ProcessRecord)msg.obj;
synchronized (ActivityManagerService.this) {
processContentProviderPublishTimedOutLocked(app);
}
} break;
private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
cleanupAppInLaunchingProvidersLocked(app, true);
mProcessList.removeProcessLocked(app, false, true, "timeout publishing content providers");
}
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;
}
private final boolean removeDyingProviderLocked(ProcessRecord proc, ContentProviderRecord cpr, boolean always) {
final boolean inLaunching = mLaunchingProviders.contains(cpr);
if (!inLaunching || always) {
synchronized (cpr) {
cpr.launchingApp = null;
cpr.notifyAll(); //通知处于等待状态的进程
}
mProviderMap.removeProviderByClass(cpr.name, UserHandle.getUserId(cpr.uid));
String names[] = cpr.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
mProviderMap.removeProviderByName(names[j], UserHandle.getUserId(cpr.uid));
}
}
for (int i = cpr.connections.size() - 1; i >= 0; i--) {
ContentProviderConnection conn = cpr.connections.get(i);
if (conn.waiting) {
if (inLaunching && !always) {
continue;
}
}
ProcessRecord capp = conn.client;
conn.dead = true;
if (conn.stableCount > 0) {
if (!capp.persistent && capp.thread != null
&& capp.pid != 0
&& capp.pid != MY_PID) {
//非persistent进程,则杀掉跟provider具有依赖关系的进程
capp.kill("depends on provider "
+ cpr.name.flattenToShortString()
+ " in dying proc " + (proc != null ? proc.processName : "??"), true);
}
} else if (capp.thread != null && conn.provider.provider != null) {
//unstable的类型则不会被杀,也会调用到
capp.thread.unstableProviderDied(conn.provider.provider.asBinder());
cpr.connections.remove(i);
if (conn.client.conProviders.remove(conn)) {
stopAssociationLocked(capp.uid, capp.processName, cpr.uid, cpr.name);
}
}
}
if (inLaunching && always) {
mLaunchingProviders.remove(cpr);
}
return inLaunching;
removeDyingProviderLocked()方法的功能非常值得注意,引用计数跟进程的存活息息相关:
- 对于stable类型的provider(即conn.stableCount > 0),则会杀掉所有跟该provider建立stable连接的非persistent进程.
- 对于unstable类的provider(即conn.unstableCount > 0),并不会导致client进程被级联所杀.
boolean removeProcessLocked(ProcessRecord app,
boolean callerWillRestart, boolean allowRestart, String reason) {
final String name = app.processName;
final int uid = app.uid;
if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES,
"Force removing proc " + app.toShortString() + " (" + name + "/" + uid + ")");
ProcessRecord old = mProcessNames.get(name, uid);
if (old != app) {
// This process is no longer active, so nothing to do.
Slog.w(TAG, "Ignoring remove of inactive process: " + app);
return false;
}
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) {
mService.mPidsSelfLocked.remove(app);//移除mPidsSelfLocked的进程信息。
mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);//removeMessages PROC_START_TIMEOUT_MSG,每个进程创建都会发生一个timeout 广播 :PROC_START_TIMEOUT_MSG
mService.mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
if (app.isolated) {
mService.mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
mService.getPackageManagerInternalLocked().removeIsolatedUid(app.uid);
}
}
boolean willRestart = false;
//如果是persistent app 就重启。
if (app.isPersistent() && !app.isolated) {
if (!callerWillRestart) {
willRestart = true;
} else {
needRestart = true;
}
}
app.kill(reason, true);//杀死进程,输出event log 。
mService.handleAppDiedLocked(app, willRestart, allowRestart);
if (willRestart) {
removeLruProcessLocked(app);
mService.addAppLocked(app.info, null, false, null /* ABI override */);
}
} else {
mRemovedProcesses.add(app);
}
return needRestart;
}
void kill(String reason, boolean noisy) {
if (!killedByAm) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill");
if (mService != null && (noisy || info.uid == mService.mCurOomAdjUid)) {
mService.reportUidInfoMessageLocked(TAG,
"Killing " + toShortString() + " (adj " + setAdj + "): " + reason,
info.uid);
}
if (pid > 0) {
//在event log中会搜索到am_kill 关键字。
EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);
Process.killProcessQuiet(pid);
ProcessList.killProcessGroup(uid, pid);
} else {
pendingStart = false;
}
if (!mPersistent) {
killed = true;
killedByAm = true;
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
总结:contentprovide timeout 不会产生ANR,跟之前的servcie ,broadcast 不相同。而是会杀死相关进程。
而关键的log是:1.EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);
2. EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);