整体流程图

  • 一、启动电源以及系统启动

按下电源,引导芯片开始从rom执行,加载引导程序到ram,然后执行。
  • 二、引导程序Bootloader

Bootloader的主要作用是初始化基本的硬件设备(如 CPU、内存等)并且建立内存空间映射,为装载Linux 内核准备好合适的运行环境。 一旦Linux内核装载完毕,Bootloader将会从内存中清除掉。
如果在Bootloader运行期间,按下预定义的的组合键,可以进入系统的更新模块。Android的下载更新可以选择进入 Fastboot模式或者Recovery模式:
Fastboot是Android设计的一套通过USB来更新Android分区映像的协议,方便开发人员快速更新指定分区。
Recovery是Android特有的升级系统。利用Recovery模式可以进行恢复出厂设置,或者执行OTA、补丁和固件 升级。进入Recovery模式实际上是启动了一个文本模式的Linux。
  • 三、装载和启动Linux内核

Android把boot.img映像装载进内存,boot.img存放的就是Linux内核和一个根文件系统。然后Linux内核会执行整个系统的初始化。然后装载根文件系统。内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找“init”文件,然后启动系统的第一个进程Init进程。
  • 四、启动Init进程

Init进程是系统的第一个进程。
内核启动后,在kernel层会启动一个pid=2的kthread进程,在用户空间会启动一个pid=1的init进程。

main.c:

文件位置:kernel/common/init/main.c;
执行方法:kernel_init;
该方法会启动init.rc
static int __ref kernel_init(void *unused)
{
    ...
    
    if (execute_command) {
        ret = run_init_process(execute_command);
        if (!ret)
            return 0;
    }
    if (CONFIG_DEFAULT_INIT[0] != '\0') {
    ret = run_init_process(CONFIG_DEFAULT_INIT);
    if (ret)
        pr_err("Default init %s failed (error %d)\n",CONFIG_DEFAULT_INIT, ret);
      else
        return 0;
    }

if (!try_to_run_init_process("/sbin/init") ||
    !try_to_run_init_process("/etc/init") ||
    !try_to_run_init_process("/bin/init") ||
    !try_to_run_init_process("/bin/sh"))
    return 0;
}

static int try_to_run_init_process(const char *init_filename)
{
    int ret;
    ret=run_init_process(init_filename):
    if(ret&&ret!=-ENOENT){
        pr_err("starting init: %s exists but couldn't execute it (error %d)in",
                init_filename,ret);
    return ret;
}
static int run_init_process(const char *init_filename)
{
    const char *const *p;

    argv_init[0] = init_filename;
    pr_info("Run %s as init process\n",init_filename);
    pr_debug("with arguments:\n");
    for(p=argv_init;*p;p++)
        pr_debug("%s\n",*p);
    pr_debug("with environment:\n");
    for(p=envp_init;*p;p++)
        pr_debug("    %s\n",+p);
    return kernel_execve(init_filename,argv_init,envp_init);
}

然后执行init中的main()方法执行init进程的职责

main.cpp:

init的入口函数main.cpp;

文件位置:aosp/system/core/init/main.cpp;

执行方法:main();

int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif

    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap function_map;

            return SubcontextMain(argc, argv, &function_map);
        }

        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }

        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }

    return FirstStageMain(argc, argv);
}

依次执行FirstStageMain->SetupSelinux->SecondStageMain

Init.rc:

解析init.rc:/system/core/rootdir/init.rc

在SecondStageMain中调用LoadBootScripts(am.sm)->parser.ParseConfig()->ParseConfigDir(path)&ParseConfigFile(path)->ParseData来解析init.rc;

为了保证init进程活着,有一个while(true)的死循环。epoll.Wait(epoll_timeout)等待;

init启动serviceManager:init

on init

    ...
    
    # Start logd before any other services run to ensure we capture all of their logs. 
    start logd 

    # Start essential services.
    start servicemanager
    ...

init.rc启动zygote:late-init

on late-init
    //启动vold服务(管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化等)
    trigger early-fs
    trigger fs
    trigger post-fs
    trigger late-fs

    //挂载/data , 启动 apexd 服务
    trigger post-fs-data

    # 读取持久化属性或者从/data 中读取并覆盖属性
    trigger load_persist_props_action

    //启动zygote服务!!在启动zygote服务前会先启动netd服务(专门负责网络管理和控制的后台守护进程)
    trigger zygote-start

    //移除/dev/.booting 文件
    trigger firmware_mounts_complete

    trigger early-boot
    trigger boot  //初始化网络环境,设置系统环境和守护进程的权限

在init.rc文件中,执行late-init之后,启动zygote;

总结:

Init进程启动过程中,Init进程处理的重要事情:

FirstStageMain:
  • 挂载Android的文件系统
  • 挂载 system、cache、data 等系统分区
Selinux:
  • 设置selinux安全策略
SecondStageMain:
  • 初始化属性服务,注册到epoll中
  • 解析init.rc
  • 启动serviceManager、zygote--启动Android重要的守护进程,像usb守护进程,adb守护进程,、vold守护进程、rild守护进程
  • 开启死循环,循环等待事件发生--init会变为一个守护进程执行修改属性请求,重启崩溃的进程等操作

五、启动ServiceManager

ServiceManager的主要作用是管理Binder服务,负责Binder服务的注册与查找。 ServcieManager 是一个守护进程,这个进程会一直存在于后台。当SystemServer启动 AMS,WMS,PMS等服务的时候,会将服务的binder注册到ServiceManager中,由ServcieManager来进行统一的保存。当某个进程如App进程 想调用AMS和其他进程通信的时候,就会去ServiceManager中获取AMS的b/inder,然后通过这个binder来调用AMS 的代码进行相关的操作

六、启动zygote进程

Init进程初始化结束时,会启动Zygote进程。Zygote通过fork(复制进程)的方式创建android中几乎所有的应用程序进程和SystemServer进程。另外在Zygote进程启动的时候会创建DVM或者ART虚拟机,因此使用fork而建立的应用程序进程和SystemServer进程可以在内部得到一个DVM或者ART的实例副本,这样就保障了每个app进程在Zygote fork的那一刻就有了虚拟机。

Zygote是所有应用进程的父进程:

  • Zygote进程初始化时会创建Android 虚拟机、预装载系统的资源文件和Java类
  • 所有从Zygote进程fork出的用户进程都将继承和共享这些预加载的资源,不用浪费时间重新加载,加快了应用程序的启动过程
  • 启动结束后,Zygote进程也将变为守护进程,负责响应启动APK的请求。

Native层:

启动app_main.cpp

init.rc文件中采用了如下所示的Import类型语句来导入Zygote启动脚本:

import /init.environ.rc  //导入全局环境变量
import /init.usb.rc   //adb 服务、USB相关内容的定义
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服务

这里根据属性ro.zygote的内容来导入不同的Zygote启动脚本。从Android 5.0开始,Android开始支持64位程序,Zygote有 了32/64位之别,ro.zygote属性的取值有4种:

init.zygote32.rc

init.zygote64.rc

init.zygote64_32.rc

init.zygote32_64.rc---在android12以后,被删除

打开zygote.rc,可以看到:

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
     class main
     priority -20
     user root
     group root readproc reserved_disk
     socket zygote stream 660 root system
     socket usap_pool_primary stream 660 root system
     onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
     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
     critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

意思就是,执行 app_process64,该程序的路径是 /system/bin/app_process64 ,类名是 main,进程名为 zygote。

查看android.bp文件可知,/system/bin/app_process对应文件就是app_main.cpp

文件路径:frameworks/base/cmds/app_process/android.bp;

执行app_main.cpp

文件路径:frameworks/base/cmds/app_process/app_main.cpp;

执行方法:

int main(int argc, char* const argv[])
  {
      
      ...
  
      // Parse runtime arguments.  Stop at first unrecognized option.
      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) {
              zygote = true;
              niceName = 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) {
              niceName.setTo(arg + 12);
          } else if (strncmp(arg, "--", 2) != 0) {
              className.setTo(arg);
              break;
          } else {
              --i;
              break;
          }
      }
      
      ...
  
      if (zygote) {
          runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
      } else if (className) {
          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.");
      }
  }
  

可以看到,app_main根据启动时传入参数的区别,分为zygote 模式和application模式。根据下面的if判断,进入当前的zygote模式。

zygote的Native启动:

runtime.start会触发到AndroidRuntime.cpp的start方法;

文件路径:frameworks/base/core/jni/AndroidRuntime.cpp;

执行方法:start

然后通过CallStaticVoidMethod方法启动zygoteInit.java的main方法:

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { 
    // 1.启动 java 虚拟机 
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) { 
        return; 
    } 
    onVmCreated(env); 
 
    // 2.为Java虚拟机注册JNI方法 
    if (startReg(env) < 0) { 
        ALOGE("Unable to register all android natives\n"); 
        return; 
    } 
 
    // 3.classNameStr是传入的参数,值为com.android.internall.os.ZygoteInit 
    classNameStr = env->NewStringUTF(className); 
    /* 
     4.使用toSlashClassName函数将className的 "." 替换为 "/",得到com/android/internal/os/ZygoteInit 
     */
    char* slashClassName = toSlashClassName(className != NULL ? className : ""); 
    jclass startClass = env->FindClass(slashClassName); 
    if (startClass == NULL) { 
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); 
    } else { 
        // 5.找到 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); 
        } else { 
            // 6.使用JNI调用ZygoteInit的main函数 
            env->CallStaticVoidMethod(startClass, startMeth, strArray); 
        } 
    } 
} 

Zygote在启动过程中分别做了以下几件事:

  1. 启动java虚拟机;
  2. 注册android SDK需要使用的JNI方法;
  3. 执行ZygoteInit的main函数,进而启动zygote的java层代码,最终Zygote就从Native层 进入了Java FrameWork层。

Zygote的java执行:

文件路径:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java;

执行方法:main

执行ZygoteInit.java的main方法:

public static void main(String argv[]) {
        // Server socket class for zygote processes. 
        ZygoteServer zygoteServer = null; //用来管理和子进程通信的socket服务端
        
        // Mark zygote start. This ensures that thread creation will throw 
        // an error. 
        //这里其实只是设置一个标志位,为创建Java线程时做判断处理,如果是zygote进程,
        //则不需要开启线程 
        ZygoteHooks.startZygoteNoThreadCreation();  
        
        // 代码省略...
        
        try {
            // 代码省略...
            if (!enableLazyPreload) {
               // 代码省略...
                preload(bootTimingsTraceLog); //预加载,加快进程的启动
                // 代码省略...
            }
            // 代码省略...

            //启动socket服务,不用binder,防止死锁
            zygoteServer = new ZygoteServer(isPrimaryZygote); 

            if (startSystemServer) {
                //fork SystemServer进程,AMS由SystemServer启动
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); 
                if (r != null) {
                    // 启动SystemServer
                    r.run();
                    return;
                }

            }
             
            Log.i(TAG, "Accepting command socket connections");

           // ZygoteServer进入无限循环,处理请求
            caller = zygoteServer.runSelectLoop(abiList); //死循环,用于接收AMS传过来的消息,也保证该进程不会结束。
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket(); //关闭socket
            }
        }
        // 代码省略...
    
    }

zygote java层的大概流程我们已经梳理完了,现在我们来总结一下:

  1. 创建ZygoteServer ,这个server存在的目的是让zygote接收来自socket的请求,进而fork进程,zygoteServer 里面封装了socket。
  2. preload(bootTimingsTraceLog):预加载系统资源res,加载 Android sdk class资源 和其他libc。
  3. forkSystemServer,就是fork 产生了SystemServer进程。
  4. 调用 runSelectLoop() ,接收其他进程发送的socket消息,进而创建子进程。

tips:

  • 调用preload完成系统资源的预加载,主要包括preloadClasses,preloadResources,preloadDrawables, preloadSharedLibraries。这些资源并不是给zygote自己实际显示使用的,它之所以存在,是为后面fork 出来的App 去运行而准备的。因为app 进程需要运行就需要framework 层的系统资源,而这些资源就会在这里得到加载。
  • zygote使用跨进程通信,通过的是socket。zygote是被fork的进程,在linux中,被fork的进程通常是不允许有多线程的,因为会产生死锁的问题。

总结:

zygote进程的启动分为两大部分,

native:

执行Native层面的代码,这个过程主要包含:虚拟机启动,JNI资源函 数的注册,启动zygote的java层;

java:

执行java层面的代码,这个过程主要包含:预加载公用的各种资源,创建socket服务器并在runSelectLoop中死循环等待socket消息,fork 了systemServer进程等操作

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐