Android系统总体启动流程
Boot ROM
(启动只读存储器,Loader层
)当电源按下时
,引导芯片代码会从预定义的地方(固化在ROM中,Read Only Memory)开始执行,加载引导程序BootLoader到RAM(Random Access Memory),然后执行
Boot Loader
(启动加载器,类似于Windows的bios系统,Loader层
)- 引导操作系统启动
idle
进程(pid=0,process id) (Kernel层
)- 这是Android的第1个进程,也叫swapper进程
- 初始化进程管理、内存管理,加载Binder Driver、Display、Camera Driver等相关工作
- 启动
kthreadd
进程(pid=2,这个是Kernel层
的进程)和init进程(pid=1,这个是native层
的进程)
init
(pid=1) (C/C++ FrameworkNative层
)用户空间
的鼻祖,用户空间的进程都是由init进程或其子孙进程创建而来的
zygote
进程 (少部分Native
层和大部分Java Framework层
)Java进程
的鼻祖,Java层的进程都是通过zygote创建的- 我们的进程一般都是通过zygote fork出来的,
比如:要启动我们的app进程,是通过SystemServer进程中的AMS服务,去通知zygote进程fork出我们的app进程
SystemServer
进程 (Java Framework层
)- 系统服务有90多种,如:AMS、WMS、PMS等
App
进程 (App层
)
init进程的启动
首先,init进程是由idle进程启动的,而idle进程是属于kernel层的,所以我们从kernel层去寻找启动init进程的地方.
代码执行流程:(kernel\common\init\main.c
)
- android-kernel\common\init\main.c 找到kernal层init进程的main.c文件
- -> kernel_init()
- -> try_to_run_init_process(“/bin/init”) //这里就是启动我们手机系统中的init进程
- -> run_init_process()
- -> kernel_execve()
init的入口函数:(system/core/init/main.cpp
)
- init/main.cpp文件下的main()函数,下面是这个main()函数中的几个步骤.
-
if (argc > 1) { if (!strcmp(argv[1], "subcontext")) { android::base::InitLogging(argv, &android::base::KernelLogger); const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap(); return SubcontextMain(argc, argv, &function_map); } //TOOD 第二步 if (!strcmp(argv[1], "selinux_setup")) { return SetupSelinux(argv); } //TODO 第三步 if (!strcmp(argv[1], "second_stage")) { return SecondStageMain(argc, argv); } } //TODO 第一步 return FirstStageMain(argc, argv);
-
- FirstStageMain 第1阶段 文件目录:
system/core/init/first_stage_init.cpp
- 挂载创建文件
- 通过mount命令
- 重定向输入输出
- SetStdioToDevNull(argv);
- 初始化内核的日志打印
- InitKernelLogging(argv);
- 启动selinux_setup liunux这块的安全策略 Android权限:最小权限原则
- 挂载创建文件
- SecondStageMain 第2阶段 文件目录:
system/core/init/init.cpp SecondStageMain
- 初始化属性域
- PropertyInit()
- 监听子进程终止信号,并销毁子进程
- (防止僵尸进程.所谓僵尸进程,就是子进程挂掉了,但是父进程没有监听并销毁他,从而导致了已经挂掉的子进程依然占用系统资源)
-
InstallSignalFdHandler(&epoll); InstallInitNotifier(&epoll); StartPropertyService(&property_fd);
- 匹配命令和函数之间的关系(GetBuiltinFuctionMap)
- 如:为mkdir、mount、chmod命令的使用提前做好准备
- 解析init.rc文件
- LoadBootScrips(am, sm);
- CreateParser 创建解析器
-
parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, GetSubcontext(), std::nullopt)); parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext())); parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
-
- parser.ParseConfig(“/system/etc/init/hw/init.rc”); 解析init.rc文件,解析器ParserConfig的目录在:
system/core/init/parse.cpp
- ParseConfigDir(解析文件目录)->ParseConfigFile(最终解析文件目录中的文件)
- ParseConfigFile(解析文件)
- ParseData 解析数据
- 解析init.rc文件(二进制格式)
- ParseData 解析数据
- CreateParser 创建解析器
- LoadBootScrips(am, sm);
- 进入while循环(等待)
- auto pending_functions = epoll.Wait(epoll_timeout);
- 初始化属性域
init处理的重要事情:(重点)
- 挂在创建文件
- 通过
mount
命令实现挂载,比如:我们的U盘插入Linux系统的电脑,会将我们的U盘中的文件和Linux系统中的文件夹绑定起来,从而我们可以通过这个文件夹读取U盘中的文件
- 通过
- 设置selinux(安全策略)
- SelinuxInitialize();
- 开启属性服务,注册到epoll中
- StartPropertyService(&property_fd);
- 解析init.rc文件
- 解析init.rc文件中就包含了启动zygote指令(
trigger zygote-start
),在下面的while循环中就会去执行这个命令
- 解析init.rc文件中就包含了启动zygote指令(
- 循环处理脚本 (包括启动zygote进程)
- 通过while循环
- 循环等待 (防止init进程结束)
- 通过epoll.Wait(epoll_timeout);
总结:
- init进程是在idle进程中启动的,而idle进程属于内核层,所以我们从kernel目录下的main.c文件中的main()函数中去分析init进程的启动流程,最终执行到kernel_execve()方法.
- 接着我们我们从init目录下,main.cpp文件中的main()函数中,去分析init进程启动流程中做了哪些处理,里面分为了两个阶段:FirstStageMain和SecondStageMain,分别做了如下操作:挂起文件、设置Linux安全策略(selinux)、开启属性服务并注册到epoll中、解析init.rc文件、循环处理脚本和循环等待
扩展:Android.mk(旧)->Android.bp(新) 脚本文案,用于代码编译;启动init进程的init文件,也就是手机系统system/bin/init文件,是通过Android.bp编译init/main.cpp文件生成的,所以我们可以通过init/main.cpp文件去研究init进程的启动流程.
init进程启动流程图如下:
zygote进程的启动
在init.rc(所在目录:system/core/rootdir
)文件中就包含了启动zygote的指令(start zogote
),通过执行这个命令就会去启动zygote进程;然后启动zygote会解析如下文件,根据手机系统解析相应的文件:init.zygote32.rc
、init.zygote64.rc
、init.zygote32_64.rc
和init.zygote64_32.rc
.
同时在AS中的Device File Explore工具中,可以在system/bin目录下查看到启动的zogote文件,也就是app_process、app_process32和app_process64,根据手机cpu系统来分别执行相应的文件,这些文件的来源如下:
frameworks/base/cmds/app_process/Android.bp
文件中会执行app_main.cpp
相关代码,也就是说Android.bp
通过编译app_main.cpp
得到我们的system/bin/app_process
文件,下来我们就通过app_main.cpp文件中的main()函数来研究zygote的启动.
zygote的启动流程:
- Native层
- main() @app_main.cpp
- 目录:
frameworks/base/cmds/app_process/app_main.cpp
- 目录:
- 解析
app_process
目录下的init.zygote32.rc
文件中的参数- 该文件中第1行中,后面标记选中部分就是参数,从-Xzygote开始:service zygote /system/bin/app_process
-Xzygote /system/bin --zygote --start-system-server
- 该文件中第1行中,后面标记选中部分就是参数,从-Xzygote开始:service zygote /system/bin/app_process
- 解析到参数时做变量标记,后续执行相应的代码逻辑
- zygote=true和startSystemmServer=true,启动完成zygote进程后,接着就会根据startSystemServer变量启动SystemServer进程
- 调用ART的start()方法
- runtime.start(“com.android.internal.os.ZygoteInit”, args, zygote);
- 注意:"com.android.internal.os.ZygoteInit"这个目录是Java Framework中ZygoteInit.java的全类名路径,所以最终会调用到Java Framework层中ZygoteInit.java中的main()方法.
- 这里AppRuntime中没有实现start方法,该方法是由他的父类AndroidRuntime实现的.
- runtime.start(“com.android.internal.os.ZygoteInit”, args, zygote);
- start() @AndroidRuntime.cpp
- startVm() 启动虚拟机
- 由于Android虚拟机都是通过zygote进程通过一句代码来完成的,所以虚拟机仅仅是用来实现进程对内存空间的管理.
- startReg(env) 启动注册表,也就是注册jni
- 我们项目中通过Java中的native方法,去调用C++中的方法,就是通过这个注册的jni作为桥梁来实现的,因为Java层是无法直接与Native层进行通信的.
- 代码举例:AndroidRuntime.cpp
int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env) { //TODO 这里Java中的nativeZygoteInit方法, //就会调用到C++中的com_android_internal_os_ZygoteInit_nativeZygoteInit方法, //从而将Java层与Native关联起来 const JNINativeMethod methods[] = { { "nativeZygoteInit", "()V", (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit }, }; return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit", methods, NELEM(methods)); }
- CallStaticVoidMethod(startClass, startMeth, strArray);
- jmethodID startMeth = env->GetStaticMethodID(startClass, “main”, “([Ljava/lang/String;)V”);
- 这里就会调用到Java Framework层中的ZygoteInit.java中的main()方法,也就完成了从Native层到Java Framework层的跨越.
- 这里之所以能实现,
是因为native层中的方法同样可以通过jni,调用到Java层类中的方法
;我们熟悉的是Java层通过jni作为桥梁,实现了Java中的native方法调用到native层中的方法;
- startVm() 启动虚拟机
- main() @app_main.cpp
- java层: main() @ZygoteInit.java
- 预加载,会去加载一些class文件、resource文件和共享的包等
- preload(bootTimingsTraceLog);
- 创建Soket服务器,以便于接收socket消息,然后fork进程
- zygoteServer = new ZygoteServer(isPrimaryZygote);
- 通过fork创建SystemServer进程
- Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
- 通过Looper进入循环
- Runnable caller = zygoteServer.runSelectLoop(abiList);
- 预加载,会去加载一些class文件、resource文件和共享的包等
总结:
- 通过app_main.cpp的main()函数去解析init.zagote.rc文件
- 通过解析init.rc文件中的命令,从而去启动zygote进程;启动zygote进程时,需要通过app_main.cpp文件中的main()函数,根据手机系统型号去解析相应的init.zygote.rc文件,解析init.zygote.rc文件中的参数和命令时会相应的去启动Zygote和添加启动SystemServer的参数.
- 启动zagote的流程:
- Native层
- 通过app_main.cpp中的main函数去解析init.zygote.rc文件,
- 调用AndroidRuntme.cpp中的start()方法,
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
- 这个方法中包含了启动虚拟机startVm、启动JNI注册startReg和调用静态方法CallStaticVoidMethod(startClass, startMeth, strArray);注意:这个静态方法其实是一个jni方法,可以调用到Java层ZygoteInit.java类中的main()方法.
- Java层
- ZygoteInit.java类中的main()方法做了哪些事情:
- 预加载,加载一些class和resource资源,preload(bootTimingsTraceLog);
- 创建Soket服务器ZygoteServer,用于接收soket消息并fork进程.
- 通过fork创建SystemServer进程
- 通过Looper进入无限循环,通过接收soket消息然后fork出进程.
zygote进程启动流程图如下:
SystemServer进程的启动
SystemServer进程是用来做服务管理的,他会启动一些引导服务、核心服务和其他服务,总共有90多个服务,通过如下代码来启动服务:
startBootstrapServices(t);//启动引导服务10个,如:ATMS、AMS、PowerManagerService等
startCoreServices(t);//启动核心服务9个,如:BatteryService、LooperStatusService、WebViewUpdateService等
startOtherServices(t);//启动其他服务70多个,如:BluetoothService、ShortcutService等
启动SystemServer进程流程:
- Runnable r =
forkSystemServer()
@ZygoteInit.main()
返回Runnable,在最后会调用他的run()方法Zygote.forkSystemServer()
@ZygoteInit.main()
该方法会返回进程的pid,pid=0表示子进程,pid!=0表示zygote进程nativeForkSystemServer()
@Zygote.java- 在zagote的app_main.cpp注册jni中去找这个native方法的实现,先找zygote类的注册,然后再从zygote类中的方法里去寻找.
com_android_internal_os_Zygote_nativeForkSystemServer()
- 路径:
/frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
- 路径:
forkCommon()
pid_t pid = fork();
- 这里会调用Linux系统的fork()方法创建进程
handleSystemServerProcess()
@ZygoteInit.main()
根据pid=0的逻辑判断,去处理创建的SystemServer进程,并返回Runnable,这个Runnable是通过反射得来的;
pid=0表示孩子进程(这里就是Zygote启动的孩子SystemServer进程),pid!=0表示zygote进程ZygoteInit.zygoteInit()
RuntimeInit.applicationInit()
findStaticMain()
@RuntimeInit.java- 通过反射得到SystemServer的Class对象,并获取到main()方法;
Class<?> cl = Class.forName(className, true, classLoader);
Method m = cl.getMethod("main", new Class[] { String[].class });
- 通过反射得到SystemServer的Class对象,并获取到main()方法;
MethodAndArgsCaller()
@RuntimeInit.java
继承自Runnable,包含了Method mMethod和String[] mArgs两个成语变量- run()
mMethod.invoke(null, new Object[] { mArgs });
- run()
r.run();
@ZygoteInit.main()- 启动Runnable的run方法,最后就会调用到MethodAndArgsCaller类中的run()方法,然后调用这段代码:
mMethod.invoke(null, new Object[] { mArgs });
执行SystemServer.java的main()方法
- 启动Runnable的run方法,最后就会调用到MethodAndArgsCaller类中的run()方法,然后调用这段代码:
SystemServer.main()
里面会直接调用其run()方法
通过反射调用SystemServer中的main方法,这里面做了如下几件事情:- 创建SystemServiceManager,用于启动服务和管理服务
- new SystemServiceManager(mSystemContext);
- mSystemServiceManager.startService(new AlarmManagerService(context));//启动服务
- 启动引导服务、核心服务和其他服务,代码如下:
startBootstrapServices(t);//启动引导服务 startCoreServices(t);//启动核心服务 startOtherServices(t);//启动其他服务
- Looper.loop();
- 启动Looper循环,保持SystemServer进程一直存活
SystemServer进程涉及到的几个类:
SystemServiceManager
- 启动和管理Service
SystemService
- 抽象类,所有的服务要么直接继承自SystemService;要么在该类中重写一个LifeCycle内部类继承自SystemService,并且LifeCycle里面包含了一个当前类的成员变量.
AMS
- 具体的服务实现类
ServiceManager
是一个进程- 用于存储我们的服务,以map的形式存储服务,通过Name和服务的Binder的方式存储
- 通过具体的Service,如:ATMS类的内部类LifeCycle的onStart()方法里,通过这个方法将这个服务添加到ServiceManager中去:
publishBinderService(Context.ACTIVITY_TASK_SERVICE, mService);
总结:
- 在ZygoteInit.java的main()方法中,通过forkSystemServer()方法,创建SystemServer进程,这个方法会调用到Native层Zygote.cpp文件中的nativeForkSystemServer()函数,最终会调用Linux系统的fork()方法,创建SystemServer进程并返回进程的pid;
- 根据创建的进程pid=0的逻辑判断,最终通过反射调用到SystemServer.java中的main()方法,在SystemServer进程中做一些处理.
该方法主要做了以下几个操作:
- 创建SystemServiceManager,用于启动和管理服务;
- 启动一些引导服务、核心服务和其他服务,总共有90多个服务;
- 通过Looper开启循环,保证SystemServer进程一直存活.
App进程的启动流程
应该就是通过从ServiceManager中取出AMS,然后通过AMS给Zygote进程发送Sockct消息,Zygote进程在ZygoteServer中接收到消息后,通过fork()创建App进程,然后通过配置文件中的去启动我们的app的首页.