本文用于记录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的onZygoteInit
。onZygoteInit
主要是启动线程池。
进入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的start
→startViaZygote
,在startViaZygote
中,会讲应用进程的启动参数保存在argsForZygote中,方法的最后会调用zygoteSendArgsAndGetResult
。zygoteSendArgsAndGetResult
需要两个参数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进行通信的。