相關文章:
ATMS中去pause Activity A.
- ATMS拉起新程式
- 堆疊
- resumeTopActivityInnerLocked:1684, ActivityStack
- startProcessAsync:5617, ActivityTaskManagerService
- startProcess:19641, ActivityManagerService$LocalService (com.android.server.am)
- startProcessLocked:3170, ActivityManagerService
- startProcessLocked:2441, ProcessList
- startProcessLocked:2319, ProcessList
- startProcessLocked:1943, ProcessList
- startProcessLocked:1991, ProcessList
- handleProcessStart:2055, ProcessList
- startProcess:2296, ProcessList
- startProcess:2296, ProcessList
- start:372, ZygoteProcess
- 新程式呼叫attachApplication時,系統resume待啟動的Activity
- attachApplication:5458, ActivityManagerService
- attachApplicationLocked:5378, ActivityManagerService
- attachApplication:6890, ActivityTaskManagerService$LocalService
- attachApplication:1944, RootWindowContainer
- startActivityForAttachedApplicationIfNeeded:1965, RootWindowContainer
- realStartActivityLocked:856, ActivityStackSupervisor
ATMS拉起新程式
這個流程相對複雜一點,並不是一直呼叫下來,中間做了幾次往Handler轉發的操作.我的理解是:
- 平衡負載,把不同的邏輯執行到不同的執行緒上,可以及時釋放binder執行緒的執行資源.
- 及時釋放鎖資源.啟動新程式相對是個耗時的任務,而在ActivityStarter.execute,是持有了Android中的com.android.server.wm.WindowManagerGlobalLock鎖的.轉發到其他執行緒去處理也可以儘快其他邏輯,及時釋放鎖資源.
堆疊
startProcessAsync:5617, ActivityTaskManagerService
resumeTopActivityInnerLocked:1684, ActivityStack (com.android.server.wm)
resumeTopActivityUncheckedLocked:1511, ActivityStack (com.android.server.wm)
resumeFocusedStacksTopActivities:2299, RootWindowContainer (com.android.server.wm)
startActivityInner:1731, ActivityStarter (com.android.server.wm)
startActivityUnchecked:1521, ActivityStarter (com.android.server.wm)
executeRequest:1186, ActivityStarter (com.android.server.wm)
execute:669, ActivityStarter (com.android.server.wm)
startActivityAsUser:1100, ActivityTaskManagerService (com.android.server.wm)
startActivityAsUser:1072, ActivityTaskManagerService (com.android.server.wm)
startActivity:1047, ActivityTaskManagerService (com.android.server.wm)
onTransact:1422, IActivityTaskManager$Stub (android.app)
execTransactInternal:1154, Binder (android.os)
execTransact:1123, Binder (android.os)
startProcessLocked:1988, ProcessList (com.android.server.am)
startProcessLocked:1943, ProcessList (com.android.server.am)
startProcessLocked:2319, ProcessList (com.android.server.am)
startProcessLocked:2441, ProcessList (com.android.server.am)
startProcessLocked:3170, ActivityManagerService (com.android.server.am)
startProcess:19641, ActivityManagerService$LocalService (com.android.server.am)
accept:-1, -$$Lambda$qMFJUmfG50ZSjk7Tac67xBia0d4 (com.android.server.wm)
doInvoke:360, PooledLambdaImpl (com.android.internal.util.function.pooled)
invoke:201, PooledLambdaImpl (com.android.internal.util.function.pooled)
run:97, OmniFunction (com.android.internal.util.function.pooled)
handleCallback:938, Handler (android.os)
dispatchMessage:99, Handler (android.os)
loop:223, Looper (android.os)
run:67, HandlerThread (android.os)
run:44, ServiceThread (com.android.server)
這個堆疊和上一篇檔案中ATMS中去pause Activity A.是一樣的.在AMTS呼叫Activity A 去執行Pause後. 就會檢查待啟動的Activity B是否已經有程式了.
resumeTopActivityInnerLocked:1684, ActivityStack
if (pausing) {
if (next.attachedToProcess()) {
next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
true /* activityChange */, false /* updateOomAdj */,
false /* addPendingTopUid */);
} else if (!next.isProcessRunning()) {
// Since the start-process is asynchronous, if we already know the process of next
// activity isn't running, we can start the process earlier to save the time to wait
// for the current activity to be paused.
final boolean isTop = this == taskDisplayArea.getFocusedStack();
mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
isTop ? "pre-top-activity" : "pre-activity");
}
if (lastResumed != null) {
lastResumed.setWillCloseOrEnterPip(true);
}
return true;
}
mAtmService.startProcessAsync
:呼叫ATMS的startProcessAsync
startProcessAsync:5617, ActivityTaskManagerService
void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,
String hostingType) {
try {
// Post message to start process to avoid possible deadlock of calling into AMS with the
// ATMS lock held.
final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
isTop, hostingType, activity.intent.getComponent());
mH.sendMessage(m);
}
}
這裡就是簡單的新建了一個PooledLambda的message,然後通過mH傳送出去了,這個mH物件的執行緒是android.display.
startProcess:19641, ActivityManagerService$LocalService (com.android.server.am)
上一節傳送了一個ActivityManagerInternal::startProcess到mH的handler去執行.mAmInternal 獲取的程式碼 mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
對應ActivityManagerService.所以這裡實際是會執行到startProcess:19641, ActivityManagerService
,這裡只是簡單呼叫startProcessLocked
startProcessLocked:3170, ActivityManagerService
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
keepIfLarge, null /* ABI override */, null /* entryPoint */,
null /* entryPointArgs */, null /* crashHandler */);
}
這裡很簡單的呼叫ProcessList的startProcessLocked.
startProcessLocked:2441, ProcessList
@GuardedBy("mService")
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,
boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs,
Runnable crashHandler) {
long startTime = SystemClock.uptimeMillis();
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
// If we are in the background, then check to see if this process
// is bad. If so, we will just silently fail.
if (mService.mAppErrors.isBadProcessLocked(info)) {
if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+ "/" + info.processName);
return null;
}
} else {
// When the user is explicitly starting a process, then clear its
// crash count so that we won't make it bad until they see at
// least one crash dialog again, and make the process good again
// if it had been bad.
if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+ "/" + info.processName);
mService.mAppErrors.resetProcessCrashTimeLocked(info);
if (mService.mAppErrors.isBadProcessLocked(info)) {
EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
UserHandle.getUserId(info.uid), info.uid,
info.processName);
mService.mAppErrors.clearBadProcessLocked(info);
if (app != null) {
app.bad = false;
}
}
}
}
- 首先判斷當前待啟動的程式是否是isolated的,這裡是非isolated程式,那麼程式就是可以複用的,所以從當前的程式檢視是否有相同名稱,以及相同uid的程式,有的話那麼直接返回這個程式
- 如果是從後臺啟動且程式是badProcess,那麼直接返回;如果是前臺啟動的且badprocess,那麼clearBadProcessLocked.並把app的bad值設定為false.
else { // if (isolated)
// If this is an isolated process, it can't re-use an existing process.
app = null;
}
如果是isolated性質的程式,則不能複用,直接新啟動一個.
ProcessRecord precedence = null;
if (app != null && app.pid > 0) {
if ((!knownToBeDead && !app.killed) || app.thread == null) {
// We already have the app running, or are waiting for it to
// come up (we have a pid but not yet its thread), so keep it.
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App already running: " + app);
// If this is a new package in the process, add the package to the list
app.addPackage(info.packageName, info.longVersionCode, mService.mProcessStats);
checkSlow(startTime, "startProcess: done, added package to proc");
return app;
}
如果上一步找到了一個可用的app.並且這個app的thread為空,並且這個app不是已經死亡或者正在被kill的程式,那麼說明之前已經有一個這樣的程式,我們直接使用即可
// An application record is attached to a previous process,
// clean it up now.
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app);
checkSlow(startTime, "startProcess: bad proc running, killing");
ProcessList.killProcessGroup(app.uid, app.pid);
checkSlow(startTime, "startProcess: done killing old proc");
Slog.wtf(TAG_PROCESSES, app.toString() + " is attached to a previous process");
// We are not going to re-use the ProcessRecord, as we haven't dealt with the cleanup
// routine of it yet, but we'd set it as the precedence of the new process.
precedence = app;
app = null;
}
如果前面已經找到了一個程式,但是這個程式是之前遺留的出錯程式,那麼直接殺死它.
if (app == null) {
checkSlow(startTime, "startProcess: creating new process record");
app = newProcessRecordLocked(info, processName, isolated, isolatedUid, hostingRecord);
if (app == null) {
Slog.w(TAG, "Failed making new process record for "
+ processName + "/" + info.uid + " isolated=" + isolated);
return null;
}
app.crashHandler = crashHandler;
app.isolatedEntryPoint = entryPoint;
app.isolatedEntryPointArgs = entryPointArgs;
if (precedence != null) {
app.mPrecedence = precedence;
precedence.mSuccessor = app;
}
checkSlow(startTime, "startProcess: done creating new process record");
}
前面找到的程式有問題,或者沒有找到程式,那麼這裡new一個ProcessRecord物件出來.
else {
// If this is a new package in the process, add the package to the list
app.addPackage(info.packageName, info.longVersionCode, mService.mProcessStats);
checkSlow(startTime, "startProcess: added package to existing proc");
}
雖然存在ProcessRecord,但是這個ProcessRecord並沒有實際拉起來過(!pid>0),那麼這裡就把待啟動的app相關資訊給它.
// If the system is not ready yet, then hold off on starting this
// process until it is.
if (!mService.mProcessesReady
&& !mService.isAllowedWhileBooting(info)
&& !allowWhileBooting) {
if (!mService.mProcessesOnHold.contains(app)) {
mService.mProcessesOnHold.add(app);
}
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
"System not ready, putting on hold: " + app);
checkSlow(startTime, "startProcess: returning with proc on hold");
return app;
}
系統沒有啟動好,這個時候就先不實際去啟動程式了
checkSlow(startTime, "startProcess: stepping in to startProcess");
final boolean success =
startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride);
checkSlow(startTime, "startProcess: done starting proc!");
return success ? app : null;
呼叫startProcessLocked執行後續部分.
總結一下:這裡就是看系統有沒有可以複用的ProcessRecord.
startProcessLocked:2319, ProcessList
final boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
int zygotePolicyFlags, String abiOverride) {
return startProcessLocked(app, hostingRecord, zygotePolicyFlags,
false /* disableHiddenApiChecks */, false /* disableTestApiChecks */,
false /* mountExtStorageFull */, abiOverride);
}
直接轉發了
startProcessLocked:1943, ProcessList
boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,
boolean mountExtStorageFull, String abiOverride) {
if (app.pendingStart) {
return true;
}
如果暫時不需要啟動的,那麼直接返回.
long startTime = SystemClock.uptimeMillis();
if (app.pid > 0 && app.pid != ActivityManagerService.MY_PID) {
checkSlow(startTime, "startProcess: removing from pids map");
mService.removePidLocked(app);
app.bindMountPending = false;
mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
checkSlow(startTime, "startProcess: done removing from pids map");
app.setPid(0);
app.startSeq = 0;
}
如果待啟動的app已經有pid了.這個時候先清理一下資訊.
TODO:前面已經判斷過了pid的值,這個值為什麼還會出現>0的情況?
try {
try {
final int userId = UserHandle.getUserId(app.uid);
AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
int uid = app.uid;
int[] gids = null;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
if (!app.isolated) {
int[] permGids = null;
try {
checkSlow(startTime, "startProcess: getting gids from package manager");
final IPackageManager pm = AppGlobals.getPackageManager();
permGids = pm.getPackageGids(app.info.packageName,
MATCH_DIRECT_BOOT_AUTO, app.userId);
if (StorageManager.hasIsolatedStorage() && mountExtStorageFull) {
mountExternal = Zygote.MOUNT_EXTERNAL_FULL;
} else {
StorageManagerInternal storageManagerInternal = LocalServices.getService(
StorageManagerInternal.class);
mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
app.info.packageName);
}
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
獲取一些APP需要mount哪些記憶體地址的資訊
// Remove any gids needed if the process has been denied permissions.
// NOTE: eventually we should probably have the package manager pre-compute
// this for us?
if (app.processInfo != null && app.processInfo.deniedPermissions != null) {
for (int i = app.processInfo.deniedPermissions.size() - 1; i >= 0; i--) {
int[] denyGids = mService.mPackageManagerInt.getPermissionGids(
app.processInfo.deniedPermissions.valueAt(i), app.userId);
if (denyGids != null) {
for (int gid : denyGids) {
permGids = ArrayUtils.removeInt(permGids, gid);
}
}
}
}
gids = computeGidsForProcess(mountExternal, uid, permGids);
}
處理拒絕許可權:把被拒絕的許可權重gids中移除
app.mountMode = mountExternal;
checkSlow(startTime, "startProcess: building args");
if (mService.mAtmInternal.isFactoryTestProcess(app.getWindowProcessController())) {
uid = 0;
}
int runtimeFlags = 0;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
runtimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
runtimeFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;
// Also turn on CheckJNI for debuggable apps. It's quite
// awkward to turn on otherwise.
runtimeFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
// Check if the developer does not want ART verification
if (android.provider.Settings.Global.getInt(mService.mContext.getContentResolver(),
android.provider.Settings.Global.ART_VERIFIER_VERIFY_DEBUGGABLE, 1) == 0) {
runtimeFlags |= Zygote.DISABLE_VERIFIER;
Slog.w(TAG_PROCESSES, app + ": ART verification disabled");
}
}
// Run the app in safe mode if its manifest requests so or the
// system is booted in safe mode.
if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 || mService.mSafeMode) {
runtimeFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
}
if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) != 0) {
runtimeFlags |= Zygote.PROFILE_FROM_SHELL;
}
if ("1".equals(SystemProperties.get("debug.checkjni"))) {
runtimeFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
String genDebugInfoProperty = SystemProperties.get("debug.generate-debug-info");
if ("1".equals(genDebugInfoProperty) || "true".equals(genDebugInfoProperty)) {
runtimeFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO;
}
String genMiniDebugInfoProperty = SystemProperties.get("dalvik.vm.minidebuginfo");
if ("1".equals(genMiniDebugInfoProperty) || "true".equals(genMiniDebugInfoProperty)) {
runtimeFlags |= Zygote.DEBUG_GENERATE_MINI_DEBUG_INFO;
}
if ("1".equals(SystemProperties.get("debug.jni.logging"))) {
runtimeFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
}
if ("1".equals(SystemProperties.get("debug.assert"))) {
runtimeFlags |= Zygote.DEBUG_ENABLE_ASSERT;
}
if ("1".equals(SystemProperties.get("debug.ignoreappsignalhandler"))) {
runtimeFlags |= Zygote.DEBUG_IGNORE_APP_SIGNAL_HANDLER;
}
if (mService.mNativeDebuggingApp != null
&& mService.mNativeDebuggingApp.equals(app.processName)) {
// Enable all debug flags required by the native debugger.
runtimeFlags |= Zygote.DEBUG_ALWAYS_JIT; // Don't interpret anything
runtimeFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO; // Generate debug info
runtimeFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE; // Disbale optimizations
mService.mNativeDebuggingApp = null;
}
if (app.info.isEmbeddedDexUsed()
|| (app.info.isPrivilegedApp()
&& DexManager.isPackageSelectedToRunOob(app.pkgList.mPkgList.keySet()))) {
runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
}
if (!disableHiddenApiChecks && !mService.mHiddenApiBlacklist.isDisabled()) {
app.info.maybeUpdateHiddenApiEnforcementPolicy(
mService.mHiddenApiBlacklist.getPolicy());
@ApplicationInfo.HiddenApiEnforcementPolicy int policy =
app.info.getHiddenApiEnforcementPolicy();
int policyBits = (policy << Zygote.API_ENFORCEMENT_POLICY_SHIFT);
if ((policyBits & Zygote.API_ENFORCEMENT_POLICY_MASK) != policyBits) {
throw new IllegalStateException("Invalid API policy: " + policy);
}
runtimeFlags |= policyBits;
if (disableTestApiChecks) {
runtimeFlags |= Zygote.DISABLE_TEST_API_ENFORCEMENT_POLICY;
}
}
String useAppImageCache = SystemProperties.get(
PROPERTY_USE_APP_IMAGE_STARTUP_CACHE, "");
// Property defaults to true currently.
if (!TextUtils.isEmpty(useAppImageCache) && !useAppImageCache.equals("false")) {
runtimeFlags |= Zygote.USE_APP_IMAGE_STARTUP_CACHE;
}
runtimeFlags |= decideGwpAsanLevel(app);
String invokeWith = null;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// Debuggable apps may include a wrapper script with their library directory.
String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
if (new File(wrapperFileName).exists()) {
invokeWith = "/system/bin/logwrapper " + wrapperFileName;
}
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}
String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
if (requiredAbi == null) {
requiredAbi = Build.SUPPORTED_ABIS[0];
}
String instructionSet = null;
if (app.info.primaryCpuAbi != null) {
instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
}
app.gids = gids;
app.setRequiredAbi(requiredAbi);
app.instructionSet = instructionSet;
// If instructionSet is non-null, this indicates that the system_server is spawning a
// process with an ISA that may be different from its own. System (kernel and hardware)
// compatililty for these features is checked in the decideTaggingLevel in the
// system_server process (not the child process). As TBI is only supported in aarch64,
// we can simply ensure that the new process is also aarch64. This prevents the mismatch
// where a 64-bit system server spawns a 32-bit child that thinks it should enable some
// tagging variant. Theoretically, a 32-bit system server could exist that spawns 64-bit
// processes, in which case the new process won't get any tagging. This is fine as we
// haven't seen this configuration in practice, and we can reasonable assume that if
// tagging is desired, the system server will be 64-bit.
if (instructionSet == null || instructionSet.equals("arm64")) {
runtimeFlags |= decideTaggingLevel(app);
}
處理傳遞到zygote的一些配置
// the per-user SELinux context must be set
if (TextUtils.isEmpty(app.info.seInfoUser)) {
Slog.wtf(ActivityManagerService.TAG, "SELinux tag not defined",
new IllegalStateException("SELinux tag not defined for "
+ app.info.packageName + " (uid " + app.uid + ")"));
}
final String seInfo = app.info.seInfo
+ (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
final String entryPoint = "android.app.ActivityThread";
return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,
runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi,
instructionSet, invokeWith, startTime);
}
呼叫startProcessLocked 去處理.
startProcessLocked:1991, ProcessList
boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,
int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startTime) {
app.pendingStart = true;
app.killedByAm = false;
app.removed = false;
app.killed = false;
if (app.startSeq != 0) {
Slog.wtf(TAG, "startProcessLocked processName:" + app.processName
+ " with non-zero startSeq:" + app.startSeq);
}
if (app.pid != 0) {
Slog.wtf(TAG, "startProcessLocked processName:" + app.processName
+ " with non-zero pid:" + app.pid);
}
處理一些異常情況
app.mDisabledCompatChanges = null;
if (mPlatformCompat != null) {
app.mDisabledCompatChanges = mPlatformCompat.getDisabledChanges(app.info);
}
final long startSeq = app.startSeq = ++mProcStartSeqCounter;
app.setStartParams(uid, hostingRecord, seInfo, startTime);
app.setUsingWrapper(invokeWith != null
|| Zygote.getWrapProperty(app.processName) != null);
mPendingStarts.put(startSeq, app);
待啟動程式資訊,放到PendingStarts中
if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {
if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,
"Posting procStart msg for " + app.toShortString());
mService.mProcStartHandler.post(() -> handleProcessStart(
app, entryPoint, gids, runtimeFlags, zygotePolicyFlags, mountExternal,
requiredAbi, instructionSet, invokeWith, startSeq));
return true;
} else {
try {
final Process.ProcessStartResult startResult = startProcess(hostingRecord,
entryPoint, app,
uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo,
requiredAbi, instructionSet, invokeWith, startTime);
handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
startSeq, false);
} catch (RuntimeException e) {
Slog.e(ActivityManagerService.TAG, "Failure starting process "
+ app.processName, e);
app.pendingStart = false;
mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
false, false, true, false, false, app.userId, "start failure");
}
return app.pid > 0;
}
}
根據配置非同步或者同步啟動執行緒.
同步和非同步流程是差不多的,但是非同步複雜一點,我們直接看非同步流程.這裡通過mService.mProcStartHandler.post(() -> handleProcessStart( app, entryPoint, gids, runtimeFlags, zygotePolicyFlags, mountExternal, requiredAbi, instructionSet, invokeWith, startSeq));
直接post了一個runable到procStart的執行緒.
handleProcessStart:2055, ProcessList
private void handleProcessStart(final ProcessRecord app, final String entryPoint,
final int[] gids, final int runtimeFlags, int zygotePolicyFlags,
final int mountExternal, final String requiredAbi, final String instructionSet,
final String invokeWith, final long startSeq) {
// If there is a precede instance of the process, wait for its death with a timeout.
// Use local reference since we are not using locks here
final ProcessRecord precedence = app.mPrecedence;
if (precedence != null) {
final int pid = precedence.pid;
long now = System.currentTimeMillis();
final long end = now + PROC_KILL_TIMEOUT;
try {
Process.waitForProcessDeath(pid, PROC_KILL_TIMEOUT);
// It's killed successfully, but we'd make sure the cleanup work is done.
synchronized (precedence) {
if (app.mPrecedence != null) {
now = System.currentTimeMillis();
if (now < end) {
try {
precedence.wait(end - now);
} catch (InterruptedException e) {
}
}
}
if (app.mPrecedence != null) {
// The cleanup work hasn't be done yet, let's log it and continue.
Slog.w(TAG, precedence + " has died, but its cleanup isn't done");
}
}
} catch (Exception e) {
// It's still alive...
Slog.wtf(TAG, precedence.toString() + " refused to die, but we need to launch "
+ app);
}
}
如果ProcessRecord對應有個先啟動過的程式,這裡先kill掉
todo:整個流程kill了幾次,為什麼呢?什麼情況會出現到這裡還存在上一次啟動的程式沒有殺死的情況?同步為什麼不需要這樣判斷呢?
try {
final Process.ProcessStartResult startResult = startProcess(app.hostingRecord,
entryPoint, app, app.startUid, gids, runtimeFlags, zygotePolicyFlags,
mountExternal, app.seInfo, requiredAbi, instructionSet, invokeWith,
app.startTime);
synchronized (mService) {
handleProcessStartedLocked(app, startResult, startSeq);
}
}
呼叫startProcess去實際啟動程式,handleProcessStartedLocked處理程式啟動後的資訊.
startProcess:2296, ProcessList
private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags,
int mountExternal, String seInfo, String requiredAbi, String instructionSet,
String invokeWith, long startTime) {
try {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkSlow(startTime, "startProcess: asking zygote to start proc");
final boolean isTopApp = hostingRecord.isTopApp();
if (isTopApp) {
// Use has-foreground-activities as a temporary hint so the current scheduling
// group won't be lost when the process is attaching. The actual state will be
// refreshed when computing oom-adj.
app.setHasForegroundActivities(true);
}
如果是位於最上面的APP,那麼先設定為has-foreground-activities,防止oom 殺死它?
Map<String, Pair<String, Long>> pkgDataInfoMap;
Map<String, Pair<String, Long>> whitelistedAppDataInfoMap;
boolean bindMountAppStorageDirs = false;
boolean bindMountAppsData = mAppDataIsolationEnabled
&& (UserHandle.isApp(app.uid) || UserHandle.isIsolated(app.uid))
&& mPlatformCompat.isChangeEnabled(APP_DATA_DIRECTORY_ISOLATION, app.info);
// Get all packages belongs to the same shared uid. sharedPackages is empty array
// if it doesn't have shared uid.
final PackageManagerInternal pmInt = mService.getPackageManagerInternalLocked();
final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
app.info.packageName, app.userId);
final String[] targetPackagesList = sharedPackages.length == 0
? new String[]{app.info.packageName} : sharedPackages;
pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, targetPackagesList, uid);
if (pkgDataInfoMap == null) {
// TODO(b/152760674): Handle inode == 0 case properly, now we just give it a
// tmp free pass.
bindMountAppsData = false;
}
// Remove all packages in pkgDataInfoMap from mAppDataIsolationWhitelistedApps, so
// it won't be mounted twice.
final Set<String> whitelistedApps = new ArraySet<>(mAppDataIsolationWhitelistedApps);
for (String pkg : targetPackagesList) {
whitelistedApps.remove(pkg);
}
whitelistedAppDataInfoMap = getPackageAppDataInfoMap(pmInt,
whitelistedApps.toArray(new String[0]), uid);
if (whitelistedAppDataInfoMap == null) {
// TODO(b/152760674): Handle inode == 0 case properly, now we just give it a
// tmp free pass.
bindMountAppsData = false;
}
int userId = UserHandle.getUserId(uid);
StorageManagerInternal storageManagerInternal = LocalServices.getService(
StorageManagerInternal.class);
if (needsStorageDataIsolation(storageManagerInternal, app)) {
bindMountAppStorageDirs = true;
if (pkgDataInfoMap == null ||
!storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(),
app.processName)) {
// Cannot prepare Android/app and Android/obb directory or inode == 0,
// so we won't mount it in zygote, but resume the mount after unlocking device.
app.bindMountPending = true;
bindMountAppStorageDirs = false;
}
}
// If it's an isolated process, it should not even mount its own app data directories,
// since it has no access to them anyway.
if (app.isolated) {
pkgDataInfoMap = null;
whitelistedAppDataInfoMap = null;
}
計算需要繫結的目錄資訊等.
final Process.ProcessStartResult startResult;
if (hostingRecord.usesWebviewZygote()) {
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName, app.mDisabledCompatChanges,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
} else if (hostingRecord.usesAppZygote()) {
final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
// We can't isolate app data and storage data as parent zygote already did that.
startResult = appZygote.getProcess().start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
/*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap,
false, false,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap,
whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
}
checkSlow(startTime, "startProcess: returned from zygote!");
return startResult;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
分為不同的情況啟動不同的zygote虛擬機器
todo:這幾種具體有什麼分別?
startProcess:2296, ProcessList
呼叫到ZygoteProcess的start
start:372, ZygoteProcess
呼叫 startViaZygote啟動程式.
todo:具體怎麼呼叫到虛擬機器,後續再開篇文章分析.
新程式呼叫attachApplication時,系統resume待啟動的Activity
堆疊資訊
obtain:94, ResumeActivityItem (android.app.servertransaction)
realStartActivityLocked:856, ActivityStackSupervisor (com.android.server.wm)
startActivityForAttachedApplicationIfNeeded:1965, RootWindowContainer (com.android.server.wm)
lambda$5fbF65VSmaJkPHxEhceOGTat7JE:-1, RootWindowContainer (com.android.server.wm)
apply:-1, -$$Lambda$RootWindowContainer$5fbF65VSmaJkPHxEhceOGTat7JE (com.android.server.wm)
doInvoke:315, PooledLambdaImpl (com.android.internal.util.function.pooled)
invoke:201, PooledLambdaImpl (com.android.internal.util.function.pooled)
apply:78, OmniFunction (com.android.internal.util.function.pooled)
forAllActivities:3620, ActivityRecord (com.android.server.wm)
forAllActivities:1331, WindowContainer (com.android.server.wm)
forAllActivities:1324, WindowContainer (com.android.server.wm)
attachApplication:1944, RootWindowContainer (com.android.server.wm)
attachApplication:6890, ActivityTaskManagerService$LocalService (com.android.server.wm)
attachApplicationLocked:5378, ActivityManagerService (com.android.server.am)
attachApplication:5458, ActivityManagerService (com.android.server.am)
上一步程式已經從zygote啟動,並且呼叫attchApplication,這個呼叫就會到AMS中
attachApplication:5458, ActivityManagerService
public final void attachApplication(IApplicationThread thread, long startSeq) {
if (thread == null) {
throw new SecurityException("Invalid application interface");
}
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}
簡單的獲取呼叫者的pid 和 uid ,然後就呼叫attachApplicationLocked(thread, callingPid, callingUid, startSeq);
attachApplicationLocked:5378, ActivityManagerService
這個函式是應用程式起來後,第一次呼叫到系統.系統需要做比較多的工作,我們這裡分段來檢視
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*/);
removePidLocked(app);
app = null;
}
} else {
app = null;
}
首先到系統的mPidsSelfLocked去查詢是否程式號是否已經對應了一個ProcessRecord .如果系統已經這個ProcessRecord,並且這個啟動序號seq,uid和當前程式不一致,說明該程式之前用於過其他的APP.那麼這個時候就呼叫cleanUpApplicationRecordLocked(app, false, false, -1, true /*replacingPid*/);
清理一下相關資訊.
繼續往下看
// 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;
}
}
上一個獲取的ProcessReord app變數兩種情況下可能為空 1. 該程式還沒有加到mPidsSelfLocked裡面.2 該程式號在mPidsSelfLocked可以找到,但是並不是當前程式. 這個時候就需要從 mProcessList.mPendingStarts中去獲取這個pending的ProcessRecord.
繼續往下看
if (app == null) {
Slog.w(TAG, "No pending application record for pid " + pid
+ " (IApplicationThread " + thread + "); dropping process");
EventLogTags.writeAmDropProcess(pid);
if (pid > 0 && pid != MY_PID) {
killProcessQuiet(pid);
//TODO: killProcessGroup(app.info.uid, pid);
mProcessList.noteAppKill(app, ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
ApplicationExitInfo.SUBREASON_UNKNOWN, "attach failed");
} else {
try {
thread.scheduleExit();
} catch (Exception e) {
// Ignore exceptions.
}
}
return false;
}
如果mPidsSelfLocked 中沒有, mProcessList.mPendingStarts也沒有,說明這個程式不是系統拉起來的.那麼就不該拉起它來. 如果這個程式不是系統程式,那麼直接殺死這個程式.如果是系統程式,就直接退出這個執行緒了.
// If this application record is still attached to a previous
// process, clean it up now.
if (app.thread != null) {
handleAppDiedLocked(app, true, true);
}
看註釋即可,按道理這裡應該不會這樣.不確定是否pending中獲取的是否也有這個情況.
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),
ZYGOTE_POLICY_FLAG_EMPTY);
return false;
}
註冊死亡回撥,這樣在由於oom,apk自己crash等異常死亡的時候,系統有機會來執行相關的清理工作.
app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
mOomAdjuster.setAttachingSchedGroupLocked(app);
app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, 0, false);
app.hasShownUi = false;
app.setDebugging(false);
app.setCached(false);
app.killedByAm = false;
app.killed = false;
一些變數的初始化工作
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,
ContentResolver.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS);
}
generateApplicationProvidersLocked
從PMS中獲取對應程式名的provider資訊.並把相關資訊儲存到mProviderMap,以及程式的pubProviders中.
final BackupRecord backupTarget = mBackupTargets.get(app.userId);
try {
int testMode = ApplicationThreadConstants.DEBUG_OFF;
if (mDebugApp != null && mDebugApp.equals(processName)) {
testMode = mWaitForDebugger
? ApplicationThreadConstants.DEBUG_WAIT
: ApplicationThreadConstants.DEBUG_ON;
app.setDebugging(true);
if (mDebugTransient) {
mDebugApp = mOrigDebugApp;
mWaitForDebugger = mOrigWaitForDebugger;
}
}
設定新啟動的ProcessRecord app的debug狀態
boolean enableTrackAllocation = false;
if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) {
enableTrackAllocation = true;
mTrackAllocationApp = null;
}
當前APP是否需要跟蹤記憶體分配情況
// If the app is being launched for restore or full backup, set it up specially
boolean isRestrictedBackupMode = false;
if (backupTarget != null && backupTarget.appInfo.packageName.equals(processName)) {
isRestrictedBackupMode = backupTarget.appInfo.uid >= FIRST_APPLICATION_UID
&& ((backupTarget.backupMode == BackupRecord.RESTORE)
|| (backupTarget.backupMode == BackupRecord.RESTORE_FULL)
|| (backupTarget.backupMode == BackupRecord.BACKUP_FULL));
}
當前程式是否拉起來只是用於備份操作.
final ActiveInstrumentation instr = app.getActiveInstrumentation();
if (instr != null) {
notifyPackageUse(instr.mClass.getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
+ processName + " with config "
+ app.getWindowProcessController().getConfiguration());
ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info;
app.compat = compatibilityInfoForPackage(appInfo);
todo : 沒看太懂
ProfilerInfo profilerInfo = null;
String preBindAgent = null;
if (mProfileData.getProfileApp() != null
&& mProfileData.getProfileApp().equals(processName)) {
mProfileData.setProfileProc(app);
if (mProfileData.getProfilerInfo() != null) {
// Send a profiler info object to the app if either a file is given, or
// an agent should be loaded at bind-time.
boolean needsInfo = mProfileData.getProfilerInfo().profileFile != null
|| mProfileData.getProfilerInfo().attachAgentDuringBind;
profilerInfo = needsInfo
? new ProfilerInfo(mProfileData.getProfilerInfo()) : null;
if (mProfileData.getProfilerInfo().agent != null) {
preBindAgent = mProfileData.getProfilerInfo().agent;
}
}
} else if (instr != null && instr.mProfileFile != null) {
profilerInfo = new ProfilerInfo(instr.mProfileFile, null, 0, false, false,
null, false);
}
if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) {
// We need to do a debuggable check here. See setAgentApp for why the check is
// postponed to here.
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
String agent = mAppAgentMap.get(processName);
// Do not overwrite already requested agent.
if (profilerInfo == null) {
profilerInfo = new ProfilerInfo(null, null, 0, false, false,
mAppAgentMap.get(processName), true);
} else if (profilerInfo.agent == null) {
profilerInfo = profilerInfo.setAgent(mAppAgentMap.get(processName), true);
}
}
}
if (profilerInfo != null && profilerInfo.profileFd != null) {
profilerInfo.profileFd = profilerInfo.profileFd.dup();
if (TextUtils.equals(mProfileData.getProfileApp(), processName)
&& mProfileData.getProfilerInfo() != null) {
clearProfilerLocked();
}
}
程式效能分析相關的東西配置
if (mActiveInstrumentation.size() > 0 && instr == null) {
for (int i = mActiveInstrumentation.size() - 1;
i >= 0 && app.getActiveInstrumentation() == null; i--) {
ActiveInstrumentation aInstr = mActiveInstrumentation.get(i);
if (!aInstr.mFinished && aInstr.mTargetInfo.uid == app.uid) {
if (aInstr.mTargetProcesses.length == 0) {
// This is the wildcard mode, where every process brought up for
// the target instrumentation should be included.
if (aInstr.mTargetInfo.packageName.equals(app.info.packageName)) {
app.setActiveInstrumentation(aInstr);
aInstr.mRunningProcesses.add(app);
}
} else {
for (String proc : aInstr.mTargetProcesses) {
if (proc.equals(app.processName)) {
app.setActiveInstrumentation(aInstr);
aInstr.mRunningProcesses.add(app);
break;
}
}
}
}
}
}
todo
// If we were asked to attach an agent on startup, do so now, before we're binding
// application code.
if (preBindAgent != null) {
thread.attachAgent(preBindAgent);
}
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
thread.attachStartupAgents(app.info.dataDir);
}
在系統呼叫APP的BindApplication之前,會呼叫attachAgent
和attachStartupAgents
.這裡是可以有一些工作在bindApplication之前做的.
// Figure out whether the app needs to run in autofill compat mode.
AutofillOptions autofillOptions = null;
if (UserHandle.getAppId(app.info.uid) >= Process.FIRST_APPLICATION_UID) {
final AutofillManagerInternal afm = LocalServices.getService(
AutofillManagerInternal.class);
if (afm != null) {
autofillOptions = afm.getAutofillOptions(
app.info.packageName, app.info.longVersionCode, app.userId);
}
}
APP 的自動填充用到的一些操作
ContentCaptureOptions contentCaptureOptions = null;
if (UserHandle.getAppId(app.info.uid) >= Process.FIRST_APPLICATION_UID) {
final ContentCaptureManagerInternal ccm =
LocalServices.getService(ContentCaptureManagerInternal.class);
if (ccm != null) {
contentCaptureOptions = ccm.getOptionsForPackage(app.userId,
app.info.packageName);
}
}
內容捕捉的一些東西.具體還不是很清楚
bindApplicationTimeMillis = SystemClock.elapsedRealtime();
mAtmInternal.preBindApplication(app.getWindowProcessController());
final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
if (mPlatformCompat != null) {
mPlatformCompat.resetReporting(app.info);
}
final ProviderInfoList providerList = ProviderInfoList.fromList(providers);
bindApplication之前ATMS要做些處理.
if (app.isolatedEntryPoint != null) {
// This is an isolated process which should just call an entry point instead of
// being bound to an application.
thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
} else if (instr2 != null) {
thread.bindApplication(processName, appInfo, providerList,
instr2.mClass,
profilerInfo, instr2.mArguments,
instr2.mWatcher,
instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.mDisabledCompatChanges);
} else {
thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.mDisabledCompatChanges);
}
if (profilerInfo != null) {
profilerInfo.closeFd();
profilerInfo = null;
}
// Make app active after binding application or client may be running requests (e.g
// starting activities) before it is ready.
app.makeActive(thread, mProcessStats);
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
mProcessList.updateLruProcessLocked(app, false, null);
checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
// We need kill the process group here. (b/148588589)
Slog.wtf(TAG, "Exception thrown during bind of " + app, e);
app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient();
app.kill("error during bind", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, true);
handleAppDiedLocked(app, false, true);
return false;
}
呼叫新程式的BindApplication,新程式在這個過程中做不少的事情.我們單獨開一篇文章將這個.
// Remove this record from the list of starting applications.
mPersistentStartingProcesses.remove(app);
if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
"Attach application locked removing on hold: " + app);
mProcessesOnHold.remove(app);
boolean badApp = false;
boolean didSomething = false;
從mPersistentStartingProcesses
,mProcessesOnHold
移除這個程式資訊,因為我們已經把它拉起來了.並且執行了BindApplication,此時APP已經可以開始工作了.
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
從堆疊可以看到resume Activity就是從這裡離進入的.
// Find any services that should be running in this process...
if (!badApp) {
try {
didSomething |= mServices.attachApplicationLocked(app, processName);
checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
badApp = true;
}
}
看看是否有服務需要從這個程式啟動.
// Check if a next-broadcast receiver is in this process...
if (!badApp && isPendingBroadcastProcessLocked(pid)) {
try {
didSomething |= sendPendingBroadcastsLocked(app);
checkTime(startTime, "attachApplicationLocked: after sendPendingBroadcastsLocked");
} catch (Exception e) {
// If the app died trying to launch the receiver we declare it 'bad'
Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
badApp = true;
}
}
是否有有序廣播需要傳送給它?
// Check whether the next backup agent is in this process...
if (!badApp && backupTarget != null && backupTarget.app == app) {
if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
"New app is backup target, launching agent for " + app);
notifyPackageUse(backupTarget.appInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_BACKUP);
try {
thread.scheduleCreateBackupAgent(backupTarget.appInfo,
compatibilityInfoForPackage(backupTarget.appInfo),
backupTarget.backupMode, backupTarget.userId);
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e);
badApp = true;
}
}
是否下一個備份的app是它?
if (badApp) {
app.kill("error during init", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, true);
handleAppDiedLocked(app, false, true);
return false;
}
如果前面出錯了就殺死這個程式.
if (!didSomething) {
updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked");
}
更新oom資訊
attachApplication:6890, ActivityTaskManagerService$LocalService
我們分析的是attach->resume的流程,所以還是回到主線,繼續往下看.
public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
synchronized (mGlobalLockWithoutBoost) {
try {
return mRootWindowContainer.attachApplication(wpc);
}
}
}
簡單的呼叫mRootWindowContainer
的attachApplication
attachApplication:1944, RootWindowContainer
boolean attachApplication(WindowProcessController app) throws RemoteException {
final String processName = app.mName;
boolean didSomething = false;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
final ActivityStack stack = display.getFocusedStack();
if (stack == null) {
continue;
}
mTmpRemoteException = null;
mTmpBoolean = false; // Set to true if an activity was started.
final PooledFunction c = PooledLambda.obtainFunction(
RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this,
PooledLambda.__(ActivityRecord.class), app, stack.topRunningActivity());
stack.forAllActivities(c);
c.recycle();
if (mTmpRemoteException != null) {
throw mTmpRemoteException;
}
didSomething |= mTmpBoolean;
}
if (!didSomething) {
ensureActivitiesVisible(null, 0, false /* preserve_windows */);
}
return didSomething;
}
對於每個顯示區域焦點堆疊中的所有Acitivity呼叫startActivityForAttachedApplicationIfNeeded.
當前的顯示區域的焦點堆疊就是待啟動的Activity所在的堆疊了
跳過一些lambda操作
startActivityForAttachedApplicationIfNeeded:1965, RootWindowContainer
private boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r,
WindowProcessController app, ActivityRecord top) {
try {
if (mStackSupervisor.realStartActivityLocked(r, app, top == r /*andResume*/,
true /*checkConfig*/)) {
mTmpBoolean = true;
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new application when starting activity "
+ top.intent.getComponent().flattenToShortString(), e);
mTmpRemoteException = e;
return true;
}
return false;
}
簡單的呼叫mStackSupervisor.realStartActivityLocked
,從名字可以看到這裡是真的要去拉起新的Activity了.
realStartActivityLocked:856, ActivityStackSupervisor
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {
if (!mRootWindowContainer.allPausedActivitiesComplete()) {
return false;
}
這裡會檢視是否所有的需要pause的Activity是否執行完成了,沒有的話還需要等待Activity的Pause.保證同時只有一個Activity處於Resumed狀態.
final Task task = r.getTask();
final ActivityStack stack = task.getStack();
// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
final DisplayContent dc = r.getDisplay().mDisplayContent;
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
r.assistToken, r.createFixedRotationAdjustmentsIfNeeded()));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
前面有部分程式碼沒看太懂,後面主要就是scheduleTransaction
把LaunchActivityItem
和ResumeActivityItem
傳遞到新啟動的程式去執行了.