到这篇文章为止,我们已经简要地了解过了Android系统的启动流程了,其中比较重要的内容有Zygote进程的启动和SystemService以及Launcher的启动,接下来我们将要学习的是Android应用程序的启动过程,这篇文章将会比较简单地介绍这个过程,下面是一张个人总结出来的流程图:
其实在之前Zygote服务启动的过程中,我们已经提到了这个Zygote服务将会创建出一个Socket来用于给ActivityManagerService使用,应用程序进程的启动就需要ActivityManagerService来给Zygote的服务端发送请求。
首先我们介绍ProcessRecord类,这个类是Android系统中用于表示应用程序进程的数据结构。每当应用程序启动时,系统都会为其创建一个ProcessRecord对象来跟踪该进程的状态和信息。
具体来说,在ActivityMangerService中也是通过这个类来启动进程的,来看看这个方法:
@GuardedBy("mService")
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();
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);
}
// Clear any residual death recipient link as the ProcessRecord could be reused.
app.unlinkDeathRecipient();
app.setDyingPid(0);
if (DEBUG_PROCESSES && mService.mProcessesOnHold.contains(app)) Slog.v(
TAG_PROCESSES,
"startProcessLocked removing on hold: " + app);
mService.mProcessesOnHold.remove(app);
checkSlow(startUptime, "startProcess: starting to update cpu stats");
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();
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);
externalStorageAccess = storageManagerInternal.hasExternalStorageAccess(uid,
app.info.packageName);
if (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();
}
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 (mService.mAtmInternal.isFactoryTestProcess(app.getWindowProcessController())) {
uid = 0;
}
int runtimeFlags = 0;
...........
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);
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);
final String entryPoint = "android.app.ActivityThread";
return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,
runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi,
instructionSet, invokeWith, startUptime, startElapsedTime);
} catch (RuntimeException e) {
Slog.e(ActivityManagerService.TAG, "Failure starting process " + app.processName, e);
mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
false, false, true, false, false, app.userId, "start failure");
return false;
}
}
这里截取了部分代码,其实这个方法里做的主要就是获取到了应用程序的一些信息,比如Gid,Uid等,然后把获取到的信息设置到要启动的App中:
app.setGids(gids);
app.setRequiredAbi(requiredAbi);
app.setInstructionSet(instructionSet);
然后最后还需要调用一层重载方法开始正式进行进程的启动:
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) {
............
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) {
Slog.e(ActivityManagerService.TAG, "Failure starting process "
+ app.processName, 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;
}
}
这里它又会调用到startProcess和handleProcessStartedLocked方法,startProcessLocked 方法用于启动新的进程,而 handleProcessStartedLocked 方法用于处理进程启动完成后的回调,更新进程状态并通知其他模块有关进程启动完成的事件。这两个方法共同协作以实现进程的启动和管理。
在这里我们主要还是看进程的启动,所以着重来看startProcess方法,这个方法又将调用到Process的start方法:
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()});
所以接下来看Process的start方法,这个方法又会调转到ZygoteProcess的start方法,并继续跳转到startViaZygote方法中,我们接下来看一看这个方法:
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<>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
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());
}
..........
synchronized(mLock) {
// The USAP pool can not be used if the application will not use the systems graphics
// driver. If that driver is requested use the Zygote application start path.
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
zygotePolicyFlags,
argsForZygote);
}
}
这个变量名argsForZygote的数组显然是用作传参用的,这个方法做的主要也就是创建一个字符串列表argsForZygote,并将应用程序的启动参数保存在这个列表中,最后调用zygoteSendArgsAndGetResult方法将其传给zygote执行,这实际上就是达到了AMS向zygote发送请求的目的:
private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
try {
final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
zygoteWriter.write(msgStr);
zygoteWriter.flush();
Process.ProcessStartResult result = new Process.ProcessStartResult();
result.pid = zygoteInputStream.readInt();
result.usingWrapper = zygoteInputStream.readBoolean();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
} catch (IOException ex) {
zygoteState.close();
Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
+ ex.toString());
throw new ZygoteStartFailedEx(ex);
}
}
在这个过程中会调用到上面这个方法,将应用参数的启动数据等写入zygote中,实际上就是向zygote发送了请求了。里面出现的ZygoteState类就是用于表示与Zygote的通信状况的。
再回到之前的
zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
zygotePolicyFlags,
argsForZygote);
这里的请求就是通过第一个参数(其实也是方法)的socket传达的,我们来看一看这个方法:
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
try {
attemptConnectionToPrimaryZygote();
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
if (mZygoteSecondarySocketAddress != null) {
// The primary zygote didn't match. Try the secondary.
attemptConnectionToSecondaryZygote();
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
}
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to zygote", ioe);
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}
实际上就是根据abi参数来建立与Zygote的Socket连接,其实就是根据Zygote的启动脚本类型来建立不同的连接,这里我们就不深入了。
所以到目前为止,ActivityManagerService就成功地读取应用程序的相关信息并将其打包发给Zygote,请求Zygote创建进程了,接下来我们看Zygote是如何响应AMS的请求的。
在之前的文章中,其实我们已经提到过了,Zygote将在创建完自身的Socket后等待AMS的请求,具体是在ZygoteInit的main方法中:
caller = zygoteServer.runSelectLoop(abiList);
其实这个方法里还是继续跳转,我们直接跳过中间步骤,来到最终调用到的ZygoteConnection方法中:
Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
ZygoteArguments parsedArgs;
try (ZygoteCommandBuffer argBuffer = new ZygoteCommandBuffer(mSocket)) {
while (true) {
try {
parsedArgs = ZygoteArguments.getInstance(argBuffer);//1-----1
}
.........
if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote
|| !multipleOK || peer.getUid() != Process.SYSTEM_UID) {
// Continue using old code for now. TODO: Handle these cases in the other path.
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);//2-----2
try {
if (pid == 0) {
// in child
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
return handleChildProc(parsedArgs, childPipeFd,
parsedArgs.mStartChildZygote);//3--------3
} else {
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
} else {
ZygoteHooks.preFork();
Runnable result = Zygote.forkSimpleApps(argBuffer,
zygoteServer.getZygoteSocketFileDescriptor(),
peer.getUid(), Zygote.minChildUid(peer), parsedArgs.mNiceName);
if (result == null) {
// parent; we finished some number of forks. Result is Boolean.
// We already did the equivalent of handleParentProc().
ZygoteHooks.postForkCommon();
// argBuffer contains a command not understood by forksimpleApps.
continue;
} else {
// child; result is a Runnable.
zygoteServer.setForkChild();
Zygote.setAppProcessName(parsedArgs, TAG); // ??? Necessary?
return result;
}
}
}
}
........
}
方法很长,我们主要看注释出的三处,第一处的
parsedArgs = ZygoteArguments.getInstance(argBuffer);
方法显然是将我们之间通过AMS发送过来的启动参数给获取出来了。接着注释二处通过zygote将要启动的应用程序的进程就已经fork出来了,到此为止,实际上要启动的进程已经被创建出来了,只不过创建出来后我们还需要将这个进程进行一些处理,所以接下来会调用到注释三处的handleChildProc方法,到了这里之后又会跳转,具体来说会跳转到ZygoteInit.zygoteInit方法,这个方法我们在之前的Zygote的启动中也提到过,它首先会启动进程的Binder进程池,这样这个进程就可以与其他进程进行Binder进程间通信了,然后它会执行具体类的main方法。在这里,他将会启动ActivityThread的main方法。
这个ActivityThread类是Android系统中的核心类之一,它负责管理应用程序的主线程(UI线程)以及应用程序的生命周期和消息处理。每个应用程序在启动时都会创建一个ActivityThread实例,并在该实例的主线程中执行应用程序的主要逻辑。ActivityThread类的主要职责包括:
应用程序的初始化:在ActivityThread的main()方法中,会创建Application实例,并调用其onCreate()方法来进行应用程序的初始化工作。
管理Activity的生命周期:ActivityThread负责跟踪和管理应用程序中所有Activity的生命周期。它会接收来自系统的生命周期回调消息,并分发给相应的Activity进行处理,例如调用Activity的onCreate()、onStart()、onResume()等方法。
处理消息和事件:ActivityThread通过一个消息循环机制,处理来自系统和应用程序的消息和事件。它会接收并分发消息给对应的Handler进行处理,例如处理用户界面事件、处理来自其他组件的消息等。
启动Activity和Service:ActivityThread负责启动应用程序中的Activity和Service组件。它会接收来自系统的启动请求,并负责创建和启动相应的组件实例。
处理窗口和界面更新:ActivityThread负责处理窗口和界面的更新操作,包括创建和管理窗口、更新界面布局、处理用户界面事件等。
那么接下来我们就来简单看看它的main方法:
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// Install selective syscall interception
AndroidOs.install();
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
// Call per-process mainline module initialization.
initializeMainlineModules();
Process.setArgV0("" );
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
ActivityThread thread = new ActivityThread();
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);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
可以看到这个main方法中会自动创建出一个消息Looper和一个默认的Handler,然后会自动开启消息队列的循环使它可以处理消息。接下来Activity就将由ActivityThread管理启动了,这就已经完成了应用程序进程的启动了。