Android开机启动流程简析

Android开机启动流程简析 (一)


前言

在学习Android过程中开机启动是必要了解的,在这里我主要谈一谈我所学习的看法和经验,可能总结的不到位,望海涵;


一、开机启动的流程概述

第一步
手机开机后(引导芯片启动)–>ROM(预设代码执行)–>RAM(加载引导程序到RAM)—>bootloader(检查RAM,初始化硬件参数)

第二步
Kernel层(硬件初始化参数后)—主要加载一些硬件设备驱动,初始化进程管理操作。

第三步
Kernel层加载完毕–>HAL层(硬件设备驱动与之进行交互)
初始化进程操作–>启动INIT进程
------->这些都在Native层

第四步
Init进程(pid=1;init进程是所有进程的鼻祖第一个启动)启动–>启动adbd,logd等用户守护进程—并启动servicemanager(binder 服务管家)----并孵化出zygote进程
(这里属于C++Framework,代码为C++代码);

第五步
Zygote进程—init进程解析ini.rc文件后fork生成----会加载虚拟机,启动System Server(zygote孵化的第一个进程)
System Server:负责启动和管理整个java Framework(包含 ActivityManager,WindowManager,PackageManager,PowerManager等服务)

第六步
Zygote同时会启动相关的App进程—启动的第一个进程是Launcher,然后启动其他进程(所有的APP都有zygote fork生成)

总结来说就是:
Power on ->boot rom ->bootloader->kernel
----通俗易懂,给器件供电后加载配置驱动完成后,开始启动系统

二、Android的启动过程分析

(1).总体流程

Init > Zygote > SystemServer > launcher
Kernel中启动的第一个用户进程是init程序;而init 会通过解析init.rc来启动zygote, servicemanager, surfaceflinger, mediaserver服务;而zygote又会进一步的启动SystemServer。在SystemServer中,Android会启动一系列的系统服务共用户调用服务例如 ams, pms等启动完后启动launcher。

init简述

1.init进程概述:
Init是安卓启动的第一个进程,进程号PID=1,当bootloader启动后,启动 kernel,
kernel启动完后,再启动init进程,再通过init进程,来读取 init.rc中的相关配置,从而来启动其他相关进程以及其他操作。它的生命周期贯穿整个Linux内核运行的始终,adb shell ps可以查看所有进程,可以看到init进程和 pid 值。

2.init进程启动
代码路径:system/core/init/main.cpp
Init进程源码启动入口main函数根据参数分别执行
1.ueventd_main init进程创建子进程ueventd,并将创建设备节点文件的工作托付给ueventd,ueventd通过两种方式创建设备节点文件
2.FirstStageMain启动第一阶段
3.SubcontextMain初始化日志系统
4.SetupSelinux加载selinux规则,并设置selinux日志,完成SELinux相关工作5.SecondStageMain启动第二阶段

Ueventd_main负责节点创建:
代码路径:Platform/system/core/init/ueventd.cpp
ueventd通过两种方式创建设备节点文件分别是冷启动和热启动:
1.冷启动:通俗讲就是已经设定好的,比如 cpu频率,统一创建好的文件节 点。
2.执启动:诵俗讲就是动态创建的比加 ush插拔等节占。
(简要代码如下所示:)

//这一块是冷启动
if ( landroid: : base::GetEoolProperty(kColdBootDoneProp,false)){
         ColdBoot cold_boot (uevent_listener,uevent _handlers,
         ueventd_configuration.enable_parallel_restorecon) ;
        cold_boot.Run () :
    }
for (aut o& uevent_handler : uevent_handlers){
     uevent_handler->ColdbootDone() :
     }
//这一块是监听驱动的热插拔处理。
// Restore prio before main loop
setpriority (PRIO_PROCESs0,o) :
uevent_listener.Poll([&uevent_handlers](const Uevent& uevent) {
   for (auto& uevent_handler : uevent_handlers) {
      uevent__handler->HandleUevent (uevent) :
}
      return ListenerAction: : kContinue ;
});
      return 0;
}

init分为三个阶段具体代码不展开分析,主要总括一下各阶段的职责:
总结:
1.第一阶段做的主要工作是挂载分区,创建设备节点和一些关键目录,初始化日志输出系统,启用SELinux安全策略。
2.第二阶段主要工作是初始化屑性系统,解析SELinux 的匹配规则,启动系统属性服务,可以说每一项都很关键,如果说第一阶段是为属性系统,SELinux微准备,那么第二阶段就是真正去把这些功能落实。
3.第三阶段主要是解析 init.rc来启动其他进程,进入无限循环,进行子进程实时监控

Zygote简述

在这里插入图片描述

Zygote启动后–>入口app_main.cpp的main方法:
入口函数调用AndroidRuntime的startVM()方法创建虚拟机;
在调用startReg()注册JNI函数通过JNI方式调用ZygoteInit.main()。
注册socket进行预加载,fork systemserver进程

Init.zygote32与init.zygote64区别:
HAD init.zygote32.rc
HAD init.zygote64.rc
HAD init.zygote64_32.rc
纯32位模式:属性ro.zygote 的值为zygote32
纯64位模式:属性ro.zygote的值为zygote64
混64位模式(即 64位为主,32位为辅)模式:属性ro.zygote值为zygote64_32这些文件主要针对32位系统和 64位系统,现在主流基本上是zygote64_32/system/core/rootdir/init.zygote64_32.rc

load zygote 的 rc 文件:
在这里插入图片描述

init main函数入口:
Zygote本身是一个Native的应用程序,刚开始的进程名称为“app_process”,运行过程中,通过调用setArgv0将名字改为zygote或者 zygote64(根据操作系统而来),最后通过runtime的start()方法来加载虚拟机并进入JAVA程序。

lli; l //Skip unused " parent dir" argument.
while (i < argc){
    const char* arg = argv[i+t]:
if (strcmp(arg,--zygote") == 0){
       zygote = true ;
       niceiame = ZYGOTE_NICE_NAME;
}else if (strcmp(arg, “—-start-system-server" ) == 0){
       startSystemServer = true ;
}else if (strcmp(arg,"—-application" ) == 0){
       application = true ;
}else if (strncmp(arg,“—-nice-name=", 12) == 0){
       nicelame.setTo(arg +12):
}else if (strncmp(arg,--*2) != 0){
       className.setTo(arg);
       break ;
}else {
        --i ;
        break ;
   }
}

1.对于64位系统nice_name为 zygole64;32位系统为zygoteniceName = ZYGOTE_NICE_NAME;
2.是否需要启动system server
startSystemServer = true;
3.启动进入独立的程序模式
application = true;

在这里插入图片描述
1.如果是zygote启动模式,则加载Zygotelnit
2.如果是application启动模式,则加载RuntimeInit
3.没有指定类名或zy gote,参数错误

AppRuntime继承自AndroidRuntime类,并且重载了onVmCreated , onStarted、onZygoteInit和 onExit函数。我们发现并没有重载start函数,而在 app_main.cpp 的 main()函数的最后runtime.start函数,所以具体执行在AndroidRuntime类的start函数。

在这里插入图片描述

void AndroidRuntime:.start调用startVm开启虚拟机,调用startReg注册JNI方法,通过JNI把Zygote进程启动。

JniInvocation jni_invocation ;
jni_invocation. Init (NULL);
JNIEnv*env;
if (startVm (&mJ avaVM,&env,zygote,primary_zygote) != 0){
   return;
}
   onVmCreated(env) ;

 //Register android functions.
 
if (startReg(env) <0){
LOGE ( "Unable to register all android nativesin" ) ;
return:
}

Zygotelnit.main()函数
代码路径:frameworks \base\core \java\com \android\internal \os\ZygoteInit.java

Main方法主要处理
1.调用preload()来预加载类和资源
2.调用ZygoteServer()创建两个Server端的Socket用来等待ActivityManagerService来请求Zygote来创建新的应用程序进程。
3.调用forkSystemServer来启动SystemServer进程
4.最后调用runSelectLoop 函数来等待客户端请求Zygote进程,通过fork()函数,最终孵化出system_server的进程,通过反射的方法启动

Preload预加载资源:

static void preload(TimingsTraceLog bootTimingsTraceLog) {
Log.d(TAG,“begin preload");
bootTimingsTraceLog.traceBegin("BeginPreload");
beginPreload();
bootTimingsTraceLog.traceEnd() ; //BeginPreload
bootTimingsTraceLog.traceBegin("PreloadClasses");
preloadC1asses();
bootTimingsTraceLog.traceEnd(); // PreloadClasses
bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
cacheNonBootClasspathClassLoaders():
bootTimingsTraceLog.traceEnd(): // CacheNonBootClasspathClassLoaders
bootTimingsTraceLog.traceBegin("PreloadResources");
preloadResources();
bootTimingsTraceLog.traceEnd(); //PreloadResources
Trace.traceBegin(Trace.TRACE_TAG_DALVIK"PreloadAppProcessHALs");
nativePreloadAppProcessHALs();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK"PreloadGraphicsDriver" );
maybePreloadGraphicsDriver();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
preloadSharedlibraries();
preloadTextResources();
// Ask the WebViewFactory to do any initialization that must run in the zygote proce;
// for memory sharing purposes.
WebviewFactory.prepareWebViewInZygote();
endPreload();
warmUpJcaProviders();
Log.d(TAG" end preload" );
sPreloadComplete = true ;
}

预加载资源是指zygote进程启动的时候就只加载一次,以后有其他进程需要用时不用加载,直接调用,加快应用启动速度;例如系统的一些resource,一些class等

ZygoteInit.java Runnable forkSystemServer线程方法
frameworks/base/config/preloaded-classes。

在这里插入图片描述

pid 返回0时,表示当前为system_server子进程;
当pid >0时,是进入父进程,即 Zygote 进程;
Zygote启动完成,最后启动的systemserver;

Zygote怎么孵化应用进程:

在这里插入图片描述
在这里插入图片描述

  • 7
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值