目录
问题:Zygote的IPC通信为什么不采用Binder?如果采用Binder的话会有什么问题?
问题:孵化应用进程为什么不交给SystemServer?而是专门设计一个Zygote?
zygote的作用
- 启动SystemServer
系统服务进程SystemServer是由Zygote进程fork出的(系统中比较重要的ActivityManagerService、PackageManagerService,WindowManagerService以及PowerManagerService等也是由SystemServer进程创建而来的),fork出的SystemServer进程会继承Zygote的资源,比如:常用类、JNI函数、主题资源、共享库等。
2.孵化应用进程
参考android的启动流程 , 里面有一个方法zygoteSendArgsAndGetResult
方法,就是AMS请求Zygote来创建新的应用程序进程的。
补充 :
启动三段式(独立进程都符合) : 进程启动->准备工作->LOOP(接收/处理)
zygote的启动流程
init进程是Linux进程的第一个进程,它会加载启动配置文件init.rc。init.rc包含了众多的系统配置服务,里面就包含了要启动Zygote进程的配置
采用fork+execve模式启动,pid为0是子进程;默认情况,创建子进程是继承了父进程的系统资源,但是调用了execve系统调用去加载另一个二进制程序的话,继承的父进程的系统资源就会被替换成加载的二进制程序
问题:启动进程有几种方式?
两种 : fork+handle / fork+execve
流程:
- 调用fork()函数
- 判断pid是不是等于0来确定当前进程是父进程还是子进程
补充:
- 父子进程判断:fork()函数获取pid,父进程返回的是子进程的pid,
- 信号处理--SIGCHLD : 父进程fork出子进程,如果子进程挂了,父进程会收到sigchld信号, 比如zygote进程挂了,init进程收到信号会重启zygote进程
问题:Zygote进程启动之后做了什么?
(一)先执行native函数
启动Android虚拟机->注册AndroidJNI函数->切换到java
主要:在app_main.cpp中执行main()函数,内部执行JNI_CreateJavaVM()创建虚拟机
补充:
创建虚拟机的位置在: AndroidRuntime.cpp
中的startVm
方法来启动虚拟机,startReg
来注册JNI函数,CallStaticVoidMethod(startClass, startMeth, strArray)
来调用ZygoteInit
类的main方法,启动java部分。
注意:
应用程序的虚拟机是继承Zygote进程的,然后再重置虚拟机的状态,再重启下虚拟机。
(二)切换到java后
- Preload Resources:为fork子进程时提供相关的类,主题相关的资源,共享库
- fork后,启动SystemServer
- 启动loop循环, 等待socket消息, 使用socket与SystemServer进行通信
用于AMS通信,参考android启动流程中的ZygoteState.connect(mSocket),这里会创建Socket链接,在接受到AMS跨进程发过来的消息后,会调用handleChildProc启动ActivityThread.main()方法,进入新的进程了
问题:Zygote fork为什么要单线程执行
Zygote里面有很多其他线程,为了保证状态一致,在fork子进程的时候,会停掉其他线程,在fork完成后,再恢复。可以理解为fork只能拷贝当前线程,不支持多线程的fork
Zygote的工作原理
问题:Zygote的IPC通信为什么不采用Binder?如果采用Binder的话会有什么问题?
Zygote的IPC通信使用的是Socket
Zygote的mian方法中会创建一个server端Socket(LocalSocket\LocalServerSocket),用于等待AMS请求Zygote来创建新的应用程序进程的,并且封装了TCP/IP协议,去掉网络相关。
原因:
- 为了避免父亲进程死锁、状态不一致等其他多线程问题,如果采用binder,在父进程binder线程有锁,然后子进程的主线程一直在等其子线程的资源,但是其实父进程的子进程并没有被拷贝过来,造成死锁,所以fork流程不允许存在多线程。而Binder通信是多线程的。
- 对于Zygote和SystemServer而言,Socket更加简单便捷,也符合单线程规范。
注意:
binder线程的初始化是在ServiceManger初始化的,而ServiceManger是Init进程孵化的,比Zygote进程更早,所以就不存在先后顺序问题。
问题:孵化应用进程为什么不交给SystemServer?而是专门设计一个Zygote?
因为效率问题,SystemServer里面会跑一些其他的服务,如果SystemServer来fork进程,可能造成资源污染,不适合继承。而Zygote进程专门设计来干这事的。
zygote启动总结
- init进程fork出zygote进程
- 启动虚拟机, 注册JNI函数
- 预加载系统资源
- 启动SystemServer
- 启动Socket Loop, 等待socket消息