Zygote的作用
1)启动SystemServer(使用zygote的资源:常用类,JNI函数,主题资源,共享库)
2)孵化app应用进程
如何启动的
1)通过init进程,init进程是系统启动后用户空间第一个进程,它通过读取init.rc读取那些系统服务需要启动,如zygote, service manager, 启动是通过fork() + execve()做的。
fork+execve
pid_t pid = fork();
if(pid == 0){
//child process
execve(path, argv, env);
}else{
//parent process
}
2)子进程会继承父进程的资源,但是如果调用execve()执行了新程序,那继承的资源就会被清掉,被新的二进制程序替换掉。
3)启动后的流程 native层:zygote启动后,执行了execve系统调用,执行了c++的二进制程序,有main函数做入口,虽然zygote天生就是native的,做好准备工作后,就切到java世界运行了。 java层:
int main(int argc, char *argv[]){
javaVM *jvm;
JNIEnv *env;
JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args); //创建虚拟机
jclass clazz = env->FindClass("ZygoteInit"); //找到zygoteinit java类
jmethodID method = env->GetStaticMethodID(clazz, "Main", "([java/lang/String;)V"); //找到里面的main函数
env->CallStaticVoidMethod(clazz, method, args); //运行main函数
jvm->DestroyJavaVM();
}
整理流程为:
1)启动Android虚拟机
2)注册Android的JNI函数
3)通过JNI调用,进入JAVA世界
ZygoteInit的main方法
public static void main(String argv[]) {
//zygote服务类
ZygoteServer zygoteServer = new ZygoteServer();
//不允许创建新的线程否则会报错
ZygoteHooks.startZygoteNoThreadCreation();
//绑定进程
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
final Runnable caller;
try {
....
省略一些log输出
....
//注册ddms
RuntimeInit.enableDdms();
//标识是否要启动系统服务
boolean startSystemServer = false;
//socket名称
String socketName = "zygote";
String abiList = null; // abi列表(armeabi、armeabi-v7a、x86等)
//标识是否要预加载资源
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true; //启动系统服务
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true; //预加载资源
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());//获取abi
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());//获取socket名称
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
if (abiList == null) {
//异常情况
throw new RuntimeException("No ABI list supplied.");
}
zygoteServer.registerServerSocketFromEnv(socketName); //注册socket
if (!enableLazyPreload) {
//启动预加载
....
preload(bootTimingsTraceLog);
....
} else {
//降低进程优先级
Zygote.resetNicePriority();
}
...
gcAndFinalize(); //进行一次gc
...
//初始化native访问安全
Zygote.nativeSecurityInit();
//卸载storage空间
Zygote.nativeUnmountStorageOnInit();
//通知虚拟机可以创建线程了
ZygoteHooks.stopZygoteNoThreadCreation();
//启动系统服务
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
//上文提到过fork进程会有两次回调,这里如果r==null则是Zygote进程,否则是SystemServer进程
if (r != null) {
r.run();
return;//SystemServer进程就直接返回了
}
}
//父进程中会执行到这里,轮询Socket发的命令
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
zygoteServer.closeServerSocket();//子进程断开与Socket的连接
}
//执行子进程
if (caller != null) {
caller.run();
}
}
main方法总结:
整体流程主要涉及获取c++调用层传递过来的参数,包括是否启动系统服务、是否预加载系统资源、获取abi和绑定socket名称。在进程创建开始前禁止创建新的线程,做好初始化之后才允许创建新的线程,最后绑定Socket进行轮询。
preload方法
static void preload(TimingsTraceLog bootTimingsTraceLog) {
....
preloadClasses(); //Class.forName方式预加载Class
....
preloadResources();//预加载系统资源resource,如drawable、color
....
preloadOpenGL(); //加载openGL
....
preloadSharedLibraries(); //System.loadLibrary方式加载一些公共库
preloadTextResources(); //加载Text资源、字体等
WebViewFactory.prepareWebViewInZygote(); //WebViewFactory在Zygote初始化
endIcuCachePinning();
warmUpJcaProviders();
sPreloadComplete = true; //预加载完成标记
}
preload方法总结:
preloadClassess 将framework.jar里的preloaded-classes 定义的所有class load到内存里,preloaded-classes 编译Android后可以在framework/base下找到。而preloadResources 将系统的Resource(不是在用户apk里定义的resource)load到内存。资源preload到Zygoted的进程地址空间, 所有fork的子进程将共享这份空间而无需重新load, 这大大减少了应用程序的启动时间,但反过来增加了系统的启动时间。通过对preload 类和资源数目进行调整可以加快系统启动。Preload也是Android启动最耗时的部分之一。
forkSystemServer方法
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
... 省略一些参数
//启动SystemServer命令
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer", //这个参数代表着系统进程fork成功后回执行SystemServer中的main方法
};
//处理参数信息
....
int pid;
try {
....
处理参数信息
....
//fork系统服务
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.runtimeFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
if (pid == 0) {
//这里是子进程的回调
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket(); //子进程并不需要保持zygote socket的连接了,所以进行断开操作
return handleSystemServerProcess(parsedArgs); //开始处理系统服务
}
return null;
}
handleSystemServerProcess方法最终的核心是调用ZygoteInit.zygoteInit
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
//初始化log
RuntimeInit.redirectLogStreams();
//初始化log打印和线程崩溃回调
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
//RuntimeInit类去执行到SystemServer的main方法
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
....
return findStaticMain(args.startClass, args.startArgs, classLoader);
}
protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class> cl;
....
cl = Class.forName(className, true, classLoader);
....
Method m;
....
m = cl.getMethod("main", new Class[] { String[].class });
....
return new MethodAndArgsCaller(m, argv); //执行到SystemServer的main方法
}
ZygoteServer
ZygoteServer是Zygote用来与Socket建立连接的,主要涉及registerServerSocketFromEnv
和runSelectLoop
。
registerServerSocketFromEnv方法
void registerServerSocketFromEnv(String socketName) {
if (mServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;//socket全名
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env); //socket句柄(int值)
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
mServerSocket = new LocalServerSocket(fd);//通过LocalServerSocket进行监听
mCloseSocketFd = true;
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
runSelectLoop
Runnable runSelectLoop(String abiList) {
ArrayList fds = new ArrayList();
ArrayList peers = new ArrayList();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
//开启一个死循环从socket中获取数据
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);//系统的poll机制
} 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);//每一次循环都是取出来ZygoteConnection
final Runnable command = connection.processOneCommand(this); //processOneCommand方法fork出进程,App的进程就是通过AMS向Zygote发送socket消息,通过这里经过ZygoteConnection执行的
if (mIsForkChild) {
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
} else {
....
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
....
}
runSelectLoop方法通过轮询的方式不断从socket中取出消息,来完成进程的创建。AMS通过向Zygote绑定的socket中发送消息来请求Zygote来fork出app的进程。
zygote启动过程的2个细节:
1)zygote在fork时要保证单线程, 因为不管父进程有多少个线程,子进程创建时只有一个线程,多的线程就不见了,会导致很多奇怪的问题:子进程死锁,状态不一致,所以不如直接,fork子进程时,停掉其他线程,创建完了子进程再重启那些线程,zygote就是这么做的,它不只有主线程,还有与虚拟机相关的守护线程。
2)zygote的IPC没有采用binder机制, 它采用的是socket,所以应用的binder机制不是从zygote继承的,而是AP进程创建后自己启动的binder机。
1.孵化AP问啥不交给systemServer,而是专门设计一个zygote?
应用在启动的时候,需要做很多准备工作,如启动虚拟机,加载各个类系统资源,都非常耗时, 如果zygote把init工作做好,再在fork时共享给子进程,那效率就非常高。 这就是zygote存在的价值,systemServer不能做,因为它跑了一堆系统服务,他们不能被继承AP进程。 而且AP启动时,内存空间除了必要的资源外,最好是干净的,不要继承一堆乱七八糟的东西, 所以,不如给systemServer和AP进程都要用的资源抽出来单独放在一个进程里,这就是zygote进程.
2,zyogte的IPC为什么不用binder?用binder会有问题吗?
不用binder有个原因:
1)如果用了binder,zygote要先启动binder机制,打开binder驱动,获得描述符,mmap进程内存映射,注册binder线程,还要创建一个binder对象注册到serviceManager,另外AMS要想zygote发起创建应用进程请求的话,要先从serviceManager查询zygote的binder对象,再发起binder调用,非常繁琐。 相比之下,zygote和systemserver本就是父子关系,对于简单的消息通信,用管道或者socket非常方便。
2)如果zygote用了binder机制,再fork systemServer,那systemServer就继承了zygote的描述符和映射的内存,这两个进程在binder驱动层就会共用一套数据结构,这肯定是不行的。那还得把旧的描述符关掉,再重新启动一遍binder机制,自找麻烦。