前言:
应用程序的启动过程就是此时AMS服务已经创建成功并拉起了Launcher界面,此时在Launcher界面点击某个应用,会先判断这个应用程序需要的应用程序进程是否存在,不存在就会请求Zygote进程将需要的应用程序进程启动(PS:全篇讲的是应用程序进程的启动过程,并不是应用程序的启动过程如根Activity的启动)
相关文章:
android 系统启动流程
一:应用程序进程的启动流程
应用程序的启动流程主要可以总结为两个部分
1.AMS发送启动应用程序进程的请求
2.Zygote进程接收请求并创建应用程序进程
接下来我们就从这两个方面进行解析
二:框架图
以下是整个应用程序进程的启动过程,抽出了比较重要的部分,不是完全,可当作参考
三:AMS发送启动应用程序的请求
AMS调用startProcessLocked来想Zygote进程发送启动应用程序请求
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
...省略
if (!app.isolated) {
if (ArrayUtils.isEmpty(permGids)) {
gids = new int[2];
} else {
gids = new int[permGids.length + 2];
System.arraycopy(permGids, 0, gids, 2, permGids.length);
}
gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));
}
...省略
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
...省略
} catch (RuntimeException e) {
...省略
}
}
...省略
}
在startProcessLocked方法中可以看出最后是调用了Process.start()方法,传入了app相关信息、uid等参数,其中有一个参数是entryPoint ,如果为空的话赋值"android.app.ActivityThread",对于这个类想必大家都很熟悉,我们先看Process.start又调用了startViaZygote
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[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
...省略
}
}
看下startViaZygote具体做了些什么
private static 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[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
...省略
//保存启动参数的List
ArrayList<String> argsForZygote = new ArrayList<String>();
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
...省略
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
...
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
可以看到这个方法创建了一个List,把uid、gid、processClass(如果为空取值:android.app.ActivityThread)等都放入了这个List对象里面,然后调用了zygoteSendArgsAndGetResult
private static ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {
//获取Zygote的BufferedWriter ,然后把参数写入
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
writer.write(Integer.toString(args.size()));
writer.newLine();
int sz = args.size();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
if (arg.indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx(
"embedded newlines not allowed");
}
writer.write(arg);
writer.newLine();
}
writer.flush();
ProcessStartResult result = new ProcessStartResult();
result.pid = inputStream.readInt();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
result.usingWrapper = inputStream.readBoolean();
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}
可以看到zygoteSendArgsAndGetResult方法其实就是把刚才保存启动的应用程序进程的信息List写入ZygoteState里面,我们看下ZygoteState这个参数是怎么生成的
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
//与Zygote进程创建的服务端Socket建立链接
primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
} 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(SECONDARY_ZYGOTE_SOCKET);
} 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);
ZygoteState.connect(ZYGOTE_SOCKET)与Zygote进程创建的服务端Socket建立链接,如果连接name为“zygote”的Socket返回的primaryZygoteState与当前的abi不匹配,则会 ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET),这两个Socket区别就是:name为”zygote”的Socket是运行在64位Zygote进程中的,而name为“zygote_secondary”的Socket则运行在32位Zygote进程中。既然应用程序进程是通过Zygote进程fock产生的,当要连接Zygote中的Socket时,也需要保证位数的一致。
至此:AMS发送启动应用程序的请求告一段落
四:Zygote进程接收请求并创建应用程序进程
在Zygote进程初始化的时候,会调用ZygoteInit的main方法,main方法中调用了registerZygoteSocket创建了Zygote的Socket服务端
public static void main(String argv[]) {
...省略
try {
...省略
//注册Zygote用的Socket
registerZygoteSocket(socketName);
...省略
//预加载类和资源
preload();//2
...省略
if (startSystemServer) {
//启动SystemServer进程
startSystemServer(abiList, socketName);
}
Log.i(TAG, "Accepting command socket connections");
//等待客户端请求
runSelectLoop(abiList);
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
在runSelectLoop方法中来等待客户端的请求,就是上一步所说的操作。当请求来了runSelectLoop方法会调用runOnce()这个方法
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
Log.w(TAG, "IOException on command socket " + ex.getMessage());
closeSocket();
return true;
}
...省略
try {
parsedArgs = new Arguments(args);
...省略
//Zygote进程foke出请求的应用程序进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir);
} catch (ErrnoException ex) {
...省略
}
try {
if (pid == 0) {
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
return true;
} else {
// in parent...pid of < 0 means failure
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
可以看到forkAndSpecialize方法返回的pid如果是0的话会调用handleChildProc,如果不是0的话会调用handleParentProc
我们主要看下handleParentProc()方法
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
...省略
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
看下RuntimeInit.zygoteInit
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
redirectLogStreams();
commonInit();
nativeZygoteInit();
applicationInit(targetSdkVersion, argv, classLoader);
}
nativeZygoteInit()方法是一个native方法,我们不做过多赘述,但是这个方法也很重要,阿简认为记住结论即可,nativeZygoteInit方法的作用是:前线程注册到Binder驱动程序中,创建的线程就加入了Binder线程池中,这样新创建的应用程序进程就支持Binder进程间通信了
我们接下来看下zygoteInit方法中调用的applicationInit方法做了些什么
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
...省略
final Arguments args;
try {
args = new Arguments(argv);
} catch (IllegalArgumentException ex) {
Slog.e(TAG, ex.getMessage());
return;
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
可以看到调用了invokeStaticMain()方法
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
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);
}
...省略
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
这个方法中className就是我们传入的”android.app.ActivityThread“类,这里就是反射调用了ActivityThread的main方法
至此:Zygote进程接收请求并创建应用程序进程告一段落
参考资料:《android进阶解密》