一、Zygote的启动
1.1 启动进程的方式
- fork + handle
- fork + execve
pid 子进程返回的pid是0 父进程返回的pid是子进程的pid。
信号处理:==SIGCHLD==
当子进程挂了之后父进程就会收到这个信号,然后父进程就会做一些处理,比如释放资源或者重新fork子进程。
2.1 Zygote启动
2.1.1 Zygote的native层
- 启动Android虚拟机
- 注册Android的JNI函数
- 利用JNI调用ZygoteInit的main函数 进入java层面
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
/* start the virtual machine */第一步
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {//1
return;
}
//这个时候env里面就有值了
onVmCreated(env);
if (startReg(env) < 0) {//2 这里是第二步 注册JNI函数
ALOGE("Unable to register all android natives\n");
return;
}
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
//创建数组
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
//从app_main的main函数得知className为com.android.internal.os.ZygoteInit
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
assert(optionsStr != NULL);
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
//找到ZygoteInit的main函数
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");//3 第三步
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
//通过JNI调用ZygoteInit的main函数 进入java世界
env->CallStaticVoidMethod(startClass, startMeth, strArray);//4
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
...
}
2.1.2 Zygote的Java层
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
...
try {
...
//注册Zygote用的Socket 创建服务端的socket
registerZygoteSocket(socketName);//1
...
//预加载类和资源
preload();//2
...
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}
Log.i(TAG, "Accepting command socket connections");
//等待客户端请求
runSelectLoop(abiList);//4
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
//创建server端的socket name 为zygote
void registerServerSocket(String socketName) {
if (mServerSocket == null) {
...
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
mServerSocket = new LocalServerSocket(fd);
} catch (IOException ex) {
}
}
小结:
- 创建server端的socket
- ==预加载== 这里是加载一些给应用进程共享的一些资源,也就是==系统资==源(sdk中大部分类和资源文件),应用进程只需要加载自己的资源就可以了。
- forkSystemServer 创建SystemServer进程
- 开启loop 等待AMS来请求
启动SystemServer
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
//启动Binder进程
ZygoteInit.nativeZygoteInit();
//从native层启动SystemServer
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
进入SystermServer的main方法
void main(){
// Initialize native services
System.loadLibrary("android_servers");
// Check whether we failed to shut down last time we tried.
// This call may not return.
performPendingShutdown();
// Initialize the system context.
createSystemContext();
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Prepare the thread pool for init tasks that can be parallelized
SystemServerInitThreadPool.get();
} finally {
traceEnd(); // InitBeforeStartServices
}
// Start services.启动一些系统服务
startBootstrapServices();
startCoreServices();
startOtherServices();
}
SystemServer启动总结:
- 启动Binder线程池
- 创建SystemServiceManager 用于管理系统服务
- 启动系统各种服务(AMS就在这里启动)
==两个细节==:
- Zygote fork进程要在单线程中进行,否则容易造成死锁和资源不一致
- Zygote里面的通信是采用的LocalSocket
两个问题:
==问题一==:fork进程的任务为什么不交给SystermServer进程,而是单独交给Zygote进程?
我们知道,应用在启动的时候需要做很多准备工作,==包括启动虚拟机,加载各类系统资源等等,这些都是非常耗时的==,==如果能在zygote里就给这些必要的初始化工作做好,子进程在fork的时候就能直接共享,那么这样的话效率就会非常高。这个就是zygote存在的价值==,这一点呢SystemServer是替代不了的,主要是因为SystemServer里跑了一堆系统服务,这些是不能继承到应用进程的。而且我们应用进程在启动的时候,内存空间除了必要的资源外,最好是干干净净的,不要继承一堆乱七八糟的东西。所以呢,不如给SystemServer和应用进程里都要用到的资源抽出来单独放在一个进程里,也就是这的zygote进程,然后zygote进程再分别孵化出SystemServer进程和应用进程。孵化出来之后,SystemServer进程和应用进程就可以各干各的事了。
==问题二==:为什么Zygote的IPC不采用Binder机制?
第一个原因,我们可以设想一下采用binder调用的话该怎么做,首先zygote要启用binder机制,需要打开binder驱动,获得一个描述符,再通过mmap进行内存映射,还要注册binder线程,这还不够,还要创建一个binder对象注册到serviceManager,另外AMS要向zygote发起创建应用进程请求的话,要先从serviceManager查询zygote的binder对象,然后再发起binder调用,这来来回回好几趟非常繁琐,相比之下,zygote和SystemServer进程本来就是父子关系,对于简单的消息通信,用管道或者socket非常方便省事。第二个原因,如果zygote启用binder机制,再fork出SystemServer,那么SystemServer就会继承了zygote的描述符以及映射的内存,这两个进程在binder驱动层就会共用一套数据结构,这显然是不行的,所以还得先给原来的旧的描述符关掉,再重新启用一遍binder机制,这个就是自找麻烦了。==第三:zygote fork进程要在单线程中进行,而Binder恰好是多线程的==。
面试题:==谈谈你对Zygote进程的理解==
我们采用三段式去回答,这也是回答问题的套路
- ==What== :zygote的作用是什么?
- ==How==:zygote的启动流程?
- ==Why==:zygote的启动原理?