ActivityManagerService 启动进程
简述
上一节我们介绍了Activity的启动流程,这一节会在上一节的基础上介绍当要启动的Activity所在的进程之前没有启动,这个情况下是怎么样启动一个新的进程,并且继续启动Activity。
我们知道Android是基于linux系统开发的,而linux系统启动一个应用进程都是通过原来的进程fork出来的,Android里面的app都是通过Zygote进程fork启动的。
fork后进程的uid,权限等会继承原来的进程,而app有几种不同的情况,system app,三方app等,所以fork出来的进程还会进行降权。
上一节Activity启动的流程中有两个入口会调用ActivityTaskManagerService.startProcessAsync来启动进程。一个是在resumeTopActivity时,如果发现有Activity需要先pause,再resume新的Activity时会调用,这样可以节约时间,pause的同时去启动新进程;第二个情况就是正常resume的流程中,startSpecificActivity时,发现目标Activity所在的进程还未启动,则会调用startProcessAsync来启动进程。我们就从startProcessAsync开始。
启动Activity 过程中启动app进程
1.1 ActivityManagerService.startProcessAsync
void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,
String hostingType) {
try {
// ...
// 发送一个startProcess消息,详见1.2
final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
isTop, hostingType, activity.intent.getComponent());
mH.sendMessage(m);
} finally {
// ...
}
}
1.2 ActivityManagerService.startProcess
加了AMS大锁,调用startProcessLocked
public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,
boolean isTop, String hostingType, ComponentName hostingName) {
try {
synchronized (ActivityManagerService.this) {
// 详见1.3
startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
new HostingRecord(hostingType, hostingName, isTop),
ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
false /* isolated */);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
1.3 ActivityManagerService.startProcessLocked
调用ProcessList.startProcessLocked
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
boolean isolated) {
// 详见1.4
return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
false /* isSdkSandbox */, 0 /* sdkSandboxClientAppUid */,
null /* sdkSandboxClientAppPackage */,
null /* ABI override */, null /* entryPoint */,
null /* entryPointArgs */, null /* crashHandler */);
}
1.4 ProcessList.startProcessLocked
首先会处理bad app相关的逻辑,一个app如果多次Crash则会标记未bad,我们常看到的xxx app 屡次崩溃的弹框就是bad app的逻辑。
然后会检查是否可以复用之前到进程,或者是否是已经在启动过程中了,如果是则什么都不做直接返回。
否则构建一个新的ProcessRecord,然后调用重载函数startProcessLocked进行进程启动。
ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,
boolean isSdkSandbox, int sdkSandboxUid, String sdkSandboxClientAppPackage,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
long startTime = SystemClock.uptimeMillis();
ProcessRecord app;
// 不是独立进程则可以考虑复用ProcessRecord
if (!isolated) {
app = getProcessRecordLocked(processName, info.uid);
checkSlow(startTime, "startProcess: after getProcessRecord");
if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
// 如果是后台启动,不能启动一个bad app。比如连续多次Crash就会被标记为bad app
if (mService.mAppErrors.isBadProcess(processName, info.uid)) {
return null;
}
} else {
// 如果是显示启动,清空bad app的计数。
mService.mAppErrors.resetProcessCrashTime(processName, info.uid);
if (mService.mAppErrors.isBadProcess(processName, info.uid)) {
EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
UserHandle.getUserId(info.uid), info.uid,
info.processName);
mService.mAppErrors.clearBadProcess(processName, info.uid);
if (app != null) {
app.mErrorState.setBad(false);
}
}
}
} else {
// 如果是独立进程,则不能复用ProcessRecord
app = null;
}
// 如果是已经有ProcessRecord,并且有关联pid,并且并没有记录它已经被kill或者死了或者没有关联线程,这种情况不需要做任何事。
// 这种情况要不就是已经有进程在运行,要不就是已经在启动进程了。
ProcessRecord predecessor = null;
if (app != null && app.getPid() > 0) {
if ((!knownToBeDead && !app.isKilled()) || app.getThread() == null) {
app.addPackage(info.packageName, info.longVersionCode, mService.mProcessStats);
checkSlow(startTime, "startProcess: done, added package to proc");
return app;
}
// 否则清理之前关联进程。
checkSlow(startTime, "startProcess: bad proc running, killing");
ProcessList.killProcessGroup(app.uid, app.getPid());
checkSlow(startTime, "startProcess: done killing old proc");
predecessor = app;
app = null;
} else if (!isolated) {
// 因为app 被kill的情况,检查是否在mDyingProcesses里
predecessor = mDyingProcesses.get(processName, info.uid);
if (predecessor != null) {
if (app != null && app != predecessor) {
app.mPredecessor = predecessor;
predecessor.mSuccessor = app;
} else {
app = null;
}
Slog.w(TAG_PROCESSES, predecessor.toString() + " is attached to a previous process "
+ predecessor.getDyingPid());
}
}
if (app == null) {
checkSlow(startTime, "startProcess: creating new process record");
// 构建新的ProcessRecord
app = newProcessRecordLocked(info, processName, isolated, isolatedUid, isSdkSandbox,
sdkSandboxUid, sdkSandboxClientAppPackage, hostingRecord);
if (app == null) {
return null;
}
app.mErrorState.setCrashHandler(crashHandler);
app.setIsolatedEntryPoint(entryPoint);
app.setIsolatedEntryPointArgs(entryPointArgs);
if (predecessor != null) {
app.mPredecessor = predecessor;
predecessor.mSuccessor = app;
}
checkSlow(startTime, "startProcess: done creating new process record");
} else {
app.addPackage(info.packageName, info.longVersionCode, mService.mProcessStats);
checkSlow(startTime, "startProcess: added package to existing proc");
}
// 如果系统服务还没有启动完成,添加到mProcessesOnHold队列中。
if (!mService.mProcessesReady
&& !mService.isAllowedWhileBooting(info)
&& !allowWhileBooting) {
if (!mService.mProcessesOnHold.contains(app)) {
mService.mProcessesOnHold.add(app);
}
return app;
}
checkSlow(startTime, "startProcess: stepping in to startProcess");
// 调用重载函数startProcessLocked,详见1.5
final boolean success =
startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride);
checkSlow(startTime, "startProcess: done starting proc!");
return success ? app : null;
}
1.5 ProcessList.startProcessLocked
首先清理了ProcessRecord内的变量,然后从PMS中获取进程相关的gids,用户组影响了进程的权限,app启动后需要配置好权限,所以在这里的需要获取gids,且被拒绝的权限需要移除对应的gids。
接下来就是计算RuntimeFlag,主要是一些和debug相关的启动flag。
最终会调用startProcessLocked重载方法,entryPoint作为参数传入,entryPoint被设置为android.app.ActivityThread,新启动的进程java虚拟机会以android.app.ActivityThread的main方法作为入口。
boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,
String abiOverride) {
// 防止重入
if (app.isPendingStart()) {
return true;
}
final long startUptime = SystemClock.uptimeMillis();
final long startElapsedTime = SystemClock.elapsedRealtime();
// 清理之前Pid相关记录,以及启动超时的定时器
if (app.getPid() > 0 && app.getPid() != ActivityManagerService.MY_PID) {
checkSlow(startUptime, "startProcess: removing from pids map");
mService.removePidLocked(app.getPid(), app);
app.setBindMountPending(false);
mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
checkSlow(startUptime, "startProcess: done removing from pids map");
app.setPid(0);
app.setStartSeq(0);
}
// 清理死亡回调监听器
app.unlinkDeathRecipient();
app.setDyingPid(0);
// 从mProcessesOnHold移除,mProcessesOnHold记录的是service没就绪导致需要延迟启动的app
mService.mProcessesOnHold.remove(app);
checkSlow(startUptime, "startProcess: starting to update cpu stats");
// 触发cpu使用记录,anr时候会打印相关信息以便于排查anr
mService.updateCpuStats();
checkSlow(startUptime, "startProcess: done updating cpu stats");
try {
final int userId = UserHandle.getUserId(app.uid);
try {
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;
boolean externalStorageAccess = false;
if (!app.isolated) {
int[] permGids = null;
try {
checkSlow(startUptime, "startProcess: getting gids from package manager");
final IPackageManager pm = AppGlobals.getPackageManager();
// 从PMS中获取app相关的gids
// 后续启动app之后需要配置相关gid以保证权限正常。
permGids = pm.getPackageGids(app.info.packageName,
MATCH_DIRECT_BOOT_AUTO, app.userId);
StorageManagerInternal storageManagerInternal = LocalServices.getService(
StorageManagerInternal.class);
mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
app.info.packageName);
// sdcard读写权限
externalStorageAccess = storageManagerInternal.hasExternalStorageAccess(uid,
app.info.packageName);
if (mService.isAppFreezerExemptInstPkg()
&& pm.checkPermission(Manifest.permission.INSTALL_PACKAGES,
app.info.packageName, userId)
== PackageManager.PERMISSION_GRANTED) {
Slog.i(TAG, app.info.packageName + " is exempt from freezer");
app.mOptRecord.setFreezeExempt(true);
}
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
// 如果该进程特定权限被拒绝,需要去掉相关的gids
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, externalStorageAccess);
}
app.setMountMode(mountExternal);
checkSlow(startUptime, "startProcess: building args");
if (app.getWindowProcessController().isFactoryTestProcess()) {
uid = 0;
}
int runtimeFlags = 0;
boolean debuggableFlag = (app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
boolean isProfileableByShell = app.info.isProfileableByShell();
boolean isProfileable = app.info.isProfileable();
if (app.isSdkSandbox) {
ApplicationInfo clientInfo = app.getClientInfoForSdkSandbox();
if (clientInfo != null) {
debuggableFlag |= (clientInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
isProfileableByShell |= clientInfo.isProfileableByShell();
isProfileable |= clientInfo.isProfileable();
}
}
// ... 配置runtimeFlags,一些和debug相关的启动flag
// dex2oat flag
if (app.info.isEmbeddedDexUsed()) {
runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
}
// hide api检查相关的flag
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;
}
// ...
// ... abi相关配置
app.setGids(gids);
app.setRequiredAbi(requiredAbi);
app.setInstructionSet(instructionSet);
ApplicationInfo definingAppInfo;
if (hostingRecord.getDefiningPackageName() != null) {
definingAppInfo = new ApplicationInfo(app.info);
definingAppInfo.packageName = hostingRecord.getDefiningPackageName();
definingAppInfo.uid = uid;
} else {
definingAppInfo = app.info;
}
runtimeFlags |= Zygote.getMemorySafetyRuntimeFlags(
definingAppInfo, app.processInfo, instructionSet, mPlatformCompat);
// 检查sepolicy 上下文。每个app必须有sepolicy上下文。(sepolicy也是linux的权限检查机制,比用户组权限更加精细)
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 + ")"));
}
String seInfo = updateSeInfo(app);
// 启动入口类
final String entryPoint = "android.app.ActivityThread";
// 调用重载,详见1.6
return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,
runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi,
instructionSet, invokeWith, startUptime, startElapsedTime);
} catch (RuntimeException e) {
mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
false, false, true, false, false, app.userId, "start failure");
return false;
}
}
1.6 ProcessList.startProcessLocked
这个方法设置了以些ProcessRecord里面的变量标记,然后根据mService.mConstants.FLAG_PROCESS_START_ASYNC判断是否需要异步调用启动线程,无论是否异步都是通过调用startProcess和handleProcessStartedLocked来启动线程的,所以我们直接来看startProcess
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 startUptime, long startElapsedTime) {
// ...配置一些ProcessRecord里的标记
// 默认这个FLAG_PROCESS_START_ASYNC为ture,其实handleProcessStart和下面的逻辑一样会调用startProcess和handleProcessStartedLocked,只是post了一下
if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {
// 由于最终还是调用了startProcess和handleProcessStartedLocked,我们直接来看startProcess,详见1.7
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, startUptime);
handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
startSeq, false);
} catch (RuntimeException e) {
app.setPendingStart(false);
mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
false, false, true, false, false, app.userId, "start failure");
}
return app.getPid() > 0;
}
}
1.7 ProcessList.startProcess
更新前后台状态,用于后续odj值更新。
判断app进程启动后是否需要执行prepareStorageDirs,来创建app私有目录。
调用appZygote.getProcess().start来启动进程。
根据前面的判断,如果需要则调用prepareStorageDirs。
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) {
// 更新前后台状态,后续用于更新odj值更新
app.mState.setHasForegroundActivities(true);
}
Map<String, Pair<String, Long>> pkgDataInfoMap;
Map<String, Pair<String, Long>> allowlistedAppDataInfoMap;
boolean bindMountAppStorageDirs = false;
boolean bindMountAppsData = mAppDataIsolationEnabled
&& (UserHandle.isApp(app.uid) || UserHandle.isIsolated(app.uid)
|| app.isSdkSandbox)
&& mPlatformCompat.isChangeEnabled(APP_DATA_DIRECTORY_ISOLATION, app.info);
final PackageManagerInternal pmInt = mService.getPackageManagerInternal();
final String[] targetPackagesList;
if (app.isSdkSandbox) {
targetPackagesList = new String[]{app.sdkSandboxClientAppPackage};
} else {
// 获取所有和该进程共享uid的包名
final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
app.info.packageName, app.userId);
targetPackagesList = sharedPackages.length == 0
? new String[]{app.info.packageName} : sharedPackages;
}
// ...
int userId = UserHandle.getUserId(uid);
StorageManagerInternal storageManagerInternal = LocalServices.getService(
StorageManagerInternal.class);
if (needsStorageDataIsolation(storageManagerInternal, app)) {
// 将会在Zygote fork app之后调用prepareStorageDirs
// prepareStorageDirs如果app目录还没有创建,就会创建目录
if (pkgDataInfoMap != null && storageManagerInternal.isFuseMounted(userId)) {
bindMountAppStorageDirs = true;
} else {
app.setBindMountPending(true);
bindMountAppStorageDirs = false;
}
}
// ...判断app是否处在后台,设置标识位,将会约束部分能力
final Process.ProcessStartResult startResult;
boolean regularZygote = false;
app.mProcessGroupCreated = false;
app.mSkipProcessGroupCreation = false;
// 应用分几种类型,分为通过WebviewZygote来fork,通过Zygote来fork,通过system_server来fork。
// 一般的app都是通过Zygote来fork,我们来看这个路径。
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.getDisabledCompatChanges(),
new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
} else if (hostingRecord.usesAppZygote()) {
final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
// 详见1.8
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.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap,
false, false,
new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
} else {
regularZygote = true;
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.getDisabledCompatChanges(), pkgDataInfoMap,
allowlistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
app.mProcessGroupCreated = true;
}
// ...
// 根据前面判断的逻辑决定是否需要调用prepareStorageDirs来创建app的私有目录
if (bindMountAppStorageDirs) {
storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(),
app.processName);
}
checkSlow(startTime, "startProcess: returned from zygote!");
return startResult;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
1.8 ZygoteProcess.start
调用startViaZygote
public final Process.ProcessStartResult start(@NonNull final String processClass,
final String niceName,
int uid, int gid, @Nullable int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
@Nullable String seInfo,
@NonNull String abi,
@Nullable String instructionSet,
@Nullable String appDataDir,
@Nullable String invokeWith,
@Nullable String packageName,
int zygotePolicyFlags,
boolean isTopApp,
@Nullable long[] disabledCompatChanges,
@Nullable Map<String, Pair<String, Long>>
pkgDataInfoMap,
@Nullable Map<String, Pair<String, Long>>
allowlistedDataInfoList,
boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] zygoteArgs) {
//...
try {
// 详见1.9
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData,
bindMountAppStorageDirs, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
1.9 startViaZygote
收集参数,加入到argsForZygote列表里,包含了所有关键信息,uid,gid,应用包名,sepolicy info等。然后调用zygoteSendArgsAndGetResult
private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
@Nullable final String niceName,
final int uid, final int gid,
@Nullable final int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
@Nullable String seInfo,
@NonNull String abi,
@Nullable String instructionSet,
@Nullable String appDataDir,
@Nullable String invokeWith,
boolean startChildZygote,
@Nullable String packageName,
int zygotePolicyFlags,
boolean isTopApp,
@Nullable long[] disabledCompatChanges,
@Nullable Map<String, Pair<String, Long>>
pkgDataInfoMap,
@Nullable Map<String, Pair<String, Long>>
allowlistedDataInfoList,
boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<>();
// 添加参数列表,包含了uid,gid等等。
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
argsForZygote.add("--runtime-flags=" + runtimeFlags);
if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
argsForZygote.add("--mount-external-default");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
argsForZygote.add("--mount-external-installer");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_PASS_THROUGH) {
argsForZygote.add("--mount-external-pass-through");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) {
argsForZygote.add("--mount-external-android-writable");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
final StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
final int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
if (instructionSet != null) {
argsForZygote.add("--instruction-set=" + instructionSet);
}
if (appDataDir != null) {
argsForZygote.add("--app-data-dir=" + appDataDir);
}
if (invokeWith != null) {
argsForZygote.add("--invoke-with");
argsForZygote.add(invokeWith);
}
if (startChildZygote) {
argsForZygote.add("--start-child-zygote");
}
if (packageName != null) {
argsForZygote.add("--package-name=" + packageName);
}
if (isTopApp) {
argsForZygote.add(Zygote.START_AS_TOP_APP_ARG);
}
if (pkgDataInfoMap != null && pkgDataInfoMap.size() > 0) {
StringBuilder sb = new StringBuilder();
sb.append(Zygote.PKG_DATA_INFO_MAP);
sb.append("=");
boolean started = false;
for (Map.Entry<String, Pair<String, Long>> entry : pkgDataInfoMap.entrySet()) {
if (started) {
sb.append(',');
}
started = true;
sb.append(entry.getKey());
sb.append(',');
sb.append(entry.getValue().first);
sb.append(',');
sb.append(entry.getValue().second);
}
argsForZygote.add(sb.toString());
}
if (allowlistedDataInfoList != null && allowlistedDataInfoList.size() > 0) {
StringBuilder sb = new StringBuilder();
sb.append(Zygote.ALLOWLISTED_DATA_INFO_MAP);
sb.append("=");
boolean started = false;
for (Map.Entry<String, Pair<String, Long>> entry : allowlistedDataInfoList.entrySet()) {
if (started) {
sb.append(',');
}
started = true;
sb.append(entry.getKey());
sb.append(',');
sb.append(entry.getValue().first);
sb.append(',');
sb.append(entry.getValue().second);
}
argsForZygote.add(sb.toString());
}
if (bindMountAppStorageDirs) {
argsForZygote.add(Zygote.BIND_MOUNT_APP_STORAGE_DIRS);
}
if (bindMountAppsData) {
argsForZygote.add(Zygote.BIND_MOUNT_APP_DATA_DIRS);
}
if (disabledCompatChanges != null && disabledCompatChanges.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--disabled-compat-changes=");
int sz = disabledCompatChanges.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(disabledCompatChanges[i]);
}
argsForZygote.add(sb.toString());
}
argsForZygote.add(processClass);
if (extraArgs != null) {
Collections.addAll(argsForZygote, extraArgs);
}
synchronized(mLock) {
// 调用zygoteSendArgsAndGetResult,详见1.9
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
zygotePolicyFlags,
argsForZygote);
}
}
1.9 zygoteSendArgsAndGetResult
参数检查,然后拼接成一个String,后续调用attemptUsapSendArgsAndGetResult
private Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args)
throws ZygoteStartFailedEx {
// 参数检查,不能有换行符或者\r
for (String arg : args) {
if (arg.indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx("Embedded newlines not allowed");
} else if (arg.indexOf('\r') >= 0) {
throw new ZygoteStartFailedEx("Embedded carriage returns not allowed");
}
}
// 参数拼接成一个String
String msgStr = args.size() + "\n" + String.join("\n", args) + "\n";
if (shouldAttemptUsapLaunch(zygotePolicyFlags, args)) {
try {
// 调用attemptUsapSendArgsAndGetResult,详见1.10
return attemptUsapSendArgsAndGetResult(zygoteState, msgStr);
} catch (IOException ex) {
Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - "
+ ex.getMessage());
}
}
return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);
}
1.10 attemptUsapSendArgsAndGetResult
syste_server和Zygote进程是通过LocalSocket进行通信的,这里就是通过LocalSocket将参数指令发送给Zygote。
private Process.ProcessStartResult attemptUsapSendArgsAndGetResult(
ZygoteState zygoteState, String msgStr)
throws ZygoteStartFailedEx, IOException {
try (LocalSocket usapSessionSocket = zygoteState.getUsapSessionSocket()) {
final BufferedWriter usapWriter =
new BufferedWriter(
new OutputStreamWriter(usapSessionSocket.getOutputStream()),
Zygote.SOCKET_BUFFER_SIZE);
final DataInputStream usapReader =
new DataInputStream(usapSessionSocket.getInputStream());
// 通过LocalSocket发送启动指令
usapWriter.write(msgStr);
usapWriter.flush();
Process.ProcessStartResult result = new Process.ProcessStartResult();
result.pid = usapReader.readInt();
result.usingWrapper = false;
if (result.pid >= 0) {
return result;
} else {
throw new ZygoteStartFailedEx("USAP specialization failed");
}
}
}
Zygote启动进程
Zygote和app启动都是启动的进程app_process,但是里面走的逻辑不同。
2.1 app_process.main
这里启动java虚拟机,如果是zygote,入口类是ZygoteInit,否则是RuntimeInit,我们先来看Zygote。
int main(int argc, char* const argv[])
{
// ...
if (zygote) {
// 如果是Zygote,java虚拟机入口是ZygoteInit类,详见2.2
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (!className.isEmpty()) {
// 否者入口是RuntimeInit
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
}
2.2 ZygoteInit.main
fork出来的子进程会和主进程逻辑一样,从fork的地方继续走代码逻辑,这里runSelectLoop会监听socket命令,Zygote自身会一直在runSelectLoop里面的循环,而fork出来的子进程则会跳出循环,走到caller.run
public static void main(String[] argv) {
ZygoteServer zygoteServer = null;
ZygoteHooks.startZygoteNoThreadCreation();
// zygote需要root权限
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
Runnable caller;
try {
// ...省略不关心的逻辑
// 这里会注册LocalSocket
zygoteServer = new ZygoteServer(isPrimaryZygote);
// ...如果是SystemServer就启动SystemServer然后直接return
// runSelectLoop进入循环,监听命令,详见2.3
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with fatal exception", ex);
throw ex;
} finally {
if (zygoteServer != null) {
// 关闭和SystemServer的socket
zygoteServer.closeServerSocket();
}
}
// fork出来的子进程会走这里。
if (caller != null) {
caller.run();
}
}
2.3 ZygoteServer.runSelectLoop
通过poll来监听socket的fd
如果fd有事件,通过processCommand来fork子进程
之后Zygote继续循环监听消息,而fork出来的子进程则跳出循环返回。
由2.2可知fork出来的子进程跳出runSelectLoop会执行caller.run(),caller是这里processCommand返回的。
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
ArrayList<ZygoteConnection> peers = new ArrayList<>();
// 这里的Socket是在之前ZygoteServer构造函数里创建的。
socketFDs.add(mZygoteSocket.getFileDescriptor());
peers.add(null);
mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
while (true) {
// ...省略细节逻辑
int pollReturnValue;
try {
// 调用poll在fd上等待,也就是会在socket上等待消息。
pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
if (pollReturnValue == 0) {
mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;
} else {
boolean usapPoolFDRead = false;
while (--pollIndex >= 0) {
// 遍历fd,确认是哪个fd的事件
if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
continue;
}
if (pollIndex == 0) {
// Zygote server socket
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
} else if (pollIndex < usapPoolEventFDIndex) {
// Session socket accepted from the Zygote server socket
try {
ZygoteConnection connection = peers.get(pollIndex);
boolean multipleForksOK = !isUsapPoolEnabled()
&& ZygoteHooks.isIndefiniteThreadSuspensionSafe();
// 调用processCommand做实际的fork操作,详见2.4
final Runnable command =
connection.processCommand(this, multipleForksOK);
// 前面在processCommand已经fork出来子进程了,如果是子进程则直接return command跳出循环
// 如果是Zygote进程,做一些后续处理之后,进入下一次循环继续监听消息。
if (mIsForkChild) {
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
} else {
if (command != null) {
throw new IllegalStateException("command != null");
}
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(pollIndex);
socketFDs.remove(pollIndex);
}
}
} catch (Exception e) {
// ...
} finally {
mIsForkChild = false;
}
} else {
// ...
}
}
// ...
}
// ...
}
}
2.4 ZygoteConnection.processCommand
调用Zygote.forkAndSpecialize来fork子进程,该方法会通过jni调用到native层,后续最终通过fork来fork出子进程,fork子进程之后还会调用一些linux的接口让子进程进行一些配置,如配置uid,gid,capability,进程名等等。这里我们就不跟了,感兴趣可以自己去看一下源码。主要逻辑在com_android_internal_os_Zygote_nativeForkAndSpecialize里。
这里顺带提一下capability,了解linux的同学应该知道linux里面有一个root用户,可以拥有非常高的权限。例如可以访问几乎所有文件(不考虑sepolicy的情况下),但是实际上linux并不是因为他的uid为0就可以访问所有用户组的文件,而是因为它的capability对应的位为1,capability是一个掩码,每一个位都代表一个特权,也就是说root用户之所以有那个多权限并不是因为它多uid为0,而是因为它的capability。
fork子进程后,如果返回值是0,则代表当前是子进程,否则就是原来的Zygote进程。Zygote进程后续就会进入下一次循环,我们主要来看子进程。
handleChildProc返回的Runnable后续会执行,实际上这里的Runable就相当于是子进程的入口了,这里的入口是由参数决定的,也就是1.5提到的ActivityThread。
Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
ZygoteArguments parsedArgs;
try (ZygoteCommandBuffer argBuffer = new ZygoteCommandBuffer(mSocket)) {
while (true) {
try {
// 解析参数
parsedArgs = ZygoteArguments.getInstance(argBuffer);
} catch (IOException ex) {
throw new IllegalStateException("IOException on command socket", ex);
}
if (parsedArgs == null) {
isEof = true;
return null;
}
// ... 一些参数的处理
if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote
|| !multipleOK || peer.getUid() != Process.SYSTEM_UID) {
// 这里会通过jni调用到native层,后续最终通过fork来fork出子进程
// fork子进程之后还会调用一些linux的接口让子进程进行一些配置,如配置uid,gid,capability,进程名等等,我们就不跟了。
pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits,
parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName,
fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,
parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,
parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
parsedArgs.mBindMountAppStorageDirs);
try {
// 如果forkAndSpecialize返回值是0,则是子进程
if (pid == 0) {
// in child
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
// 子进程则需要调用handleChildProc获取返回值,这个返回值是一个Runnable,子进程后续会执行。
// 这里的返回值入口是由参数决定的,也就是我们1.5提到的ActivityThread。详见2.5
return handleChildProc(parsedArgs, childPipeFd,
parsedArgs.mStartChildZygote);
} else {
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
// 做一些参数清理的操作
handleParentProc(pid, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
} else {
// ...
}
}
}
// ...
}
子进程启动
这里我们来到子进程启动。
3.1 ActivityThread.main
做一些初始化后调用了thread.attach,然后就进入了Looper的消息循环,我们知道app主线程是一直在Looper的消息循环里等待消息,就是这里进去的。
关于Looper的消息队列机制我们这里就不讲了,后面也许会单独写一章,逻辑比较多,但是底层逻辑是比较简单的,通过linux epoll来等待消息通知,消息会通过一个pipe的fd来唤醒线程。
public static void main(String[] args) {
// 初始化参数,环境的处理
ActivityThread thread = new ActivityThread();
// 详见3.2
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 进入loop循环
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
3.2 ActivityThread.attach
主要调用了AMS的attachApplication
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mConfigurationController = new ConfigurationController(this);
mSystemThread = system;
mStartSeq = startSeq;
if (!system) {
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManager.getService();
try {
// 这里会调用到SystemServer侧 AMS attachApplication
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
// ...
} else {
// ...
}
// ...
}
3.3 ActivityManagerService.attachApplication
调用attachApplicationLocked
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);
}
}
3.4 ActivityManagerService.attachApplicationLocked
更新了一些app状态标志,注册binder死亡回调,然后binder调用回app侧。
private void attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
// ...
// ... 一些进程状态更新,注册binder死亡回调等。
// ... 调用回app ActivityThread.bindApplication
if (app.getIsolatedEntryPoint() != null) {
// This is an isolated process which should just call an entry point instead of
// being bound to an application.
thread.runIsolatedEntryPoint(
app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
} else if (instr2 != null) {
// 详见3.5
thread.bindApplication(processName, appInfo,
app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
providerList,
instr2.mClass,
profilerInfo, instr2.mArguments,
instr2.mWatcher,
instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.getCompat(), getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.getDisabledCompatChanges(), serializedSystemFontMap,
app.getStartElapsedTime(), app.getStartUptime());
} else {
thread.bindApplication(processName, appInfo,
app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
providerList, null, profilerInfo, null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.getCompat(), getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.getDisabledCompatChanges(), serializedSystemFontMap,
app.getStartElapsedTime(), app.getStartUptime());
}
// ...
}
3.5 Activity.handleBindApplication
中间省略了一个消息post的流程,直接到handleBindApplication
初始化VMRuntime一些参数,以及Applcation到Configuration,包括Local、事件12/24小时制等,创建Context,配置网络代理。
调用Applcation onCreate
回调AMS finishAttachApplication
private void handleBindApplication(AppBindData data) {
// ... 初始化VMRuntime一些参数,以及Applcation到Configuration,包括Local、事件12/24小时制等。
// ... 配置是否严格模式
final InstrumentationInfo ii;
if (data.instrumentationName != null) {
ii = prepareInstrumentation(data);
} else {
ii = null;
}
final IActivityManager mgr = ActivityManager.getService();
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
mConfigurationController.updateLocaleListFromAppContext(appContext);
// ... 配置网络代理
try {
try {
mInstrumentation.onCreate(data.instrumentationArgs);
}
catch (Exception e) {
throw new RuntimeException(
"Exception thrown in onCreate() of "
+ data.instrumentationName + ": " + e.toString(), e);
}
try {
// ...调用Application OnCreate
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
// ...
}
} finally {
// ...
}
// ... 获取字体
try {
// 回调AMS finishAttachApplication,详见3.6
mgr.finishAttachApplication(mStartSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
3.6 ActivityManagerService.finishAttachApplication
public final void finishAttachApplication(long startSeq) {
// ...
final long origId = Binder.clearCallingIdentity();
try {
// 详见3.7
finishAttachApplicationInner(startSeq, uid, pid);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
3.7 ActivityManagerService.finishAttachApplicationInner
调用ActivityTaskManagerService.attachApplication
private void finishAttachApplicationInner(long startSeq, int uid, int pid) {
// ...
synchronized (this) {
// ...
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
// 详见3.8
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
// ...
}
3.8 ActivityTaskManagerService.attachApplication
调用RootWindowContainer.attachApplication
public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
synchronized (mGlobalLockWithoutBoost) {
try {
return mRootWindowContainer.attachApplication(wpc);
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
}
3.9 RootWindowContainer.attachApplication
调用AttachApplicationHelper.process
boolean attachApplication(WindowProcessController app) throws RemoteException {
try {
// 详见3.10
return mAttachApplicationHelper.process(app);
} finally {
mAttachApplicationHelper.reset();
}
}
3.10 AttachApplicationHelper.process
用RootWindowContainer.ensureActivitiesVisible,里面会调用每个节点的ensureActivitiesVisible
Task.ensureActivitiesVisible 我们在Activity启动流程1.19中介绍过了,会找到对应ActivityRecord,更新状态和可见性,并且通知app侧。
boolean process(WindowProcessController app) throws RemoteException {
mApp = app;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
getChildAt(displayNdx).forAllRootTasks(this);
if (mRemoteException != null) {
throw mRemoteException;
}
}
if (!mHasActivityStarted) {
// 调用RootWindowContainer.ensureActivitiesVisible,里面会调用每个节点的ensureActivitiesVisible
// Task.ensureActivitiesVisible 我们在Activity启动流程1.19中介绍过了。
ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
false /* preserveWindows */);
}
return mHasActivityStarted;
}
小结
本节我们介绍了Activity启动时,当目标进程原本没有启动的情况的流程。
SystemServer会通过Socket来通知Zygote需要启动一个进程。
而Zygote会fork出子进程,以ActivityThread为子进程的入口点。
子进程会调用attach,然后通知AMS bindApplication,AMS再回调回app,App完成Application onCreate后在回调AMS finishAttachApplication。
SystemServer会通过ensureActivitiesVisible来寻找需要resume的Activity,后续的流程和上一节启动的1.19开始的流程就一样了。
AMS的这些流程都看起来很复杂,因为它的调用链很长,但是我们只要知道它核心逻辑是在做什么,还是比较好理解的。需要多看几遍。
下一节会介绍app侧的状态流转。