序
上篇文章我们谈到进入安卓系统的启动流程,大致梳理了从Native到Framework的流程,到达Framework阶段后,到应用程序启动,这之间仍然有一些工作需要处理,这次,我们就一起学习这部分的工作。
一、概览
上篇文章学习到了Zygote进程,但并未有具体分析Zygote进程的工作,本篇文章,我们就一起学习Zygote进程的具体工作,以及第一个App——Launcher的启动过程。
二、Zygote进程的工作
ZygoteInit的main方法方法大概就做了六件事情:
- 创建 ZygoteServer,Android O 上把与 Socket 的操作都封装到了ZygoteServer 类中
- 解析app_main.cpp传来的参数 。
- 创建一个 Server 端的 Socket,作用是当 Zygote 进程将SystemServer 进程启动后,就会在这个 Socket 上来等待ActivityManagerService 请求,即请求创建我们自己 APP 应用程序进程
- 预加载类和资源,包括颜色、R文件、drawable 、 类等
- 启动 system_server 进程 这是上层 framework 的运行载体,ActivityManagerService 就是运行在这个进程里面的
- 开启一个循环,等待着接收ActivityManagerService 的请求,随时待命,当接收到创建新进程的请求时立即唤醒并执行相应工作
我们主要学习其中的这几个步骤:
- 创建 Server 端的 Socket
- 启动SystemServer进程
- SystemServer处理过程
- 资源预加载
- 等待AMS请求创建新的应用程序进程
2.1 创建 Server 端的 Socket
在ZygoteInit.java的main方法,是这样来创建 Server 端的 Socket的:
zygoteServer.registerServerSocket(socketName);
那我们就来看看ZygoteServer的registerServerSocket方法到底做了什么。关键代码如下:
void registerServerSocket(String socketName) {
if (mServerSocket == null) {
int fileDesc;
//拼接Socket的名称
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
//得到Socket的环境变量的值
String env = System.getenv(fullSocketName);
//将Socket环境变量的值转换为文件描述符的参数
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
//创建文件描述符
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
//创建服务器端 Socket
mServerSocket = new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
拼接Socket的名称时,socketName的值是传进来的“zygote”,因此fullSocketName的值是“ANDROID_SOCKET_zygote”,然后将这个值转换为环境变量的值,再转换为文件描述符的参数。之后创建文件描述符,并传入此前的文件描述符参数,最后创建LocalServerSocket(fd),也就是服务器端 Socket,并将文件描述符传进去。再Zygote进程将SystenServer进程启动后,就会在这个服务器端的Socket上等待AMS请求zygote进程创建新的应用程序进程。
2.2 启动SystemServer进程
ZygoteInit进程是通过startSystemServer(abiList, socketName, zygoteServer)函数来启动SystemServer进程的,接下来我们学习此部分关键代码:
private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)
throws Zygote.MethodAndArgsCaller, RuntimeException {
······
//创建args数组,这个数组用来保存启动SystemServer的启动参数
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
//创建SystemServer子线程
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
//以下代码运行在子线程中
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
//处理SystemServer进程
handleSystemServerProcess(parsedArgs);
}
return true;
}
可以看到,这个函数首先创建args数组,保存启动参数,并封装Arguments对象供forkSystemServer调用,而forkSystemServer函数内部会调用nativeSystemServer的这个Native方法,最终通过fork函数在当前进程创建一个子进程,也就是SystemServer进程,并执行pid == 0的代码,也就是关键的handleSystemServerProcess(parsedArgs)函数。
2.3 SystemServer处理过程
这一节紧接上节,主要学习handleSystemServerProcess()函数发生的事情。主要代码如下:
private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs)
throws Zygote.MethodAndArgsCaller {
······
if (parsedArgs.invokeWith != null) {
······
} else {
ClassLoader cl = null;
if (systemServerClasspath != null) {
//创建PathClassLoader
cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
Thread.currentThread().setContextClassLoader(cl);
}
//调用ZygoteInit的zygoteInit方法
ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
}
这里重点是调用了ZygoteInit的zygoteInit方法,关键代码如下:
public static final void zygoteInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();
//启动binder线程池
ZygoteInit.nativeZygoteInit();
//进入SystemServer的main方法
RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
这里主要调用了nativeZygoteInit()方法,作用是调用Native层的代码,来启动Binder线程池,这样SystemServer就可以使用Binder与其他进程进行通信。然后进入SystemServer的main方法。下面分别介绍这两部分:
int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
{
const JNINativeMethod methods[] = {
{ "nativeZygoteInit", "()V",
(void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
};
return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
methods, NELEM(methods));
}
nativeZygoteInit()是一个Native方法,需要查找其对应的JNI文件,通过JNI的gMethods数组,可以看到其对应的是AndroidRuntime.cpp的com_android_internal_os_ZygoteInit_nativeZygoteInit函数,如下:
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}
这里gCurRuntime是AndroidRuntime类型的指针,指向AppRuntime,在app_main_cpp中定义,关键代码如下:
virtual void onZygoteInit()
{
sp proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
//启动一个Binder线程池
proc->startThreadPool();
}
看到这里,我们大致就了解了nativeZygoteInit方法主要是启动Binder线程池的。
再回到ZygoteInit的zygoteInit方法,我们还没结束这段代码:
public static final void zygoteInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();
//启动binder线程池
ZygoteInit.nativeZygoteInit();
//进入SystemServer的main方法
RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
第二部分,调用了RuntimeInit的applicationInit方法,来进入SystemServer的main方法,applicationInit关键代码如下:
protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws Zygote.MethodAndArgsCaller {
······
// Remaining arguments are passed to the start class's static main
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
看到,在其中调用了invokeStaticMain方法,这个方法启动SystemServer的main方法过程比较复杂,为了清除堆栈帧,使用了抛出异常然后捕获异常的方法,总之会经过一串过程,最终进入SystemServer的main方法中。那么我们就看看这个main方法:
public static void main(String[] args) {
new SystemServer().run();
}
里面只有一行run方法,run方法主要代码如下:
private void run() {
try {
······
//创建消息Looper
Looper.prepareMainLooper();
// 加载动态库libandroid_servers.so
System.loadLibrary("android_servers");
performPendingShutdown();
// 创建系统的contex
createSystemContext();
// 创建SystemServiceManager
mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
SystemServerInitThreadPool.get();
} finally {
traceEnd(); // InitBeforeStartServices
}
try {
traceBeginAndSlog("StartServices");
//启动引导服务
startBootstrapServices();
//启动核心服务
startCoreServices();
//启动其他服务
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
······
}
可以看到,这段代码主要启动系统的各种服务,这些服务大致如下:
- 引导服务:AMS,PowerMS,PachageMS
- 核心服务:DropBoxManagerService,BatteryService,UsageStateService和web ViewUpdateService
- 其他服务:Camera、Alarm、VrManager等等
服务的总数有100多个,这里就不在详细讨论了。这些服务的启动逻辑是类似的,直接调用SystemServiceManager的startService方法,会将服务注册到服务列表中,然后调用服务的onStart函数完成启动。
下面总结下SystemServer进程的工作:
- 启动Binder线程池,可以与其他进程通信
- 创建SystemServiceManager,用于对系统的服务进行创建、启动和生命周期管理
- 启动各种系统服务
2.4 资源预加载
好,现在让我们回到ZygoteInit进程,接下来是资源的预加载过程,那么预加载是什么呢?Android 系统资源加载分两种方式,预加载和使用进程中加载。 预加载是指在 zygote 进程启动的时候就加载,这样系统只在 zygote 执行一次加载操作,所有 APP 用到该资源不需要再重新加载,减少资源加载时间,加快了应用启动速度,一般情况下,系统中 App 共享的资源会被列为预加载资源。
预加载的原理很简单,就是在 zygote 进程启动后将资源读取出来,保存到 Resources 一个全局静态变量中,下次读取系统资源的时候优先从静态变量中查找。这主要靠 zygoteInit.java 类的man方法调用preload()方法完成,下面我们来看看这部分关键代码:
static void preload(BootTimingsTraceLog bootTimingsTraceLog) {
Log.d(TAG, "begin preload");
bootTimingsTraceLog.traceBegin("BeginIcuCachePinning");
beginIcuCachePinning();
bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinning
bootTimingsTraceLog.traceBegin("PreloadClasses");
//预加载类
preloadClasses();
bootTimingsTraceLog.traceEnd(); // PreloadClasses
bootTimingsTraceLog.traceBegin("PreloadResources");
//预加载资源
preloadResources();
bootTimingsTraceLog.traceEnd(); // PreloadResources
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
//预加载图形接口
preloadOpenGL();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
preloadSharedLibraries();
//预加载文字资源
preloadTextResources();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
WebViewFactory.prepareWebViewInZygote();
endIcuCachePinning();
warmUpJcaProviders();
Log.d(TAG, "end preload");
sPreloadComplete = true;
}
可以看到,这个方法主要是通过调用各种预加载方法去实现预加载的,具体的方法预加载方法在这里就不在细究,等有机会再深入学习。
2.5 等待AMS请求创建新的应用程序进程
启动SystemServer进程后,会执行ZygoteServer的zygoteServer.runSelectLoop(abiList)方法:
zygoteServer.runSelectLoop(abiList);
这个方法无限循环,等待AMS的请求,主要代码如下:
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
ArrayList fds = new ArrayList();
ArrayList peers = new ArrayList();
//之前创建的服务器端Socket,获得该Socket的fd字段,并添加到列表
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
//无限循环等待AMS请求
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
//遍历fds,将信息转移到pollFds数组
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);
}
//遍历pollFds数组
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
//i等于0,说明服务器端Socket与客户端连接上了,即当前Zygote与AMS建立连接
if (i == 0) {
//得到ZygoteConnection并添加到连接列表
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
//添加fd列表,以便可以接收到AMS的请求
fds.add(newPeer.getFileDesciptor());
} else {
//i不等于0,说明AMS向Zygote发送了请求,则创建新的应用程序进程
//调用runOnce函数创建新的应用程序进程
boolean done = peers.get(i).runOnce(this);
//成功后,在Socket连接列表和fds中清除这个请求
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}
根据上述代码,可以看到这个函数是通过无限循环来处理AMS的请求,每次成功创建新的应用程序进程,就将其从列表清除。
三、Lanucher启动过程
Laucher启动较为复杂,放在另外一篇文章中进行学习。
四、总结
结合这几篇文章,就可以总结出安卓启动的完整流程,主要有下列几部分:
- 启动电源以及系统启动
按下电源,引导芯片代码从预设位置(ROM)执行。加载BootLoader到RAM,然后执行。 - 引导程序BootLoader
拉起OS。 - Linux内核启动
设置缓存、被保护寄存器、计划列表、加载驱动,完成系统设置后,在系统文件中寻找Init.rc文件,并启动init进程。 - init进程启动
初始化和启动属性服务,启动Zygote进程 - Zygote进程启动
创建java虚拟机并注册JNI方法,创建服务器端Socket,启动SystenmServer进程。 - SystemServer进程启动
启动Binder线程池和SystemServiceManager,启动各种系统服务。 - Launcher启动
AMS启动Launcher,将安装应用程序的快捷图标显示到界面上。
给出图示如下:
文笔简陋,如有错误,还请见谅。