写了这么久的Android应用程序,是时候来八一八Android程序的启动原理了,文章不长,喜欢的朋友点个收藏谢谢。
只要是Android系统,运行的第一个程序一定是引导程序,可以这么说,所有的unix系统都有引导加载程序。这个引导加载程序的作用是在在加载 Linux 内核之前进行低级(底层)系统初始化。
Android系统启动的第一阶段是将recovery镜像加载到系统flash里(就是我们的固定内存Rom),这也是引导程序的主要功能。
引导程序会检测手机按键(实体按键,刷机的小伙伴不陌生,recovery模式下有些不能用触屏,要使用方向键和关机键配合操作),我们可以用这些案件切换功能和模式,比如快速启动或实现某个功能,比如重新刷写镜像,下载和执行内核image。
最终的效果就是会把内核加载到RAM中(这里通常是/boot flash分区中的内核)。Linux内核
内核在启动构建Android的用户空间程序和应用程序之前,会完成大部分硬件,驱动程序和文件系统的初始化,只要包括:
- 核心内核初始化(内存和I/O区初始化,中断启动,进程表初始化)
- 驱动程序初始化
- 挂载/root文件系统
- 启动第一个用户空间进程init(我之前写过一篇init.rc加载的文章,那个是脚本,这个是进程)
在启动时,Android回家再Linux内核并启用进程号为1(pid=1)的名叫init的进程,这个和其他linux系统的启动是一样的,我们可以通过ps打印出来:
init程序是 Android 启动序列的关键组件,它是初始化 Android 系统的主要元素。
Android.init会处理两个文件,执行它里面的脚本。
第一个是通用的init.rc,有兴趣的小伙伴可以去看下那篇文章,都有中文注释,看了大概能搞明白init启动过程。这里我们简单过一下。init.rc适用于所有的Android设备,每个版本的init.rc文件内容会有一些区别。第二个rc文件是根据设备厂商来的,比如nexus7的rc文件名称是init.flo.rc
。
在这些文件中,我们可以找到负责启动名为daemons的进程的命令。它们位于硬件抽象层之上,然后通过sockets监听一些数据,比如下面的:
- ADBD 全名叫做Android Debug Bridge Daemon,用于管理Adb连接。
- Debugger Daemon管理调试程序请求,比如dump内存等。
- Radio Interface Layer Daemon这个我们见得不多,因为他是跟基带调试调节器相关的,用于管理无线电通讯的,手机必须有这个才能称作电话。
然后他还启动了系统服务,这个服务很重要,我们在framework层申请的所有服务都要通过这个服务来申请,我们暂且理解为所有服务的老大哥。
然后你往下看还能找到决定开机动画的代码,你知道我们其实可以通过adb shell随时调用开机动画吗?
adb shell bootanimation
然后你就会看到这个:
启动 Linux 守护进程后,init 进程启动了一个非常简洁的进程,称为Zygote。(做逆向的肯定不陌生,因为附加进程都是在这个孵化进程执行的时候)。这只是 Android 平台所有其余部分的开始,Zygote 进程基本上是一个预热的ART/Dalvik VM,加载了所有标准核心包(如 java.util.HashMap ,j包括java包下mac地址,zygote孵化出应用的时候都会用到这些核心标准组件,这也就是为什么不能在程序启动后通过hook修改真实mac地址的原因)。
zygote加载后它会睡眠状态。当需要启动新的应用程序时,系统会向该进程发送一个 Intent(带有类似于“执行 com.example.MainActivity”的消息)。Zygote 进程被唤醒,fork一个进程子进程 ,创建一个新的 VM 实例并加载请求的组件,例如。com.example.MainActivity),然后重新进入睡眠状态。
所以每个应用程序都运行在自己的进程中,互不干扰。
Zygote 是 Android 应用程序启动如此之快的原因。
此时我们已经启动了一堆子流程:
Init 启动运行时进程
Runtime 是AppRuntime的一个实例,他是AndroidRuntime的子类。
Runtime这个进程做了一件非常重要的事情:
它启动了SystemManager(服务管理器),这实际上是Binder 的上下文管理器,用于处理服务注册和查找(如 DNS服务)。
同时它将 Service Manager 注册为 Binder 服务的默认上下文管理器。
接下来,Zygote fork 一个新的 ART/Dalvik VM 实例并启动System Server。
System Server 用来启动像 Surface Flinger、Audio Flinder 一样的系统服务,例如:
- Entropy Service
- Power Manager
- Activity Manager
- Telephony Registry
- Package Manager
- Battery Service
- Lights Service
- Vibrator Service
- Alarm Manager
- Window Manager
- Bluetooth Service
- 以及其他的一些服务。
可以点击这里看源码实现;
上面这些服务都会把自己注册到ServiceManager中。
如果要使用这些服务,你只需要这么调用:
val powerManager = context.getSystemService(Context.POWER_SERVICE)
是不是贼方便?
System准备好了
到这个时候你就可以启动home应用了,比如launcher。
Activity Manager会发送一个请求到Zygote然后告诉他“我现在要启动一个activity并且订阅的filter是”Intent.ACTION_MAIN 和 Intent.CATEGORY_HOME
,这时会触发Zygote执行fork操作并使用Home Activity 和新的 ART/Dalvik VM 加载这个新进程。
这个时候你已经进入到系统桌面了。
接下来我们来看看,我们开发的your.app.MainActivity是怎么被启动的呢?
- 点击应用程序图标。Home应用程序(Launcer)会执行下面代码:
val launchIntent = packageManager.launchIntentForPackage("your.app.MainActivity")
startActivity(launchIntent)
- 在 PackageManager 和 ActivityManager 的配合下使用你的包名your.app/your.app.MainActivity调用 Zygote,你可以把它和命令行执行java类比:
java -cp your.app your.app.Main
- zygote 然后使用新的 ART/Dalvik VM fork 并加载活动组件your.app.MainActivity。
到这里整个系统启动并启用应用程序就分析完了,如果你觉得有帮助,欢迎点赞收藏让更多的人看到哦。