详解Android系统启动是如何启动的

首先对Android的系统启动流程进行一个介绍,这个启动流程是贯穿Android四层架构的过程:

    一、启动电源以及系统启动:引导芯片代码从固化在ROM上的预定义地方开始执行,加载引导程序BootLoader到RAM然后执行

    二、引导程序BootLoader:是在Android系统启动前的程序,其主要作用是把系统OS拉起来并运行

    三、Linux内核启动:在启动时,设置缓存、被保护存储器、计划列表、加载驱动。当内核完成系统设置,会首先寻找init.rc文件并启动init进程

    四、init进程启动:初始化和启动属性服务,并且启动Zygote进程

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

        (2)解析init.rc配置文件并启动Zygote服务进程

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

    五、Zygote进程启动:创建java虚拟机并为java虚拟机注册JNI方法,创建服务端Socket启动SystemServer进程

        (1)init.rc采用Import来引入Zygote启动脚本,会根据ro.zygote来引入不同的文件

        (2)在app_main.cpp中判断是否运行在Zygote进程中,如果是就会调用runtime.start()

        (3)AndroidRuntime里的start()会启动java虚拟机并为其注册JNI方法

        (4)通过JNI调用ZygoteInit的main函数进入Zygote的java框架

        (5)通过registerZygoteSocket方法创建服务器端Socket通过runSelectLoop方法等待AMS的请求来创建新的应用程序进程

        (6)启动SystemServer

    六、SystemServer进程:启动Binder线程池和SystemServerManager,并启动各种服务。

        (1)Zygote进程启动SystemServer进程

        (2)Zygoteinit内创建Binder线程池,与其他进程通信

        (3)进入SystemServer的main()

        (3)创建SystemServiceManger对系统服务进行创建,启动和管理

        (4)启动3种系统服务:引导服务、核心服务、其他服务

    七、Launcher启动:被SystemServer进程启动的AMS会启动Launcher,启动后会将以安装应用的快捷图标显示到界面上

        (1)SystemServer启动Launcher

        (2)应用图标显示过程

一、启动电源

    当启动电源键的时候硬件电路会产生一个确定的复位时序,保证CPU是最后一个被复位的器件,如果CPU第一个被复位,则当CPU复位后开始运行时,其他硬件内部的寄存器状态可能还没有准备好比如磁盘或者内存,那么久可能出现外围硬件初始化错误。当正确完成复位后,CPU开始执行第一条指令,引导芯片代码从预定义的地方开始执行。

二、引导程序BootLoader

    这时加载引导程序BootLoader到RAM中然后执行,该引导程序BootLoader是在Android操作系统运行前的一个小程序主要作用是把系统来起来运行。该指令所在的内存地址是固定的,这由CPU的制造者指定。不同的CPU可能会从不同的地址获取指令,但这个地址必须是固定的,这个固定地址所保存的程序往往被称为引导程序(BootLoader)。

    对于Android而言,最常用的bootloader还是U-boot,其作用就是初始化硬件设备,比如网口、SDRAM、RS232等,并提供一些调试功能,比如像NAND Flash写入新的数据,这可用于开发过程中的内核烧写、等级等。U-boot的启动过程大致上可以分为两个阶段:

    第一阶段汇编代码:U-boot的第一条指令从cpu/armXXX/start.S文件开始

    第二阶段C代码:从文件/lib_arm/board.c的start_armboot()函数开始。

三、启动Linux内核层

    Linux启动分为3个步骤分别是:

    1.自解压过程

    2.设置ARM处理器的工作模式

    3.C代码进行Android的初始化全部工作。

    Linux内核启动的第一个阶段是从start_kernel函数开始的。start_kernel是所有Linux平台进入系统内核初始化后的入口函数,它主要完成剩余与硬件平台的相关初始化工作,当内核启动的时候:设置环境、开启MMU建立列表、初始化串口、加载驱动、挂载根目录系统。

    挂载根目录的原因是启动第一个init进程时必须以根目录系统为载体,在内核完成系统设置后,会首先在根文件系统中寻找init.rc并启动init进程,当Linux找到init服务后会让init负责后续初始化系统使用的工作。

    严格上讲,Android系统实际上是运行于Linux内核之上的一系列"服务进程",并不算一个完成意义上的"操作系统";而这一系列进程是维持Android设备正常工作的关键,所以它们肯定有一个"根进程",这个"根进程"衍生出了这一系列进程。这个"根进程"就是init进程。

四、启动init进程

    init进程是Android系统启动的第一个进程,进程号为1,作为第一个进程需要创建Zygote(孵化器)和属性服务等。Android系统启动流程的前几步,以引入init进程为主。它通过解析init.rc脚本来构建出系统的初始形态。其他的"一系列"Android系统进程大部分也是通过"init.rc"来启动的。init进程主要用来初始化和启动属性服务,也用来启动Zygote进程。

    在Linux内核加载完成之后会执行根目录下的init文件,启动init进程并且进入init进程的入口函数是main函数,并且查找init.rc文件。

    1.init进程入口函数

    在init进程的入口函数内创建和挂载启动所需的文件目录,其中挂载了五种文件系统:tmpfs、devps、proc、sysfs和selinuxfs。这些都是系统运行时的目录,只在系统运行的时候会存在,系统停止时会消失。之后会调用函数:

        (1)property_init():对属性服务进行初始化

        (2)singl_handler_init():设置子进程信号处理函数,当Zygote进程异常退出时会发出一个信号,init进程就会调用该函数接收信号并处理,处理过程是调用handler_singal找到Zygote进程移除信息并重启Zygote服务带有onestart选项的服务。用来防备子进程成为僵尸进程。

        (3)start_property_service():启动属性服务

        (4)ParseConfig("/init.rc"):解析init.rc配置文件

        (5)restart_processes():重启死去的进程

    2.解析init.rc配置文件

    init.rc是一个非常重要的配置文件,由Android初始化语言编写的脚本,包含五种类型语句Action、Command、Service、Option、Import。在Android8.0对init.rc进行了拆分,使每个服务对应一个rc文件,通过Service来通知init进程创建Zygote进程,所以Zygote在init.zygoteXX.rc中定义。这里的Service和组件里的Service是两种东西。 Service类型语句采用ServiceParser来进行解析。

    ServiceParser会通过两个函数对Service语句进行解析:

        (1)ParseSection():可以解析Service的rc文件,用来搭建Service的架子。在函数内部会根据参数构造一个Service对象并完成对象的填充以及添加进Service链表。

        (2)ParseLineSection():用于解析子项。

    

    3.init启动Zygote的Service

    在init.rc中有一个命令class_start,对应的函数为do_class_start(),在init.rc中会通过该命令启动classname为main的Service,Zygote的classname就是main。在do_class_start()中通过ForEachServiceInClass()来遍历Service链表找到Zygote,并执行StrartIfNotDisabled函数对该Service执行Start()进行启动。

    在Start函数里会判断Service是否已经运行,如果已经运行则不启动,还需要判断需要启动的Service对应的执行文件是否存在,如果不存在就不启动。如果子进程没有启动就会调用fork函数创建子进程,调用execve(),Service子进程就会被启动并会进入该Service的main函数里。如果Service是Zygote那么就会进入执行路径下的文件app_main里的main(),在这个函数里会调用runtime.start(“com.android.internal.os.ZygoteInit”,args,zygote),就会启动Zygote。

    4.init启动属性服务。

    同时init还会进行属性服务的初始化以及启动,当init进程启动的时候就会启动属性服务,属性服务的主要功能是即使系统或者软件重启还能够根据之前的注册表中的记录进行相应的初始化工作,在启动时就会分配内存用来存储属性,如果之后需要直接读取即可。通过property_init()、start_property_service()进行初始化以及启动属性服务。

    (1)在property_init()内是_system_property_area_init()用来初始化属性内存区域

    (2)通过create_socket在内部先创建非阻塞的Socket并通过listen()对其进行监听的同时也可以设置最多为几个用户提供服务,这样创建的Socket就成为了Server也就是属性服务。

    (3)将property_set_fd放入register_epoll_handler中,用来监听property_set_fd,当有数据到来时init进程将调用handle_property_set_fd()进行处理。

    系统属性分为两种类型:一种是普通属性,还有一种是控制属性,所以handle_property_set函数分为两个处理分支进行处理。property_set主要对普通属性进行修改,首先判断属性是否合法,如果合法就从属性控件上查找该属性,如果属性存在就更新属性值否则就添加该属性。

五、Zygote进程启动

    在Android系统中DVM,ART,应用程序进程以及运行系统的关键服务SystemServer都是由Zygote创建的,Zygote通过fork的形式来复制创建应用程序进程和SystemServer进程,Zygote进程在启动时会创建DVM或者ART,因此通过fork而创建的应用程序和SystemServer可以在内部获取一个DVM或者ART的实例。

    1.Zygote启动脚本

    在init.rc里使用了Import类型语句引入Zygote启动脚本,但是不会直接引入一个固定的文件而是根据属性ro.zygote的内容来引入不同的文件:init.zygote32.rc、init.zygote32_64.rc、init.zygote64.rc、init.zygote64_32.rc。

    Zygote初始化过程:

    

    2.app_main.cpp

    (1) init文件启动Zygote是在app_main.cpp内是通过AndroidRuntime.cpp的start()实现的。因为Zygote是通过fock自身来创建进程,所以它的子进程都可以进入app_main的main().

    (2)为了可以区分main()运行在哪一个进程,判断进入app_main.cpp的main()的进程是否是Zygote,通过判断参数是否包含--zygote,如果包含了main()就运行在Zygote里

    (3)如果运行在Zygote进程中就会调用AppRuntime的start()

    

    3.AppRuntime.cpp

    (1)在start()内会通过startVm()来创建虚拟机。

    (2)startReg()为java虚拟机注册JNI方法。

    (3)将传入的className转换为文件路径并赋值给slashClassName,在通过FindFindClass()找到ZygoteInit。

    (4)通过JNI方法调用ZygoteInit的main(),当前运行在Native层,但是ZygoteInit的main()是java编写的所以需要通过JNI来调用java,JNI调用ZygoteInit的main方法使Zygote进入java框架层。在这个步骤之前是没有代码进入java框架层的。

    4.ZygoteInit

    (1)通过registerServerSocket()创建一个Server端的Socket,这个socket用于等待ActivityManagerService请求Zygote来创建新的应用程序进程,当Zygote进程将SystemServer进程启动之后就会在这个服务端上的Scoket等待AMS请求Zygote进程来创建新的应用程序。

    (2)通过preload()预加载类和资源

    (3)通过startSystemServer()内会创建一个args数组来保存启动Systemserver的启动参数,然后将args封装成Arguments对象供forkSystemServer()调用,调用forkSyatemServer()来fork当前进程创建的一个子进程,也就是SyatemServer进程,该进程会启动系统的服务。

    (4)在zygoteServer.runSelectLoop()中获得registerServerSocket()创建的Server端的Socket并添加进fd列表fds中,fds列表是存储通过mServerSocket.getFileDescriptor()获得的socket的fd字段。接下来无限循环等待AMS的请求,创建新的应用进程。之后会对存储的信息进行遍历判断服务器端Socket是否与客户端连接上,也就是Zygote和AMS建立了连接。当AMS向Zygote进程发送了一个创建应用进程的请求,ZygoteConnection.runOnce()会创建一个新的应用进程,并在创建之后将这个连接从socket连接列表peers和fd列表fds中删除。peers列表是存储通过acceptCommandPeer得到的ZygoteConnection类。

六、SystemServer进程

    SystemServer进程主要用于创建系统服务,比如AMS、WMS和PMS都是它创建的。

    SystemServer的启动过程:

    

    1.Zygote启动SystemServer

    (1)在ZygoteInit的startSystemServer()启动了SystemServer

    (2)在startSystemServer()内会调用handleSystemServerProcess()来启动SystemServer进程

    (3)在handleSystemProcess()内调用了ZygoteInit.nativeZygoteInit()来启动Binder线程池,这样就可以使用Binder与其他进程进行通信。

    2.启动Binder线程池

    (1)nativeZygoteInit()是一个Native方法,对应的JNI文件是AndroidRuntime.cpp的com_android_internal_os_ZygoteInit_nativeZygoteInit(),在方法内gCUrRuntime->onZygoteInit();

    (2)gCUrRuntime具体指向app_main.cpp的AppRuntime类的onZygoteInit(),通过proc->startThreadPool();来启动线程池

   3.进入SystemServer的main()

    (1)在zygoteInit()里会有Runtime.applicationInit(),在该方法中调用了invokeStaticMain()

    (2)在invokeStaticMain()内通过反射得到SystemServer类,并找到该类的main()

    (3)将找到的main()传入Zygote.MethodAndArgsCaller()并抛出异常,不再invokeStaticMain()内调用main()是希望这种抛出异常的处理会清除过程中的堆栈帧,这会让SystemServer的main()像是该进程的入口方法,因为在Zygote启动SystemServer进程之后做了很多准备工作而这些工作是在调用main()之前的行为。

    (4)会在ZygoteInit.java的main()会捕获该异常并调用SystemServer的main()

    (5)当ZygoteInit.java的main()捕获到时就会调用MethodAndArgsCaller的run(),MethodAndArgsCaller是Zygote.java的静态内部类,在该方法内会调用inoke()进入SystemServer的main()

    4.解析SystemServer进程

    (1)在SystemServer的main()里直接new SystemServer().run();

    (2)在run()内创建了消息Looper,加载了动态库libandroid_servers.so它会对系统服务进行创建、启动、生命周期管理,创建了SystemServerManager,并启动引导服务、核心服务、其他服务,这些服务的父类均为SystemServer

七、Launcher启动

    启动launcher是用来显示系统中已经安装的应用程序,在Launcher的启动过程中会请求PackageManagerService返会系统中已经安装的应用程序的信息,并封装成一个快捷图标显示在系统屏幕上。

    Launcher代表系统的桌面,作为系统的启动器用于启动相应的应用程序,显示和管理应用程序的图标和组件。Launcher是用工作区的形式来显示系统安装的应用程序的快捷图标,每个工作区都是用来描述一个抽象桌面,由n个屏幕组成,每个屏幕又分为n个单元格,每个单元格用来显示一个应用程序的快捷图标,Launcher完成启动后,作为桌面会显示应用程序图标,与应用程序开发有所关联,应用程序图标是用户进入应用程序的入口。

    Launcher启动过程:

   1.SystemServer启动Launcher

    (1)SystemServer进程在启动的时候会启动PackageManagerService,启动后会将系统中的应用程序安装完成。在此前AMS会将Launcher启动起来。AMS的systemReady()作为Launcher的入口。

    (2)systemReady()在SystemServer的startOtherServices()被调用,该方法内调用了ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(),以上方法会调用描述Activity堆栈的ActivityStack.resumeTopActivityUncheckedLocked()

    (3)在resumeTopActivityUncheckedLocked()中会调用AMS的startHomeActivityLocked(),在该方法中判断工厂模式和mTopAction的值符合要求就执行下去,如果mFactoryTest的模式为低级工厂模式并且mTopAction等于null时就返回false。符合要求即非低级工厂且不为null就会继续执行下去,会通过getHomeIntent()创建Intent。

    (4)getHomeIntent()中创建Intent,并将mTopAction和mTopData传入,最后返回Intent再回到AMS的startHomeActivityLocked(),然后启动应用程序Launcher。因为Launcher的AndroidManifest文件中的intent-filter设置的category为HOME,使Launcher为主Activity。

    2.Launcher中应用图标显示过程

    (1)Launcher的onCreate()里会获取LauncherAppState的实例,通过LauncherAppState.setLauncher()将Launcher对象传入,

之会调用Launcher.initialize(),在该方法内会将传入的Launcher封装成一个弱引用对象

    (2)在onCreate()会调用startLoad(),该方法在LauncherModel里创建具有消息循环的线程HandlerThread对象、同时将创建的Handler对象以及LoaderTask对象,并将Handler和LoaderTask传入HandlerThread的Looper,这里Handler的作用就是向HandlerThread发出消息而LoaderTask则是作为消息被发送。

    (3)LoaderTask类实现了Runnable接口,当其描述的消息被处理的时候就会调用它实现的run方法:加载工作区信息,绑定工作区信息,加载系统已经安装的应用程序信息等。

    (4)通过loadAllApps()加载已安装的应用程序信息,通过Launcher.bindAllApplications()调用setApps(),将包含信息列表的apps传进去。并在AllAppsContainerView中将包含应用信息的列表设置给mApps,会有一个onFinishInflate()用来显示App列表通过向AllAppsRecyclerView()传入mApps和Adapter就可以显示应用程序快捷图标的列表。

猜你喜欢

转载自blog.csdn.net/ZytheMoon/article/details/89438213