Android系统启动流程

Android系统启动流程

对于纯Android应用层开发来讲,了解一些Android的启动流程的知识并不会直接提高自己的代码质量。但是作为整个Android系统的开端,这部分的流程时刻影响着应用层的方方面面。这些知识也是作为Android开发进阶必须要了解的一部分。

过去你可能会有疑问,比如为什么所有应用的父进程号都是同一个?ActivityManagerService是怎么来的?Android上的Java虚拟机什么时候被加载的?

本文来分析总结一下Android 系统在启动的Init、Zygote、SystemServer,来帮助大家了解一下。

一:Init

当用户按下开机键的时候,引导芯片加载BootLoader到内存中,开始拉起Linux OS,一旦Linux内核启动完毕后,它就会在系统文件中寻找 init.rc 文件,并启动init 进程。

什么是 init.rc 文件?

init.rc文件是一个非常重要的配置文件,它由AIL语言(Android Init Language)编写。

(init.rc的一个小细节:Android8.0后对init.rc文件进行了拆分,比如64位的Zygote的启动脚本在init.zygote64.rc文件中)

在启动的init进程中,会进入system/core/init/init.cpp文件的main方法中,关键代码如下:

int main(int argc,char ** argv){
    
    ...
    if(is_first_stage){
        //创建和挂在启动所需要的文件目录
        mount("tmpfs","/dev","tmpfs",MS_NOSUID,"mode=0755");
        mkdir("/dev/pts",0755);
        //创建和挂在很多...
        ...
    }
    
    ...
    //对属性服务进行初始化
    property_init();
    
    ...
    //用于设置子进程信号处理函数(如Zygote),如果子进程异常退出,init进程会调用该函数中设定的信号处理函数来处理
    signal_handler_init();
    
    ...

    //启动属性服务
    start_property_service();
    
    ...
    
    //解析init.rc配置文件
    parser.ParseConfig("/init.rc");
    
}

上述代码中,有一个概念是 属性服务,经常玩Windows 的同学应该知道WIndows注册表,注册表采用键值对的形式来记录用户、软件的一些使用信息,这样即使系统或者软件重启也能够根据之前注册表中的记录来进行相应的初始化。init进程启动的属性服务,就是用来储存这些属性的。

属性服务的查询和修改都是通过Socket进行的,系统文件内定义对多为8个用户提供服务。并且属性服务中的系统属性分为两种:普通属性和控制属性。控制属性用来执行一些命令,比如开机的动画就使用了这种属性。

在处理了繁多的任务后,init进程会进行最关键的一部操作: 启动Zygote

代码在 frameworks/base/cmds/app_process/app_main.cpp中:

int main(int argc ,char* const argv[]){
    ...
    if(zygote){
        //启动Zygote进程
        runtime.start("com.android.internal.os.ZygoteInit",args,zygote);
    }
}

总结一下,init进程启动后做了哪几件事:

(1)创建和挂载启动所需要的文件和目录

(2)初始化和启动属性服务。

(3)解析init.rc配置文件,并且启动了Zygote进程

二:Zygote

(1)Zygote概述:

在Android系统中,DVM(Dalvik虚拟机)和ART、应用程序进程以及运行系统关键服务的SystemServer进程都是由Zygote进程创建的,我们也将它称为孵化器(本来字面意思就是受精卵…)。它通过fork复制进程的形势来创建应用进程和SystemServer进程,由于Zygote进程在启动时会创建DVM或者ART,因此通过fork而创建的应用程序进程和SystemServer进程可以在内部获取一个DVM或者ART的实例副本。

init.rc文件引入Zygote的启动脚本,这些脚本都是由AIL编写的。

由于Android 5.0后,Android开始支持64位程序,Zygote也就有了32位与64位之分。一共有四种Zygote启动脚本:

init.zygote32.rc

init.zygote32_64.rc

init.zygote64.rc

init.zygote64_32.rc

(2)Zygote启动流程

Zygote启动时主要调用app_main.cpp的main()中的AppRuntime的start方法来启动Zygote进程。我们先展示app_main.cpp中的main函数。

frameworks/base/cmds/app_process/app_main.cpp:

int main(int argc,char* const argv[]){
    ...
    
    while( i < argc ){
        const char* arg=argv[i++];
        
        if(strcmp(arg,"--zygote")==0){
            //如果当前进程在Zygote中,则设置zygote=true
            zygote=true;
            niceName=ZYGOTE_NICE_NAME;
        }else if(strcmp(arg,"--start-system-server")==0){
            //如果当前进程在SystemServer中,将startSystemServer=true
            startSystemServer=true;
        }
        ...
    }
    ...
    //承接上面Init进程中的代码
    if(zygote){
        //启动Zygote进程
        runtime.start("com.android.internal.os.ZygoteInit",args,zygote);
    }
}

由于Zygote进程都是通过fock自身来创建子进程,这样Zygote进程和他的子进程(比如SystemServer)都可以进入app_main.cpp的main函数中,因此需要区分一下当前进程运行在哪个进程里。

接下来我们进入 runtime.start中看看:

frameworks/base/core/jni/AndroidRuntime.cpp:

void AndroidRuntime::start(const char* className,const Vector<String8>& options,bool zygote){
    ...
    
    //startVm函数用于启动Java虚拟机
    if(startVm(&mJavaVM,&env,zygote)!=0){
        return;
    }
    onVmCreated(env);
    //为Java虚拟机注册JNI方法
    if(startReg(env)<0){
        return;
    }
    ...
    //从app_main的main方法中得知,className是com.android.internal.os.ZygoteInit
    classNameStr=env->NewStringUTF(className);
    
    ...
    
    //找到ZygoteInit类
    jclass startClass=env->FindClass(slashClassName);
    
    ...
    //找到ZygoteInit的main方法
    jmethodID startMeth=env->GetStaticMethodID(startClass,"main","([Ljava/lang/String;)V");
    
    ...
    //通过JNI调用ZygoteInit的main方法
    env->CallStaticVoidMethod(startClass,startMeth,strArray);
}

以上代码就厉害了,它从Init进程中的AndroidRuntime的main函数,启动了Java虚拟机,并且通过JNI启动了Zygote,一波操作之后,Zygote顺利从Native层进入了Java层。

随后我们进入ZygoteInit中,看看它的main方法做了什么。

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java:

public static void main(String argv[]){
    ...
    //创建一个Server端的Socket,socketName值为:zygote
    zygoteServer.registerServerSocket(socketName);
    
    if(!enableLazyPreload){
        ...
        //预加载类和资源
        preload(bootTimingsTraceLog);
    }else{
        ...
    }
    
    if(startSystemServer){
        //启动SystemServer进程
        startSystemServer(abiList,socketName,zygoteSerer);
    }
    //等待AMS的请求
    zygoteServer.runSelectLoop(abiList);
    zygoteServer.closeServerSocket();
}

大致代码就此结束。

总结一下ZygoteInit的main方法都做了哪些事情:

1.创建了一个Server端的Socket

2.预加载类和资源

3.启动了SystemServer进程

4.等待AMS请求创建新的应用程序进程


最后再总结一下Zygote进程启动公做了几件事:

1.创建AndroidRuntime并调用其start方法,启动Zygote进程。

2.创建Java虚拟机并为Java虚拟机注册JNI方法。

3.通过JNI调用ZygoteInit的main函数进入Zygote的java框架层。

4.通过registerZygoteSocket方法创建服务端Socket,并通过runSelectLoop方法等待AMS的请求来创建新的应用程序进程。

5.启动SystemServer。

三:SystemServer

SystemServer进程主要用于创建系统服务,我们熟知的AMS、WMS、PMS都是由它来创建的。

在前面讲到过,Zygote进程启动了SystemServer进程,我们看一下启动部分的代码。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java:

private static boolean startSystemServer(String abiList,String socketName){
    ...
    //判断进程是否是SystemServer
    if(pid == 0){
        ...
        //关闭Zygote的Socket
        zygoteServer.closeServerSocket();
        //启动SystemServer进程
        handleSystemServerProcess(parsedArgs);
    }
}

由于SystemServer是Zygote进程fork出来的,所以该进程也拥有一个ZygoteServer所开启等待AMS连接的Socket实例副本。在这里并不需要这个Socket,所以关闭。

接下来看看handleSystemServerProcess()方法。

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java:

private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs){
    ...
    ClassLoader cl=null;
    if(systemServerClasspath!=null){
        //在这里创建了PathClassLoader
        cl = createPathClassLoader(systemServerClasspath,parsedArgs.targetSdkVersion);
        Thread.currentThread().setContextClassLoader(cl);
    }
    //zygoteInit方法
    ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,parsedArgs.remainingArgs,cl);
}

就是这里,创建了大名鼎鼎的 PathClassLoader

接下来看看zygoteInit方法。

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java:

public static final void zygoteInit(int targetSdkVersion,String[] argv,ClassLoader classLoader){
    ...
    //就在该方法中,启动了Binder线程池
    ZygoteInit.nativeZygoteInit();
    //进入SystemServer的main方法
    RuntimeInit.applicationInit(targetSdkVersion,argv,classLoader);
}

nativeZygoteInit方法一看名称,就知道是在Native层的代码。用来启动Binder线程池,这样SystemServer进程就可以使用Binder与其他进程进行通信了。

再讲一下RuntimeInit的applicationInit方法,该方法用于启动SystemServer(以及后来我们的应用程序进程的启动)。

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java:

protected static void applicationINit(int targetSdkVersion,String[] argv,ClassLoader classLoader){
    ...
    invokeStaticMain(args.startClass,args.startArgs,classLoader);
}

...

private static void invokeStaticMain(String className,String[] argv,ClassLoader classLoader){
    Class<?> cl;
    ...
    
    //className是com.android.server.SystemServer
    cl=Class.forName(className,true,classLoader);
    
    ...
    //找到SystemServer的main方法
    m=cl.getMethod("main",new Class[]{String[].class});
    
    ...
    //抛出异常,这里抛出异常中调用了SystemServer的main方法
    throw new Zygote.MethodAndArgsCaller(m,argv);
    
}

在invokeStaticMain方法最后,以抛出异常的方式调用了SystemServer的main方法(之后在启动其他应用进程的时候,也是这样调用ActivityThread的main方法的)。这种处理会清除所有设置过程需要的堆栈帧。

接下来我们解析一下SystemServer进程。

frameworks/base/services/java/com/android/server/SystemServer.java:

public static void main(String[] args){
    //就一行代码
    new SystemServer().run();
}

private void run(){
    ...
    //创建消息Looper
    Looper.prepareMainLooper();
    //加载动态库
    System.loadLibrary("android_servers");
    //创建SystemServiceManager
    mSystemServiceManager=new SystemServiceManager(mSystemContext);
    
    ...
    //启动引导服务
    startBootstrapServices();
    //启动核心服务
    startCoreServices();
    //启动其他服务
    startOtherServices();
    
    ...
}

我们可以看到SystemServer在启动后,陆续启动了各项服务,包括ActivityManagerService,PowerManagerService,PackageManagerService等等,而这些服务的父类都是SystemService。

最后总结一下SystemServer进程:

1.启动Binder线程池

2.创建了SystemServiceManager(用于对系统服务进行创建、启动和生命周期管理)

3.启动了各种服务

结尾

到此为止,本文基本结束了。Android系统启动代码繁多,我们只截取了部分关键代码作为展示。最后总结一下,Init进程、Zygote、SystemServer的关系,如果还是有不懂的童鞋可以记住:

盘古(Linux 内核)开天辟地后,世上诞生了女娲(Init进程),女娲过于孤独决定要个孩子,就用泥巴捏了个亚当(Zygote),后来亚当也觉得整天就跟他妈在一起也太烦了,决定造个女孩,于是用自己的肋骨(fork)创建了一个夏娃(SystemServer),于是万物开始…

本文大量参考《Android 进阶解密》一书,同时建议对Android底层有兴趣的童鞋搞一本看看,里面讲解的必然比本文精辟不少。

本文纯手打,欢迎各位点亮爱心,给个小小的赞以资鼓励,谢谢

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android系统启动流程可以分为以下几个步骤: 1. 启动电源以及系统启动:当电源按下时,引导芯片代码开始执行,加载引导程序Bootloader到RAM,并执行该程序。 2. 引导程序Bootloader:引导程序是一个小程序,其主要作用是将系统OS启动起来并运行。 3. Linux内核启动:内核启动时,进行系统设置,包括设置缓存、被保护存储器、计划列表,并加载驱动。内核会在系统文件中寻找"init"文件,并启动init进程或系统的第一个进程。 4. init进程启动:init进程是Android系统的第一个用户空间进程,它负责启动和管理其他系统进程。init进程会读取init.rc文件,根据其中的配置启动系统服务和应用进程。 5. Zygote进程和SystemServer进程启动:Zygote进程是一个特殊的进程,它作为应用进程的模板,用于快速创建新的应用进程。SystemServer进程是Android系统的核心服务进程,负责启动和管理各种系统服务。 6. 应用层进程启动:在Android系统中,应用层进程包括Launcher进程,即主屏幕的进程,以及其他应用程序的进程。这些进程会根据用户的操作和应用的需求来启动和管理。 总结起来,Android系统启动流程包括引导程序Bootloader的加载和执行、Linux内核的启动、init进程的启动、Zygote进程和SystemServer进程的启动,以及应用层进程的启动。这些步骤共同完成了Android系统的初始化和启动。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [Android系统启动流程(一)解析init进程启动过程](https://blog.csdn.net/itachi85/article/details/54783506)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Android系统启动流程](https://blog.csdn.net/xhmj12/article/details/128149490)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Android 面试必备 - 系统、App、Activity 启动过程“一锅端”](https://blog.csdn.net/zzz777qqq/article/details/115698795)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值