本文开始的时候,先提一个面试中常问的问题:
- Android应用程序启动的入口到底在哪儿?
你可能会回答:
- 启动Activity的onCreate(...)中?
- Application中的onCreate(...)中?
两样都不是?接下来可能就是一段长时间的沉默,你可以回家了,这个问题很基本,但是不看过源码的人很多都不知道。接下来我们就分析一下Android应用程序的启动流程,告诉你Android应用程序真正的启动入口在什么地方。
一、应用程序进程介绍
一个应用程序的进程名称就是AndroidManifest.xml中定义的标签:
manifest节点中的package标签。
应用程序四要素:
- 有一段程序供其运行
- 拥有专用的系统堆栈空间
- 在内核存在对应的进程控制块
- 拥有独立的用户存储空间
通常情况下,我们开发的一个应用程序至少有一个独立的进程,在这个进程中,我们有独立的存储空间,可以分配一些资源,处理一些特定的事情。
之前的文章<Service组件源码全面剖析>和<Android广播剖析之发送广播、接收广播>都明确讲过,在处理service和分发广播之前,都会判断当前的应用程序进程是否存在,如果存在则复用,如果不存在就创建一个。
这个创建是怎么个创建法?谁创建?这是我们本章探讨的重点。
二、应用程序创建
当前应用进程不存在,创建进程的起点就是AMS->startProcessLocked(...)
这儿不得不贴一些代码,见谅。
private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startTime) {
app.pendingStart = true;
app.killedByAm = false;
app.removed = false;
app.killed = false;
final long startSeq = app.startSeq = ++mProcStartSeqCounter;
app.setStartParams(uid, hostingType, hostingNameStr, seInfo, startTime);
if (mConstants.FLAG_PROCESS_START_ASYNC) {
mProcStartHandler.post(() -> {
try {
synchronized (ActivityManagerService.this) {
final String reason = isProcStartValidLocked(app, startSeq);
if (reason != null) {
app.pendingStart = false;
return;
}
app.usingWrapper = invokeWith != null
|| SystemProperties.get("wrap." + app.processName) != null;
mPendingStarts.put(startSeq, app);
}
final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
requiredAbi, instructionSet, invokeWith, app.startTime);
synchronized (ActivityManagerService.this) {
handleProcessStartedLocked(app, startResult, startSeq);
}
} catch (RuntimeException e) {
synchronized (ActivityManagerService.this) {
mPendingStarts.remove(startSeq);
app.pendingStart = false;
forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
false, false, true, false, false,
UserHandle.getUserId(app.userId), "start failure");
}
}
});
return true;
} else {
try {
final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app,
uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet,
invokeWith, startTime);
handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
startSeq, false);
} catch (RuntimeException e) {
app.pendingStart = false;
forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
false, false, true, false, false,
UserHandle.getUserId(app.userId), "start failure");
}
return app.pid > 0;
}
}
代码比较长。核心判断就是当前是异步启动进程吗?当前是异步启动进程。
final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
requiredAbi, instructionSet, invokeWith, app.startTime);
真正核心的调用时这句代码,传入了启动进程必要的参数。其中这个entryPoint是什么?循着调用的路径向上找一下。找上一步调用中发现了:
final String entryPoint = "android.app.ActivityThread";
return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
startTime);
这儿赋值为android.app.ActivityThread,接下来看他怎么用。
AMS->startProcess
这里面还分为两种情况,webview_service和其他的情况,普通的应用程序就是其他的情况。直接调用的函数是:
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});
Process->start
ZygoteProcess->start
ZygoteProcess->startViaZygote
synchronized(mLock) {
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
用一个ArrayList将要用的参数加到列表中。执行openZygoteSocketIfNeeded(...)
ZygoteProcess->openZygoteSocketIfNeeded(...)
ZygoteState->connect(...)
public static ZygoteState connect(LocalSocketAddress address) throws IOException {
DataInputStream zygoteInputStream = null;
BufferedWriter zygoteWriter = null;
final LocalSocket zygoteSocket = new LocalSocket();
try {
zygoteSocket.connect(address);
zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
zygoteWriter = new BufferedWriter(new OutputStreamWriter(
zygoteSocket.getOutputStream()), 256);
} catch (IOException ex) {
try {
zygoteSocket.close();
} catch (IOException ignore) {
}
throw ex;
}
String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
Arrays.asList(abiListString.split(",")));
}
zygoteSocket连接的address是在Porcess中定义的zygoteProcess变量:
public static final String ZYGOTE_SOCKET = "zygote";
public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";
public static final ZygoteProcess zygoteProcess =
new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET);
两个zygoteSocket服务,当第一个没有连接上,尝试第二个,保证socket通信正常。
创建了名为zygote的socket,此socket与本地的驱动设备/dev/socket/zygote绑定一起,通过LocalSocket找到/dev/socket/目录下的zygote文件,然后与之绑定在一起,连接成功。
其中zygoteInputStream为获取当前Zygote socket的输入流对象,然后定义zygoteWriter的写对象,以便向socket中写入数据。
三、socket接收
Zygote进程启动的时候,会执行一个函数,等待一个名为zygote或者zygote_secondary的socket,执行的函数在ZygoteInit->forkSystemServer(...)
ZygoteInit->forkSystemServer(...)
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}
这在创建system_sever进程函数中会执行waitForSecondaryZygote(...)函数。
ZygoteInit->waitForSecondaryZygote
private static void waitForSecondaryZygote(String socketName) {
String otherZygoteName = Process.ZYGOTE_SOCKET.equals(socketName) ?
Process.SECONDARY_ZYGOTE_SOCKET : Process.ZYGOTE_SOCKET;
ZygoteProcess.waitForConnectionToZygote(otherZygoteName);
}
也会连接到这个socket上,然后双方都会连接到socket上,然后会执行
caller = zygoteServer.runSelectLoop(abiList);
if (caller != null) {
caller.run();
}
启动一个线程专门监听/dev/socket/zygote是否有信息发送,如果有信息发送,则执行ZygoteServer->run()中的:
final Runnable command = connection.processOneCommand(this);
ZygoteConnection->processOneCommand(...)
执行到native层fork一个新的进程,进程名就是传入的pkgName。
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);
创建进程成功之后,会进入下面的判断流程:
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;
}
当pid=0,表明是在当前新创建的子进程中执行的,一般就是我们认为的应用程序进程。
ZygoteConnection->handleChildProc(...)
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
// Should not get here.
throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
} else {
if (!isZygote) {
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
null /* classLoader */);
} else {
return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
当前传入的invokeWith为null,执行else下面的判断。
ZygoteInit->zygoteInit(...)
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
RuntimeInit->applicationInit(...)
这儿设置了虚拟机的targetSdk以及对大小等等虚拟机设置。
RuntimeInit->findStaticMain(...)
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);
}
return new MethodAndArgsCaller(m, argv);
}
通过classLoader反射调用ActivityThread->main(...)方法,最终的执行在MethodAndArgsCaller静态内部类中执行了反射的调用:
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);
}
}
}
四、未决的问题
- Binder线程池什么地方创建的?
- 消息循环什么时候创建的?
这两个问题很重要,没有Binder线程池,那么在此进程空间中,和外部的进程binder调用,就会耗时耗内存,产生很大的性能问题,启动了Binder线程池,可以提升这些问题。同样的,如果没有消息循环,Android基本的运行框架都不存在的,无法处理一个个消息,图形无法展示,事情无法处理。
4.1 Binder线程池创建
ZygoteInit.nativeZygoteInit();
此函数建立Binder线程池。深入看其中的代码调用流程。
4.2 消息循环
ActivityThread->main(...)中执行的有关消息循环的代码如下:
Looper.prepareMainLooper();
//......
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
//......
Looper.loop();
应用程序进程中创建一个主线程的Looper,启动loop(),开始消息循环机制,我们就可以在进程中处理消息机制了。Android的核心机制就是消息机制。
五、小结
通过上面文章的分析,我们知道了启动一个应用程序进程需要下面的几步:
- zygote进程创建socket监听
- 应用程序需要创建的时候向socket发送数据,带上启动进程所需的必要信息。
- 启动crash log监听handler
- 创建binder线程池
- 开启消息循环机制
- Android应用程序的入口----> ActivityThread->main(...)
网友评论