一、基础概念理解
init进程
Android系统所有进程的祖先,是Android系统内核初始化完毕后,进入用户空间启动的第一个进程。
Android虚拟机
Dalvik虚拟机是谷歌自己设计的用于Android平台的虚拟机。Android4.4同时提供了Dalvik和ART虚拟机。Android5.0以后,Dalvik虚拟机彻底被删除,ART虚拟机取而代之。
Zygote
中文翻译为“受精卵、结合子”
Zygote是Android系统中,负责孵化所有其他应用进程的一个进程,Android系统是基于Linux内核的系统,所以Zygote进程是由Linux启动的用户级init进程创建的,Zygote是init进程的子进程,Zygote是一个java进程,负责启动Android虚拟机(Dalvik、ART)。
二、Android系统启动过程
第一步:BootLoader
BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。
第二步:Kernel
Kernel指的是操作系统内核Linux初始化及启动。
第三步:init进程启动
init进程是Android内核初始化之后创建并启动的第一个进程,是所有进程的父进程,init进程首先调用/system/core/init/init.cpp的main方法,该方法做了两件事:
(1),搭建系统运行环境,创建相关目录,设置相关路径和属性;
(2),解析rc配置文件,执行rc配置文件所要求的动作和命令
三、Zygote进程启动
1,init如何启动Zygote服务
(1)解析init.rc
init.cpp的main方法中其中有一句代码parser.ParseConfig("/init.rc");用来读取rc配置并执行init.rc位于/system/core/rootdir/init.rc
7 import /init.environ.rc
8 import /system/etc/init/hw/init.usb.rc
9 import /init.${ro.hardware}.rc
10 import /vendor/etc/init/hw/init.${ro.hardware}.rc
11 import /system/etc/init/hw/init.usb.configfs.rc
12 import /system/etc/init/hw/init.${ro.zygote}.rc
...
946 # It is recommended to put unnecessary data/ initialization from post-fs-data
947 # to start-zygote in device's init.rc to unblock zygote start.
948 on zygote-start && property:ro.crypto.state=unencrypted
949 wait_for_prop odsign.verification.done 1
950 # A/B update verifier that marks a successful boot.
951 exec_start update_verifier_nonencrypted
952 start statsd
953 start netd
954 start zygote
955 start zygote_secondary
956
957 on zygote-start && property:ro.crypto.state=unsupported
958 wait_for_prop odsign.verification.done 1
959 # A/B update verifier that marks a successful boot.
960 exec_start update_verifier_nonencrypted
961 start statsd
962 start netd
963 start zygote
964 start zygote_secondary
965
966 on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
967 wait_for_prop odsign.verification.done 1
968 # A/B update verifier that marks a successful boot.
969 exec_start update_verifier_nonencrypted
970 start statsd
971 start netd
972 start zygote
973 start zygote_secondary
/init.${ro.zygote}.rc会根据硬件实际的配置,选择导入32位还是64位。在Android12上有这几个选择:init.zygote32.rc,init.zygote64.rc,init.zygote64_32.rc
(2)启动Zygote服务
start zygote是启动Zygote服务的方式,所以Zygote服务就会被启动
Zygote服务就是下面配置文件中的服务【service zygote】
比如设备是64位的,则init启动的就是/system/core/rootdir/init.zygote64.rc配置文件中的【service zygote】
1 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
2 class main
3 socket zygote stream 660 root system
4 onrestart write /sys/android_power/request_state wake
5 onrestart write /sys/power/state on
6 onrestart restart audioserver
7 onrestart restart cameraserver
8 onrestart restart media
9 onrestart restart netd
10 writepid /dev/cpuset/foreground/tasks
综上所述,Zygote进程是Init进程通过解析init.rc过程中又去解析了init.zygote64.rc或者init.zygote32.rc配置文件,以Service的方式创建并启动
2,Zygote服务启动后,做了什么
上面的zygote service配置中,有一个重要选项/system/bin/app_process64,通过执行app_process来进入zygote进程。
app_process主要作用是解析启动参数,然后根据启动参数选择不同的启动模式
执行 /system/bin/app_process64命令之后,程序就会执行到/frameworks/base/cmds/app_process/,该目录下面就是可执行文件,该路径下有app_main.cpp,最终执行的就是app_main.cpp的main方法:
/system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
上面标红的是调用app_main.cpp的main()方法的入参,使用中间的空格符切割一下,得到5个值如下:
- /system/bin/app_process64
- -Xzygote
- /system/bin
- --zygote
- --start-system-server
下面的main()函数两个入参,int argc,char* const argv[],其中argc是传入参数的数目,这里应该等于5,argv是传入参数的值,就是上面这5个切割后的字符串
int main(int argc, char* const argv[])
{
...
//argc=5
// argv[0]="/system/bin/app_process64"
// argv[1]="-Xzygote"
// argv[2]="/system/bin"
// argv[3]="--zygote"
// argv[4]="--start-system-server"
argv[0]="/system/bin/app_process64"被传入runtime
//AppRuntime继承自AndroidRuntime,
//这里创建AppRuntime对象,main方法的操作都是通过这个runtime完成的
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
argc--;//执行此语句块后,argc=4
argv++;//argv[0]被忽略
// argc=4
// argv[1]="-Xzygote"
// argv[2]="/system/bin"
// argv[3]="--zygote"
// argv[4]="--start-system-server"
int i;
for (i = 0; i < argc; i++) {
if (argv[i][0] != '-') {//很明显遍历到argv[2]="/system/bin"时候直接break
break;
}
if (argv[i][1] == '-' && argv[i][2] == 0) {
++i; // Skip --.
break;
}
//只有argv[1]="-Xzygote"会走到这一步,再往后遍历直接break了
runtime.addOption(strdup(argv[i]));
}
//上一步又使用了一个参数argv[1]="-Xzygote"。忽略掉,所以代码走到这里还剩下三个参数
// argc=3
// argv[2]="/system/bin"
// argv[3]="--zygote"
// argv[4]="--start-system-server"
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
++i; // Skip unused "parent dir" argument.
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
// argv[3]="--zygote"满足条件,zygote=true,表示当前进程是zygote
zygote = true;
//static const char ZYGOTE_NICE_NAME[] = "zygote64";
//static const char ZYGOTE_NICE_NAME[] = "zygote";
niceName = ZYGOTE_NICE_NAME;//设置niceName为zygote64或者zygote
} else if (strcmp(arg, "--start-system-server") == 0) {
// argv[4]="--start-system-server",这里说明需要启动System Server
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
//设置后面调用ZygoteInit.java的main方法或者RuntimeInit.java的Main方法的参数
//这里的参数先是传给了Runtime的start方法,start方法里面又将其转成Java参数的
Vector<String8> args;
if (!className.isEmpty()) {
//非Zygote模式,这种情况可能是application模式或者tool模式
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);
} else {
//Zygote模式,这里可以证明后续调用ZygoteInit的main方法,会启动System Server服务
if (startSystemServer) {
args.add(String8("start-system-server"));
}
char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
ABI_LIST_PROPERTY);
return 11;
}
String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag);
// In zygote mode, pass all remaining arguments to the zygote
// main() method.
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
//niceName在参数解析时被设置。此处变更了app_process启动的进程名为zygote。
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string());
set_process_name(niceName.string());
}
//runtime.start启动Android运行环境
if (zygote) {
//com.android.internal.os.ZygoteInit是Android Java运行时环境的初始化类,
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
//非Zygote模式,则执行RuntimeInit.java的main方法
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
return 10;
}
}
app_main.cpp的main方法,主要做了三件事儿:
- 初始化AndroidRuntime;
- 解析main函数的参数,判断当前是不是Zygote模式;
- 根据是否是Zygote模式,调用AndroidRuntime的start方法传入不同的参数
app_process是c++本地程序,源码目录为 frameworks/base/cmds/app_process/
app_process是可以执行java代码的命令(因为它启动了一个java虚拟机),它有两种启动模式:
1.zygote 模式:通常情况下,在–start-system-server启动参数的配置下,app_process启动之后,直接fork system_server 子进程,拉起整个android系统,之后用来孵化apk进程
2.非zygote模式:分两种子模式
(1).application模式:这种模式是zygote 创建进程后通过shell来重新加载app_process命令再执行的
(2).tool模式:这个模式主要是用来执行调试命令(如am\pm\wm等等)
AppRuntime继承自AndroidRuntime,AndroidRuntime的start方法,我们暂且先看下它的注释吧:
启动Android运行时。这涉及到启动虚拟机并在类中调用“static void main(String[] args)”方法由“className”命名。
传递给main函数两个参数,类名和指定的选项字符串。
/frameworks/base/core/jni/AndroidRuntime.cpp的start方法
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;
//startVm 创建、启动虚拟机,并且设置相关参数。Dalvik或者ART虚拟机
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
return;
}
onVmCreated(env);
/*
*向虚拟机注册Android JNI native函数,(系统so库,用户自定义so库,加载函数等)
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
//给接下来要调用的java main方法准备参数
//非常经典的在Native层创建Java层对象的操作:
//创建一个java.lang.String的数组对象
//并根据传入的参数对数组对象逐个元素进行赋值
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);
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);
}
....
//找到传进来的类的main方法,比如ZygoteInit的main方法
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
//通过JNI技术调用main方法
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
...
}
综上所述,AndroidRuntime.star方法,主要做了三件事儿:
- 创建、启动了Android虚拟机;
- 向虚拟机注册了Android JNI native函数;
- 利用JNI技术调用了参数传进来的className对应类的main()函数。
如果不考虑非Zygote模式,那么Zygote服务的启动,执行app_main.cpp的main方法
而app_main.cpp的main方法做了四件事:
- 创建、启动了Android虚拟机;
- 向虚拟机注册了Android JNI native函数;
- 准备Java类的main方法的参数
- 利用JNI技术调用了ZygoteInit的main()方法。
下面就要分析ZygoteInit了
3,执行ZygoteInit.java的main方法
ZygoteInit:负责Zygote进程Java层的初始化工作
public static void main(String argv[]) {
//创建Zygote服务管理类,用来注册Socket监听
ZygoteServer zygoteServer = new ZygoteServer();
//这里主要目的是拦截创建线程,
//调用了这句代码以后,标记着Zygote进程开始Java层的初始化工作
//如果此时创建线程会产生错误
ZygoteHooks.startZygoteNoThreadCreation();
// 将Zygote设置进他自己的进程组
try {
//将参数pid指定进程所属的组识别码设为参数pgid指定的组识别码。
//Os.setpgid(int pid, int pgid)
//pid=0表示设置当前进程所在的组的进程组pgid
//pgid=0表示当前进程的PID为进程组pgid
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
final Runnable caller;
try {
// Report Zygote start time to tron unless it is a runtime restart
...日志打印
//启动DDMS虚拟机监控调试服务
RuntimeInit.enableDdms();
//参数解析
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
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)) {
//abi类型,"--abi-list="这个参数也是传经来的
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
//解析Socket name
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {//未知参数
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
//没有指定ABI参数会抛异常
if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}
//注册Zygote的Socket服务端,用来监听接收启动应用程序的消息,这里的IPC不是Binder通信
zygoteServer.registerServerSocketFromEnv(socketName);
// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {//没有延迟加载
...
//执行预加载操作,包括系统预加载类,FrameWork资源,OpenGL资源
preload(bootTimingsTraceLog);
...
} else {//有延迟加载
//重置线程优先级,设置为默认的Thread.NORM_PRIORITY
Zygote.resetNicePriority();
}
...
//运行几个指定的GC,尝试清除几代的软引用和可达的对象,以及任何其他垃圾。
//这只在fork()之前有用。强制进行了一次垃圾收集
gcAndFinalize();
...
//在fork之前调用一些安全初始化操作
Zygote.nativeSecurityInit();
//将整体的的存储目录/storage卸载,取而代之的是挂载临时目录,
//这个动作和Android的沙箱(隔离存储)有关
Zygote.nativeUnmountStorageOnInit();
//呼应前面的ZygoteHooks.startZygoteNoThreadCreation()方法
//告诉虚拟机,现在可以创建县城了
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) {//启动systemServer进程
//这里的forkSystemServer方法导致进程进程发生了fork,也就是孵化裂变
//从Zygote进程变成了Zygote和systemserver两个进程,fork会导致堆栈段的复制
//进程会切换执行,涉及到CPU的切换,上下文的切换导致两个进程代码执行都停留在fork函数
//两个进程都执行到fork函数等待返回,因此fork函数我们看代码是两次返回。
//实际上fork函数的两次返回,是在两个进程中进行的:
//先是在父进程中返回了被fork出来的子进程的pid
//CPU执行切换到子进程之后因为在没有fork子进程,所以返回了0
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
//如果r=null,说明当前代码在Zygote进程中执行,直接跳过
if (r != null) {
//如果r!=null,说明当前代码在子进程(systemserver)中执行
//启动进程后返回
//因为Runnable的run方法实际上包装了SystemServer的main方法,所以这里会运行main方法
r.run();
return;
}
}
//走到这一步,代码没有返回,说明这里的代码是在Zygote进程中执行的,
//因为如果是孵化的子进程的话,走不到这一步代码就return了
//此处进入一个无限循环,处理Zygote Socket接收到的数据,
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
//关闭释放Sockte连接
//这里的代码主要是给子进程调用的,因为Zygote进程在runSelectLoop中无限循环阻塞了,
//正常情况不会执行到这
//子进程是由Zygote这个父进程fork出来的,所以也会附带有Socket连接,
//但是子进程不需要Zygote的Socket服务,这里保证关闭
zygoteServer.closeServerSocket();
}
//我们在子进程中并退出了select循环。继续执行命令。
if (caller != null) {
caller.run();
}
}
(1)registerServerSocketFromEnv注册Zygote的Socket服务
void registerServerSocketFromEnv(String socketName) {
...
//这里的socketName来源于上面的main函数zygote
//所以最终fullSocketName=ANDROID_SOCKET_zygote
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
...
//找到名称为ANDROID_SOCKET_zygote的环境变量
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
...
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
//创建一个本地socket服务,赋值给全局变量mServerSocket
mServerSocket = new LocalServerSocket(fd);
...
}
注意上面的这句代码:
String env = System.getenv(fullSocketName);
获取进程中名字为ANDROID_SOCKET_zygote的环境变量,那么这个环境变量是什么时候写进去的呢?我们前面分析/system/core/rootdir/init.rc时候讲到,他会解析/system/core/rootdir/init.zygote64.rc这个配置文件,init.zygote64.rc里面有这样一句socket zygote stream 660 root system,init进程在解析到这句配置的时候,会创建一个Socket fileDesc(简称socket fd)也就进程独有的文件描述符并且与ANDROID_SOCKET_zygote这个名字绑定,然后将socket名字(ANDROID_SOCKET_zygote)和socket fd注册到init进程的环境变量里面。其他进程都是init进程的子进程,可以通过System.getenv("ANDROID_SOCKET_zygote")获取到这个环境变量。
我们感兴趣的可以看下某 socket fd长什么样子?如下:
root@ubuntu:~# ll /proc/1583/fd
total 0
lrwx------ 1 root root 64 Jul 19 12:37 7 -> socket:[18892]
lrwx------ 1 root root 64 Jul 19 12:37 8 -> socket:[18893]
LocalSocket是Google为我们带来的,比Java的socket效率更高,没有经过协议栈,是Android自己实现的类似共享内存一样的东西,在传输大量数据的时候就需要用到。
(2)preload预加载
Android的Java进程都是通过Zygote进程fork的,Zygote通过预加载类和资源可以加快子进程的执行速度和内存优化,因为预加载的类和资源比较多,所以开机时也需要重点关注preload的耗时。
static void preload(TimingsTraceLog bootTimingsTraceLog) {
//设置软引用保护,避免在预加载期间创建的引用被GC回收
beginIcuCachePinning();
//预加载系统类
//读取设备本地/system/etc/preloaded-classes文件,解析该文件,
//通过反射技术加载文件中声明的所有类,不同的手机厂商定义的类数量有差异,
//有时需要加载数千个类,这也是设备启动慢的原因之一
//Android12中preloaded-classes的源码在/frameworks/base/config/preloaded-classes
preloadClasses();
//预加载系统资源
//com.android.internal.R.array.preloaded_drawables
//com.android.internal.R.array.preloaded_color_state_lists
//Android系统有一个framework-res.apk包,这些系统资源就是存在这个当中
//Android应用可以使用这些公共资源
preloadResources();
//调用native方法加载HAL(硬件抽象层)代码
//所谓HAL硬件抽象层
nativePreloadAppProcessHALs();
加载OpenGL资源
preloadOpenGL();
//加载一些so库:libandroid.so、libcompiler_rt.so、libjnigraphics.so
preloadSharedLibraries();
//加载字体资源
preloadTextResources();
//要求WebViewFactory所有初始化必须在Zygote进程中进行
WebViewFactory.prepareWebViewInZygote();
//与前面的beginIcuCachePinning()呼应,取消软引用保护
endIcuCachePinning();
//初始化JCA相关参数
warmUpJcaProviders();
sPreloadComplete = true;
}
Zygote进程启动时候预加载了不少资源,那么后续Zygote在fork新进程的时候,采用了COW(copy-on-write)技术,即写时拷贝技术。当App通过fork创建的时候,为了节省开销、加快应用启动,Zygote fork子进程不进行内存复制,而是共享Zygote进程预加载的系统类和系统资源,只有当子进程需要修改共享资源时,才会将共享内存复制到自己的进程内做修改。
(3)forkSystemServer孵化systemserver进程并启动
SystemServer是Android基本服务的提供者,是Android系统运行的最基本需求,所有Service运行在一个叫system_server的进程中,system_server为Android系统提供了各种Service。system_server进程是Android Java虚拟机中第一个进程,可以说整个Android系统的业务都是system_server展开的。
forkSystemServer方法,为孵化SystemServer进程准备参数,并且fork出systemServer进程
注意,forkSystemServer方法因为是fork新的进程出来,新进程代码也会执行到forkSystemServer方法,这就会导致Zygote进程、system_server进程一起从fork函数返回。如果方法是在Zygote进程中执行的,则返回被fork出的SystemServer进程的Runnable对象;如果方法是在SystemServer进程中执行的,则因为其没有继续fork子进程,所以没有需要执行的Runnable任务,返回null
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
...
//参数准备
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",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
//参数解析,生成目标函数
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
boolean profileSystemServer = SystemProperties.getBoolean(
"dalvik.vm.profilesystemserver", false);
if (profileSystemServer) {
parsedArgs.runtimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
}
//这里是重点,fork出system_server进程,并运行system_server进程
//fork动作会产生一个新的与Zygote一样的新的进程,并且云心新进程,
//这样就导致了Zygote进程与system_server两个进程CPU执行权切换,
//两个进程都停留在fork方法等待返回,两个fork方法是在两个进程中运行的,自然分别有对应返回值。
//当fork方法运行在Zygote进程中时候,则返回其fork出子进程的pid,也就是system_server的pid;
//当fork方法运行在system_server进程中时候,因为其没有继续fork的子进程,所以返回0
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.runtimeFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
//走到这里说明当前代码运行在system_Server进程当中
if (hasSecondZygote(abiList)) {
//如果设备同时配置了两个Zygote进程,那么这里等待第二个Zygote进程
//这里主要是一些设备配置了init.zygote32_64.rc或者init.zygote64_32.rc
//这样就会启动两个Zygote进程,一个为主,一个为次
waitForSecondaryZygote(socketName);
}
//子进程是由Zygote孵化出来的,所以也具备了zygoteServer的Socket服务
//但是子进程用不到,所以直接关闭
zygoteServer.closeServerSocket();
//handleSystemServerProcess方法的作用:
//利用反射技术找到SystemServer的main函数,并将这个函数包装到Runnable的run方法中
//返回包装后的Runnable对象
return handleSystemServerProcess(parsedArgs);
}
return null;
}
(4)zygoteServer.runSelectLoop进入循环阻塞等待for新进程的请求
Zygote进程会启动一个Socket本地服务,等待Socket客户端连接请求,当新的App启动的时候,就会请求zygote server服务fork新的进程。
zygoteServer.runSelectLoop会进入循环阻塞等待,等待处理启动新应用的请求,一旦收到请求会fork新的进程出来。
与上面的forkSystemServer一个道理,Zygote在fork新的进程,就会造成新老进程的runSelectLoop方法都执行但是返回值不同。当在子进程中时,会跳出runSelectLoop的循环,返回Runnable对象,也就是说在子进程中是不存在阻塞的,Zygote进程会保持阻塞监控新的连接请求
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
//执行完下面这句代码,表示fds中只有一个元素,那就是mServerSocket
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
//每次循环都会动态创建新的pollFds
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.pull是Linux系统的一个处理文件描述符的方法,等待文件描述符上的某个事件,I/O服用机制
//监听pollFds数组中的事件,当pollFds有事件到来就往下执行
//这里的-1表示当没有事件到来时一直阻塞,
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
//代码走到这里说明上面的poll阻塞方法有返回了,也就是pollFds有数据到来了
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
//采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;
//否则进入continue,跳出本次循环。
continue;
}
if (i == 0) {
//fds[0]是mServerSocket
//Socket服务端是LocalServerSocket,Socket客户端应该是LocalSocket
//acceptCommandPeer方法就是给mServerSocket创建了一个与之连接的LocalSocket客户端
//ZygoteConnection内部分装了LocalSocket客户端
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
//将通信对象添加到fds
fds.add(newPeer.getFileDesciptor());
} else {
//这里就是遍历到了上面新添加的Socket通信对象
try {
ZygoteConnection connection = peers.get(i);
//processOneCommand会读取参数并且fork新的子进程及相关操作
//因为这里最终会是fork操作,所以同样的会造成父进程子进程都运行这段代码
//当在子进程中运行,则command不为空,Zygote中command为空
final Runnable command = connection.processOneCommand(this);
if (mIsForkChild) {
//已经fork了子进程,并且当前代码运行在子进程
if (command == null) {
//保证fork子进程后必须有command返回
throw new IllegalStateException("command == null");
}
//在子进程中,返回command
return command;
} else {
if (command != null) {
//保证父进程不能存在command
throw new IllegalStateException("command != null");
}
//Zygote进程,完成了子进程的fork后,应该关闭本次的Socket连接,并清除该连接
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
} catch (Exception e) {
if (!mIsForkChild) {
//发生异常后清除操作
ZygoteConnection conn = peers.remove(i);
conn.closeSocket();
fds.remove(i);
} else {
Log.e(TAG, "Caught post-fork exception in child process.", e);
throw e;
}
} finally {
//每次处理完客户端请求后,保证mIsForkChild为false
mIsForkChild = false;
}
}
}
}
}
下面看下connection.processOneCommand(this)方法的源码
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
//读取参数
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
throw new IllegalStateException("IOException on command socket", ex);
}
...
//解析参数
parsedArgs = new Arguments(args);
if (parsedArgs.abiListQuery) {
handleAbiListQuery();
return null;
}
if (parsedArgs.preloadDefault) {
handlePreload();
return null;
}
if (parsedArgs.preloadPackage != null) {
handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs,
parsedArgs.preloadPackageLibFileName, parsedArgs.preloadPackageCacheKey);
return null;
}
if (parsedArgs.apiBlacklistExemptions != null) {
handleApiBlacklistExemptions(parsedArgs.apiBlacklistExemptions);
return null;
}
if (parsedArgs.hiddenApiAccessLogSampleRate != -1) {
handleHiddenApiAccessLogSampleRate(parsedArgs.hiddenApiAccessLogSampleRate);
return null;
}
if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
throw new ZygoteSecurityException("Client may not specify capabilities: " +
"permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
}
//参数检查和设置
// 检查客户端手有权限指定进程的用户ID、组ID
// 如果是 root 进程,可以任意指定
// 如果是 sys 进程,需要在ro.factorytest值 > 0时可以指定
applyUidSecurityPolicy(parsedArgs, peer);
// 判断是否具有invoke-with的执行权限
applyInvokeWithSecurityPolicy(parsedArgs, peer);
// 如果ro.debuggable是1的话,启动JDWP协议
applyDebuggerSystemProperty(parsedArgs);
// 如果ro.debuggable是1的话,启动JDWP协议
applyInvokeWithSystemProperty(parsedArgs);
...
//fork子进程,fork方法孵化子进程后,与Zygote进程都会运行并返回值
//当前代码运行在Zygote进程中时,返回的pid就是fork得到的子进程的pid
//当前代码如果运行在子进程中,则pid=0
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);
try {
if (pid == 0) {
//当前处于子进程中
zygoteServer.setForkChild();
//子进程由Zygote进程fork出来,所以也具备了zygoteServer,但是不需要,所以关闭
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
//在子进程中完成子进程的初始化工作
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
} else {
//fork完子进程后,父进程中处理一些关闭及清理的工作
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
我们来看下fork出子进程之后,子进程是如何完成初始化的操作的,handleChildProc方法源码如下
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) {
//关闭本次操作的Socket连接
closeSocket();
...
if (parsedArgs.invokeWith != null) {
//启动参数有--invoke-with
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 {//通常情况下--invoke-with参数为空,所以代码会进入这里
if (!isZygote) {
//很显然当前是在子进程运行而非Zygote进程中,所以代码执行这里
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
null /* classLoader */);
} else {
return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
}
我们进入ZygoteInit.zygoteInit方法
public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
...
//一些通用的简单初始化
RuntimeInit.commonInit();
//调用了一个本地native方法,最终调用了我们前面提到的AndroidRuntime的子类AppRuntime的onZygoteInit()方法
//初始化binder的使用环境
ZygoteInit.nativeZygoteInit();
//这里最终调用了RuntimeInit.findStaticMain方法
return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
classLoader);
}
我们先来看一下AppRuntime的onZygoteInit()方法的源码,源码在app_main.cpp的AppRuntime下面
virtual void onZygoteInit(){
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
这个onZygoteInit主要就是用来初始化Binder的使用环境
我们最后看下RuntimeInit.findStaticMain方法,其实这个方法在前面forkSystemServer中也用过这个方法,findStaticMain方法,会将参数传入的className通过反射的技术,找到其main方法,并且包装到Runnable的run方法中返回
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);
}
...
return new MethodAndArgsCaller(m, argv);
}
static class MethodAndArgsCaller implements Runnable {
private final Method mMethod;
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
...
mMethod.invoke(null, new Object[] { mArgs });
...
}
}
而我们这里,handleChildProc方法,最终返回的MethodAndArgsCaller(Runnable的子类),实际上是利用反射技术将android.app.ActivityThread的main()方法封装到Runnable的run()方法里面。而ActivityThread的main方法正式整个App入口。
(5)caller.run()子进程调用App启动入口方法ActivityThread.main
我们回顾一下ZygoteInit.main方法的最后处理逻辑
public static void main(String argv[]) {
...
final Runnable caller;
try {
...
if (startSystemServer) {//启动systemServer进程
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
if (r != null) {
r.run();
return;
}
}
//如果当前代码运行在Zygote进程,则返回null
//如果当前代码运行在子进程,则返回caller
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
zygoteServer.closeServerSocket();
}
//根据前面的讲解,我们能够知道Zygote在fork进程时会发生两个进程各自运行同一处代码,
//根据桑上面的runSelectLoop方法会将Zygote进程处于阻塞状态,无限循环等待Socket客户端
//发起请求,比如App的启动会出发zygoteServer与Zocket客户端连接,然后fork出App的进程
//当代码运行在App进程(子进程)中时,将会跳出阻塞,返回caller,Zygote父进程继续保持
//阻塞监听。
if (caller != null) {
//执行到这一步,我们可以确定当前代码运行在子进程,此处的run方法运行的就是ActivityThread
//的main方法。
caller.run();
}
}
4,Android如何利用Zygote启动一个新进程
Android启动一个新的进程都是在ActivityManagerService(简称AMS)中完成的,可能会有很多原因导致系统启动一个新的进程,最终在AMS中都是通过调用startProcess()方法来实现。
通过查看ActivityManagerService.startProcess的源码,找到了关键的代码,最终调用了ZygoteProcess类的一个私有方法startViaZygote()方法,我们重点看下startViaZygote的关键代码
private Process.ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
boolean startChildZygote,
String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
argsForZygote.add("--runtime-flags=" + runtimeFlags);
if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
argsForZygote.add("--mount-external-default");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
argsForZygote.add("--mount-external-read");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
argsForZygote.add("--mount-external-write");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
if (instructionSet != null) {
argsForZygote.add("--instruction-set=" + instructionSet);
}
if (appDataDir != null) {
argsForZygote.add("--app-data-dir=" + appDataDir);
}
if (invokeWith != null) {
argsForZygote.add("--invoke-with");
argsForZygote.add(invokeWith);
}
if (startChildZygote) {
argsForZygote.add("--start-child-zygote");
}
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
//关键代码就是这一句
//1,openZygoteSocketIfNeeded会创建与Zygote进程ServerSocket的连接
//2,zygoteSendArgsAndGetResult会将进程启动的参数发送给Zygote进程,fork出新进程后会将进程的pid返回
synchronized(mLock) {
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
openZygoteSocketIfNeeded方法源码
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
//与Zygote的Socket服务建立连接
primaryZygoteState = ZygoteState.connect(mSocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
...
}
...
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
//针对一些设备配置了init.zygote32_64.rc或者init.zygote64_32.rc
//需要与另一个Zygote的Socket服务建立连接
secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
...
}
...
}
ZygoteState的connect方法
public static ZygoteState connect(LocalSocketAddress address) throws IOException {
...
final LocalSocket zygoteSocket = new LocalSocket();
...
try {
zygoteSocket.connect(address);
...
} catch (IOException ex) {
try {
zygoteSocket.close();
} catch (IOException ignore) {
}
throw ex;
}
...
return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
Arrays.asList(abiListString.split(",")));
}
zygoteSendArgsAndGetResult方法源码
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
...
//输出流,参数写入给Zygote
final BufferedWriter writer = zygoteState.writer;
//输入流,从Zygote进程读取fork得到的新进程
final DataInputStream inputStream = zygoteState.inputStream;
writer.write(Integer.toString(args.size()));
writer.newLine();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);
writer.newLine();
}
//App启动参数写入发送
writer.flush();
//fork子进程后读取新的进程
Process.ProcessStartResult result = new Process.ProcessStartResult();
result.pid = inputStream.readInt();
result.usingWrapper = inputStream.readBoolean();
...
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}
四、总结
Android系统启动流程,前两步我们简单说明下
1,BootLoader
BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境;
2,Kernel
Kernel指的是操作系统内核Linux初始化及启动;
3,init进程启动
硬件初始化、内核初始化及启动之后,init将会启动
init进程启动先调用了init.cpp中的main()方法,init.cpp的main()方法中有这样一句代码:parser.ParseConfig("/init.rc"),解析init.rc文件,init.rc文件中有zygote start等启动zygote的命令,而且有导入zygote配置的语句import /system/etc/init/hw/init.${ro.zygote}.rc,$(ro.zygote).rc这个引用具体会指向设备具体的配置文件,配置文件按照不同的硬件厂商目前有3种:
init.zygote32.rc、init.zygote32_64.rc、init.zygote64.rc,这三种文件决定了启动32位还是64位的Zygote服务。不过这几个文件中第一行配置就是service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server这一句,service zygote意思是Zygote进程是以Service服务的方式启动,所以会先启动一个Zygote service服务,/system/bin/app_process64表示回去执行app_process,最终会去执行app_main.cpp中的main方法,并且会将下面的参数传给app_main.cpp的main方法:
- /system/bin/app_process64
- -Xzygote
- /system/bin
- --zygote
- --start-system-server
app_main.cpp的main方法,主要干了三件事:
- 初始化AndroidRuntime的子类:AppRuntime;
- 解析main函数的参数,判断当前是不是Zygote模式;
- 根据是否是Zygote模式,调用AndroidRuntime的start方法传入不同的参数
AndroidRuntime的start方法主要做三件事
- 创建、启动了Android虚拟机;
- 向虚拟机注册了Android JNI native函数;
- 利用JNI技术调用了参数传进来的className对应类的main()函数
我们上面的分析,传给start方法的className是ZygoteInit,所以最终会调用ZygoteInit的main方法
我的理解是Zygote进程在上面的init解析init.zygote.rc配置文件后,以service的方式启动了。所以在调用ZygoteInit.java的main方法之前,Zygote进程已经启动了
ZygoteInit的main方法是通过Zygote进程去调用的,总结一下ZygoteInit.java的main方法做了什么:
- ZygoteHooks.startZygoteNoThreadCreation()拦截线程创建;
- Os.setpgid(0, 0)将Zygote设置进他自己的进程组;
- RuntimeInit.enableDdms()启动DDMS虚拟机监控调试服务;
- 解析AndroidRuntime传进来的参数;
- zygoteServer.registerServerSocketFromEnv(socketName)创建注册本地LocalServerSocket服务,用来与后面的客户端LocalSocket通信,注意这里并不是Binder通信;
- preload预加载,包括预加载系统类、Framwork资源、OpenGL等;
- gcAndFinalize在执行fork之前,做一次GC垃圾回收;
- Zygote.nativeSecurityInit()在fork之前调用一些安全初始化操作;
- Zygote.nativeUnmountStorageOnInit()将整体的的存储目录/storage卸载,取而代之的是挂载临时目录,这个动作和Android的沙箱(隔离存储)有关;
- ZygoteHooks.stopZygoteNoThreadCreation()呼应前面的ZygoteHooks.startZygoteNoThreadCreation()方法告诉虚拟机,现在可以创建线程了;
- Runnable r = forkSystemServer fork出system_server进程。如果当前代码执行在system_server进程中,则返回的Runnable不为空,继续执行run方法之后return,这里的run方法就是SystemServer的main方法;如果当前代码执行在Zygote进程中,则Runnable为空,跳过run方法。
- caller = zygoteServer.runSelectLoop,当前代码执行在Zygote进程中则代码进入阻塞无线循环,等待并且等待Socket发起的请求,如果有新的进程要创建启动,则Zygote会fork出新的进程。此时,如果代码运行在Zygote进程中,则继续保持阻塞,等待下一次请求;如果代码运行在子进程,则return跳出runSelectLoop方法,返回caller,意味着子进程跳出阻塞。
- caller.run();这是main方法的最后一步,只有跳出阻塞的子进程才会走到这一步,这里的run方法与上面的forkSystemServer原理一样,都是利用反射技术,将某一个类的main方法封装到Runnable的run方法中,这里封装的是ActivityThread的main方法。
五、题外,为什么Zygote进程与其子进程的通信采用的是Socket而非Binder
(133条消息) android中AMS通知Zygote去fork进程为什么使用socket而不使用binder?_失落夏天的博客-CSDN博客_安卓socke zygote