一.系统启动
1.启动架构图
2.简要流程分析
1.BootRom->BootLoader->Kernel->Init->Zygote->SystemServer->Launcher
- 手机开机后,引导芯片启动,会运行固化在ROM中的预设代码,加载引导程序到Ram,BootLoader检查Ram,初始化硬件等参数;
- 硬件初始化之后,会进入到Kenerl,主要加载一些硬件驱动,初始化进程管理的操作,启动Swapper进进程(pid=0),用于初始化进程管理,内存管理、加载驱动等操作,在启动的Kthread,它是内核进程的鼻祖;
- kernel加载完后,硬件驱动和HAL层交互,初始化进程管理等操作启动INIT进程
- init进程启动后,会启动adbd、logd等用户进程,并且启动servicemanager进程、mediaserver进程、surfaceFlinger进程、Zygote孵化进程
- Zygote会加载虚拟机、预设资源、fork systemserver进程、开启serverSocket监听孵化请求等
- SystemServer进程会启动各种服务,将服务的BBinder添加到ServerManager中去,然后启动Launcher,
当然Launcher进程也是通过和Zygote交互孵化出来的进程,在通过AMS、WMS等将界面展现出来。
二.Init进程
1. 什么是init进程?
当android系统启动时,系统会经过BootLoader->Kernel->内核启动的第一个用户空间的进程,它就是init进程,我们可以通过adb shell ps查看,它的进程号pid是1,它的ppid是0,这也印证是内核进程创建了它。
2. init启动都干了啥?
init进程实际上也是一段可执行程序,他的代码路径是/system/core/init/init.cpp,它
会做一些挂载创建文件等操作,然后去读取init.rc,并执行这个任务清单,我们来看看init.rc里面都有哪些任务清单,源码目录:/system/core/rootdir/init.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc //启动Zygote进程的脚本
...
...
on post-fs
# Load properties from
# /system/build.prop,
# /odm/build.prop,
# /vendor/build.prop and
# /factory/factory.prop
load_system_props
# start essential services
start logd
start servicemanager //启动serviceManager进程,这个进程是用来管理各种系统服务的binder
start hwservicemanager
start vndservicemanager
3. init进程有什么用?
1.启动系统关键的服务(如打电话、网络、蓝牙、铃声等服务)
2.守护关键服务,如果其中一个关键服务被杀死,手机将会被重启
同样我们可以通过adb shell ps 通过查看进程id和ppid.可以看到他们之间的关系,
3.启动ServiceManager
我么也可以通过kill由init进程守护的进程,来看看是否他们会重启,
所以我们如果想实现一个系统服务不被杀死,最好的方式由init进程启动且称为关键服务。
二.Zygote服务的启动
1. zygote服务是怎么启动的?
由init进程启动,我们可以了解到,它启动时读取的init.rc脚本里面有一个就是启动zygote进程的执行代码init.{ro.zygote}.rc,{ro.zygote}理解它是一个占位符,它会根据系统类型分为32位和64位,我们来看看init.zygote.rc这个里面相关代码,代码路径:
/system/core/rootdir/
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
我们看第一行它首先执行/system/bin/app_process下面的main.c,并且传入相关参数,那么我们就来看看这个app_process这个代码,代码路径/frameworks/base/cmds/app_process/app_main.cpp
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME; //修改app_process进程名为Zygote
}...
}
...
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);//执行AndroidRuntime.cpp的start方法
}
...
我们可以看到原来Zygote进程本来叫app_process,是启动时改成了这个NICE_NAME。Zygote虽然是在Framework native中由C语言main入口执行的,但因为init进程是在用户空间,所以它也是在用户空间。
我们在来看看runtime.start(),这个里面干了什么,我们打开这段代码,他的目录是在/framework/base/core/jni/AndroidRuntime.cpp
JNIEnv* env; //启动jvm
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
if (startReg(env) < 0) { //注册jni
ALOGE("Unable to register all android natives\n");
return;
}
...
//开启java世界,反射执行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 */
}
...
通过上面的代码,我们可以看到,AndroidRuntime主要做了三件事情:
1.启动虚拟机(这里面可以对虚拟机进行调优)
2.动态注册java调用native中的jni(让我们可以在java层调用native方法)
3.反射调用ZygoteInit中的main方法(开启java世界)
2. ZygoteInit都在干什么?
我们通过上面知道,Zygote进程通过runtime开启了java世界,它执行了ZygoteInit中的main方法,我们来看看main方法中的代码,代码路径:/framework/base/core/java/com/android/internal/os/ZygoteInit
//创建serverSocket
ZygoteServer zygoteServer = new ZygoteServer();
...
//加载系统类、系统资源类
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
}
...
//创建systemserver
if (startSystemServer) {
startSystemServer(abiList, socketName, zygoteServer);
}
...
//开启ZygoteServerScoket循环,等待接收socket接收fork app进程的消息,没有消息就会阻塞休眠等待,为什么要循环?不循环进程就结束了额!!!
zygoteServer.runSelectLoop(abiList);
通过上面的代码,我们可以知道,main入口方法也主要做了三件事情。
1.预加载系统资源,如系统类、资源、系统共享库等
预加载的好处就是不需要每个app进程都去加载这个资源类,直接使用这些提前预加载好的类和资源
2.创建ZygoteServer,也就是ServerSocket,循环等待通知fork子进程!
首先我们要理解fork就是复制,Zygote fork进程就是在Zygote的基础上复制一个子进程,子进程拥有父进程处理好的资源。
3.创建SystemServer进程
SystemServer进程是Zygote创建的第一个子进程!!!
三.SystemServer进程
由上面我们知道SystemServer他是由Zygote进程通过启动Zygote进程通过ZygoteInit中的main方法调用startSystemServer启动的,我们来看看它的代码!
public static void main(String[] args) {
new SystemServer().run();
}
...
private void run(){
//->>>1.初始化SYstem Context
createSystemContext();
//system_server进程启动服务管理类
mSystemServiceManager = new SystemServiceManager(mSystemContext);
...
//启动引导服务
startBootstrapServices();
//启动核心服务
startCoreServices();
//启动其他服务
startOtherServices()
...
}
...
private void startBootstrapServices() {
// 启动ams服务
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
//启动pms服务
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
...
}
...
通过代码我们可以看到SystemServer其实就是启动一些引导服务、核心服务和其他服务,这些服务都运行在system_server进程中,而且这些服务也都运行在这个进程中,由于这些服务较多,所以用SystemServiceManager来管理这些服务。
1.孵化server进程简单梳理
孵化主要是通过native层进行,最终经过一些操作后反射执行SystemServer的main方法
2.服务启动简单分析
我们至少需要理清楚它的8个阶段,这个定义在SystemService代码中,源码路径是:base\services\core\java\com\android\server\SystemService.java,并且当阶段改变时,也会回调对应的service中的方法onBootPhase方法,这个是由SystemServiceManager中startBootPhase方法来调用,代码路径为:\services\core\java\com\android\server\SystemServiceManager.java
其中PHASE_BOOT_COMPLETED=1000,该阶段是发生在Boot完成和home应用启动完毕。系统服务更倾向于监听该阶段,而不是注册广播ACTION_BOOT_COMPLETED,从而降低系统延迟。
四.问题思考
1.Zygote进程的原始进程是什么?
原始进程叫app_process,它是在init启动时被启动的,在app_main.c被修改的
2.Zygote是在内核空间还是在用户空间?
当然是在用户空间拉,它是有init进程启动,而init也是在用户空间。
3.app进程的启动,为什么是从Zygote fork,而不是有init进程fork?
Zygote创建到启动,做了很多事情,比如创建虚拟机,注册jni,预加载等,fork进程就是复制,如果不在Zygote,那么创建新进程就要对上面的流程重新走一遍,如果从
Zygote去fork,app进程可以使用父进程的相关资源,不需要在处理。而init进程主要做的是挂在文件、解析init.rc脚本,启动其他进程。
4.Zygote为什么用socket而不是binder?
原因1:并发问题。假如使用binder,由于binder支持多线程,就有个并发问题,并发问题的处理方式就是加锁,加锁可能导致死锁,为什么会出现死锁?比如ams使用binder告知Zygote去fork一个app进程,为了保证不发生并发问题,就会获取对方的binder代理并加锁,Zygote去fork应用进程时把binder的锁状态也复制进去了,那么app进程的binder的锁谁来解?子进程没有解锁就会出现死锁!
原因2:时序问题。安卓中一般使用的binder引用,都是保存在ServiceManager进程中的,而如果想从ServiceManager中获取到对应的binder引用,前提是需要注册,而注册的行为是在对应的逻辑代码执行时才会去注册的。流程上,是Init产生Zygote进程和ServiceManager进程,然后Zygote进程产生SystemServer进程。如果AMS想通过binder向Zygote发送信号,必须向ServiceManager获取Zygote的binder引用,而前提是Zygote进程中必须提前注册好才行。而实际上,虽然Init进程是先创建ServiceManager,后创建Zygote进程的。虽然Zygote更晚创建,但是也不能保证Zygote进程去注册binder的时候,ServiceManager已经初始化好了。当然有人说,等ServiceManager完全初始化好再去注册不就好了吗?可当然可以了,但是什么时候才能可以注册呢?这个时间点无法保证,如果想保证就必须通过另外一种跨进程通讯的方式来保证,这样设计不就变得复杂了吗?还有人说,我Zygote启动后,延时10秒或者20秒再去向ServiceManager进程注册不就好了吗?这样做自然也是可以的,但是有没有考虑下,如果用户恰好在这期间点击了应用图标尝试去启动APP应该怎么办呢?岂不就是没有反应了吗?所以,AMS无法获取到Zygote的binder引用,是原因之一。
5.ServiceManager和SystemServiceManager的关系?
ServiceManager是一个独立的进程,它和Zygote一样,都是有init进程通过执行init.rc的脚本去启动的,它是管理system_server进程中各种服务binder的,而SysteServiceManager则是SystemerServer中对启动服务的集中管理。