Android系统的启动

本文用于记录Android系统相关知识点。主要是文字总结~

一、Android系统架构

Android系统架构分为五层:
① 应用层(APP)
② 应用框架层(Framework)
③系统运行库层(native C/C++,比如OpenGL ES;Android runtime以及Android基础库)
④ 硬件抽象层(内核与硬件电路之间的接口层)
⑤ Linux内核层(内存管理,进程管理)

二、Android系统启动

① init进程

init进程是Android系统中用户空间的第一个进程,被赋予了很多重要的职责,比如创建Zygote和属性服务等。

介绍init之前,先了解系统的启动:

  • 当电源按下时引导芯片代码从预定的地方(固化在ROM)开始执行。加载引导程序BootLoader到RAM中,然后执行。BootLoader是Android系统运行前的一个小程序,负责把系统OS拉起来并运行。
  • 当内核启动时,设置缓存,被保护存储器,计划列表,加载驱动。在内核完成系统设置后,会在系统文件中寻找init.rc文件,并启动init进程。
  • init进程用来初始化和启动属性服务,也用来启动Zygote进程。

简单说就是,顺序就是:

引导程序 ➡️➡️➡️  Linux内核  ➡️➡️➡️  init进程

从init进程的main函数可以看出,它主要是做了以下三件事:

  • 创建和挂在启动所需的文件目录
  • 初始化和启动属性服务。(属性服务类似注册表管理器,用键值对记录用户和软件的一些使用信息,在系统或软件重启时,能根据这些记录,进行相应的初始化)
  • 解析init.rc 配置文件并启动Zygote进程。

② Zygote进程

Zygote之所以叫孵化器,是因为DVM和ART,应用程序进程以及运行系统的关键服务的SystemServer进程都是由Zygote进程所创建的。
Zygote进程在启动时会创建DVM或者ART,通过fork而创建的APP进程以及SystemServer进程可以在内部获取一个DVM或者ART的实例副本。

在init.rc(使用的是Android Init Language)中决定要启动哪一个Zygote脚本(使用的是Android Init Language)。

init启动Zygote,会找到要启动的Zygote脚本,判断进程是否启动,如果没有就fork函数创建子进程,并返回pid值。如果进程被启动,就会进入Zygote的main函数,也就是app_main.cpp的main函数中,并调用runtime的start函数启动ZygoteInit。

Zygote进程都是通过fork创建子进程,所以它们都可以进入app_main.cpp的main函数。main函数的参数可以判断该进程是什么进程(是Zygote还是SystemServer还是其他)。
如果是Zygote进程,会调用AppRuntime的start函数。该函数会先创建java虚拟机,为虚拟机注册JNI方法。通过参数(ZygoteInit的名字)找到ZygoteInit的main方法,并通过JNI调用该main的方法。也就是这里从Native层进入Java框架层。

ZygoteInit的main函数主要做了四件事:

  • ZygoteServer创建一个Server端的Scoket(ScoketName为zygote,用来等待AMS请求Zygote进程赉 创建新的应用程序进程)
  • 预加载类和资源
  • 启动SystemServer进程(Zygote通过fork,进程名为system_server)
  • 等待AMS请求创建新的应用程序进程(ZygoteServer的runSelectLoop,无限循环等待AMS的请求)

所以从上面来看,程序运行的顺序如下:

app_main  ➡️➡️➡️  AndroidRuntime ➡️➡️➡️ ZygoteInit ➡️➡️➡️ ZygoteServer

Zygote进程启动总结:

  • 创建AppRuntime并调用其start方法,启动Zygote进程。
  • 创建java虚拟机并为java虚拟机注册JNI方法。
  • 通过JINI调用ZygoteInit的main函数进入Zygote的java框架层。
  • 通过registerZygoteSocket方法创建服务器端Scoket,并通过runSelectLoop方法等待AMS的请求来创建新的应用程序。
  • 启动SystemServer进程。

③ SystemServer进程

SystemServer进程用于创建系统服务(AMS,WMS和PMS等)。
SystemServer是在ZygoteInit的startSystemServer方法中启动的,SystemServer进程是Zygote的fork,需要关闭对其进程没用的Socket。
除了startSystemServer还要执行handleSystemServerProcess,即处理SystemServer进程,主要的处理呢有启动Binder线程池(nativeZygoteInit)和进入SystemServer的main方法。

ZygoteInit  ➡️➡️➡️  SystemServer

nativeZygoteInit是一个JNI方法,底层是AppRuntime的onZygoteInitonZygoteInit主要是启动线程池。

进入SystemServer是通过RuntimeInit的applicationInit,接着调用invokeStaticMain,通过反射得到SystemServer类,找到SystemServer类的main方法,通过Zygote中的静态类MethodAndArgsCaller动态调用(这个有点不理解?)。

接下来就直行道SystemServer的main函数,main函数主要有以下作用:

  • 创建消息Looper
  • 加载动态库
  • 创建SystemServiceManager(会对系统服务进行创建、启动和生命周期管理)
  • 启动服务(引导服务、核心服务、其他服务),启动比较简单,直接通过startServer,并添加在mServices中。

所以,SystemServer的启动流程主要经过了以下的过程:

Zygote ➡️➡️➡️ AndroidRuntime ➡️➡️➡️  RuntimeInit ➡️➡️➡️ MethodAndArgsCaller ➡️➡️➡️ systemServer

SystemServer的主要工作:

  • 启动Binder线程池,这样就可以与其他进程进行通信。
  • 创建SystemServiceManager,用于对系统服务的创建、启动和生命周期管理
  • 启动各种系统服务

④ Launcher进程

Launcher是Android系统的桌面,也是一个应用程序,用来启动应用程序和管理应用程序的图标。Launcher在启动过程中会请求PMS返回安装的应用程序的信息,从而才能展示。
SystemService进程启动过程中会启动PMS,PMS启动后会将系统中的应用程序安装完成。然后已经启动的AMS会把Launcher启动起来。

在SystemServer的startOtherServices中,AMS会调用systemReady。systemReady里面
ActivityStackSupervisor(监督者)去resumeXXX,底层是让ActivityStack去resumeXXX,饶了一圈,最终会调用AMS的startHomeActivityLocked
其中的调用流程如下图:

SystemServer ➡️➡️➡️ AMS ➡️➡️➡️ ActivityStackSupervisor ➡️➡️➡️ ActivityStack 
➡️➡️➡️ ActivityStackSupervisor ➡️➡️➡️  AMS

AMS的startHomeActivityLocked是最终启动的关键,创建了Launcher启动所需的Intent,Launcher是一个程序,所以有对应的AndroidManifest.xml,通过AndroidManifest.xml的action和category可以有符合的应用程序已经启动,没有的话调用ActivityStarterde startHomeActivityLocked来启动Launcher。在 startHomeActivityLocked``中,会启动Launcher,并进入Launcher的onCreate```。

Launcher启动后还会做很多工作,比如显示应用程序图标。这些都是在onCreate中完成。

那应用程序图标是怎么显示的呢?

onCreate中,主要涉及到以下这些类:

Launcher ➡️➡️➡️ LauncherAppState  ➡️➡️➡️  LauncherModel

最终会在LauncherModel的startLoader里面创建具有消息循环的线程HandlerThread对象,创建Handler,传入HandlerThread的Looper。也就需要子线程来处理某个任务,这个任务就是LauncherModel的内部类LoaderTask,LoaderTask主要用来加载工作区信息和绑定工作区信息(Launcher是用工作区的形式来显示系统安装的应用程序的图标的),以及加载系统已经安装的应用程序信息loadAllApps,但是loadAllApps是用了mHandler的post方法,所以加载app信息这块实际上跳到主线程去执行,loadAllApps实际上又调用了Launcher的bindAllApplications,而bindAllApplications其实就是设置UI(mAppView)。mAppView是一个AllAppsContainerView,将app信息数组传递给mAppView的setApps方法,mAppView在其onFinishInflate利用recycleView实现app信息的展示。

这样图标的显示流程就结束了。

⑤ APP进程

要启动APP,AMS要先检查APP所需的APP进程是否存在,不存在就会请求Zygote进程启动需要的APP进程。Zygote创建的Scoket就是用来等待AMS请求Zygote来创建新的APP进程。Zygote进程通过Fork自身创建APP进程,APP进程就会获得Zygote在启动时创建的虚拟机实例,也创建了Binder线程池和消息循环。

所以,APP进程的启动通过分割可以分为两个步骤:

  • AMS发送启动APP进程请求
  • Zygote接受请求并创建APP进程
AMS发送启动APP进程请求

AMS通过调用startProcessLocked方法向Zygote进程发送请求。在startProcessLocked主要处理数据(用户ID,线程名等),然后调用Process(线程类)的start,又跳转到ZygoteProcess的startstartViaZygote,在startViaZygote中,会讲应用进程的启动参数保存在argsForZygote中,方法的最后会调用zygoteSendArgsAndGetResultzygoteSendArgsAndGetResult需要两个参数ZygoteState和argsForZygote,ZygoteState是ZygoteProcessopenZygoteSocketIfNeeded返回的,在openZygoteSocketIfNeeded中,与Zygote进程建立Scoket连接,并返回ZygoteState。这边有点绕,ZygoteProcess不是Zygote进程的角色,是用来保持与Zygote进程的通信状态,ZygoteState是ZygoteProcess的静态内部类,用来表示与Zygote进程通信的状态。

走到这步,ZygoteProcess与Zygote进程算是连接成功了,zygoteSendArgsAndGetResult会将argsForZygote写入到ZygoteState,Zygote进程会通过ZygoteState收到一个创建新的APP进程的请求。

所以,大概的流程如下:

AMS  ➡️➡️➡️  Process  ➡️➡️➡️   ZygoteProcess  ➡️➡️➡️  ZygoteState

ZygoteState是一个最终的桥梁。

Zygote接受请求并创建APP进程

在之前讲到的中,ZygoteInit的main中,zygoteServer会创建Scoket,runSelectLoop来等待AMS请求。那runSelectLoop又做了哪些事?runSelectLoop开启了一个死循环,用来等待ZygoteConnection的runOnce执行,```runOnce``做了以下的事情

  • 获取应用程序进程的启动参数
  • 封装成新的参数
  • 创建应用程序进程
  • 关闭Socket(不需要Socket)
  • 处理应用程序进程(ZygoteInit的zygoteInit

其他几条好理解,处理应用程序进程是执行ZygoteInit的zygoteInit,又让RuntimeInit和ZygoteInit做了一些事,概括起来就是创建Binder线程池,通过反射获取到ActivityThread类和main方法,最终执行其main方法,至此就是完成APP进程的创建并运行了主线程的管理类ActivityThread。

大概的流程如下:

Zygote  ➡️➡️➡️  ZygoteServer  ➡️➡️➡️   ZygoteConnection  ➡️➡️➡️  RuntimeInit   ➡️➡️➡️  ActivityThread

还有一个需要补充的点, Binder线程池的启动过程

Binder线程池的启动在ZygoteInit的zygoteInit方法中,是调用ZygoteInit的nativeZygoteInit,这是一个JNI方法,对应的CPP实现是AndroidRuntime的方法,AppRuntime继承自AndroidRuntime,最终又是调用AppRuntime的onZygoteInit(实现在app_main.cpp),通过ProcessState的startThreadPool来启动Binder线程池。
支持Binder通信的进程中都有一个ProcessState类,其中有个mThreadPoolStarted属性来保证被启动一次。没有启动的情况会调用spawnPooledThread来创建线程池的第一个线程,也就是线程池的主线程。
Binder线程是PoolThread类型(继承Thread),在创建的时候会将当前线程注册到Binder驱动程序中,这样该线程也加入了Binder线程池中,新创建的APP进程也就支持Binder进程间通信了。
我们只需创建当前进程的Binder对象,并将它注册到ServiceManager中就可以实现Binder进程间通信,而不必关心进程间是如何通过Binder进行通信的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容