1. 概述
ActivityThread的main()方法是应用进程的入口,ActivityThread在应用运行过程起了不可或缺的作用,并且每个进程只有一个ActivityThread实例,ActivityThread在进程启动的过程中创建的,常常好奇是如何创建ActivityThread并执行其main方法完成应用初始化的。本文只是应用进程启动流程的学习笔记,希望对应用启动流程有个大概的认识,后面还有非常多的知识需要掌握。
This manages the execution of the main thread in an
application process, scheduling and executing activities,
broadcasts, and other operations on it as the activity
manager requests.
本文基于Android P 源码
总体的流程图:
2. 判断进程是否进程是否存活
以在launcher中启动应用为例,启动过程中会执行到ActivityStackSupervisor.startSpecificActivityLocked()的方法,然后根据应用的包名和UID判断当前进程是否正在运行,ActivityManagerService维护着存活进程的列表mProcessNames,通过检索该列表可判断进程是否正在运行。ProcessRecord 是进程在framework的抽象表现。
ActivityStackSupervisor:
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
// 判断进程是否正在运行
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
getLaunchTimeTracker().setLaunchTime(r);
if (app != null && app.thread != null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
// Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
app.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode,
mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
// 该进程没有正在运行,重新启动一个新的进程
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
ActivityManagerService:
final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
if (uid == SYSTEM_UID) {
// 获取shareuid为SYSTEM_UID的ProcessRecord
// The system gets to run in any process. If there are multiple
// processes with the same uid, just pick the first (this
// should never happen).
SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(processName);
if (procs == null) return null;
final int procCount = procs.size();
for (int i = 0; i < procCount; i++) {
final int procUid = procs.keyAt(i);
if (UserHandle.isApp(procUid) || !UserHandle.isSameUser(procUid, uid)) {
// Don't use an app process or different user process for system component.
continue;
}
return procs.valueAt(i);
}
}
// 检索mProcessNames并返回
ProcessRecord proc = mProcessNames.get(processName, uid);
.....
return proc;
}
3. system_process 系统进程侧流程
通过AMS(ActivityManagerService)的startProcessLocked() 方法启动进程, 主要构建ProcessRecord、准备启动进程所需参数以及进行各种安全检查等等。 中间省略了很多代码,此处只关注主要流程。
- 构建ProcessRecord
startProcessLocked()方法中通过newProcessRecordLocked(info, processName, isolated, isolatedUid)构建ProcessRecord然后保存至mProcessNames,上面就是依赖该缓存值判断进程是否正在运行。ProcessRecord是进程在framework中的表示。
ActivityManagerService:
@GuardedBy("this")
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
null /* crashHandler */);
}
@GuardedBy("this")
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
long startTime = SystemClock.elapsedRealtime();
ProcessRecord app;
.......
String hostingNameStr = hostingName != null
? hostingName.flattenToShortString() : null;
if (app == null) {
checkTime(startTime, "startProcess: creating new process record");
// 新建一个ProcessRecord并保存到mProcessNames中
app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
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;
checkTime(startTime, "startProcess: done creating new process record");
} else {
// If this is a new package in the process, add the package to the list
app.addPackage(info.packageName, info.versionCode, mProcessStats);
checkTime(startTime, "startProcess: added package to existing proc");
}
.....
checkTime(startTime, "startProcess: stepping in to startProcess");
// 继续往下执行,启动进程
final boolean success = startProcessLocked(app, hostingType, hostingNameStr, abiOverride);
checkTime(startTime, "startProcess: done starting proc!");
return success ? app : null;
}
- 传参:ActivityThread全限定名
把ActivityThread全限定名(android.app.ActivityThread)作为参数往下传递。最终执行Process.start方法
ActivityManagerService:
/**
* @return {@code true} if process start is successful, false otherwise.
*/
@GuardedBy("this")
private final boolean startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
......
// 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(hostingType, hostingNameStr, entryPoint, app, uid, gids,
runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
startTime);
.....
}
.....
private ProcessStartResult startProcess(String hostingType, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startTime) {
.....
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
......
}
- 开始与Zygote进程打交道
进入Process类后,流程非常简单和直接:Process.start()–>ZygoteProcess.start()–>ZygoteProcess.startViaZygote()。主要关注ZygoteProcess.startViaZygote()方法中最后几行。
Process:
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
return zygoteProcess.start(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}
ZygoteProcess:
private Process.ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] extraArgs)
throws ZygoteStartFailedEx {
.......
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
synchronized(mLock) {
// 重点关注
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
- 通过Socket与Zygote进程通信
通过openZygoteSocketIfNeeded() 打开Socket通道传输数据至Zygote过程,启动进程过程利用Socket机制进行跨进程通信而不是Binder。
然后zygoteSendArgsAndGetResult()方法将数据写入至基于Socket机制创建的output writer,数据将会在Zygote进程中被接收处理。
ZygoteProcess:
/**
* Tries to open socket to Zygote process if not already open. If
* already open, does nothing. May block and retry. Requires that mLock be held.
*/
@GuardedBy("mLock")
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
// 打开与zygote进程的socket 连接
primaryZygoteState = ZygoteState.connect(mSocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
}
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
// The primary zygote didn't match. Try the secondary.
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
}
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}
public static class ZygoteState {
final LocalSocket socket;
final DataInputStream inputStream;
final BufferedWriter writer;
final List<String> abiList;
.......
public static ZygoteState connect(String socketAddress) throws IOException {
DataInputStream zygoteInputStream = null;
BufferedWriter zygoteWriter = null;
final LocalSocket zygoteSocket = new LocalSocket();
try {
zygoteSocket.connect(new LocalSocketAddress(socketAddress,
LocalSocketAddress.Namespace.RESERVED));
zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
// 利用该output wirter 传输数据给Zygote进程
zygoteWriter = new BufferedWriter(new OutputStreamWriter(
zygoteSocket.getOutputStream()), 256);
} catch (IOException ex) {
try {
zygoteSocket.close();
} catch (IOException ignore) {
}
throw ex;
}
String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
Log.i("Zygote", "Process: zygote socket " + socketAddress + " opened, supported ABIS: "
+ abiListString);
return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
Arrays.asList(abiListString.split(",")));
}
....
}
.....
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {
// Throw early if any of the arguments are malformed. This means we can
// avoid writing a partial response to the zygote.
int sz = args.size();
for (int i = 0; i < sz; i++) {
if (args.get(i).indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx("embedded newlines not allowed");
}
}
/**
* See com.android.internal.os.SystemZygoteInit.readArgumentList()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
* the child or -1 on failure, followed by boolean to
* indicate whether a wrapper process was used.
*/
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
writer.write(Integer.toString(args.size()));
writer.newLine();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);
writer.newLine();
}
writer.flush();
// Should there be a timeout on this?
Process.ProcessStartResult result = new Process.ProcessStartResult();
// Always read the entire result from the input stream to avoid leaving
// bytes in the stream for future process starts to accidentally stumble
// upon.
result.pid = inputStream.readInt();
result.usingWrapper = inputStream.readBoolean();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}
4. Zygote进程侧流程
既然通过Socket与Zygote进程进行通信,那么Zygote进程肯定有相应的Socket链接来接收数据。
- 不断循环监听获取Socket流
在Zygote进程被init进程启动时会执行ZygoteInit.main()方法,main方法会调用ZygoteServer.runSelectLoop(),在这个方法里面发现while (true)不断地去执行ZygoteConnection.processOneCommand() 获取传输过来的参数然后处理。
重点: runSelectLoop方法会在Zygote进程无限运行,但在子进程中获取到Runnable后会退出,怎么做到的呢?因为zygote进程调用fork()函数创建出的子进程,与Zygote进程共享代码区和链接信息。
The select loop returns early in the child process after a fork and
loops forever in the zygote.
ZygoteServer:
/**
* Runs the zygote process's select loop. Accepts new connections as
* they happen, and reads commands from connections one spawn-request's
* worth at a time.
*/
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
try {
ZygoteConnection connection = peers.get(i);
final Runnable command = connection.processOneCommand(this);
if (mIsForkChild) {
// We're in the child. We should always have a command to run at this
// stage if processOneCommand hasn't called "exec".
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
} else {
// We're in the server - we should never have any commands to run.
if (command != null) {
throw new IllegalStateException("command != null");
}
// We don't know whether the remote side of the socket was closed or
// not until we attempt to read from it from processOneCommand. This shows up as
// a regular POLLIN event in our regular processing loop.
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
} catch (Exception e) {
if (!mIsForkChild) {
// We're in the server so any exception here is one that has taken place
// pre-fork while processing commands or reading / writing from the
// control socket. Make a loud noise about any such exceptions so that
// we know exactly what failed and why.
Slog.e(TAG, "Exception executing zygote command: ", e);
// Make sure the socket is closed so that the other end knows immediately
// that something has gone wrong and doesn't time out waiting for a
// response.
ZygoteConnection conn = peers.remove(i);
conn.closeSocket();
fds.remove(i);
} else {
// We're in the child so any exception caught here has happened post
// fork and before we execute ActivityThread.main (or any other main()
// method). Log the details of the exception and bring down the process.
Log.e(TAG, "Caught post-fork exception in child process.", e);
throw e;
}
} finally {
// Reset the child flag, in the event that the child process is a child-
// zygote. The flag will not be consulted this loop pass after the Runnable
// is returned.
mIsForkChild = false;
}
}
}
}
}
- Fork新进程
ZygoteConnection的processOneCommand获取数据,并通过Zygote.forkAndSpecialize() fork出一个新的进程,接下来的流程都将在子进程中执行,并设置子进程的标志位,然后handleChildProc()对进程进行一些配置和初始化以及关闭socket, 最终进程的初始化由**ZygoteInit.zygoteInit()**来处理。
重点: Zygote.forkAndSpecialize()会返回两次,如果pid==0,则表示在子进程中返回了,如果pid!=0,则还在Zygote进程中进行执行handleParentProc()进入无限循环的状态不断监听socket数据。
ZygoteConnection:
Runnable processOneCommand(ZygoteServer zygoteServer) {
........
//fork 一个新的进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
parsedArgs.instructionSet, parsedArgs.appDataDir);
try {
// 判断是否Zygote 孵化出来的子进程,并已在子进程中运行以下流程
if (pid == 0) {
// in child,设置进入子进程的标志位
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
// 对该进程做一些初始化
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
} else {
// In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc.
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) {
......
if (!isZygote) {
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
null /* classLoader */);
} else {
return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
.......
}
- ZygoteInit.zygoteInit()进行初始化
上述创建进程后由ZygoteInit.zygoteInit()进行初始化,执行RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
RuntimeInit:
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
// shutdown an Android application gracefully. Among other things, the
// Android runtime shutdown hooks close the Binder driver, which can cause
// leftover running threads to crash before the process actually exits.
nativeSetExitWithoutCleanup(true);
// We want to be fairly aggressive about heap utilization, to avoid
// holding on to a lot of memory that isn't needed.
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args = new Arguments(argv);
// The end of of the RuntimeInit event (see #zygoteInit).
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Remaining arguments are passed to the start class's static main
return findStaticMain(args.startClass, args.startArgs, classLoader);
}
- 加载ActivityThread类和获取main方法
终于终于终于到了加载ActivityThread的地方了(太激动了),findStaticMain()的参数args.startClass就是“android.app.ActivityThread”,还记得上面第3节的第二点么?ActivityThread的全限定名被作为参数传递下来,最终存放在args.startClass字段作为该进程启动的第一个Java 对象,并获取其main方法。
RuntimeInit:
protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;
try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}
/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/
return new MethodAndArgsCaller(m, argv);
}
static class MethodAndArgsCaller implements Runnable {
/** method to call */
private final Method mMethod;
/** argument array */
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException(ex);
}
}
}
- 运行ActivityThread main方法
回到ZygoteInit的main方法,其中Runnable caller为上面返回的MethodAndArgsCaller,然后执行,注意!!Zygote进程的runSelectLoop并未退出,依旧不断在循环监听socket数据,随时为启动一个新进程准备着。
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
.....
try{
.......
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
zygoteServer.closeServerSocket();
}
// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run();
}
}
5. 总结
ActivityThread的创建以及其main方法的执行流程很清晰并没有很绕的地方,只是调用栈稍长了一点。总结一下有几点需要注意的:
- Zygote的跨进程通信依赖Socket机制而非Binder机制;
- ActivityThread是通过参数传递下去并被加载执行的;
- AMS维护了一个存活线程列表mProcessNames;
- runSelectLoop方法会在Zygote进程无限运行下去,因为zygote进程调用fork()函数创建出的子进程,与Zygote进程共享代码区和链接信息,并且Zygote.forkAndSpecialize()会返回两次,分别进去子进程逻辑和Zygote进程逻辑;
简单地过了一遍应用进程的启动流程,对其有个大概的认识,但是涉及的内容非常多并且里面的每个细节都值得好好研究与学习,谨记。