安卓启动流程与期间核心组件工作原理

目录

1.总览

1.1 冷启动 / 温启动 / 热启动

1.2 启动流程

2. 又冷启动视角-核心步骤详解与关键角色

2.1  Launcher、AMS

2.2  Zygote fork

2.3 Instrumentation

2.4  Application初始化

2.5  Activity启动

2.6  View绘制

3 关键角色

3.双启动视角-可能出来的问题

 4.叒启动视角-核心组件原理

1.packageManagerService(PMS)

2.androidManifest.xml

3.context

4.Activity 的启动过程(AMS 、application、activity)

5.activity生命周期

 6.LayoutInflater、资源的加载与匹配

7.WMS

8.window与windowmanager

9.view与viewgroup

10.渲染阶段-surfaceflinger/choregrapher/vsync/renderthread

4. 异常场景

4.2 资源加载失败

4.1 启动闪退异常汇总

5. 耗时操作有哪些

5.2 首帧耗时

5.3 白屏检测

6. 优化

6.2 业务侧优化

6.3 业务防劣化

7. 常用的技术

8. 总结

8.3 后续方向

9.参考链接


前言

之前在app启动那块写业务需求,写着写着就被人找:闪退啦,优先看一下~卡死了~黑屏了~跳转失败啦~启动性能又劣化了200ms,看看呢,我的kpi快跑路了~为什么我们的view和别人的view争c位没争赢!蛙趣!这俩view叠一起了。我们业务的view怎么没出来!切换一下tab把别人2个tab的业务的事件分发干掉了?切换了一下版本app冻结了?又掉帧了~这动画咋不动了?这动画咋少播了一秒,skip了吧!你不能在这加view啊,耗时又得增加几十毫秒,框架肯定会找过来的!你们的预加载结束是不是这个api~场景a+b+c+d...的情况下这个埋点数据不对劲啊?又oom啦...开发这个功能是业务自己消费数据还是框架消费数据?业务b:我要在这里加载不同类型尺寸的图片,看起来不对劲,你改一下这个bug。你们给的生命周期不对劲啊!这个沉浸式导航栏怎么不沉浸了?弹窗在其他业务页面上飘出来了。。。咦!广播怎么接收不到?投放的数据呢?这版本升级你改一下这个api,咦~这api是干啥的?看看这功能咋降级了,我手机可是高端机呢!启动白了800ms,老板用的是今年最新旗舰版的xxx手机。。。主页又被系统回收了。这个折叠屏咋回事,单屏双屏看起来都怪怪的?视觉:这ui不能用代码写吗?我都会写了?!toast没展示呢~icon展示很慢呢~icon空了~上次那个需求导致有的业务日活低了很多找上门来了,这个版本赶紧插个改进策略优化一下。这保活写的真的是活着但还不如死了。你是说搞了个包体极的优化就把xml里面的动画干没了?想从桌面进app内部页面但是又不想看到启动页?进app在loading页卡住了,看看呢~

每天真的是睁眼一黑又一黑又一黑又一黑又一黑。。。不敢睁开眼希望是我的错觉。尝试解决,部分尝试未果。阴暗扭曲爬行ing

最常出现的问题如下所示:

  • 日常维护遇到的问题:各种类型的闪退、任意一行代码都在闪退、找不到资源闪退、被系统回收、白屏、黑屏、各种类型的跳转失败、卡死、展示首帧时长太长、兼容几千款机型、生命周期、jvm

  • 业务开发常遇见的问题:启动耗时劣化、生命周期异常、页面层级太多导致触摸事件不知道是那一层拦截或者响应了事件、界面ui乱飞、各业务的view叠在一起、因在启动这个特殊的位置开发业务一启动系统资源被完全霸占完了就导致启动业务的一些view渲染失败、卡顿、CountDownTimer直接skip秒、手搓组件

针对上面的问题,需要补充的知识点大概有:启动流程、生命周期及编排/mock、资源加载、jvm、保活、hook、插件化、常见性能知识(防首帧耗时劣化、卡顿、启动链路性能监控)、框架级设计的app路由方式、view管控、view渲染机制、自定义view、事件分发、CountDownTimer、竞态、兼容性问题分析及解决思路、外跳。

       其中最难解决的是闪退、跳转失败、资源找不到、兼容性相关问题。这类问题涉及到不同安卓系统的底层兼容、app框架为了性能优化/各种黑科技在启动阶段搞的各种奇技淫巧、竞态、整app的框架路由设计、厂商魔改aosp。其他的基本都是性能问题和业务问题,业务问题基本能解决。

       启动闪退问题占大头且非常难分析和解决,所以本文更加偏向于安卓启动流程、优化、性能相关知识,尝试从各种角度分析安卓启动,如:最常见的冷启动、context、androidmanifest.xml解析、wms/ams、view绘制原理,然后常见的冷启动优化奇技淫巧,耗时监控,给排查启动闪退相关问题和性能优化提供思路,其他知识点只是带过。俺只是普通业务开发,技术水平有限,梦到哪说哪吧,业务脱敏版。相关知识是从书籍和博客、源码里面翻出来的,问题是平时遇到的,不知道对不对,如想线上环境使用,请先谨慎辨别。文章可能绕了半天也没绕到怎么解决遇到的那几个闪退问题,很正常哈,就是没解决掉才有这篇文章的,解决掉了俺才不写文章呢,该文章只是把知识点先汇在一起找找思路(菜鸡挣扎ing),以厂商、app框架魔改方式为线索,提供分析问题的可能方向。现在开始学,等下次再去做相关业务的时候再遇到类似问题说不定就解决了。

先回顾一下最简单的安卓冷启动流程~

安卓冷启动流程:

  1. 用户点图标

  2. Launcher → AMS

  3. AMS → Zygote

  4. Zygote fork → 新进程跑 ActivityThread.main()

  5. ActivityThread → Application.onCreate()

  6. ActivityThread → Activity.onCreate() → setContentView()

  7. 界面显示

用户手指点击 → Launcher里的onClick()被触发
Launcher调用 startActivity() 
    → 内部通过Binder(跨进程通信) 
    → 调用到 SystemServer进程里的 AMS.startActivity()
AMS判断目标App进程不存在 
    → 通过Socket(不是Binder) 
    → 通知Zygote进程执行 fork()
Zygote执行 fork() 系统调用 
    → 复制出子进程 
    → 子进程里调用 ActivityThread.main() 作为入口
ActivityThread.main() 
    → 内部调用 handleBindApplication() 
    → 通过反射/类加载 创建 Application对象 
    → 调用 Application.onCreate()
ActivityThread 调用 performLaunchActivity() 
    → 通过反射创建 Activity对象 
    → 调用 Activity.attach() 绑定上下文 
    → 调用 Activity.onCreate() 
    → 开发者写的 setContentView() 被执行

1.总览

1.1 冷启动 / 温启动 / 热启动

冷启动:进程不存在,Application 和 Activity 全部重新创建。最慢,本文主要讨论的对象。

温启动:进程存在,但 Activity 实例被销毁了(比如按了返回键退出,或系统内存回收了),需要重新创建 Activity。比冷启动快,因为 Application 还在,不需要重新 fork 进程和初始化 Application。

热启动:按HOME键压后台了。进程存在,Activity 实例也存在,只是被停止(onStop)了,直接 onRestart → onStart → onResume 走一遍就行,不需要重新创建任何东西。最快。

为什么冷启动是重点:冷启动走的是完整链路,所有卡点和坑都集中在这里。遇到的那些奇形怪状的闪退,十有八九是冷启动阶段 Application 还没准备好、ClassLoader 还没加载完、Context 还没正确注入的时候,Activity 抢先加载了某些东西导致的。下面这张表是它们的区别:

启动类型进程ApplicationActivity实例走哪些生命周期
冷启动不存在重新创建重新创建Application.onCreate → Activity.onCreate → onStart → onResume
温启动存在复用重新创建Activity.onCreate → onStart → onResume
热启动存在复用复用(被stop)onRestart → onStart → onResume
1.2 启动流程

1.用户点击桌面图标,Launcher 响应点击,调用 startActivity(),通过 Binder 跨进程通信把启动请求发给 AMS。

2.AMS 收到请求后,调用 PMS 去解析 Intent,PMS 做三件事:解析 Intent(隐式匹配最优组件)、校验调用方权限、检查目标 Activity 在 Manifest 里有没有注册。检查完成后把目标组件信息返回给 AMS。

3.AMS 拿到目标组件信息后,检查目标 Activity 所在的进程是否存在。

4.如果进程不存在,AMS 通过 socket 通知 Zygote 进程 fork 一个子进程出来。Zygote fork 完成后,新进程的入口是 ActivityThread 的 main() 方法。ActivityThread.main() 先准备好主线程的 Looper 和消息队列,然后调用 attach() 方法,通过 Binder 告诉 AMS 这个进程已经就绪了。AMS 收到 attach 后,通过 ApplicationThread 这个 Binder 接口回调应用的 bindApplication()。应用进程收到 bindApplication 回调后,创建 LoadedApk 对象,创建 Instrumentation 对象。然后通过 Instrumentation.newApplication() 方法,用 ClassLoader 加载 Application 类并创建 Application 实例,接着调用 Application.onCreate()。

如果进程已存在,AMS 不走 Zygote fork 和 Application 初始化这几步,直接复用已有进程,跳到后面的 scheduleLaunchActivity。

5.进程就绪且 Application 初始化完成后,AMS 发送 scheduleLaunchActivity 请求给应用进程。应用进程收到后,通过 ClassLoader 加载目标 Activity 类,通过 Instrumentation.newActivity() 创建 Activity 实例。然后创建 ContextImpl 对象,调用 Activity.attach() 把 ContextImpl、Application、PhoneWindow 注入进去。接着依次调用 Activity.onCreate()、onStart()、onResume()。

6.onResume 执行完后,调用 WindowManager.addView(DecorView),内部会创建 ViewRootImpl,调用 requestLayout() 触发绘制。ViewRootImpl 执行 performTraversals(),依次执行 measure(算大小)、layout(定位置)、draw(画内容)。绘制完成后把数据提交给 SurfaceFlinger,SurfaceFlinger 合成图层后显示到屏幕上,用户看到首帧。

2. 又冷启动视角-核心步骤详解与关键角色

2.1  Launcher、AMS

用户点击桌面图标,Launcher调用startActivity(),通过Binder跨进程通信把启动请求发给AMS。

AMS收到请求后,调用PMS去解析Intent。PMS干三件事:解析Intent(隐式匹配最优组件)、校验调用方权限(没权限崩SecurityException)、查Manifest确认目标Activity有没有注册(没注册崩ActivityNotFoundException)。PMS查完把目标组件信息返回给AMS。

2.2  Zygote fork

AMS拿到目标组件信息后,检查目标Activity所在的进程存不存在。

不存在:AMS通过socket通知Zygote进程fork一个子进程。Zygote fork时用了COW机制,子进程和父进程共享内存页,只有在写入时才复制,所以fork本身很快。新进程的入口是ActivityThread.main()。

已存在:直接复用,跳到2.4。

ActivityThread.main()先准备好主线程的Looper和消息队列,然后调用attach()方法,通过Binder告诉AMS进程已就绪。

2.3 Instrumentation

Instrumentation是在ActivityThread的handleBindApplication()方法中,通过LoadedApk.makeApplication()创建的。它是应用进程内所有组件生命周期调度的“总代理”。

Instrumentation在启动链路上干三件事:

newApplication():通过ClassLoader加载Application类,调用newInstance()创建实例,调用Application.attach()和onCreate()。

newActivity():通过ClassLoader加载Activity类,调用newInstance()创建实例。

生命周期监控:Application和Activity的所有生命周期回调最终都是通过Instrumentation的方法去触发的。

2.4  Application初始化

AMS收到进程attach之后,通过ApplicationThread(ActivityThread的内部类,Binder接口)回调应用的bindApplication()。

应用进程收到bindApplication回调后:创建LoadedApk对象(承载APK信息、Resources、ClassLoader),创建Instrumentation对象。Instrumentation.newApplication()通过ClassLoader加载Application类,创建实例,调用attach()注入Context,最后调用Application.onCreate()。

2.5  Activity启动

Application初始化完成后,AMS发scheduleLaunchActivity请求过来。

应用进程收到后,ClassLoader加载目标Activity类,Instrumentation.newActivity()创建实例。创建ContextImpl,Activity.attach()把ContextImpl、Application、PhoneWindow注入进去。然后依次调用:onCreate()(setContentView触发LayoutInflater解析XML)、onStart()、onResume()。

2.6  View绘制

onResume执行完后,WindowManager.addView(DecorView)被调用。内部创建ViewRootImpl,调用requestLayout()触发绘制。ViewRootImpl执行performTraversals():

performMeasure():从DecorView递归遍历View树,计算每个View的大小。

performLayout():递归遍历,确定每个View的位置。

performDraw():递归遍历,执行每个View的绘制逻辑。

绘制完成后,ViewRootImpl通过Surface提交渲染数据到BufferQueue,SurfaceFlinger取出数据合成图层,显示到屏幕上。

3 关键角色

Launcher:系统桌面应用,点击图标后调用startActivity(),是整个流程的触发者。

AMS:系统级服务,运行在SystemServer进程。启动流程中担任总指挥,协调PMS、Zygote等完成启动。

PMS:系统级服务,运行在SystemServer进程。启动流程中负责Intent解析、权限校验、Manifest检查。

Zygote:系统孵化器进程,所有应用进程通过它fork出来。启动流程中负责接收AMS请求,fork应用子进程。

ActivityThread:应用进程的主线程类,包含main()入口。启动流程中负责进程入口初始化、Looper准备、处理AMS的调度请求。内部类ApplicationThread用于接收AMS的Binder回调。

Instrumentation:应用进程内的生命周期总代理。启动流程中负责通过ClassLoader创建Application和Activity实例,并触发其生命周期回调。

Application:应用的全局上下文,进程中只有一个实例。启动流程中在onCreate()初始化全局状态。

Activity:UI承载组件。启动流程中经过实例化、Context注入、生命周期回调后显示。

Context(ContextImpl):应用环境的上下文,提供Resources、AssetManager、系统服务访问。启动流程中在Activity.attach()时创建并注入。

Window(PhoneWindow):Activity的View容器。启动流程中在attach()时创建,setContentView()时放入DecorView。

WindowManager(WindowManagerImpl):管理Window的添加/更新/删除。启动流程中在onResume后调用addView(DecorView)触发绘制。

ViewRootImpl:连接WindowManager与DecorView的桥梁。启动流程中负责执行performTraversals()的measure/layout/draw三大流程。

DecorView:Activity的根View,包含标题栏和内容区域。启动流程中setContentView()把布局inflate到内容区域。

View:UI控件基类。启动流程中递归执行measure/layout/draw。

SurfaceFlinger:系统级服务,独立进程。启动流程中接收渲染数据,合成图层后送显。

ApplicationThread:ActivityThread的内部类,Binder接口。启动流程中接收AMS的跨进程回调。

3.双启动视角-可能出来的问题

不知道上面的讲清楚没,上面的是常见的八股文式介绍,再来另外几个启动视角。

安卓系统初始化

安卓冷启动流程

绿色的线为冷启动流程。

其中:

  1. launcher.java onClick响应这里rom厂商可以直接在这里修改代码做到应用启动前的一些操作,普通app也可以通过hook、字节码插桩把这个文件执行改了,这样可以做到拉起外部应用啥的。

  2. instrumentation,这个类是用来自动化测试的,管理activity、fragment、application。比较重要,后面的奇技淫巧的优化启动耗时就是在这里操作。在这里可以作为大型app的启动,也可以在这里设计一些app路由。

  3. LayoutInflater.inflate(...attachToRoot)方法的第3个参数attachToRoot的意义:是用来区分是系统控件还是自定义控件

  4. 自定义view的构造方法哪个不能删除?带第2个参数的不能删除,因为反射的时候用的第2个参数

  5. 想要保住view不能重复添加可以怎么做?设计框架的时候如何规范用户的使用规则?泛型、异常处理、apt编译原理

 4.叒启动视角-核心组件原理

冷启动涉及到以下流程。

PMS查档 → Manifest验身 → Context造环境 → AMS调度 → 生命周期执行 → Window挂画板 → View画内容 → 资源填充

所以需要重点讲一下下面的一些组件原理、流程、与启动的关联。

超长源码攻击预警,适合摸鱼的适合看。

1.packageManagerService(PMS)

PMS 作用: Android 系统的“App 户籍管理处”:

  • 开机时扫所有目录(system + vendor + data),把每个 APK 的包名、版本、签名、权限、安装路径等信息登记在内存里(mPackages)。

  • 扫完之后,写一份“户籍册”到硬盘(packages.xml),下次开机直接读,不用再扫一遍。

  • 所有需要查 App 信息的操作(安装、卸载、启动、权限检查)都通过 Binder 向 PMS 请求。

该步骤位于安卓系统启动流程的这个位置

SystemServer.main()
    ↓
ServerThread.initAndLoop()
    ↓
【PMS.main()】 ← 这里这里
    ↓
其他服务初始化
    ↓
Launcher 启动

与启动的关联

没有 PMS 提前把信息扫进内存,AMS 拿到包名都不知道该启动哪个 APK、从哪个入口类启动。 PMS 就是 AMS 的“信息供应方”。

PMS 源码 8 块核心职责与原理总结

模块核心职责关键代码/变量启动关联(为什么关键)
第一块:SystemServer 启动入口SystemServer 调用 PMS.main(),触发 PMS 整个启动流程ServerThread.initAndLoop() → PackageManagerService.main()PMS 是 SystemServer 启动的第一个重量级服务,它没扫完包,后面 AMS、WMS 都得等着
第二块:main 方法注册到 ServiceManager创建 PMS 实例,通过 Binder 注册到 ServiceManager,名字叫 "package"ServiceManager.addService("package", pm)其他进程(包括 AMS)通过 Binder 调用 PMS 的接口,比如 getPackageInfo()。没注册这一步,所有 App 都装不了、查不到
第三块:构造方法初始化核心成员读 SDK 版本、创建设置对象(Settings)、添加系统 UID、读权限配置、恢复 packages.xmlmSettings = new Settings()
readPermissions()
mSettings.readPw()
把之前安装过的 App 信息从硬盘读到内存。如果 packages.xml 损坏或丢失,所有已安装 App 信息丢失,相当于“恢复出厂”
第四块:外部共享库 Dex 优化扫描系统共享库(如 framework.jar),检查是否需要 dex 优化(dexopt),并清理旧的 dalvik-cachemInstaller.dexopt()
alreadyDexOpted 缓存
dalvik-cache 清理
dex 优化直接影响 App 冷启动速度。预优化过的 APK 在首次启动时不用再做 JIT 编译,启动更快。但如果全量优化,开机时间会变长——这也是“开机慢”的根源之一
第五块:扫描系统目录扫描 /system/framework/system/priv-app/system/appvendor/app 下的 APK,调用 scanDirLI() 解析安装scanDirLI(frameworkDir, ...)
AppDirObserver 监控目录变化
扫描系统预置 App,把它们的信息加载进 mPackages 集合。这些是系统的“骨架”,扫漏了某个系统 App 会导致功能异常(比如设置打不开)
第六块:处理 OTA 更新残留与系统包删除遍历 mSettings.mPackages,检查系统包是否存在;如果 OTA 后某个系统包被移除或覆盖,清除其残留数据possiblyDeletedUpdatedSystemApps
removePackageLI()
removeDataDirLI()
保证系统升级后数据一致性。如果 OTA 后没有清理旧包的数据,会导致包名冲突、存储空间浪费甚至崩溃
第七块:扫描 /data/app 与 /data/app-private扫描用户安装的第三方 App 目录(/data/app 和 /data/app-private),同样调用 scanDirLI() 解析安装scanDirLI(mAppInstallDir, ...)
scanDirLI(mDrmAppPrivateInstallDir, ...)
用户自己装的 App 全在这里。如果不扫这步,桌面 Launcher 上什么都显示不出来
第八块:收尾工作更新共享库路径、分配权限、写入 packages.xml(持久化)、触发 GC 回收updateAllSharedLibrariesLPw()
updatePermissionsLPw()
mSettings.writeLPr()
Runtime.getRuntime().gc()
把这次扫描的结果保存到硬盘,下次开机直接读 packages.xml,不用重新扫全部 APK,极大缩短开机时间

好了,开始看源码,具体代码如下:

SystemServer 启动 PMS 入口

class ServerThread {
    public void initAndLoop() {
        // 准备消息循环
        Looper.prepareMainLooper();
        // ......
        // 省去多行代码......

        // 声明 IPackageManager 临时变量
        IPackageManager pm = null;
        // 省去多行代码......
        try {
            // 通过 PackageManagerService 的静态 main 方法得到 IPackageManager 对象
            pm = PackageManagerService.main(context, installer,
                    factoryTest != SystemServer.FACTORY_TEST_OFF, onlyCore);
        } catch (RuntimeException e) {
            // 省去两行代码......
        }
        // 省去多行代码......
    }
    // 进入消息循环
    Looper.loop();
    // 省去几行代码......
}

public class SystemServer {
    public static final int FACTORY_TEST_OFF = 0;
    // 省去几行代码......
    public static void main(String[] args) {
        // 省去多行代码......
        ServerThread thr = new ServerThread();
        thr.initAndLoop();
    }
}

PMS 的 main 方法(注册到 ServiceManager)

public class PackageManagerService extends IPackageManager.Stub {
    // 省去多行代码......

    public static final IPackageManager main(Context context,
            Installer installer, boolean factoryTest, boolean onlyCore) {
        // 构造一个包管理服务对象
        PackageManagerService pm = new PackageManagerService(context,
                installer, factoryTest, onlyCore);
        // 将该包管理服务添加至 ServiceManager
        ServiceManager.addService("package", pm);
        return pm;
    }
    // ......省去多行代码......
}

PMS 构造方法(初始化核心成员变量)

public PackageManagerService(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
    // 向事件日志写入事件,标识 PackageManagerService 启动
    EventLog.writeEvent(EventLogTags.BOOT_PROCESS_PSM_START,
            SystemClock.uptimeMillis());

    /*
     * SDK 版本检查
     */
    if (mSdkVersion <= 0) {
        Slog.w(TAG, "*** ro.build.version.sdk not set!");
    }

    // 上下文环境对象
    mContext = context;
    // 开机模式是否为工厂模式
    mFactoryTest = factoryTest;
    // 是否仅启动内核
    mOnlyCore = onlyCore;
    // 如果编译版本为 eng 则不需要 dex 优化
    mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
    // 构造 DisplayMetrics 对象以便获取尺寸数据
    mMetrics = new DisplayMetrics();
    // 构造 Settings 对象存储系统运行时的设置信息
    mSettings = new Settings(context);

    /*
     * 添加一些用户 uid
     */
    mSettings.addSharedUserLPW("android.uid.system", Process.SYSTEM_UID,
            ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PRIVILEGED);
    mSettings.addSharedUserLPW("android.uid.phone", RADIO_UID,
            ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PRIVILEGED);
    mSettings.addSharedUserLPW("android.uid.log", LOG_UID,
            ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PRIVILEGED);
    mSettings.addSharedUserLPW("android.uid.nfc", NFC_UID,
            ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PRIVILEGED);
    mSettings.addSharedUserLPW("android.uid.bluetooth", BLUETOOTH_UID,
            ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PRIVILEGED);
    mSettings.addSharedUserLPW("android.uid.shell", SHELL_UID,
            ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PRIVILEGED);

    /*
     * 判断是否在不同的进程
     */
    String separateProcesses = SystemProperties.get("debug.separate_processes");
    if (separateProcesses != null && separateProcesses.length() > 0) {
        if (separateProcesses.equals("*")) {
            mSeparateProcesses = null;
        } else {
            mSeparateProcesses = separateProcesses.split(",");
        }
    } else {
        mSeparateProcesses = null;
    }

    // Installer 由 SystemServer 构造,这里通过该对象负责与底层通信
    mInstaller = installer;

    /* 测量显示对象 */
    WindowManager wm = (WindowManager) context
            .getSystemService(Context.WINDOW_SERVICE);
    Display d = wm.getDefaultDisplay();
    d.getMetrics(mMetrics);

    synchronized (mInstallLock) {
        synchronized (mPackages) {
            // 启动消息处理线程
            mHandlerThread.start();
            // 通过消息处理线程的 Looper 对象构造一个处理消息的 Handler 对象
            mHandler = new PackageHandler(mHandlerThread.getLooper());
            // 使用看门狗监测当前消息处理线程
            Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName());

            // 获取当前的 Data 目录
            File dataDir = Environment.getDataDirectory();
            // 具体对应的是 /data/data 目录
            mAppDataDir = new File(dataDir, "data");
            // 具体对应的是 /data/app 目录
            mAppInstallDir = new File(dataDir, "app");
            // 具体对应的是 /data/app-lib 目录
            mAppLibInstallDir = new File(dataDir, "app-lib");
            // 具体对应的是 /data/app-asec 目录
            mAsecInternalPath = new File(dataDir, "app-asec").getPath();
            // 具体对应的是 /data/user 目录
            mUserAppDataDir = new File(dataDir, "user");
            // 具体对应的是 /data/app-private 目录
            mDrmAppPrivateInstallDir = new File(dataDir, "app-private");

            // 构造 UserManagerService 对象
            sUserManager = new UserManagerService(context, this, mInstallLock, mPackages);

            // 读取并解析 /etc/permissions 下的权限配置文件中的信息并保存到全局变量
            readPermissions();

            // 尝试读取并解析 mac_permissions.xml 文件
            mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();

            // 读取并解析 package.xml 等配置文件
            mRestoredSettings = mSettings.readPw(this, sUserManager.getUsers(false), mSdkVersion, mOnlyCore);

            /* 判断是否有自定义的解析界面 */
            String customResolverActivity = Resources.getSystem()
                    .getString(R.string.config_customResolverActivity);
            if (TextUtils.isEmpty(customResolverActivity)) {
                customResolverActivity = null;
            } else {
                mCustomResolverComponentName = ComponentName
                        .unflattenFromString(customResolverActivity);
            }

            // 标识扫描开始时间的时间戳
            long startTime = SystemClock.uptimeMillis();
            EventLog.writeEvent(
                    EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
                    startTime);

            int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFINE_DIRECTORIES;
            if (mNoDexOpt) {
                Slog.w(TAG, "Running ENG build: no pre-dexopt!");
                // 是否对 APK 文件进行 dex 优化
                scanMode |= SCAN_NO_DEX;
            }

            // 构造一个 String 类型的 HashSet,保存已经 dex 优化的文件路径
            final HashSet<String> alreadyDexOpted = new HashSet<String>();
            // 获取 Java 启动类库的路径,并将其添加到 alreadyDexOpted
            String bootClassPath = System.getProperty("java.boot.class.path");
            if (bootClassPath != null) {
                String[] paths = splitString(bootClassPath, ';');
                for (int i = 0; i < paths.length; i++) {
                    alreadyDexOpted.add(paths[i]);
                }
            } else {
                Slog.w(TAG, "No BOOTCLASSPATH found!");
            }
        }
    }
}

外部共享库 Dex 优化逻辑

// 标识外部 lib 是否有优化
boolean didDexOpt = false;
/* 确保所有的外部 lib 都被优化 */
if (mSharedLibraries.size() > 0) {
    Iterator<SharedLibraryEntry> libs = mSharedLibraries.values().iterator();
    while (libs.hasNext()) {
        String lib = libs.next().path;
        if (lib == null) {
            continue;
        }
        try {
            if (DalvikDexFile.isDexOptNeeded(lib)) {
                alreadyDexOpted.add(lib);
                mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
                didDexOpt = true;
            }
        } catch (FileNotFoundException e) {
            Slog.w(TAG, "Library not found: " + lib);
        } catch (IOException e) {
            Slog.w(TAG, "Cannot deopt " + lib + " is it an APK or JAR? " + e.getMessage());
        }
    }
}

/* 将 /system/framework 目录下两个文件添加到 alreadyDexOpted,而不需要优化 */
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
alreadyDexOpted.add(frameworkDir.getPath() + "/framework.jar");
alreadyDexOpted.add(frameworkDir.getPath() + "/core-res.apk");

// 列出 /system/framework 目录下的文件
String[] frameworkFiles = frameworkDir.list();
if (frameworkFiles != null) {
    for (int i = 0; i < frameworkFiles.length; i++) {
        File libPath = new File(frameworkDir, frameworkFiles[i]);
        String path = libPath.getPath();
        /*
         * 跳过已经优化的文件
         */
        if (alreadyDexOpted.contains(path)) {
            continue;
        }
        /*
         * 跳过不是 APK 或 JAR 的文件
         */
        if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
            continue;
        }
        try {
            /*
             * 判断 APK 或 JAR 文件是否需要优化
             */
            if (DalvikDexFile.isDexOptNeeded(path)) {
                // 通过 Installer 进行优化
                mInstaller.dexopt(path, Process.SYSTEM_UID, true);
                didDexOpt = true;
            }
        } catch (FileNotFoundException e) {
            Slog.w(TAG, "Jar not found: " + path);
        } catch (IOException e) {
            Slog.w(TAG, "Exception reading jar: " + path, e);
        }
    }
}

/*
 * 如果上面的代码中我们对某个文件做过 dex 优化
 * 那么 didDexOpt 就会设置为 true,而本段代码逻辑就会被执行
 */
if (didDexOpt) {
    // 获取 /data/dalvik-cache 目录的 File 对象
    File dalvikCacheDir = new File(dataDir, "dalvik-cache");
    // 遍历目录下的文件
    String[] files = dalvikCacheDir.list();
    if (files != null) {
        for (int i = 0; i < files.length; i++) {
            String fn = files[i];
            /*
             * 删除以 "data@app@" 和 "data@app-private@" 开头的文件
             */
            if (fn.startsWith("data@app@")) {
                Slog.i(TAG, "Pruning dalvik file: " + fn);
                new File(dalvikCacheDir, fn).delete();
            }
            if (fn.startsWith("data@app-private@")) {
                Slog.i(TAG, "Pruning dalvik file: " + fn);
                new File(dalvikCacheDir, fn).delete();
            }
        }
    }
}

扫描系统目录(framework / priv-app / app / vendor)

/*
 * 构造 AppDirObserver 对象,监控 /system/frameworks 目录的变化
 */
mFrameworkInstallObserver = new AppDirObserver(
        frameworkDir.getPath(), OBSERVER_EVENTS, true, false);
mFrameworkInstallObserver.startWatching();
/*
 * 调用 scanDirLI 方法扫描 /system/frameworks 目录下的 apk 文件进行安装
 */
scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
        | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode
        | SCAN_NO_DEX, 0);

/*
 * 这一步与上面类似,只不过其针对的是 /system/priv-app 目录
 */
File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
mPrivilegedInstallObserver = new AppDirObserver(
        privilegedAppDir.getPath(), OBSERVER_EVENTS, true, true);
mPrivilegedInstallObserver.startWatching();
scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM_DIR
        | PackageParser.PARSE_IS_PRIVILEGED, scanMode, 0);

/*
 * 同上,针对的是 /system/app 目录
 */
File systemAppDir = new File(Environment.getRootDirectory(), "app");
mSystemInstallObserver = new AppDirObserver(
        systemAppDir.getPath(), OBSERVER_EVENTS, true, false);
mSystemInstallObserver.startWatching();
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

/*
 * 同上,针对的是 /vendor/app 目录
 */
File vendorAppDir = new File("/vendor/app");
mVendorInstallObserver = new AppDirObserver(
        vendorAppDir.getPath(), OBSERVER_EVENTS, true, false);
mVendorInstallObserver.startWatching();
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

if (DEBUG_UPGRADE) Log.v(TAG, "Running installed update commands");
mInstaller.moveFiles();

处理 OTA 更新残留与系统包删除

// 构造一个 String 类型的 ArrayList 列表,存储不存在的系统 packages 路径
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();

if (!mOnlyCore) {
    // 遍历 Settings 的成员变量 mPackages
    Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
    while (psit.hasNext()) {
        PackageSetting ps = psit.next();
        // 如果不是系统 App,则跳过
        if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
            continue;
        }

        // 如果已经被扫描到了
        final PackageParser.Package scannedPkg = mPackages.get(ps.name);
        if (scannedPkg != null) {
            // 如果在 disabled 列表中,那么说明它是通过 OTA 方式升级更新添加的
            if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
                // 移除其信息
                removePackageLI(ps, true);
                continue;
            }
        } else {
            // 如果不在 disabled 列表中,则直接清除相应的数据
            if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
                psit.remove();
                String msg = "System package " + ps.name + " no longer exists; wiping its data";
                reportSettingsProblem(Log.WARN, msg);
                removeDataDirLI(ps.name);
            } else {
                final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
                if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
                    possiblyDeletedUpdatedSystemApps.add(ps.name);
                }
            }
        }
    }
}

// 获取未完成安装的 apk 包 PackageSetting 列表
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
// 清除未完成安装的安装包
for (int i = 0; i < deletePkgsList.size(); i++) {
    cleanInstallFailedPackage(deletePkgsList.get(i));
}
// 并删除临时文件
deleteTempPackageFiles();
// 清除在 mSettings 中没有被使用的 ShareUserSettings
mSettings.pruneSharedUsersLPW();

扫描 /data/app 与 /data/app-private 目录

/*
 * 如果是普通模式,则还需要处理一些额外的情况
 */
if (!mOnlyCore) {
    EventLog.writeEvent(
            EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
            SystemClock.uptimeMillis());

    // 构造 AppDirObserver 对象,监控 /data/app 目录的变化
    mAppInstallObserver = new AppDirObserver(
            mAppInstallDir.getPath(), OBSERVER_EVENTS, false, false);
    mAppInstallObserver.startWatching();
    // 扫描目录
    scanDirLI(mAppInstallDir, 0, scanMode, 0);

    // 构造 AppDirObserver 对象,监控 /data/app-private 目录的变化
    mDrmAppInstallObserver = new AppDirObserver(
            mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false, false);
    mDrmAppInstallObserver.startWatching();
    // 扫描目录
    scanDirLI(mDrmAppPrivateInstallDir,
            PackageParser.PARSE_FORWARD_LOCK, scanMode, 0);
}

/*
 * 遍历 possiblyDeletedUpdatedSystemApps
 * 处理通过 OTA 更新和删除的 apk 文件
 */
for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
    PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
    mSettings.removeDisabledSystemPackageLPw(deletedAppName);

    String msg;
    if (deletedPkg == null) {
        msg = "Updated system package " + deletedAppName + " no longer exists; wiping its data";
        removeDataDirLI(deletedAppName);
    } else {
        msg = "Updated system app + " + deletedAppName + " no longer exists; wiping its data";
        removeDataDirLI(deletedAppName);
        deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
        PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
        deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
    }
    reportSettingsProblem(Log.WARN, msg);
}

收尾工作(更新库、权限、写文件)

// 给需要使用 ShareLibrary 的 package 找到相应的 ShareLibrary 路径
updateAllSharedLibrariesLPw();

EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
        SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: " +
        ((SystemClock.uptimeMillis() - startTime) / 1000f) + " seconds");

/* 校对 SDK 版本 */
final boolean regrantPermissions = mSettings.mInternalSdkPlatform != mSdkVersion;
if (regrantPermissions) {
    Slog.i(TAG, "Platform changed from " +
            mSettings.mInternalSdkPlatform + " to " + mSdkVersion);
    mSettings.mInternalSdkPlatform = mSdkVersion;
}

// 更新相关信息,并给需要使用的 apk 分配相应的权限
updatePermissionsLPw(null, null,
        UPDATE_PERMISSIONS_ALL | (regrantPermissions ?
                (UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL) : 0));

/*
 * 如果本次启动是第一次正常的启动
 * 那么同时还需要初始化一些默认的首选 App
 */
if (!mRestoredSettings && !onlyCore) {
    mSettings.readDefaultPreferredAppsLPw(this, 0);
}

// 将信息写到相关文件中
mSettings.writeLPr();

EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
        SystemClock.uptimeMillis());

// 通知 GC 回收资源
Runtime.getRuntime().gc();

mRequiredVerifierPackage = getRequiredVerifierLPr();

2.androidManifest.xml

AMS从PMS拿到Manifest数据后,确认目标Activity是否存在、有没有权限拦截等。这个文件是App的"身份证",决定了能不能启动、用什么方式启动。

该步骤位于安卓系统启动流程的这个位置

SystemServer.main()
↓
ServerThread.initAndLoop()
↓
PMS.main() —— PackageManagerService 主入口
↓
PMS.scanPackageLI() —— 扫描并解析 APK
↓
【PackageParser.parsePackage()】 ← 当前讲解位置(XML解析)
├── parseApplication() —— 解析 <application> 标签
│ ├── parseActivity() —— 解析 <activity> 标签
│ ├── parseService() —— 解析 <service> 标签
│ ├── parseProvider() —— 解析 <provider> 标签
│ └── parseReceiver() —— 解析 <receiver> 标签
├── parsePermission() —— 解析 <permission> 标签
└── 其他标签解析...
↓
解析后的信息保存至 PMS
↓
其他服务初始化
↓
Launcher 启动

在 PMS 扫描 APK 的过程中,通过 PackageParser 对 AndroidManifest.xml 进行逐标签解析,将配置信息转化为 Java 对象并存入 PMS 中供后续组件启动使用。

核心步骤和原理如下:

步骤方法职责
1PMS.scanPackageLI(File)入口,构造 PackageParser 并触发解析
2PackageParser.parsePackage(File)准备参数,调用真实解析方法
3PackageParser.parsePackage(Res, Parser)主循环:遍历 manifest 顶层标签
4parseApplication()解析 <application> 及其子标签(四大组件)
5parseActivity()解析 <activity> / <receiver> 及 intent-filter
6parseService() / parseProvider()类似结构,解析对应组件
7解析完成,返回 Package 对象所有组件信息存入 Package 的集合中
8PMS.scanPackageLI(Package)将解析后的信息保存至 PMS

具体代码如下:

创建 Package 对象

package android.content.pm;

public class PackageParser {
    public final static class Package { }
    public final static class Permission extends Component<IntentInfo> { }
    public final static class PermissionGroup extends Component<IntentInfo> { }
    public final static class Activity extends Component<ActivityIntentInfo> { }
    public final static class Service extends Component<ServiceIntentInfo> { }
    public final static class Provider extends Component<ProviderIntentInfo> { }
    public final static class Instrumentation extends Component { }
    public final static class ActivityIntentInfo extends IntentInfo { }
    public final static class ServiceIntentInfo extends IntentInfo { }
    public static final class ProviderIntentInfo extends IntentInfo { }
}

入口,构造 PackageParser 并触发解析

private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanMode, long currentTime, UserHandle user);

private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags, int scanMode, long currentTime, UserHandle user);
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanMode, long currentTime, UserHandle user) {
    mLastScanError = PackageManager.INSTALL_SUCCEEDED;

    // 获取文件路径
    String scanPath = scanFile.getPath();

    // 设置解析标志 mDefParseFlags 默认为 0
    parseFlags |= mDefParseFlags;

    // 使用 scanPath 作为参数构造 PackageParser 对象
    PackageParser pp = new PackageParser(scanPath);
    // ......省去两行代码......

    // 调用 PackageParser 对象的 parsePackage 方法解析 APK 文件
    final PackageParser.Package pkg = pp.parsePackage(scanFile, scanPath, mMetrics, parseFlags);
    // ......省去五行代码......

    // 调用该方法的第二种实现,将解析后的信息保存至 PMS
    PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime, user);

    // ......省去多行代码......
    return scannedPkg;
}

准备参数,调用真实解析方法

public Package parsePackage(File sourceFile, String destCodePath,
    DisplayMetrics metrics, int flags);

private Package parsePackage(Resources res, XmlResourceParser parser,
    int flags, String[] outError);
public Package parsePackage(File sourceFile, String destCodePath,
    DisplayMetrics metrics, int flags) {
    // ......省去多行代码......
    try {
        // 调用第二种实现进行解析
        pkg = parsePackage(res, parser, flags, errorText);
    } catch (Exception e) {
        // ......省去多行代码......
    }
    // ......省去多行代码......
    return pkg;
}

主循环:遍历 manifest 顶层标签

private Package parsePackage(Resources res, XmlResourceParser parser,
    int flags, String[] outError) throws XmlPullParserException,
    IOException {
    // ......省去多行代码......
    final Package pkg = new Package(pkgName);
    // ......省去多行代码......
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
        && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
        // ......省去多行代码......
        String tagName = parser.getName();
        if (tagName.equals("application")) {
            // ......省去多行代码......
            if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {
                return null;
            }
        } else if (tagName.equals("keys")) {
            if (!parseKeys(pkg, res, parser, attrs, outError)) {
                return null;
            }
        } else if (tagName.equals("permission-group")) {
            if (parsePermissionGroup(pkg, flags, res, parser, attrs,
                outError) == null) {
                return null;
            }
        } else if (tagName.equals("permission")) {
            if (parsePermission(pkg, res, parser, attrs, outError) == null) {
                return null;
            }
        } else if (tagName.equals("permission-tree")) {
            if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {
                return null;
            }
        } else if (tagName.equals("uses-permission")) {
            if (!parseUsagePermission(pkg, res, parser, attrs, outError)) {
                return null;
            }
        } else if (tagName.equals("uses-configuration")) {
            // 省去多行代码
        } else if (tagName.equals("uses-feature")) {
            // 省去多行代码
        } else if (tagName.equals("uses-sdk")) {
            // 省去多行代码
        } else if (tagName.equals("supports-screens")) {
            // 省去多行代码
        } else if (tagName.equals("protected-broadcast")) {
            // 省去多行代码
        } else if (tagName.equals("instrumentation")) {
            // 省去多行代码
        } else if (tagName.equals("original-package")) {
            // 省去多行代码
        } else if (tagName.equals("adopt-permissions")) {
            // 省去多行代码
        } else if (tagName.equals("uses-gl-texture")) {
            // 省去多行代码
        } else if (tagName.equals("compatible-screens")) {
            // 省去多行代码
        } else if (tagName.equals("supports-input")) {
            // 省去多行代码
        } else if (tagName.equals("eat-comment")) {
            // 省去多行代码
        } else {
            // 省去多行代码
        }
    }
    // 省去多行代码
    return pkg;
}

解析 <application> 及其子标签(四大组件)

private boolean parseApplication(Package owner, Resources res,
    XmlPullParser parser, AttributeSet attrs, int flags,
    String[] outError) throws XmlPullParserException, IOException {
    // ......省去对 application 节点内属性解析的代码......
    final int innerDepth = parser.getDepth();

    int type;
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
        && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
            continue;
        }
        String tagName = parser.getName();
        if (tagName.equals("activity")) {
            Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false, false);
            if (a == null) {
                // ......省去一行代码......
                return false;
            }
            owner.activities.add(a);
        } else if (tagName.equals("receiver")) {
            Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false);
            if (a == null) {
                // ......省去一行代码......
                return false;
            }
            owner.receivers.add(a);
        } else if (tagName.equals("service")) {
            Service s = parseService(owner, res, parser, attrs, flags, outError);
            if (s == null) {
                // ......省去一行代码......
                return false;
            }
            owner.services.add(s);
        } else if (tagName.equals("provider")) {
            Provider p = parseProvider(owner, res, parser, attrs, flags, outError);
            if (p == null) {
                // ......省去一行代码......
                return false;
            }
            owner.providers.add(p);
        } else if (tagName.equals("activity-alias")) {
            Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError);
            if (a == null) {
                // ......省去一行代码......
                return false;
            }
            owner.activities.add(a);
        } else if (parser.getName().equals("meta-data")) {
            if ((owner.mAppMetaData = parseMetaData(res, parser, attrs, owner.mAppMetaData, outError)) == null) {
                // ......省去一行代码......
                return false;
            }
        } else if (tagName.equals("library")) {
            // ......省去多行代码......
        } else if (tagName.equals("uses-library")) {
            // ......省去多行代码......
        } else if (tagName.equals("uses-package")) {
            // ......省去一行代码......
        } else {
            // ......省去多行代码......
        }
    }
    return true;
}

解析 <activity> / <receiver> 及 intent-filter

private Activity parseActivity(Package owner, Resources res,
    XmlPullParser parser, AttributeSet attrs, int flags,
    String[] outError, boolean receiver, boolean hardwareAccelerated)
    throws XmlPullParserException, IOException {
    // ......省去多行代码......
    mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
    // ......省去多行代码......
    // 注意,这里的 Activity 是继承于 Component 的,而非我们平时应用开发所用的 Activity
    Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
    // ......省去多行代码......
    int outerDepth = parser.getDepth();
    int type;
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
        && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
            continue;
        }
        if (parser.getName().equals("intent-filter")) {
            ActivityIntentInfo intent = new ActivityIntentInfo(a);
            if (!parseIntent(res, parser, attrs, true, intent, outError)) {
                return null;
            }
            if (intent.countActions() == 0) {
            } else {
                a.intents.add(intent);
            }
        } else if (!receiver && parser.getName().equals("preferred")) {
            ActivityIntentInfo intent = new ActivityIntentInfo(a);
            if (!parseIntent(res, parser, attrs, false, intent, outError)) {
                return null;
            }
            if (intent.countActions() == 0) {
            } else {
                if (owner.preferredActivityFilters == null) {
                    owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();
                }
                owner.preferredActivityFilters.add(intent);
            }
        } else if (parser.getName().equals("meta-data")) {
            if ((a.metaData = parseMetaData(res, parser, attrs, a.metaData,
                outError)) == null) {
                return null;
            }
        } else {
            // ......省去多行代码......
        }
    } // ......省去 3 行代码......
    return a;
}

将解析后的信息保存至 PMS

// 调用 PackageParser 对象的 parsePackage 方法解析 APK 文件
final PackageParser.Package pkg = pp.parsePackage(scanFile, scanPath, mMetrics, parseFlags);
// ......省去五行代码......

// 调用该方法的第二种实现,将解析后的信息保存至 PMS
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime, user);

顺便提一嘴,这里用了解释器模式。平时自己写框架语言的时候可以用到。缺点是会引入大量的类

3.context

Zygote fork出新进程后,ActivityThread创建Application,同时创建ContextImpl(Context的实现类)。Context是App的"上下文环境",Application、Activity、Service都会持有它。

Context 贯穿整个应用启动过程,分别在不同的启动阶段被创建和使用:

SystemServer.main()
↓
ServerThread.initAndLoop()
↓
PMS.main() —— 扫描解析APK(PackageParser解析AndroidManifest.xml)
↓
其他服务初始化
↓
Launcher 启动
↓
点击应用图标
↓
AMS.startActivity() —— 向AMS请求启动Activity
↓
ActivityStack.startActivityLocked() —— Activity栈管理
↓
ApplicationThreadProxy —— 跨进程通知应用进程
↓
【ActivityThread.main()】 ← Context创建流程起点
↓
ActivityThread.attach(false) —— 将应用进程绑定到AMS
↓
【H.handleMessage(BIND_APPLICATION)】 ← Application Context 创建
├── handleBindApplication()
│ ├── ContextImpl.createAppContext() → 为Application创建ContextImpl
│ ├── Instrumentation.newApplication() → 创建Application对象
│ └── appContext.setOuterContext(app) → 关联Application与ContextImpl
↓
【H.handleMessage(LAUNCH_ACTIVITY)】 ← Activity Context 创建
├── handleLaunchActivity()
│ └── performLaunchActivity()
│ ├── PackageParser解析结果 → 读取ActivityInfo/ApplicationInfo
│ ├── createBaseContextForActivity() → 为Activity创建ContextImpl
│ ├── ContextImpl.createActivityContext() → 创建具体ContextImpl
│ ├── appContext.setOuterContext(activity) → 关联Activity与ContextImpl
│ ├── activity.attach() → 将Context等参数注入Activity
│ └── instrumentation.callActivityOnCreate() → 回调onCreate()
↓
Activity.onCreate() —— 开发者正式获得Context

哪些核心步骤会用到 Context

系统核心步骤使用的Context来源用途
PackageParser解析暂未创建解析时使用Resources等,不依赖Context
PMS存储组件信息暂未创建仅存储Component信息,不依赖Context
ActivityThread.main()启动通过Looper.prepareMainLooper()准备主线程准备主线程环境
handleBindApplication创建ApplicationContextImpl.createAppContext()为Application创建Context,用于全局应用环境
makeApplication创建Application对象创建好的appContext传入newApplication()构造Application时传入Context
performLaunchActivity启动ActivityContextImpl.createActivityContext()为Activity创建独立Context,包含主题、资源等
activity.attach()创建好的appContext传入attach()将Context注入Activity内部,供其使用
callActivityOnCreate()通过activity.attach()已保存在Activity中Activity使用Context执行onCreate生命周期
获取系统服务Activity/Application中的ContextgetSystemService()获取PMS、AMS等服务
资源加载Context中的ResourcesgetResources()加载布局、字符串等

Context 抽象类中的方法定义:

public abstract class Context {
    // 启动一个 Activity
    public abstract void startActivity(Intent intent);
    public abstract void startActivity(Intent intent, @Nullable Bundle options);
    // 启动多个 Activity
    public abstract void startActivities(Intent[] intents);
    public abstract void startActivities(Intent[] intents, Bundle options);
    // 获取应用程序信息
    public abstract ApplicationInfo getApplicationInfo();
    // 启动一个 Service
    public abstract ComponentName startService(Intent service);
    // 停止一个 Service
    public abstract boolean stopService(Intent service);
    // 绑定一个 Service 到 Activity
    public abstract boolean bindService(Intent service, @NonNull ServiceConnection conn, @BindServiceFlags int flags);
    // 解除绑定 Service
    public abstract void unbindService(@NonNull ServiceConnection conn);
    // 发送广播
    public abstract void sendBroadcast(Intent intent, @Nullable String receiverPermission);
    public abstract void sendBroadcast(Intent intent, String receiverPermission, int appOp);
    // 发送有序广播
    public abstract void sendOrderedBroadcast(Intent intent, @Nullable String receiverPermission);
    public abstract void sendOrderedBroadcast(@NonNull Intent intent, @Nullable String receiverPermission, BroadcastReceiver resultReceiver, @Nullable Handler scheduler, int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras);
    public abstract void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras);
    // 发送粘性广播
    public abstract void sendStickyBroadcast(Intent intent);
    public abstract void sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver, @Nullable Handler scheduler, int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras);
    // 注册广播接收者
    public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter);
    public abstract Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, @Nullable String broadcastPermission, @Nullable Handler scheduler);
    // 取消注册广播接收者
    public abstract void unregisterReceiver(BroadcastReceiver receiver);
    // 获取 ContentResolver 对象
    public abstract ContentResolver getContentResolver();
    // 获取主线程中的 Looper
    public abstract Looper getMainLooper();
    // 获取应用级的 Context 对象
    public abstract Context getApplicationContext();
    // 获取系统服务
    public abstract Object getSystemService(String name);
    // 获取 Resources 对象
    public abstract Resources getResources();
    // 获取 SharedPreferences
    public abstract SharedPreferences getSharedPreferences(String name, int mode);
    // 获取外部文件存储目录
    public abstract File getExternalFilesDir(@Nullable String type);
    public abstract File[] getExternalFilesDirs(String type);
}

ActivityThread.main() 入口方法:

public final class ActivityThread {
    public static void main(String[] args) {
        // 启动 Android 的性能分析工具
        SamplingProfilerIntegration.start();

        // 暂时关闭 CloseGuard 检测,稍后会打开
        CloseGuard.setEnabled(false);

        // 为当前用户初始化环境参数
        Environment.initForCurrentUser();

        // 配置 EventLogger
        EventLogger.setReporter(new EventLoggingReporter());

        // 为 Security 安全系统添加 AndroidKeyStoreProvider 算法
        Security.addProvider(new AndroidKeyStoreProvider());

        // 获取并确保使用凭证在目录中
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        // 设置启动标识值,标识主循环准备初始化
        Process.setArgV0("pre-initialized");

        // 准备循环主线程(也就是当前线程)中的 Looper
        Looper.prepareMainLooper();

        // 构造 ActivityThread 对象并 Attach
        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        // 获取主线程中的 Handler
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        // 调用 Looper 的 loop 方法使主线程中消息循环
        Looper.loop();

        // 如果代码执行到这里说明主线程消息循环出现异常,抛出异常终止系统运行
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
}

ActivityThread 中的 Handler(H类):

public final class ActivityThread {
    final H mH = new H();

    final Handler getHandler() {
        return mH;
    }

    private class H extends Handler {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                    r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null);
                } break;
                case BIND_APPLICATION: {
                    AppBindData data = (AppBindData) msg.obj;
                    handleBindApplication(data);
                } break;
            }
        }
    }
}

handleLaunchActivity 和 performLaunchActivity:

performLaunchActivity是处理activity启动的关键所在,其中对大量activity参数进行初始化。

public final class ActivityThread {
    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        Activity a = performLaunchActivity(r, customIntent);
    }

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // 获取 ActivityInfo 信息
        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE);
        }
        // 获取要启动的 Activity 的组件信息
        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }
        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName, r.activityInfo.targetActivity);
        }

        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClassName());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            // ......
        }

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            if (activity != null) {
                // 获取 Context 对象
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);

                // 通过 attach 方法将上述信息保存在 Activity 内部
                activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                activity.mStartedActivity = false;

                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }
                activity.mCalled = false;

                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                if (!activity.mCalled) {
                    // ......
                }
                r.activity = activity;
                r.stopped = true;
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
            }
            if (!r.activity.mFinished) {
                if (r.isPersistable()) {
                    if (r.state != null || r.persistentState != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, r.persistentState);
                    }
                } else if (r.state != null) {
                    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                }
            }
            if (!r.activity.mFinished) {
                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnPostCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnPostCreate(activity, r.state);
                }
                if (!activity.mCalled) {
                    throw new SuperNotCalledException("Activity " + r.intent.getComponent().toString() + " did not call through to super.onPostCreate()");
                }
            }
            r.paused = true;
            mActivities.put(r.token, r);
        } catch (SuperNotCalledException e) {
            // ......
        } catch (Exception e) {
            // ......
        }
        return activity;
    }
}

createBaseContextForActivity 创建 ContextImpl:

public final class ActivityThread {
    private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
        ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);
        appContext.setOuterContext(activity);
        Context baseContext = appContext;
        return baseContext;
    }
}

handleBindApplication 和 makeApplication:

public final class ActivityThread {
    private void handleBindApplication(AppBindData data) {
        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
    }
}

创建对应的application

public final class ActivityThread {
    public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }
        Application app = null;
        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass) {
            appClass = "android.app.Application";
        }
        try {
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                initializeJavaContextClassLoader();
            }
            // 获取一个 ContextImpl 对象
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            // 获取一个 Application 对象
            app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
            // 将 Application 与得到的 ContextImpl 对象关联
            appContext.setOuterContext(app);
        } catch (Exception e) {
            // ......
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;
        if (instrumentation != null) {
            try {
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                // ......
            }
        }
        return app;
    }
}

后面我们会发现启动流程这里会有2次创建application。但实际不会创建两个Application对象,如上面的代码,有判空,不为空就不创建了。为了防止rom魔改启动导致没执行handleBindApplication导致出问题。所以实际大部分还是走的handleBindApplication的逻辑,application走在activity前面。

这里创建一个application
    public final class ActivityThread {
        private void handleBindApplication(AppBindData data) {
            Application app = data.info.makeApplication(data.restrictedBackupMode, null);
        }
    }


这里创建一个application
    handleLaunchActivity()
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);

context这块用了装饰器模式

阶段创建的Context数量
Application创建时ContextImpl(通过createAppContext1个
Activity创建时ContextImpl(通过createActivityContext每个Activity 1个
Service创建时ContextImpl(通过createServiceContext每个Service 1个
BroadcastReceiver临时ReceiverRestrictedContext每次广播临时获取

Context总数 = Activity数 + Service数 + 1个Application

4.Activity 的启动过程(AMS 、application、activity)

AMS负责协调整个启动过程:管理进程状态、Activity栈、生命周期调度。应用进程创建好后,AMS通过Binder来回通信,通知应用进程该创建Activity了。

位于启动流程中的位置

用户点击桌面图标
    ↓
Launcher 调用 startActivity()
    ↓
系统处理:PMS 解析 AndroidManifest.xml(判断应用是否安装、组件是否存在)
    ↓
【检查进程是否存在】
    ├── 进程已存在 → 直接使用
    └── 进程不存在 → Zygote  fork 新进程 → 执行 ActivityThread.main()
    ↓
【Application 初始化】
    ├── ActivityThread.main() 启动主线程
    ├── ActivityThread.attach() → 绑定到 AMS
    ├── handleBindApplication() → 创建 Application 实例
    └── Application.onCreate() 回调  ← ⭐ 冷启动性能关键点
    ↓
【AMS 处理 Activity 启动】  ← 当前章节内容
    ├── AMS.startActivity()
    ├── ActivityStackSupervisor 处理任务栈
    ├── 检查 Activity 所在进程(此时已存在)
    ├── realStartActivityLocked()
    └── ApplicationThread 跨进程回调
    ↓
【应用进程创建并显示 Activity】
    ├── Handler H → LAUNCH_ACTIVITY
    ├── performLaunchActivity()
    │   ├── 反射创建 Activity 实例
    │   ├── 创建 ContextImpl
    │   ├── activity.attach()
    │   └── callActivityOnCreate() → 回调 Activity.onCreate()
    ├── handleResumeActivity()
    │   ├── performResumeActivity() → 回调 Activity.onResume()
    │   └── Activity.makeVisible() → WindowManager.addView(decor)
    └── WMS.addWindow()
    ↓
View 绘制(measure → layout → draw)
    ↓
用户看到界面

核心阶段

阶段名称起点终点
阶段一发起启动请求Activity.startActivity()Instrumentation.execStartActivity() → 跨进程调用 AMS
阶段二AMS 处理启动请求AMS.startActivityAsUser()startSpecificActivityLocked() 检查进程
阶段三跨进程回调应用进程realStartActivityLocked()ApplicationThread.scheduleLaunchActivity() 发消息
阶段四主线程处理启动消息H.handleMessage(LAUNCH_ACTIVITY)handleLaunchActivity()
阶段五创建 Activity 实例performLaunchActivity() 5 个步骤callActivityOnCreate()
阶段六Application 创建LoadedApk.makeApplication()callApplicationOnCreate() 回调
阶段七onResume 与 Window 添加handleResumeActivity()WMS.addWindow()

核心步骤和源码如下:

阶段一:发起启动请求

1.Activity.startActivity

// 文件:Activity.java
public void startActivity(Intent intent) {
    this.startActivity(intent, null);
}

public void startActivity(Intent intent, Bundle options) {
    if (options != null) {
        startActivityForResult(intent, -1, options);
    } else {
        startActivityForResult(intent, -1);
    }
}

2.startActivityForResult

// 文件:Activity.java
// ★★★ 检查 mParent(ActivityGroup 已废弃),调用 Instrumentation ★★★
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
    if (mParent == null) {
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options);
        if (ar != null) {
            mMainThread.sendActivityResult(...);
        }
    } else {
        // ActivityGroup 已废弃
        if (options != null) {
            mParent.startActivityFromChild(this, intent, requestCode, options);
        } else {
            mParent.startActivityFromChild(this, intent, requestCode);
        }
    }
    if (requestCode >= 0) {
        mStartedActivity = true;
    }
}

3.Instrumentation.execStartActivity

// 文件:Instrumentation.java
// ★★★ 跨进程调用 AMS.startActivity ★★★
public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {

    IApplicationThread whoThread = (IApplicationThread) contextThread;

    // ActivityMonitor 用于测试,可忽略
    if (mActivityMonitors != null) {
        synchronized (mSync) {
            final int N = mActivityMonitors.size();
            for (int i = 0; i < N; i++) {
                final ActivityMonitor am = mActivityMonitors.get(i);
                if (am.match(who, null, intent)) {
                    am.mHits++;
                    if (am.isBlocking()) {
                        return requestCode >= 0 ? am.getResult() : null;
                    }
                }
            }
        }
    }

    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess();

        // ★★★ 跨进程 Binder 调用 AMS.startActivity ★★★
        int result = ActivityManager.getService().startActivity(
                whoThread,
                who.getBasePackageName(),
                intent,
                intent.resolveTypeIfNeeded(who.getContentResolver()),
                token,
                target != null ? target.mEmbeddedID : null,
                requestCode,
                0, null, options);

        // ★★★ 检查启动结果,失败时抛出异常 ★★★
        checkStartActivityResult(result, intent);

    } catch (RemoteException e) {
        return null;
    }
    return null;
}

4.ActivityManager.getService

// 文件:ActivityManager.java
// ★★★ 获取 AMS 的 Binder 代理 ★★★
public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivityManager>() {
            @Override
            protected IActivityManager create() {
                // "activity" 是 AMS 在 ServiceManager 中的注册名
                final IBinder b = ServiceManager.getService("activity");
                final IActivityManager am = IActivityManager.Stub.asInterface(b);
                return am;
            }
        };

阶段二:AMS 内部处理

1.AMS.startActivityAsUser

// 文件:ActivityManagerService.java
// ★★★ 系统端入口 ★★★
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho,
        int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType,
            resultTo, resultWho, requestCode, startFlags, profilerInfo, options,
            UserHandle.getCallingUserId());
}

@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho,
        int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options,
        int userId) {
    // 检查调用者是否被隔离
    enforceNotIsolatedCaller("startActivity");
    // 处理传入的 userId
    userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId);

    // ★★★ 转发给 ActivityStackSupervisor ★★★
    return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage,
            intent, resolvedType, null, null, resultTo, resultWho, requestCode,
            startFlags, profilerInfo, null, null, options, userId, null, null);
}

2.ActivityStackSupervisor 内部流转

// 文件:ActivityStackSupervisor.java
// ★★★ 处理任务栈和启动模式 ★★★
final int startActivityMayWait(...) {
    // ... 省略参数处理 ...
    return startActivityLocked(caller, callingUid, callingPackage, intent,
            resolvedType, ...);
}

final int startActivityLocked(...) {
    // ... 省略部分逻辑 ...
    return startActivityUncheckedLocked(...);
}

final int startActivityUncheckedLocked(...) {
    // 检查启动模式、任务栈等
    // ... 省略任务栈处理 ...
    // ★★★ 转入 ActivityStack ★★★
    mTargetStack.resumeTopActivitiesLocked(...);
}

3.ActivityStack.resumeTopActivityLocked

// 文件:ActivityStack.java
// ★★★ 恢复顶层 Activity ★★★
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
    if (inResumeTopActivity) {
        return false;  // 防止递归
    }
    boolean result = false;
    try {
        inResumeTopActivity = true;
        result = resumeTopActivityInnerLocked(prev, options);
    } finally {
        inResumeTopActivity = false;
    }
    return result;
}

4.startSpecificActivityLocked

// 文件:ActivityStackSupervisor.java
// ★★★ 检查进程是否存在 ★★★
void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
    // 检查 Activity 所在进程是否已存在
    ProcessRecord app = mService.getProcessRecord(r.processName,
            r.info.applicationInfo.uid, true);

    if (app != null && app.thread != null) {
        try {
            // ★★★ 进程已存在 → 直接启动 ★★★
            realStartActivityLocked(r, app, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                    + r.intent.getComponent().flattenToShortString(), e);
        }
    }

    // ★★★ 进程不存在 → 创建进程 ★★★
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

阶段三:跨进程回调

1.realStartActivityLocked

// 文件:ActivityStackSupervisor.java
// ★★★ 跨进程回调应用进程 ★★★
final void realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        boolean andResume, boolean checkConfig) throws RemoteException {
    // ... 省略部分逻辑 ...

    // ★★★ 跨进程调用 ApplicationThread.scheduleLaunchActivity ★★★
    app.thread.scheduleLaunchActivity(
            new Intent(r.intent),
            r.appToken,
            System.identityHashCode(r),
            r.info,
            new Configuration(mService.mConfiguration),
            r.compat,
            r.task.voiceInteractor,
            app.repProcState,
            r.icicle,
            r.persistentState,
            results,
            newIntents,
            !andResume,
            mService.isNextTransitionForward(),
            profilerInfo);
}

2.ApplicationThread.scheduleLaunchActivity

// 文件:ActivityThread.ApplicationThread
// ★★★ 应用进程收到跨进程回调 ★★★
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
        ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
        IVoiceInteractor voiceInteractor, int procState, Bundle state,
        PersistableBundle persistentState, List<ResultInfo> pendingResults,
        List<Intent> pendingNewIntent, boolean notResumed, boolean isForward,
        ProfilerInfo profilerInfo) {

    updateProcessState(procState, false);

    // ★★★ 封装成 ActivityClientRecord ★★★
    ActivityClientRecord r = new ActivityClientRecord();
    r.token = token;
    r.ident = ident;
    r.intent = intent;
    r.voiceInteractor = voiceInteractor;
    r.activityInfo = info;
    r.compatInfo = compatInfo;
    r.state = state;
    r.persistentState = persistentState;
    r.pendingResults = pendingResults;
    r.pendingIntents = pendingNewIntent;
    r.startsWithNotResumed = notResumed;
    r.isForward = isForward;
    r.profilerInfo = profilerInfo;

    updatePendingConfiguration(curConfig);

    // ★★★ 发送 LAUNCH_ACTIVITY 消息到主线程 ★★★
    sendMessage(H.LAUNCH_ACTIVITY, r);
}

阶段四:主线程处理

1.Handler H 处理 LAUNCH_ACTIVITY

// 文件:ActivityThread.H
// ★★★ 切换到主线程 ★★★
private class H extends Handler {
    public static final int LAUNCH_ACTIVITY = 100;

    public void handleMessage(Message msg) {
        switch (msg.what) {
            case LAUNCH_ACTIVITY: {
                final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                r.packageInfo = getPackageInfoNoCheck(
                        r.activityInfo.applicationInfo, r.compatInfo);
                // ★★★ 调用 handleLaunchActivity ★★★
                handleLaunchActivity(r, null);
            } break;
        }
    }
}

2.handleLaunchActivity

// 文件:ActivityThread.java
// ★★★ 启动分发 ★★★
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    // ★★★ 创建 Activity 对象并回调 onCreate ★★★
    Activity a = performLaunchActivity(r, customIntent);

    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        Bundle oldState = r.state;
        // ★★★ 回调 onResume,并触发 Window 添加 ★★★
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsWithNotResumed);
    }
}

阶段五:创建 Activity 实例

1.performLaunchActivity 完整 5 个步骤

获取acitivityInfo、反射创建acitivty实例、创建application、创建contextImpl+attach、回调oncreate

// 文件:ActivityThread.java
// ★★★ 5 个步骤创建 Activity ★★★
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

    // ============================================================
    // ① 获取 ActivityInfo 和 ComponentName
    // ============================================================
    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null) {
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                Context.CONTEXT_INCLUDE_CODE);
    }

    ComponentName component = r.intent.getComponent();
    if (component == null) {
        component = r.intent.resolveActivity(mInitialApplication.getPackageManager());
        r.intent.setComponent(component);
    }

    if (r.activityInfo.targetActivity != null) {
        component = new ComponentName(r.activityInfo.packageName,
                r.activityInfo.targetActivity);
    }

    // ============================================================
    // ② 通过 ClassLoader + Instrumentation 创建 Activity 实例
    // ============================================================
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException("Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
        }
    }

    try {
        // ============================================================
        // ③ ⭐⭐⭐ 创建 Application 对象(详见阶段六) ⭐⭐⭐
        // ============================================================
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (activity != null) {
            // ============================================================
            // ④ 创建 ContextImpl 并通过 attach 注入到 Activity
            // ============================================================
            ContextImpl appContext = createBaseContextForActivity(r, activity);
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);

            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.voiceInteractor);

            // ============================================================
            // ⑤ 回调 Activity.onCreate
            // ============================================================
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }

            activity.performStart();
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException("Unable to start activity " + component
                    + ": " + e.toString(), e);
        }
    }

    return activity;
}

2.Instrumentation.newActivity

// 文件:Instrumentation.java
// ★★★ 通过反射创建 Activity ★★★
public Activity newActivity(ClassLoader cl, String className, Intent intent)
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    return (Activity) cl.loadClass(className).newInstance();
}

阶段六:Application 创建

为什么是重点?

原因说明
单例整个应用只有一个 Application,所有组件共用
最早初始化在第一个 Activity 创建之前就会完成
启动速度Application.onCreate() 里做的事情直接拖慢冷启动时间。比如SDK初始化
后续依赖所有 Activity、Service、Receiver 的 Context 都依赖它
软柿子这里还有个软柿子instrumentation。可以在这里搞些骚操作

LoadedApk.makeApplication

// 文件:LoadedApk.java
// ╔══════════════════════════════════════════════════════════════════╗
// ║  ⭐⭐⭐ 重中之重:Application 的创建过程 ⭐⭐⭐                  ║
// ║  后续启动优化中,Application.onCreate() 是最先被优化的点        ║
// ╚══════════════════════════════════════════════════════════════════╝
public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    // ★★★★★ 已经创建过,直接返回(单例!全局只有一份!) ★★★★★
    if (mApplication != null) {
        return mApplication;
    }

    Application app = null;
    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
    }

    try {
        java.lang.ClassLoader cl = getClassLoader();
        if (!mPackageName.equals("android")) {
            initializeJavaContextClassLoader();
        }

        // ① ★★★★★ 创建 ContextImpl(Application 的 Context) ★★★★★
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);

        // ② ★★★★★ 通过 Instrumentation 创建 Application 实例 ★★★★★
        app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);

        // ③ ★★★★★ 关联 Application 与 ContextImpl ★★★★★
        appContext.setOuterContext(app);

    } catch (Exception e) {
        if (!mActivityThread.mInstrumentation.onException(app, e)) {
            throw new RuntimeException("Unable to instantiate application " + appClass
                    + ": " + e.toString(), e);
        }
    }

    mActivityThread.mAllApplications.add(app);
    mApplication = app;

    // ④ ★★★★★ 回调 Application.onCreate() ★★★★★
    // ⚠️  ⚠️  ⚠️  这里执行任何耗时操作都会拖慢冷启动速度  ⚠️  ⚠️  ⚠️
    // 后面讲启动优化时,这里就是第一个要优化的地方
    if (instrumentation != null) {
        instrumentation.callApplicationOnCreate(app);
    }

    return app;
}

阶段七:onResume 与 Window 添加

handleResumeActivity

// 文件:ActivityThread.java
// ★★★ 回调 onResume 并添加 Window ★★★
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
        boolean reallyResume, int seq, String reason) {
    // ① ★★★ 回调 Activity.onResume() ★★★
    ActivityClientRecord r = performResumeActivity(token, clearHide, reason);

    if (r != null) {
        final Activity a = r.activity;

        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    // ② ★★★ 调用 Activity.makeVisible → 添加 Window ★★★
                    wm.addView(decor, l);
                } else {
                    a.onWindowAttributesChanged(l);
                }
            }
        }
        // ...
    }
}

Activity.makeVisible

// 文件:Activity.java
// ★★★ 真正添加 Window 到 WMS ★★★
void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        // ★★★ 跨进程调用 WMS.addWindow ★★★
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}

这里就把application、activity创建好了,并分配了一个window,然后activity可交互。wms、window、windowmanager会具体讲一下窗口创建和分配过程

1.5 异常处理

checkStartActivityResult

// 文件:Instrumentation.java
// ★★★ 启动失败时抛出对应异常 ★★★
public static void checkStartActivityResult(int res, Object intent) {
    if (res >= ActivityManager.START_SUCCESS) {
        return;
    }

    switch (res) {
        case ActivityManager.START_INTENT_NOT_RESOLVED:
        case ActivityManager.START_CLASS_NOT_FOUND:
            if (intent instanceof Intent && ((Intent) intent).getComponent() != null) {
                // ★★★ 最常见异常:Activity 未在 AndroidManifest.xml 中声明 ★★★
                throw new ActivityNotFoundException(
                        "Unable to find explicit activity class "
                        + ((Intent) intent).getComponent().toString()
                        + "; have you declared this activity in your AndroidManifest.xml?");
            }
            throw new ActivityNotFoundException("No Activity found to handle " + intent);

        case ActivityManager.START_PERMISSION_DENIED:
            throw new SecurityException("Not allowed to start activity " + intent);

        case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
            throw new AndroidRuntimeException(
                    "FORWARD_RESULT_FLAG used while also requesting a result");

        case ActivityManager.START_NOT_ACTIVITY:
            throw new IllegalArgumentException("PendingIntent is not an activity");

        case ActivityManager.START_NOT_VOICE_COMPATIBLE:
            throw new SecurityException(
                    "Starting under voice control not allowed for: " + intent);

        default:
            throw new AndroidRuntimeException("Unknown error code " + res
                    + " when starting " + intent);
    }
}

5.activity生命周期

AMS调度应用进程执行生命周期回调:onCreate → onStart → onResume。ActivityThread收到AMS指令后,通过反射创建Activity实例,然后依次调用这些生命周期方法。

上一个更加偏ams->application->activity。这个更加偏acitivity->view。然后有几个方法漏了再讲一下

位于应用启动流程中的位置:

用户点击桌面图标
    ↓
PMS 解析 → Zygote 创建进程 → ActivityThread.main()
    ↓
【阶段一】ActivityThread 入口与主线程初始化  ← 本章节起点
    ├── Looper.prepareMainLooper()
    ├── 创建 ActivityThread 对象
    └── thread.attach(false)
    ↓
【阶段二】AMS 绑定 Application
    ├── AMS.attachApplication(mAppThread)
    ├── AMS.attachApplicationLocked()
    └── thread.bindApplication()
    ↓
【阶段三】ActivityStackSupervisor 查找 Activity
    ├── 遍历 Activity 栈
    ├── 获取栈顶 ActivityRecord
    └── realStartActivityLocked()
    ↓
【阶段四】跨进程回调启动 Activity
    ├── app.thread.scheduleLaunchActivity()
    ├── sendMessage(H.LAUNCH_ACTIVITY)
    └── handleLaunchActivity()
    ↓
【阶段五】performLaunchActivity —— 创建 Activity
    ├── ① newActivity() 反射创建 Activity 实例
    ├── ② makeApplication() 创建 Application
    ├── ③ ContextImpl.init() 创建 Context
    ├── ④ activity.attach() 关联 Context、Application、Window
    ├── ⑤ callActivityOnCreate() → 回调 onCreate()
    └── ⑥ performStart() → 回调 onStart()
    ↓
【阶段六】handleResumeActivity —— 显示 Activity
    ├── performResumeActivity() → 回调 onResume()
    ├── wm.addView(decor, l) → WMS 添加窗口
    └── Activity.makeVisible() → DecorView 可见
    ↓
View 绘制(measure → layout → draw)
    ↓
用户看到界面

核心步骤速览

顺序核心步骤作用
1ActivityThread.main()应用入口,准备主线程 Looper,创建 ActivityThread
2ActivityThread.attach(false)获取 AMS 代理,调用 AMS.attachApplication(mAppThread) 绑定应用
3AMS.attachApplicationLocked()绑定 Application,调用 thread.bindApplication()
4ActivityStackSupervisor.attachApplicationLocked()遍历 Activity 栈,查找待启动的 Activity
5realStartActivityLocked()跨进程调用 scheduleLaunchActivity()
6ApplicationThread.scheduleLaunchActivity()发送 H.LAUNCH_ACTIVITY 消息到主线程
7H.handleMessage(LAUNCH_ACTIVITY)切换到主线程,调用 handleLaunchActivity()
8handleLaunchActivity()调用 performLaunchActivity() 和 handleResumeActivity()
9performLaunchActivity()创建 Activity、Application、Context,回调 onCreate() 和 onStart()
10handleResumeActivity()回调 onResume(),添加 DecorView 到 Window,使其可见

核心步骤源码如下:

1.ActivityThread.main() —— 应用入口

// 文件:ActivityThread.java
// ★★★ 阶段一:应用进程入口 ★★★
public static final void main(String[] args) {
    // 启动性能分析工具
    SamplingProfilerIntegration.start();
    Process.setArgv0("<pre-initialized>");

    // 1. ★ 创建主线程的 Looper ★
    Looper.prepareMainLooper();

    if (sMainThreadHandler == null) {
        sMainThreadHandler = new Handler();
    }

    // 2. ★ 创建 ActivityThread 对象 ★
    // 它封装了 UI 线程消息循环与 Activity 生命周期操作
    ActivityThread thread = new ActivityThread();

    // 3. ★★★ 核心方法:Application、Activity 的创建入口 ★★★
    thread.attach(false);

    // 4. ★ 启动 UI 线程消息循环 ★
    Looper.loop();

    // 正常情况下不会执行到这里
    thread.detach();
}

2.ActivityThread.attach() —— 绑定 AMS

// 文件:ActivityThread.java
// ★★★ 阶段二:绑定 Application 到 AMS ★★★
private final void attach(boolean system) {
    sThreadLocal.set(this);
    mSystemThread = system;

    if (!system) {
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>");
        RuntimeInit.setApplicationObject(mAppActivityManagerNativeThread.asBinder());

        // 1. ★ 获取 ActivityManagerService 实例 ★
        IActivityManager mgr = ActivityManagerNative.getDefault();

        try {
            // 2. ★★★ 将 mAppThread 与 AMS 绑定 ★★★
            // mAppThread 是 ApplicationThread 实例,用于 AMS 跨进程回调应用
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            // ...
        }
    } else {
        // 系统进程分支,省略
    }
}

3.ApplicationThread 与 H 类定义

// 文件:ActivityThread.java
// ★★★ 阶段三:内部类定义 ★★★
public final class ActivityThread {

    // ★ ApplicationThread:与 AMS 交互的 Binder 接口 ★
    final ApplicationThread mAppThread = new ApplicationThread();
    final Looper mLooper = Looper.myLooper();

    // ★ H:向主线程发送消息的 Handler ★
    final H mH = new H();

    // 发送消息到主线程
    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
    }

    // ============================================================
    // ApplicationThread:AMS 跨进程回调的入口
    // ============================================================
    private final class ApplicationThread extends ApplicationThreadNative {

        // ★ 发送 Resume Activity 消息 ★
        public final void scheduleResumeActivity(IBinder token, boolean isForward) {
            sendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0);
        }

        // ★★★ 发送 Launch Activity 消息 ★★★
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
                List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {

            ActivityClientRecord r = new ActivityClientRecord();
            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.activityInfo = info;
            r.state = state;

            // ★ 向 UI 线程发送 LAUNCH_ACTIVITY 消息 ★
            sendMessage(H.LAUNCH_ACTIVITY, r);
        }
        // ... 其他方法
    }

    // ============================================================
    // H:处理主线程消息
    // ============================================================
    private final class H extends Handler {
        public static final int LAUNCH_ACTIVITY = 100;
        public static final int PAUSE_ACTIVITY = 101;
        public static final int PAUSE_ACTIVITY_FINISHING = 102;
        // ...

        public void handleMessage(Message msg) {
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                    r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo);
                    // ★★★ 加载 Activity ★★★
                    handleLaunchActivity(r, null);
                } break;

                case PAUSE_ACTIVITY: {
                    // ★ 暂停 Activity ★
                    handlePauseActivity((IBinder) msg.obj, false, msg.arg1 != 0, msg.arg2);
                    maybeSnapshot();
                } break;
                // ...
            }
        }
    }
}

4.AMS.attachApplication() —— 系统端绑定

// 文件:ActivityManagerService.java
// ★★★ 阶段二续:AMS 处理绑定请求 ★★★
public final void attachApplication(IApplicationThread thread) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();

        // 1. ★ 转到 attachApplicationLocked ★
        attachApplicationLocked(thread, callingPid);

        Binder.restoreCallingIdentity(origId);
    }
}

private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
    ProcessRecord app;

    try {
        // 2. ★★ ApplicationThread 绑定 Application ★★
        thread.bindApplication(processName, appInfo, providers,
                app.instrumentationClass, profilerInfo,
                app.instrumentationArguments, app.instrumentationWatcher,
                app.instrumentationUiAutomationConnection, testMode,
                enableOpenGLTrace, isRestrictedBackupMode || !normalMode,
                app.persistent, new Configuration(mConfiguration), app.compat,
                getCommonServicesLocked());
    } catch (Exception e) {
        return false;
    }

    // 3. ★★★ 正常模式启动 Activity ★★★
    if (normalMode) {
        try {
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            badApp = true;
        }
    }
    return true;
}

5.ActivityStackSupervisor.attachApplicationLocked() —— 查找并启动 Activity

// 文件:ActivityStackSupervisor.java
// ★★★ 阶段三:查找待启动的 Activity ★★★
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
    final String processName = app.processName;
    boolean didSomething = false;

    // 1. ★ 遍历所有 Activity 栈 ★
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;

        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = stacks.get(stackNdx);

            if (!isFrontStack(stack)) {
                continue;
            }

            // 2. ★ 获取栈顶的 ActivityRecord ★
            ActivityRecord hr = stack.topRunningActivityLocked(null);

            if (hr != null) {
                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                        && processName.equals(hr.processName)) {
                    try {
                        // 3. ★★★ 真正启动 Activity ★★★
                        if (realStartActivityLocked(hr, app, true, true)) {
                            didSomething = true;
                        }
                    } catch (RemoteException e) {
                        throw e;
                    }
                }
            }
        }
    }
    return didSomething;
}

6.realStartActivityLocked() —— 跨进程回调应用进程

// 文件:ActivityStackSupervisor.java
// ★★★ 阶段三续:跨进程启动 ★★★
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        boolean andResume, boolean checkConfig) throws RemoteException {

    final ActivityStack stack = r.task.stack;

    // 设置 App 的 dex 文件位置
    mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());

    // ★★★ 跨进程调用 ApplicationThread.scheduleLaunchActivity ★★★
    app.thread.scheduleLaunchActivity(
            new Intent(r.intent),
            r.appToken,
            System.identityHashCode(r),
            r.info,
            new Configuration(mService.mConfiguration),
            r.compat,
            r.task.voiceInteractor,
            app.repProcState,
            r.icicle,
            r.persistentState,
            results,
            newIntents,
            !andResume,
            mService.isNextTransitionForward(),
            profilerInfo);

    return true;
}

7.handleLaunchActivity() —— 主线程处理启动

// 文件:ActivityThread.java
// ★★★ 阶段四:主线程处理启动 ★★★
private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {

    // 1. ★★★ 创建 Activity,回调 onCreate、onStart ★★★
    Activity a = performLaunchActivity(r, customIntent);

    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        Bundle oldState = r.state;

        // 2. ★★★ 回调 onResume,使 Activity 可见 ★★★
        handleResumeActivity(r.token, false, r.isForward);
    }
}

8.performLaunchActivity() —— 创建 Activity 实例

// 文件:ActivityThread.java
// ★★★ 阶段五:创建 Activity ★★★
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

    Activity activity = null;

    try {
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();

        // ① ★ 通过反射创建 Activity 实例 ★
        activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
        r.intent.setExtrasClassLoader(cl);

        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
        // ...
    }

    try {
        // ② ★ 创建 Application(单例) ★
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (activity != null) {
            // ③ ★ 创建 ContextImpl ★
            ContextImpl appContext = new ContextImpl();
            appContext.init(r.packageInfo, r.token, this);
            appContext.setOuterContext(activity);

            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mConfiguration);

            // ④ ★★★ Activity 与 Context、Application、Window 关联 ★★★
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances,
                    r.lastNonConfigurationChildInstances, config);

            // ⑤ ★★★ 回调 Activity.onCreate() ★★★
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }

            // ⑥ ★★★ 回调 Activity.onStart() ★★★
            if (!r.activity.mFinished) {
                activity.performStart();
                r.stopped = false;
            }

            r.paused = true;
            mActivities.put(r.token, r);
        }
    } catch (SuperNotCalledException e) {
        throw e;
    }
    return activity;
}

9.handleResumeActivity() —— 使 Activity 可见

// 文件:ActivityThread.java
// ★★★ 阶段六:显示 Activity ★★★
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {

    // 1. ★★★ 回调 Activity.onResume() ★★★
    ActivityClientRecord r = performResumeActivity(token, clearHide);

    if (r != null) {
        final Activity a = r.activity;

        if (r.window == null && !a.mFinished && willBeVisible) {
            // 2. ★ 获取 Window 和 DecorView ★
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);

            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

            if (a.mVisibleFromClient) {
                a.mWindowAdded = true;
                // 3. ★★★ 将 DecorView 添加到 WindowManager(跨进程 → WMS) ★★★
                wm.addView(decor, l);
            }
        }

        if (!r.activity.mFinished && willBeVisible
                && r.activity.mDecor != null && !r.hideForNow) {
            if (r.activity.mVisibleFromClient) {
                // 4. ★★★ 使 Activity 可见(DecorView 设置为 VISIBLE) ★★★
                r.activity.makeVisible();
            }
        }

        // 5. ★ 通知 AMS 该 Activity 已变为 Resume 状态 ★
        if (reallyResume) {
            try {
                ActivityManagerNative.getDefault().activityResumed(token);
            } catch (RemoteException ex) {
                // ...
            }
        }
    }
}

10.performResumeActivity() —— 执行 onResume

// 文件:ActivityThread.java
// ★★★ 阶段六:真正执行 onResume ★★★
public final ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide) {
    ActivityClientRecord r = mActivities.get(token);

    if (r != null && !r.activity.mFinished) {
        try {
            // ★★★ 执行 Activity.performResume() → 回调 onResume() ★★★
            r.activity.performResume();
        } catch (Exception e) {
            // ...
        }
    }
    return r;
}

11.setContentView() —— 布局加载流程

// 文件:Activity.java
// ★★★ 加载布局 ★★★
public void setContentView(int layoutResID) {
    getWindow().setContentView(layoutResID);
}

12.PhoneWindow.setContentView()

// 文件:PhoneWindow.java
// ★★★ Window 加载布局 ★★★
@Override
public void setContentView(int layoutResID) {
    // 1. 如果没有 mContentParent,创建 DecorView
    if (mContentParent == null) {
        installDecor();  // 生成 DecorView
    } else {
        mContentParent.removeAllViews();
    }

    // 2. ★ 将 layoutResId 的布局添加到 mContentParent 中 ★
    mLayoutInflater.inflate(layoutResId, mContentParent);
}

13.installDecor() —— 构建 DecorView

// 文件:PhoneWindow.java
// ★★★ 构建 DecorView 和 mContentParent ★★★
private void installDecor() {
    if (mDecor == null) {
        // 1. ★ 构建 DecorView(窗口顶层视图) ★
        mDecor = generateDecor();
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
    }

    if (mContentParent == null) {
        // 2. ★ 获取内容显示区域(mContentParent) ★
        mContentParent = generateLayout(mDecor);

        // 3. 设置 Title
        mTitleView = (TextView) findViewById(
            mDecor.getContext().getResources().getIdentifier(
                "title", "string", mDecor.getContext().getPackageName()));
    }
}

protected DecorView generateDecor() {
    // ★ 创建 DecorView ★
    return new DecorView(getContext(), -1);
}

14.generateLayout() —— 加载顶层布局

// 文件:PhoneWindow.java
// ★★★ 加载顶层布局,返回内容容器 ★★★
protected ViewGroup generateLayout(DecorView decor) {
    // 1. ★ 获取窗口 Style 属性 ★
    TypedArray a = getWindowStyle();

    // 2. ★ 根据主题/特性选择不同的顶层布局 ★
    int layoutResource;
    int features = getLocalFeatures();

    if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
        if (mIsFloating) {
            layoutResource = com.android.internal.R.layout.dialog_title;
        } else {
            // ★ 常规 Activity:screen_title ★
            layoutResource = com.android.internal.R.layout.screen_title;
        }
    }
    // ... 其他条件分支

    mDecor.startChanging();

    // 3. ★ 加载顶层布局,添加到 DecorView ★
    View in = mLayoutInflater.inflate(layoutResource, null);
    mDecor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));

    // 4. ★★★ 获取内容显示区域(ID_ANDROID_CONTENT) ★★★
    ViewGroup contentParent = (ViewGroup) findViewById(ID_ANDROID_CONTENT);

    // 5. 设置背景、Title 等属性
    // ...

    mDecor.finishChanging();
    return contentParent;
}

15.screen_title.xml 布局结构

<!-- 文件:screen_title.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:fitsSystemWindows="true">

    <!-- Action Mode 占位 -->
    <ViewStub android:id="@+id/action_mode_bar_stub"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <!-- ★ Title 区域 ★ -->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="?android:attr/windowTitleSize"
        style="?android:attr/windowTitleBackgroundStyle">
        <TextView android:id="@+id/action_bar_title"
            style="?android:attr/windowTitleStyle"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>

    <!-- ★★★ Content 区域(用户布局将添加到这里) ★★★ -->
    <FrameLayout
        android:id="@android:id/content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:foreground="?android:attr/windowContentOverlay" />

</LinearLayout>

16.mContentParent 与 DecorView 结构关系

DecorView (FrameLayout)
    │
    ├── 系统顶层布局 (screen_title.xml / screen_no_title.xml)
    │       │
    │       ├── Title 区域 (ActionBar / TextView)
    │       │
    │       └── ★★★ mContentParent (id = android.R.id.content) ★★★
    │               │
    │               └── 用户布局 (activity_main.xml)
    │                       ├── Button
    │                       ├── TextView
    │                       └── ...
    │
    └── 其他系统视图 (Status Bar 背景等)

17.Activity 生命周期回调顺序总结

ActivityThread.main()
    ↓
ActivityThread.attach()
    ↓
AMS.attachApplication()
    ↓
ActivityStackSupervisor.attachApplicationLocked()
    ↓
realStartActivityLocked()
    ↓
ApplicationThread.scheduleLaunchActivity()
    ↓
H 处理 LAUNCH_ACTIVITY
    ↓
handleLaunchActivity()
    ↓
performLaunchActivity()
    ├── ① newActivity() → Activity 实例创建
    ├── ② makeApplication() → Application 创建 & Application.onCreate()
    ├── ③ ContextImpl.init() → Context 创建
    ├── ④ activity.attach() → 关联 Context、Application、Window
    ├── ⑤ callActivityOnCreate() → ★★★ Activity.onCreate() ★★★
    └── ⑥ performStart() → ★★★ Activity.onStart() ★★★
    ↓
handleResumeActivity()
    ├── performResumeActivity()
    │       └── r.activity.performResume() → ★★★ Activity.onResume() ★★★
    ├── wm.addView(decor, l) → WMS 添加窗口
    └── Activity.makeVisible() → DecorView 可见
    ↓
用户看到界面

主要就是这6个阶段了

阶段方法生命周期回调
阶段一ActivityThread.main()应用入口,主线程初始化
阶段二ActivityThread.attach() → AMS.attachApplication()绑定 AMS
阶段三ActivityStackSupervisor.attachApplicationLocked()→ realStartActivityLocked()查找并启动 Activity
阶段四ApplicationThread.scheduleLaunchActivity() → H.handleMessage()跨进程回调 → 主线程切换
阶段五performLaunchActivity()onCreate()onStart()
阶段六handleResumeActivity()onResume() + 窗口显示

 6.LayoutInflater、资源的加载与匹配

这一步贯穿了整个过程:创建Application时要加载资源,解析XML时要加载资源,View绘制时要加载资源(图片、颜色、尺寸)。但最集中的阶段在View创建和绘制时,因为XML里引用了大量资源需要解析和匹配(屏幕密度、语言等)。

先讲LayoutInflater、再讲资源的加载与匹配吧

LayoutInflater 在安卓系统启动流程中的位置

SystemServer.main()
↓
ServerThread.initAndLoop()
↓
PMS.main() —— 扫描解析APK
↓
其他服务初始化
↓
Launcher 启动
↓
点击应用图标
↓
AMS.startActivity()
↓
ActivityThread.main() —— 应用入口
↓
ActivityThread.attach(false)
↓
H.handleMessage(BIND_APPLICATION) —— 创建Application和Context
↓
H.handleMessage(LAUNCH_ACTIVITY)
↓
handleLaunchActivity()
↓
performLaunchActivity()
↓
Activity.onCreate() ← 开发者调用 setContentView
↓
【PhoneWindow.setContentView()】 ← LayoutInflater 在此被调用
├── installDecor() —— 创建 DecorView
├── LayoutInflater.inflate() —— 解析布局文件
│ ├── createViewFromTag() —— 解析单个 View 标签
│ │ ├── PhoneLayoutInflater.onCreateView() —— 内置 View 加 android.widget. 前缀
│ │ └── createView() —— 通过反射构造 View
│ └── rInflate() —— 深度优先递归解析所有子 View
└── 视图树构建完成
↓
Activity.onResume() —— 视图显示到屏幕

哪些核心步骤会用到 LayoutInflater:

系统核心步骤使用场景
Activity.onCreate()开发者调用 setContentView() 时触发
PhoneWindow.setContentView()调用 LayoutInflater.inflate() 解析布局
Fragment.onCreateView()Fragment 加载布局时使用
RecyclerView/ListView 的 AdaptergetView() / onCreateViewHolder() 中解析 item 布局
Dialog 创建Dialog 加载布局时使用
LayoutInflater.inflate()任何需要将 XML 布局转换成 View 树的地方

LayoutInflater源码核心注册解析流程如下:

步骤方法职责
1ContextImpl.registerService()将 LayoutInflater 的 ServiceFetcher 注入到服务容器中
2PolicyManager.makeNewLayoutInflater()通过 Policy 代理类创建 LayoutInflater
3Policy.makeNewLayoutInflater()返回 PhoneLayoutInflater 实例
4PhoneLayoutInflater.onCreateView()为内置 View(TextView等)添加 android.widget. 前缀
5Activity.setContentView()调用 Window.setContentView()
6PhoneWindow.setContentView()构建 DecorView,调用 inflate 解析布局
7LayoutInflater.inflate()解析 XML 布局文件,构建 View 树
8createViewFromTag()根据标签名创建单个 View
9createView()通过反射构造 View 对象
10rInflate()深度优先遍历,递归解析所有子 View

LayoutInflater 是一个抽象类:

public abstract class LayoutInflater {
    // 代码省略
}

LayoutInflater 的注册过程:

registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
    public Object createService(ContextImpl ctx) {
        return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
    }
});

PolicyManager 通过反射创建 Policy:

public final class PolicyManager {
    // Policy 实现类
    private static final String POLICY_IMPL_CLASS_NAME = "com.android.internal.policy.impl.Policy";

    private static final IPolicy sPolicy;

    static {
        // 通过反射构造 Policy 对象
        try {
            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
            sPolicy = (IPolicy) policyClass.newInstance();
        } catch (ClassNotFoundException e) {
            // ......
        }
    }

    // 通过 sPolicy 创建 LayoutInflater
    public static LayoutInflater makeNewLayoutInflater(Context context) {
        return sPolicy.makeNewLayoutInflater(context);
    }
}

Policy 实现类:

public class Policy implements IPolicy {
    // 创建 PhoneWindow,这就是 Activity 中 Window 的具体实现类
    public Window makeNewWindow(Context context) {
        return new PhoneWindow(context);
    }

    // 创建 LayoutInflater,具体类为 PhoneLayoutInflater
    public LayoutInflater makeNewLayoutInflater(Context context) {
        return new PhoneLayoutInflater(context);
    }
}

PhoneLayoutInflater —— LayoutInflater 的真正实现类:

public class PhoneLayoutInflater extends LayoutInflater {
    // 内置 View 类型的前缀,如 TextView 的完整路径是 android.widget.TextView
    private static final String[] sClassNamePrefixList = {
        "android.widget.",
        "android.webkit.",
    };

    @Override
    protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
        // 在 View 名字的前面添加前缀来构造 View 的完整路径
        for (String prefix : sClassNamePrefixList) {
            try {
                View view = onCreateView(name, prefix, attrs);
                if (view != null) {
                    return view;
                }
            } catch (ClassNotFoundException e) {
                // 省略
            }
        }
        return super.onCreateView(name, attrs);
    }
}

Activity.setContentView():

public void setContentView(View view) {
    getWindow().setContentView(view);
    initActionBar();
}

PhoneWindow.setContentView():

@Override
public void setContentView(int layoutResID) {
    // 1. 当 mContentView 为空时先构建 DecorView,并且将 DecorView 包裹到 mContentView 中
    if (mContentView == null) {
        installDecor();
    } else {
        mContentView.removeAllViews();
    }
    // 2. 解析 layoutResID
    mContentView.inflate(layoutResID, mContentView);
    // 代码省略
}

LayoutInflater.inflate() 核心方法:

public View inflate(int resource, ViewGroup root) {
    // root 不为空,则会从 resource 布局解析到 View,并添加到 root 中
    return inflate(resource, root, root != null);
}

public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
    // 获取 xml 资源解析器
    XmlResourceParser parser = getContext().getResources().getLayout(resource);
    try {
        return inflate(parser, root, attachToRoot);
    } finally {
        parser.close();
    }
}

// 参数 1 为 xml 解析器,参数 2 为要解析布局的父视图,参数 3 为是否将解析的视图添加到父视图中
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
    synchronized (mConstructorArgs) {
        final AttributeSet attrs = Xml.asAttributeSet(parser);
        Context lastContext = (Context) mConstructorArgs[0];
        // Context 对象
        mConstructorArgs[0] = mContext;
        // 存储父视图
        View result = root;

        try {
            int type;
            // 找到 root 元素
            while ((type = parser.next()) != XmlPullParser.START_TAG &&
                type != XmlPullParser.END_DOCUMENT) {
                // Empty
            }
            // 代码省略
            final String name = parser.getName();

            // 1. 解析 merge 标签
            if (TAG_MERGE.equals(name)) {
                rInflate(parser, root, attrs, false);
            } else {
                // 2. 不是 merge 标签那么直接解析布局中的视图
                View temp;
                if (TAG_1995.equals(name)) {
                    temp = new BlinkLayout(mContext, attrs);
                } else {
                    // 3. 这里就是通过 xml 的 tag 来解析 layout 根视图
                    // name 就是要解析的视图的类名,如 RelativeLayout
                    temp = createViewFromTag(root, name, attrs);
                }

                ViewGroup.LayoutParams params = null;
                if (root != null) {
                    // 生成布局参数
                    params = root.generateLayoutParams(attrs);
                    // 如果 attachToRoot 为 false,那么将给 temp 设置布局参数
                    if (!attachToRoot) {
                        temp.setLayoutParams(params);
                    }
                }

                // 解析 temp 视图下的所有子 View
                rInflate(parser, temp, attrs, true);

                // 如果 Root 不为空,且 attachToRoot 为 true,那么将 temp 添加到父视图中
                if (root != null && attachToRoot) {
                    root.addView(temp, params);
                }

                // 如果 root 为空或者 attachToRoot 为 false,那么返回的结果就是 temp
                if (root == null || !attachToRoot) {
                    result = temp;
                }
            }
        } catch (Exception e) {
            // 省略 catch
        }
        return result;
    }
}

inflate 方法主要有下面几步:

  1. 解析 xml 中的根标签(第一个元素);

  2. 如果根标签是 merge,那么调用 rInflate 进行解析,rInflate 会将 merge 标签下的所有子 View 直接添加到根标签中;所以说xml里面使用<merge>标签可以减少层级,用来优化视图层级太深的问题。

  3. 如果标签是普通元素,调用 createViewFromTag 对该元素进行解析;

  4. 调用 rInflate 解析 temp 根元素下的所有子 View,并且将这些子 View 都添加到 temp 下;

  5. 返回解析到的根视图。

哈哈哈哈哈,看着跟packageParser解析AndroidManifest.xml有点像。不过packageParser用的解释器模式,适合复杂大量解析,layoutInflater用到构造器模式+反射,适合简单的解析。如果自己想写前端框架自定义解析css、自定义dsl解析器,基本就是大部分用解释器模式。执行渲染对象就用layoutinflater这种。

createViewFromTag —— 解析单个元素:

View createViewFromTag(View parent, String name, AttributeSet attrs) {
    if (name.equals("view")) {
        name = attrs.getAttributeValue(null, "class");
    }

    try {
        View view;
        // 1. 用户可以通过设置 LayoutInflater 的 factory 来自行解析 View,默认这些 factory 都为空
        if (mFactory != null) view = mFactory.onCreateView(parent, name, mContext, attrs);
        else if (mFactory2 != null) view = mFactory2.onCreateView(parent, name, mContext, attrs);
        else view = null;
        // 代码省略

        // 2. 没有 Factory 的情况下通过 onCreateView 或者 createView 创建 View
        if (view == null) {
            // 3. 内置 View 控件的解析(名字中没有包含 ".")
            if (-1 == name.indexOf('.')) {
                view = onCreateView(parent, name, attrs);
            } else {
                // 4. 自定义控件的解析(名字中包含 ".")
                view = createView(name, null, attrs);
            }
        }
        return view;
    } catch (Exception e) {
        // 省略 catch 块
    }
}

这里还有个factory(但不是直接的一个工厂模式),借鉴工厂模式的特点,讲对象的构建过程封装起来,传个xml节点名称,它把具体的view对象生产出来,不用管里面的复杂的反射逻辑。但是普通工厂一般是完全替代系统,全权负责创建,但这里更像一个钩子,系统创建view之前给一个拦截的机会。if (-1 == name.indexOf('.'))如果返回view就系统就用自定义的,没有返回就用系统的。

createView —— 通过反射构造 View 对象:

// 根据完整路径的类名通过反射机制构造 View 对象
public final View createView(String name, String prefix, AttributeSet attrs)
    throws ClassNotFoundException, InflateException {
    // 1. 从缓存中获取构造函数
    Constructor<? extends View> constructor = sConstructorMap.get(name);
    Class<? extends View> clazz = null;

    try {
        // 2. 没有缓存构造函数
        if (constructor == null) {
            // 如果 prefix 不为空,那么构造完整的 View 路径,并且加载该类
            clazz = mContext.getClassLoader().loadClass(
                prefix != null ? (prefix + name) : name).asSubclass(View.class);
            // 代码省略
        }
        // 3. 从 Class 对象中获取构造函数
        constructor = clazz.getConstructor(mConstructorSignature);
        // 4. 将构造函数存入缓存中
        sConstructorMap.put(name, constructor);
    } else {
        // 代码省略
    }

    Object[] args = mConstructorArgs;
    args[1] = attrs;
    // 5. 通过反射构造 View
    final View view = constructor.newInstance(args);

    if (view instanceof ViewStub) {
        // always use ourselves when inflating ViewStub later
        final ViewStub viewStub = (ViewStub) view;
        viewStub.setLayoutInflater(this);
    }
    return view;
    // 省略各种 catch、finally 代码
}

rInflate —— 深度优先遍历解析视图树:

void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs,
    boolean finishInflate) throws XmlPullParserException, IOException {
    // 1. 获取树的深度,深度优先遍历
    final int depth = parser.getDepth();
    int type;

    // 2. 逐个元素解析
    while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
        && type != XmlPullParser.END_DOCUMENT) {
        if (type != XmlPullParser.START_TAG) {
            continue;
        }

        final String name = parser.getName();

        if (TAG_REQUEST_FOCUS.equals(name)) {
            parseRequestFocus(parser, parent);
        } else if (TAG_INCLUDE.equals(name)) {
            // 解析 include 标签
            parseInclude(parser, parent, attrs);
        } else if (TAG_MERGE.equals(name)) {
            // 解析 merge 标签,抛出异常,因为 merge 标签必须为根视图
            throw new InflateException("<merge /> must be the root element");
        } else if (TAG_1995.equals(name)) {
            // 闪烁视图,这里可以不用管
            // 代码省略
        } else {
            // 3. 根据元素名进行解析
            final View view = createViewFromTag(parent, name, attrs);
            final ViewGroup viewGroup = (ViewGroup) parent;
            final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
            // 递归调用进行解析,也就是深度优先遍历
            rInflate(parser, view, attrs, true);
            // 将解析到的 View 添加到 viewGroup 中,也就是它的 parent
            viewGroup.addView(view, params);
        }
    }

    if (finishInflate) {
        parent.onFinishInflate();
    }
}

好,到资源的加载与匹配了,主要是Resources 与 AssetManager

Resources 与 AssetManager 在安卓系统启动流程中的位置

SystemServer.main()
↓
ServerThread.initAndLoop()
↓
PMS.main() —— 扫描解析APK
↓
其他服务初始化
↓
Launcher 启动
↓
点击应用图标
↓
AMS.startActivity()
↓
ActivityThread.main() —— 应用入口
↓
ActivityThread.attach(false)
↓
H.handleMessage(BIND_APPLICATION)
↓
H.handleMessage(LAUNCH_ACTIVITY)
↓
handleLaunchActivity()
↓
performLaunchActivity()
├── newActivity() —— 创建 Activity 实例
├── makeApplication() —— 创建 Application
└── createBaseContextForActivity() ← Resources/AssetManager 在此创建
└── ContextImpl.createActivityContext()
└── ResourcesManager.getTopLevelResources()
├── new AssetManager() —— 创建资源管理器
│ ├── init() —— Native 层创建 AssetManager,加载系统资源
│ └── addAssetPath() —— 添加应用 APK 资源路径
└── new Resources() —— 创建 Resources 对象
└── updateConfiguration() —— 设置屏幕/DPI/语言等配置
↓
activity.attach() —— 将 ContextImpl 注入 Activity
↓
callActivityOnCreate() —— 回调 onCreate()
↓
Activity.setContentView() —— 使用 Resources 加载布局
↓
Activity.onResume()

哪些核心步骤会用到 Resources/AssetManager:

系统核心步骤使用场景
ContextImpl 创建创建 Resources 和 AssetManager,加载应用资源
Activity.onCreate()setContentView() 加载布局文件
Resources.getDrawable()获取图片资源
Resources.getString()获取字符串资源
Resources.getColor()获取颜色资源
Resources.getDimension()获取尺寸资源
AssetManager.open()读取 assets 目录下的原始文件
多屏幕适配updateConfiguration() 根据设备配置匹配最合适资源

应用资源获取流程:

  1. APK 编译打包时生成 resources.arsc(资源索引表)

  2. AssetManager 通过 addAssetPath() 添加 APK 路径

  3. Native 层 AssetManager 解析 resources.arsc,建立资源索引

  4. Resources 通过 AssetManager 读取资源

  5. updateConfiguration() 设置设备配置(屏幕、DPI、语言等)

  6. Native 层根据配置匹配最合适的资源返回

资源加载核心流程图

ContextImpl.createActivityContext()
    ↓
ContextImpl 构造函数
    ↓
ResourcesManager.getTopLevelResources()
    ├── 1. 根据 ResourcesKey 查询缓存(mActiveResources)
    │   └── 有缓存 → 直接返回
    ├── 2. 无缓存 → new AssetManager()
    │   ├── AssetManager 构造函数
    │   │   ├── init() → Native 层创建 AssetManager,添加系统资源
    │   │   └── ensureSystemAssets() → 加载 framework-res.apk
    │   └── addAssetPath(resDir) → 将应用 APK 路径添加到资源列表
    ├── 3. new Resources(assets, dm, config)
    │   ├── mAssets = assets
    │   └── updateConfiguration() → 更新屏幕、DPI、语言等配置
    └── 4. 缓存到 mActiveResources

源码核心步骤如下:

步骤方法职责
1performLaunchActivity()创建 Activity、Application,构建 ContextImpl
2createBaseContextForActivity()调用 ContextImpl.createActivityContext()
3ContextImpl.createActivityContext()创建 ContextImpl,初始化资源和 AssetManager
4ContextImpl 构造函数获取 ResourcesManager,调用 packageInfo.getResources()
5ResourcesManager.getTopLevelResources()根据配置获取资源,无缓存则新建 AssetManager
6AssetManager 构造函数调用 init() 初始化 Native 层 AssetManager
7AssetManager.ensureSystemAssets()加载系统资源(framework-res.apk)
8AssetManager.addAssetPath()将 APK 路径添加到 AssetManager 资源路径列表中
9Resources 构造函数将 AssetManager 保存到 mAssets,调用 updateConfiguration()
10Resources.updateConfiguration()更新设备配置(屏幕、语言、DPI 等)
11AssetManager.setConfiguration()将配置同步到 Native 层,用于资源适配

performLaunchActivity 中创建 ContextImpl:

private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        // 1. 创建 Activity
        activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    } catch (Exception e) {
    }

    try {
        // 2. 创建 Application
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (activity != null) {
            // 3. 构建 ContextImpl
            ContextImpl appContext = createBaseContextForActivity(r, activity);
            // 启动 Activity 等代码省略
        }
    } catch (Exception e) {
    }
}

createBaseContextForActivity:

private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
    // 创建 ContextImpl 对象
    ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);
    // Outter Context 为 Activity
    appContext.setOuterContext(activity);
    Context baseContext = appContext;
    return baseContext;
}

ContextImpl.createActivityContext:

static ContextImpl createActivityContext(ActivityThread mainThread, LoadedApk packageInfo, IBinder activityToken) {
    return new ContextImpl(null, mainThread, packageInfo, activityToken, null, false, null, null);
}

ContextImpl 构造函数:

private ContextImpl(ContextImpl container, ActivityThread mainThread, 
    LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted, 
    Display display, Configuration overrideConfiguration) {
    mOuterContext = this;
    mMainThread = mainThread;
    // 获取包信息
    mPackageInfo = packageInfo;
    // 获取资源管理器
    mResourcesManager = ResourcesManager.getInstance();

    Resources resources = packageInfo.getResources(mainThread);
    if (resources != null) {
        if (activityToken != null) {
            // 根据设备配置获取对应的资源
            resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(), 
                packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(), 
                packageInfo.getApplicationInfo().sharedLibraryFiles, displayId, 
                overrideConfiguration, compatInfo, activityToken);
        }
    }
    mResources = resources;
}

ResourcesManager.getTopLevelResources:

public Resources getTopLevelResources(String resDir, String[] splitResDirs, 
    String[] overlayDirs, String[] libDirs, int displayId, 
    Configuration overrideConfiguration, CompatibilityInfo compatInfo, IBinder token) {
    final float scale = compatInfo.applicationScale;

    ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale, token);
    Resources r;

    synchronized (this) {
        // 1. 判断是否已经加载过该资源
        WeakReference<Resources> wr = mActiveResources.get(key);
        r = wr != null ? wr.get() : null;
        if (r != null && r.getAssets().isUpToDate()) {
            return r;
        }
    }

    // 2. 还未加载过,则构建 AssetManager 对象
    AssetManager assets = new AssetManager();

    // 3. 将 APK 路径添加到 AssetManager 的资源路径中
    if (resDir != null) {
        if (assets.addAssetPath(resDir) == 0) {
            return null;
        }
    }

    // 屏幕分辨率
    DisplayMetrics dm = getDisplayMetricsLocked(displayId);
    // 设备配置
    Configuration config;

    // 4. 创建资源,参数 1 为 AssetManager
    r = new Resources(assets, dm, config, compatInfo, token);

    synchronized (this) {
        // 5. 缓存资源
        mActiveResources.put(key, new WeakReference<Resources>(r));
        return r;
    }
}

AssetManager 构造函数:

public AssetManager() {
    synchronized (this) {
        // 初始化
        init(false);
        // 确保加载了系统资源
        ensureSystemAssets();
    }
}

private AssetManager(boolean isSystem) {
    init(true);
}

private static void ensureSystemAssets() {
    synchronized (sSync) {
        if (sSystem == null) {
            // 系统资源的 AssetManager 对象
            AssetManager system = new AssetManager(true);
            system.makeStringBlocks(false);
            sSystem = system;
        }
    }
}

Java 层 AssetManager.addAssetPath:

public final int addAssetPath(String path) {
    int res = addAssetPathNative(path);
    return res;
}

Resources 构造函数:

public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config,
    CompatibilityInfo compatInfo, IBinder token) {
    mAssets = assets;
    mMetrics.setToDefaults();
    // 更新配置
    updateConfiguration(config, metrics);
    assets.ensureStringBlocks();
}

Resources.updateConfiguration:

public void updateConfiguration(Configuration config, DisplayMetrics metrics, CompatibilityInfo compat) {
    synchronized (mAccessLock) {
        // 与屏幕相关的信息
        if (metrics != null) {
            mMetrics.setTo(metrics);
        }
        mCompatibilityInfo.applyToDisplayMetrics(mMetrics);

        // 设备 DPI
        if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
            mMetrics.densityDpi = mConfiguration.densityDpi;
            mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
        }
        mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;

        // 屏幕宽高
        int width, height;
        if (mMetrics.widthPixels >= mMetrics.heightPixels) {
            width = mMetrics.widthPixels;
            height = mMetrics.heightPixels;
        } else {
            width = mMetrics.heightPixels;
            height = mMetrics.widthPixels;
        }

        // 根据配置初始化 AssetManager
        mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
            locale, mConfiguration.orientation,
            mConfiguration.touchscreen,
            mConfiguration.densityDpi, mConfiguration.keyboard,
            keyboardHidden, mConfiguration.navigation, width, height,
            mConfiguration.smallestScreenWidthDp,
            mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
            mConfiguration.screenLayout, mConfiguration.uiMode,
            Build.VERSION.RESOURCES_SDK_INT);
    }
}

Native 层 AssetManager

init 函数的 Native 层实现(android_util_AssetManager.cpp):

static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem) {
    if (isSystem) {
        verifySystemImaps();
    }
    AssetManager* am = new AssetManager();  // 创建 Native 的 AssetManager
    am->addDefaultAssets();                // 添加默认的资源
    // 将 Native 层的 AssetManager 对象存储到 Java 层的 AssetManager 的 mObject 字段中
    env->SetLongField(clazz, gAssetManagerOffsets.mObject, (jlong)am);
}

addDefaultAssets 添加系统资源路径:

static const char* kSystemAssets = "framework/framework-res.apk";

bool AssetManager::addDefaultAssets() {
    const char* root = getenv("ANDROID_ROOT");
    // 构建系统路径
    String8 path(root);
    // 系统路径 + framework 资源 APK 路径,拼接成完整路径
    path.appendPath(kSystemAssets);
    return addAssetPath(path, NULL);
}

addAssetPath 添加到资源路径列表:

bool AssetManager::addAssetPath(const String8& path, void** cookie) {
    AutoMutex _l(mLock);
    asset_path ap;
    String8 realPath(path);

    ap.path = realPath;
    // 添加到资源路径列表中
    mAssetPaths.add(ap);
    return true;
}

Native 层 addAssetPathNative:

static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz, jstring path) {
    ScopedUtfChars path8(env, path);
    if (path8.c_str() == NULL) {
        return 0;
    }

    // 将 Java AssetManager 对象中的 mObject 字段转换为 AssetManager 指针
    AssetManager* am = assetManagerForJavaObject(env, clazz);
    if (am == NULL) {
        return 0;
    }

    void* cookie;
    // 将新的路径添加到资源列表中
    bool res = am->addAssetPath(String8(path8.c_str()), &cookie);
    return (res) ? (jint)cookie : 0;
}

7.WMS

核心功能:

功能说明
窗口管理维护所有窗口的添加、删除、排序、层级分配
窗口焦点管理管理当前获得焦点的窗口,分发按键事件
Z-Order 管理按层级顺序排列窗口,上层覆盖下层
输入事件分发通过 InputChannel 与 InputManager 配合分发触摸/按键事件
窗口动画管理窗口切换动画(AppTransition、WindowAnimator)
Surface 管理通过 SurfaceSession 与 SurfaceFlinger 通信,分配 Surface

WMS 在安卓系统启动流程中的位置

SystemServer.main()
↓
ServerThread.initAndLoop()
├── PMS.main() —— 扫描解析 APK
├── 其他服务初始化
└── WindowManagerService.main() ← WMS 在此启动
├── 创建 WMS 实例
├── 注册显示监听
├── 初始化窗口策略(PhoneWindowManager)
├── 创建 AppTransition(窗口切换动画)
└── 添加到 ServiceManager(服务名为 "window")
↓
Launcher 启动 —— 首次显示桌面
↓
点击应用图标
↓
AMS.startActivity()
↓
ActivityThread.main() —— 应用进程启动
↓
H.handleMessage(LAUNCH_ACTIVITY)
↓
performLaunchActivity()
↓
Activity.onCreate() —— 开发者调用 setContentView()
↓
PhoneWindow.setContentView()
↓
WindowManager.addView() —— 应用请求添加窗口
↓
ViewRootImpl.setView()
↓
Session.addToDisplay() —— 跨进程调用 WMS
↓
【WMS.addWindow()】 ← 当前讲解位置
├── 权限检查
├── 创建 WindowState
├── 创建输入通道
├── Z-Order 排序
├── 更新焦点
└── 分配层级
↓
SurfaceFlinger —— 合成并显示窗口

wms核心步骤

步骤方法职责
1SystemServer.initAndLoop()启动 WMS,调用 WindowManagerService.main()
2WindowManagerService.main()通过 Handler 同步任务创建 WMS 实例
3WindowManagerService 构造函数初始化成员变量、注册显示监听、创建 AppTransition、初始化窗口策略
4WindowManagerService.initPolicy()初始化 PhoneWindowManager(窗口策略)
5WindowManager.addView()应用/系统添加窗口,最终调用 ViewRootImpl.setView()
6ViewRootImpl.setView()通过 Session 向 WMS 发起 addToDisplay 请求
7Session.addToDisplay()调用 WMS.addWindow()
8WindowManagerService.addWindow()权限检查、窗口类型校验、创建 WindowState、分配层级、注册输入通道
9WindowState.attach()创建 SurfaceSession,与 SurfaceFlinger 建立连接
10WindowManagerService.addWindowToListInOrderLocked()按 Z-Order 顺序排列窗口
11WindowManagerService.updateFocusedWindowLocked()更新焦点窗口
12WindowManagerService.assignLayersLocked()分配最终层级值

addWindow 核心步骤总结:

  1. 权限检查 —— mPolicy.checkAddPermission()

  2. 创建/校验 WindowToken —— 区分应用窗口、输入法窗口、墙纸窗口等

  3. 构造 WindowState —— 维护窗口状态

  4. 调整窗口属性 —— adjustWindowParamsLw()

  5. 创建输入通道 —— InputChannel.openInputChannelPair()

  6. 注册到 InputManager —— 接收触摸/按键事件

  7. 将窗口添加到 WMS —— mWindowMap.put()

  8. 按 Z-Order 排序 —— addWindowToListInOrderLocked()

  9. 更新焦点窗口 —— updateFocusedWindowLocked()

  10. 分配层级值 —— assignLayersLocked()

窗口类型分类:

窗口类型说明对应常量
应用窗口Activity 所在窗口、Dialog、PopupWindowFIRST_APPLICATION_WINDOW ~ LAST_APPLICATION_WINDOW
子窗口依附于父窗口的窗口FIRST_SUB_WINDOW ~ LAST_SUB_WINDOW
系统窗口状态栏、导航栏、Toast、壁纸、输入法窗口TYPE_STATUS_BARTYPE_WALLPAPERTYPE_INPUT_METHOD 等

WMS 由 SystemServer 启动:

public void initAndLoop() {
    // 通过 WMS 的静态方法 main 获取一个 WindowManagerService 对象
    wm = WindowManagerService.main(context, power, display, inputManager, wmHandler, 
        factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL, !firstBoot, onlyCore);

    // 将 WMS 添加至 ServiceManager 中
    ServiceManager.addService(Context.WINDOW_SERVICE, wm);
}

看到这里就会发现前面pms、ams和这里的wms架构非常相似啊!initandloop的时候去创建并将其注册进systemserver,用的时候再去systemserver查找,拿到这个binder,再转成对应的service。

这是一个基于非常标准的Binder IPC 的 C/S(客户端/服务端)架构。

  • 服务端(SystemServer): 它是 Android 的系统进程,负责统一启动并初始化所有系统核心服务(PMS、WMS、AMS)。

  • 中转站(ServiceManager): 它是系统唯一的“黄页”进程,负责存储服务名(如 "activity")与服务实例(Binder 引用)的映射关系。

2. 初始化与注册(服务端启动)

  1. 启动: SystemServer 在其 main 方法中通过 initAndLoop 启动消息循环。

  2. 创建与入驻: 各服务类(如 PackageManagerService)提供静态 main() 方法,在该方法内实例化自身,并调用 ServiceManager.addService(),将自己的 Binder 句柄注册到系统中。

3. 获取与通信(客户端调用)

  1. 寻址: 客户端(如你的 App)调用 ServiceManager.getService("name"),向系统查询目标服务的 Binder 句柄(即 BinderProxy)。

  2. 代理生成: Stub.asInterface(binder) 将拿到的原始句柄封装为 Proxy(代理对象)。

  3. 调用: 客户端调用 Proxy 的方法时,该方法将数据(操作码 + 参数)打包成 Parcel,通过 Binder 驱动发送到服务端。

  4. 服务端响应: 服务端的 Stub 类接收请求,解析 Parcel,触发实际的方法实现(onTransact),执行业务逻辑并返回结果。

总结: 该架构的核心是通过 ServiceManager 将服务名映射为 Binder 引用,再通过 Stub/Proxy 将本地接口调用映射为远程进程调用,从而屏蔽了 IPC 的复杂性。

缺点也很明显,一启动就去获取代理了。所以最新aosp对此进行了架构升级。

最新aosp代码:

如:在 frameworks/base/core/java/android/app/ContextImpl.java 中搜索 getSystemService 方法。

  • 注册侧 (SystemServer):

    • 阶段化启动: SystemServiceManager 驱动生命周期。

    • 发布: 通过 publishBinderService() 将服务句柄写入内核的 ServiceManager 进程。

  • 获取侧 (Client App):

    • 入口: Context.getSystemService()。

    • 工厂模式: SystemServiceRegistry 提供 ServiceFetcher。

    • 懒加载: 对象是“用时才创建”,Binder 代理是“方法调用时才寻址”。

不再在构造函数里拿 Binder 了!它是在调用具体方法(如 getRunningAppProcesses())的时候,才去调用 ActivityManager.getService()。

这是 Android 架构的最重要变化:从“启动时获取代理”变为了“调用时懒加载获取”。现在的架构更像是“按需提供的微服务架构”,而不是原来的“一堆服务挤在一起的单体架构”。最近公司在组件化升级架构也是这样升级的。

不过我手上只有老aosp代码的资料,大概的东西都大差不差的,架构不太一样,先看着吧。

WindowManagerService.main():

public static WindowManagerService main(final Context context,
    final PowerManagerService pm, final DisplayManagerService dm,
    final InputManagerService im, final Handler wmHandler,
    final boolean haveInputMethods, final boolean showBootMsgs,
    final boolean onlyCore) {
    final WindowManagerService[] holder = new WindowManagerService[1];

    // 执行同步 Task
    wmHandler.runWithScissors(new Runnable() {
        @Override
        public void run() {
            holder[0] = new WindowManagerService(context, pm, dm, im,
                haveInputMethods, showBootMsgs, onlyCore);
        }
    }, 0);
    return holder[0];
}

WindowManagerService 构造函数:

private WindowManagerService(Context context, PowerManagerService pm,
    DisplayManagerService displayManager, InputManagerService inputManager,
    boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
    // 一些成员变量赋值
    mContext = context;
    mHaveInputMethods = haveInputMethods;
    mAllowBootMessages = showBootMsgs;
    mOnlyCore = onlyCore;
    mLimitedAlphaCompositing = context.getResources().getBoolean(
        com.android.internal.R.bool.config_sf_limitedAlpha);
    mInputManager = inputManager;
    createDisplayContentLocked.mDisplayManagerService = displayManager;

    // 获取显示服务
    mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);

    // 将 WMS 注册到显示服务中
    mDisplayManager.registerDisplayListener(this, null);

    // 为每一个 Display 分配一个 Content
    Display[] displays = mDisplayManager.getDisplays();
    for (Display display : displays) {
        createDisplayContentLocked(display);
    }

    // 构造 APP 事务对象
    mAppTransition = new AppTransition(context, mH);

    // 获取 IActivityManager 对象
    mActivityManager = ActivityManagerNative.getDefault();

    // 构造 Window 动画对象
    mAnimator = new WindowAnimator(this);

    // 初始化窗口管理策略
    initPolicy(UiThread.getHandler());

    // 开启绘制 Surface 事务
    SurfaceControl.openTransaction();
}

WMS 维护的各种窗口列表:

public class WindowManagerService extends WindowManager.Stub implements Watchdog.Monitor,
    WindowManagerPolicy.WindowManagerFuncs, DisplayManagerService.WindowManagerFuncs,
    DisplayManager.DisplayListener {
    // 已经完成启动的应用
    final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<AppWindowToken>();

    // 渐变窗口
    final ArrayList<FakeWindowImpl> mFakeWindows = new ArrayList<FakeWindowImpl>();

    // 尺寸正在改变的窗口
    final ArrayList<WindowState> mResizingWindows = new ArrayList<WindowState>();

    // 动画结束的窗口
    final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>();

    // 即将释放 Surface 的窗口
    final ArrayList<WindowState> mDestroySurface = new ArrayList<WindowState>();

    // 失去焦点的窗口
    ArrayList<WindowState> mLosingFocus = new ArrayList<WindowState>();

    // 为了释放内存需要强制关闭的窗口
    ArrayList<WindowState> mForceRemoves;

    // 等待绘制的窗口
    ArrayList<Pair<WindowState, IRemoteCallback>> mWaitingForDrawn = 
        new ArrayList<Pair<WindowState, IRemoteCallback>>();

    // 正处于动画中但需要 Relayout 的窗口
    final ArrayList<WindowState> mRelayoutWhileAnimating = new ArrayList<WindowState>();

    // 正在打开的应用
    final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();

    // 正在关闭的应用
    final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();

    // 当前获得焦点的窗口
    WindowState mCurrentFocus = null;

    // 上一个获得焦点的窗口
    WindowState mLastFocus = null;

    // 输入法窗口下方的窗口
    WindowState mInputMethodTarget = null;

    // 输入法窗口
    WindowState mInputMethodWindow = null;

    // 墙纸窗口
    WindowState mWallpaperTarget = null;

    // 在切换过程中位于墙纸 Z-Order 下方的窗口
    WindowState mLowerWallpaperTarget = null;

    // 在切换过程中位于墙纸 Z-Order 上方的窗口
    WindowState mUpperWallpaperTarget = null;

    // 得到焦点的应用
    AppWindowToken mFocusedApp = null;
}

系统窗口添加示例 —— 状态栏:

public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
    @Override
    public void createAndAddWindows() {
        addStatusBarWindow();
    }

    private void addStatusBarWindow() {
        // 获取状态栏高度
        final int height = getStatusBarHeight();

        // 根据各种标识值构造布局参数
        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            height,
            WindowManager.LayoutParams.TYPE_STATUS_BAR,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_TOUCHABLE_WINDOW_WAITING
                | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSLUCENT);
        lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        lp.gravity = getStatusBarGravity();
        lp.setTitle("StatusBar");
        lp.packageName = mContext.getPackageName();

        // 构造具体的状态栏 View,本质是一个 FrameLayout
        makeStatusBarView();

        // 将状态栏 View 添加至 WindowManager
        mWindowManager.addView(mStatusBarWindow, lp);
    }
}

Session.addToDisplay —— 向 WMS 发起请求:

final class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
    @Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
        int viewVisibility, int displayId, Rect outContentInsets,
        InputChannel outInputChannel) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
            outContentInsets, outInputChannel);
    }
}

WindowManagerService.addWindow() —— 窗口添加核心逻辑:

public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs,
    int viewVisibility, int displayId, Rect outContentInsets, InputChannel outInputChannel) {
    int[] appOp = new int[1];
    // 1. 权限检查
    int res = mPolicy.checkAddPermission(attrs, appOp);
    if (res != WindowManagerGlobal.ADD_OKAY) {
        return res;
    }

    synchronized(mWindowMap) {
        boolean addToken = false;
        WindowToken token = mTokenMap.get(attrs.token);
        
        if (token == null) {
            // 如果窗口是子窗口
            if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
                return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
            }
            // 如果窗口是输入法窗口
            if (type == TYPE_INPUT_METHOD) {
                return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
            }
            // 如果窗口是墙纸窗口
            if (type == TYPE_WALLPAPER) {
                return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
            }
            // 如果窗口是锁屏后显示的 DayDream 窗口
            if (type == TYPE_DREAM) {
                return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
            }
            // 构造 WindowToken 对象
            token = new WindowToken(this, attrs.token, -1, false);
            addToken = true;
        } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
            // 获取应用的 AppWindowToken
            AppWindowToken atoken = token.appWindowToken;
            if (atoken == null) {
                return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
            } else if (atoken.removed) {
                return WindowManagerGlobal.ADD_APP_EXITING;
            }
            if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
                return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;
            }
        } else if (type == TYPE_INPUT_METHOD) {
            if (token.windowType != TYPE_INPUT_METHOD) {
                return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
            }
        } else if (type == TYPE_WALLPAPER) {
            if (token.windowType != TYPE_WALLPAPER) {
                return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
            }
        } else if (type == TYPE_DREAM) {
            if (token.windowType != TYPE_DREAM) {
                return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
            }
        }

        // 2. 构造 WindowState 对象
        win = new WindowState(this, session, client, token, attachedWindow, 
            appOp[0], seq, attrs, viewVisibility, displayContent);
        
        if (win.mDeathRecipient == null) {
            return WindowManagerGlobal.ADD_APP_EXITING;
        }

        // 3. 根据窗口类型调整属性
        mPolicy.adjustWindowParamsLw(win.mAttrs);
        win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));

        // 4. 根据窗口类型判定权限
        res = mPolicy.prepareAddWindowLw(win, attrs);
        if (res != WindowManagerGlobal.ADD_OKAY) {
            return res;
        }

        // 5. 创建输入通道
        if (outInputChannel != null && (attrs.inputFeatures & 
            WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
            String name = win.makeInputChannelName();
            InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
            win.setInputChannel(inputChannels[0]);
            inputChannels[1].transferTo(outInputChannel);
            // 向 InputManager 中注册该通道,以便当前窗口可以接收到事件
            mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
        }

        res = WindowManagerGlobal.ADD_OKAY;
        origId = Binder.clearCallingIdentity();

        // 6. 添加 Token
        if (addToken) {
            mTokenMap.put(attrs.token, token);
        }

        // 7. 将窗口添加至 Session 和 WMS
        win.attach();
        mWindowMap.put(client.asBinder(), win);

        boolean imMayMove = true;

        // 8. 按类型将窗口添加到对应列表并排序
        if (type == TYPE_INPUT_METHOD) {
            win.mGivenInsetsPending = true;
            mInputMethodWindow = win;
            addInputMethodWindowToListLocked(win);
            imMayMove = false;
        } else if (type == TYPE_INPUT_METHOD_DIALOG) {
            mInputMethodDialogs.add(win);
            addWindowToListInOrderLocked(win, true);
            moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
            imMayMove = false;
        } else {
            addWindowToListInOrderLocked(win, true);
            if (type == TYPE_WALLPAPER) {
                mLastWallpaperTimeout = 0;
                displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
            } else if ((attrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
                displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
            } else if (mWallpaperTarget != null
                && mWallpaperTarget.mLayer >= win.mBaseLayer) {
                displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
            }
        }

        win.mWinAnimator.mEnterAnimationPending = true;

        // 9. 获取系统窗口区域的 insets
        if (displayContent.isDefaultDisplay) {
            mPolicy.getContentInsetsHintLw(attrs, outContentInsets);
        } else {
            outContentInsets.setEmpty();
        }

        if (mInTouchMode) {
            res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
        }
        if (win.mAppToken == null || !win.mAppToken.clientHidden) {
            res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
        }

        mInputMonitor.setUpdateInputWindowsNeededLw();
        boolean focusChanged = false;

        // 10. 更新焦点窗口
        if (win.canReceiveKeys()) {
            focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS, false);
            if (focusChanged) {
                imMayMove = false;
            }
        }
        if (imMayMove) {
            moveInputMethodWindowsIfNeededLocked(false);
        }

        // 11. 分配最终层级值
        assignLayersLocked(displayContent.getWindowList());

        if (focusChanged) {
            finishUpdateFocusedWindowAfterAssignLayersLocked(false);
        }
        mInputMonitor.updateInputWindowsLw(false);

        if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
            reportNewConfig = true;
        }
        if (reportNewConfig) {
            sendNewConfiguration();
        }

        Binder.restoreCallingIdentity(origId);
        return res;
    }
}

8.window与windowmanager

Activity执行onCreate时调用setContentView,内部会创建PhoneWindow(Window的唯一实现),同时通过WindowManager将Window添加到系统服务端管理。Window是Activity的"画板容器"。

Window 是一个抽象的概念,每一个 Window 都对应着一个 View 和一个 ViewRootImpl,Window 和 View 通过 ViewRootImpl 来建立联系,因此 Window 并不是实际存在的,它是以 View 的形式存在。这点从 WindowManager 的定义也可以看出,它提供的三个接口方法 addView、updateViewLayout 以及 removeView 都是针对 View 的,这说明 View 才是 Window 存在的实体。

在实际使用中无法直接访问 Window,对 Window 的访问必须通过 WindowManager。WindowManager 是外界访问 Window 的入口,Window 的具体实现位于 WindowManagerService 中,WindowManager 和 WindowManagerService 的交互是一个 IPC 过程。

Window 创建在应用启动流程中的位置

应用启动流程(从点击图标到界面显示)

点击应用图标
    ↓
AMS.startActivity()
    ↓
ActivityThread.main()                              ← 应用进程入口
    ↓
ActivityThread.attach(false)
    ↓
H.handleMessage(BIND_APPLICATION)
    ↓
handleBindApplication()                            ← 创建 Application
    ↓
H.handleMessage(LAUNCH_ACTIVITY)
    ↓
handleLaunchActivity()
    ↓
performLaunchActivity()
    ↓
【步骤一】activity = mInstrumentation.newActivity()      ← 创建 Activity 实例
    ↓
【步骤二】createBaseContextForActivity()                  ← 创建 ContextImpl
    ↓
【步骤三】activity.attach()                               ← ★★★ Window 在此创建(PhoneWindow)
    ├── mWindow = PolicyManager.makeNewWindow(this)
    └── mWindow.setCallback(this)
    ↓
【步骤四】callActivityOnCreate()                          ← 回调 onCreate()
    ↓
Activity.onCreate()
    ↓
【步骤五】setContentView(layoutResID)                     ← ★★★ 创建 DecorView
    ├── getWindow().setContentView(layoutResID)
    │   ├── installDecor()                                ← 创建 DecorView
    │   │   ├── generateDecor()                           ← new DecorView()
    │   │   └── generateLayout()                          ← 加载系统布局,初始化 mContentParent
    │   └── mLayoutInflater.inflate(layoutResID, mContentParent)  ← 加载业务布局
    └── initWindowDecorActionBar()
    ↓
callActivityOnStart()                                     ← 回调 onStart()
    ↓
callActivityOnResume()                                    ← 回调 onResume()
    ↓
handleResumeActivity()
    ├── performResumeActivity()                           ← 回调 onResume()
    └── r.activity.makeVisible()                          ← ★★★ 真正添加 Window
        ├── wm.addView(mDecor, getWindow().getAttributes())   ← 跨进程调用 WMS
        └── mDecor.setVisibility(View.VISIBLE)            ← 显示视图
    ↓
View 绘制完成,用户看到界面

启动流程中window相关核心步骤源码如下:

Activity 的 Window 创建过程

1.在 Activity.attach 中创建 PhoneWindow

// 文件:Activity.java
final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window) {
    // ... 省略其他代码 ...
    
    // ★★★ 创建 Window 对象,具体实现为 PhoneWindow ★★★
    mWindow = PolicyManager.makeNewWindow(this);
    // 设置回调接口,Activity 实现了 Window.Callback
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    
    // ... 省略其他代码 ...
}

PolicyManager.makeNewWindow:

// 文件:Policy.java
public Window makeNewWindow(Context context) {
    // ★★★ Window 的具体实现是 PhoneWindow ★★★
    return new PhoneWindow(context);
}

2.Activity.setContentView 委托给 PhoneWindow

// 文件:Activity.java
public void setContentView(int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

3.PhoneWindow.setContentView 创建 DecorView

// 文件:PhoneWindow.java
@Override
public void setContentView(int layoutResID) {
    // 1. 如果没有 DecorView,则创建它
    if (mContentParent == null) {
        installDecor();
    } else {
        mContentParent.removeAllViews();
    }
    // 2. 将 Activity 的布局添加到 DecorView 的 mContentParent 中
    mLayoutInflater.inflate(layoutResID, mContentParent);
    // 3. 回调 Activity 的 onContentChanged
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

4.installDecor 初始化 DecorView

// 文件:PhoneWindow.java
private void installDecor() {
    if (mDecor == null) {
        // 创建 DecorView(空白的 FrameLayout)
        mDecor = generateDecor();
        // ...
    }
    if (mContentParent == null) {
        // 根据主题加载具体的布局文件到 DecorView 中
        mContentParent = generateLayout(mDecor);
        // ...
    }
}

protected DecorView generateDecor() {
    return new DecorView(getContext(), -1);
}

protected ViewGroup generateLayout(DecorView decor) {
    // 根据主题选择布局资源
    // 加载系统布局(包含标题栏、内容栏等)
    View in = mLayoutInflater.inflate(layoutResource, null);
    decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    mContentRoot = (ViewGroup) in;
    
    // ★★★ mContentParent 的 id 就是 android.R.id.content ★★★
    ViewGroup contentParent = (ViewGroup) findViewById(ID_ANDROID_CONTENT);
    // ...
    return contentParent;
}

5.handleResumeActivity 中 makeVisible 真正添加 Window

// 文件:ActivityThread.java
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
        boolean reallyResume, int seq, String reason) {
    // 1. 先回调 Activity.onResume
    ActivityClientRecord r = performResumeActivity(token, clearHide, reason);
    if (r != null) {
        final Activity a = r.activity;
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    // ★★★ 添加 DecorView 到 WindowManager ★★★
                    wm.addView(decor, l);
                } else {
                    a.onWindowAttributesChanged(l);
                }
            }
        }
    }
}

Activity.makeVisible:

// 文件:Activity.java
void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        // ★★★ 真正将 DecorView 添加到 Window 中 ★★★
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}

然后就到window的添加过程啦

Window 的添加过程

Window 的添加过程需要通过 WindowManager 的 addView 来实现,WindowManager 是一个接口,它的真正实现是 WindowManagerImpl 类。

1.WindowManagerImpl 委托给 WindowManagerGlobal

// 文件:WindowManagerImpl.java
@Override
public void addView(View view, ViewGroup.LayoutParams params) {
    mGlobal.addView(view, params, mDisplay, mParentWindow);
}

@Override
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
    mGlobal.updateViewLayout(view, params);
}

@Override
public void removeView(View view) {
    mGlobal.removeView(view, false);
}

2.检查参数合法性

// 文件:WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
    // 1. 检查参数是否合法
    if (view == null) {
        throw new IllegalArgumentException("view must not be null");
    }
    if (display == null) {
        throw new IllegalArgumentException("display must not be null");
    }
    if (!(params instanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }

    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    // 如果是子 Window,调整布局参数
    if (parentWindow != null) {
        parentWindow.adjustLayoutParamsForSubWindow(wparams);
    }
    // ...
}

3.创建 ViewRootImpl 并添加到列表中

// 文件:WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
    // ...
    ViewRootImpl root;
    View panelParentView = null;

    synchronized (mLock) {
        // 存储所有 Window 所对应的 View、ViewRootImpl 和布局参数
        root = new ViewRootImpl(view.getContext(), display);
        view.setLayoutParams(wparams);

        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
    }

    try {
        // 通过 ViewRootImpl 来更新界面并完成 Window 的添加
        root.setView(view, wparams, panelParentView);
    } catch (RuntimeException e) {
        // ...
    }
}

4.ViewRootImpl.setView 触发绘制并跨进程添加

// 文件:ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        if (mView == null) {
            mView = view;
            // 请求布局,触发 View 绘制
            requestLayout();

            try {
                mOrigWindowType = mWindowAttributes.type;
                mAttachInfo.mRecomputeGlobalAttributes = true;
                collectViewAttributes();
                // ★★★ 跨进程调用 WMS 添加窗口 ★★★
                res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(),
                        mAttachInfo.mContentInsets, mInputChannel);
            } catch (RemoteException e) {
                // ...
            }
        }
    }
}

5.Session.addToDisplay → WMS.addWindow

// 文件:Session.java
final class Session extends IWindowSession.Stub {
    @Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets,
            InputChannel outInputChannel) {
        // ★★★ 最终调用 WMS 的 addWindow ★★★
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outInputChannel);
    }
}

到这里就完成了窗口的登记和surface分配,之后进程通过requestLayout -> performTraversals开始绘制view,wms通过windowAnimator持续管理和合成所有窗口,最终由surfaceFling将绘制好的surface合成显示到屏幕上。

================================华丽的分割线,顺带一下window基础介绍

Window 的类型(Type):

类型层级范围说明
应用 Window1~99对应 Activity
子 Window1000~1999需要依附父 Window,如 Dialog
系统 Window2000~2999需要权限,如 Toast、状态栏

常用 Flags:

Flag说明
FLAG_NOT_FOCUSABLEWindow 不需要获取焦点,事件直接传递给下层
FLAG_NOT_TOUCH_MODAL当前区域外的事件传递给底层 Window
FLAG_SHOW_WHEN_LOCKED显示在锁屏界面上

FLAG_NOT_FOCUSABLE常用于解dialog的一些bug,比如一些系统应用级弹窗在跟导航栏打架,然后在全屏页面带出状态栏,还有一些机型被厂商魔改全屏的时候设置match_parent的时候也会带出状态栏,一般这个标志位配合着改一下就好了。

FLAG_NOT_TOUCH_MODAL应该就是鸿蒙里面的模态和非模态。hhhhhhh

核心就这3个api

public interface ViewManager {
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

前面说了addview这个,那就再来讲一下另外2个

Window 的删除过程

// 文件:WindowManagerGlobal.java
public void removeView(View view, boolean immediate) {
    if (view == null) {
        throw new IllegalArgumentException("view must not be null");
    }

    synchronized (mLock) {
        // 查找待删除 View 的索引
        int index = findViewLocked(view, true);
        View curView = mRoots.get(index).getView();
        // 删除
        removeViewLocked(index, immediate);
        if (curView == view) {
            return;
        }
        throw new IllegalArgumentException("Calling with view " + view
                + " but the ViewAncestor is attached to " + curView);
    }
}

private void removeViewLocked(int index, boolean immediate) {
    ViewRootImpl root = mRoots.get(index);
    View view = root.getView();
    // 通过 ViewRootImpl 完成删除
    boolean deferred = root.die(immediate);
    if (view != null) {
        view.assignParent(null);
        if (deferred) {
            mDyingViews.add(view);
        }
    }
}

removeView 和 removeViewImmediate 的区别:removeView 是异步删除,发送 MSG_DIE 消息后立即返回,View 实际还未删除完成,会被添加到 mDyingViews 中;removeViewImmediate 是同步删除,直接调用 doDie 方法,不发送消息。removeViewImmediate 使用起来需要特别注意,一般来说不需要使用此方法来删除 Window,以免发生意外的错误。

Window 的更新过程

// 文件:WindowManagerGlobal.java
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
    if (view == null) {
        throw new IllegalArgumentException("view must not be null");
    }
    if (!(params instanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }

    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    view.setLayoutParams(wparams);

    synchronized (mLock) {
        int index = findViewLocked(view, true);
        ViewRootImpl root = mRoots.get(index);
        mParams.remove(index);
        mParams.add(index, wparams);
        // 更新 ViewRootImpl 中的 LayoutParams,触发重新布局
        root.setLayoutParams(wparams, false);
    }
}

9.view与viewgroup

setContentView通过LayoutInflater解析XML,反射创建View对象。ViewGroup是容器(如LinearLayout),View是叶子节点(如Button)。它们组成UI树,供后续测量、布局、绘制。

好,刚刚到requestLayout了,这一步就是绘制流程了。

绘制流程在app启动的这个位置:

用户点击桌面图标
    ↓
PMS 解析 → Zygote 创建进程 → ActivityThread.main()
    ↓
Application 创建 → AMS 启动 Activity
    ↓
performLaunchActivity() → Activity.onCreate() → setContentView()
    ↓
handleResumeActivity() → Activity.makeVisible()
    ↓
WindowManager.addView(decor, l)
    ↓
【View 绘制流程起点】ViewRootImpl.setView()
    ↓
ViewRootImpl.requestLayout()
    ↓
ViewRootImpl.performTraversals()  ← 当前讲解位置
    ├── ① performMeasure() → 测量
    ├── ② performLayout() → 布局
    └── ③ performDraw() → 绘制
    ↓
用户看到界面

核心步骤速览

顺序核心步骤作用
1ViewRootImpl.performTraversals()绘制入口,触发 measure → layout → draw
2ViewRootImpl.performMeasure()触发顶级 View 的测量
3View.measure()final 方法,调用 onMeasure
4View.onMeasure()实际测量宽/高,setMeasuredDimension
5ViewGroup.measureChildren()遍历子 View 逐个测量
6ViewGroup.getChildMeasureSpec()根据父容器规则计算子 View 的 MeasureSpec
7ViewRootImpl.performLayout()触发顶级 View 的布局
8View.layout()设置四个顶点位置
9ViewGroup.onLayout()确定子 View 位置
10ViewRootImpl.performDraw()触发顶级 View 的绘制
11View.draw()按顺序执行绘制步骤
12View.onDraw()绘制自身内容
13View.dispatchDraw()绘制子 View

核心步骤源码如下:

阶段1.ViewRootImpl 与 performTraversals

ViewRootImpl 是连接 WindowManager 和 DecorView 的纽带。在 ActivityThread.handleResumeActivity() 中创建:

// 文件:ViewRootImpl.java
// ★★★ ViewRootImpl 创建并关联 DecorView ★★★
root = new ViewRootImpl(view.getContext(), display);
root.setView(view, wparams, panelParentView);

performTraversals 是 View 绘制的总入口,依次执行三大流程:

// 文件:ViewRootImpl.java
// ★★★ performTraversals:三大流程入口 ★★★
private void performTraversals() {
    // ① 测量阶段
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    
    // ② 布局阶段
    performLayout(lp, mWidth, mHeight);
    
    // ③ 绘制阶段
    performDraw();
}

performTraversals 工作流程图

ViewRootImpl.performTraversals()
    │
    ├── performMeasure()
    │       │
    │       └── measure()
    │               │
    │               └── onMeasure()
    │                       │
    │                       └── (递归遍历子 View)
    │
    ├── performLayout()
    │       │
    │       └── layout()
    │               │
    │               └── onLayout()
    │                       │
    │                       └── (递归遍历子 View)
    │
    └── performDraw()
            │
            └── draw()
                    │
                    ├── drawBackground()
                    ├── onDraw()
                    ├── dispatchDraw()
                    └── onDrawScrollBars()

阶段二:MeasureSpec

MeasureSpec 代表一个 32 位 int 值,高 2 位代表 SpecMode,低 30 位代表 SpecSize:

// 文件:MeasureSpec.java
// ★★★ MeasureSpec 定义 ★★★
private static final int MODE_SHIFT = 30;
private static final int MODE_MASK = 0x3 << MODE_SHIFT;

public static final int UNSPECIFIED = 0 << MODE_SHIFT;
public static final int EXACTLY = 1 << MODE_SHIFT;
public static final int AT_MOST = 2 << MODE_SHIFT;

// ★ 打包:将 size 和 mode 打包成 32 位 int ★
public static int makeMeasureSpec(int size, int mode) {
    if (sUseBrokenMakeMeasureSpec) {
        return size + mode;
    } else {
        return (size & ~MODE_MASK) | (mode & MODE_MASK);
    }
}

// ★ 解包:获取 mode ★
public static int getMode(int measureSpec) {
    return (measureSpec & MODE_MASK);
}

// ★ 解包:获取 size ★
public static int getSize(int measureSpec) {
    return (measureSpec & ~MODE_MASK);
}

哈哈哈,这里也有2进制。看不懂的可以看俺的这篇文章字、字节、比特、进制、位运算_字节 字 位 比特-CSDN博客

三种 SpecMode 含义:

模式含义对应 LayoutParams
EXACTLY父容器已确定精确大小,View 的最终大小就是这个值match_parent 或固定值(100dp)
AT_MOST父容器指定了最大大小,View 不能超过这个值wrap_content
UNSPECIFIED父容器不限制,要多大给多大系统内部测量使用

阶段三:DecorView 的 MeasureSpec 创建

顶级 View(DecorView)的 MeasureSpec 由窗口尺寸自身 LayoutParams 共同确定:

// 文件:ViewRootImpl.java
// ★★★ 顶级 View 的 MeasureSpec 创建 ★★★
private static int getRootMeasureSpec(int windowSize, int rootDimension) {
    int measureSpec;
    switch (rootDimension) {
        case ViewGroup.LayoutParams.MATCH_PARENT:
            // Window can't resize. Force root view to be windowSize.
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
            break;
        case ViewGroup.LayoutParams.WRAP_CONTENT:
            // Window can resize. Set max size for root view.
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
            break;
        default:
            // Window wants to be an exact size. Force root view to be that size.
            measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
            break;
    }
    return measureSpec;
}

阶段四:View 的 measure 过程

4.1 View.measure()

// 文件:View.java
// ★★★ 测量入口(final 方法,子类不可重写) ★★★
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
    // ... 内部逻辑 ...
    onMeasure(widthMeasureSpec, heightMeasureSpec);
}

4.2 View.onMeasure()

// 文件:View.java
// ★★★ 实际测量,子类可重写 ★★★
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(
        getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
        getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)
    );
}

4.3 getDefaultSize()

// 文件:View.java
// ★★★ 获取默认大小 ★★★
public static int getDefaultSize(int size, int measureSpec) {
    int result = size;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);

    switch (specMode) {
        case MeasureSpec.UNSPECIFIED:
            result = size;  // UNSPECIFIED 时返回默认值
            break;
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            result = specSize;  // ★ 大部分情况下测量值就是 specSize ★
            break;
    }
    return result;
}

关键结论: 在 AT_MOST 和 EXACTLY 模式下,getDefaultSize 返回的是 specSize。因此,如果自定义 View 在 wrap_content 时不做特殊处理,其测量值就是父容器剩余空间,效果等同于 match_parent

4.4 getSuggestedMinimumWidth()

// 文件:View.java
// ★★★ UNSPECIFIED 模式下的默认宽度 ★★★
protected int getSuggestedMinimumWidth() {
    return (mBackground == null) ? mMinWidth : Math.max(mMinWidth, mBackground.getMinimumWidth());
}

protected int getSuggestedMinimumHeight() {
    return (mBackground == null) ? mMinHeight : Math.max(mMinHeight, mBackground.getMinimumHeight());
}

如果 View 没有设置背景,那么 View 的宽度为 mMinWidth,而 mMinWidth 对应于 android:minWidth 这个属性所指定的值。这个属性如果不指定,那么 mMinWidth 则默认为 0;如果 View 指定了背景,则 View 的宽度为 max(mMinWidth, mBackground.getMinimumWidth())。Drawable.getMinimumWidth() 返回 Drawable 的原始宽度。BitmapDrawable 有原始宽高(图片尺寸),ShapeDrawable 没有原始宽高。

4.5 自定义 View 处理 wrap_content

// ★★★ 自定义 View 重写 onMeasure ★★★
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int desiredWidth = 200;   // 默认宽度
    int desiredHeight = 100;  // 默认高度

    if (widthMode == MeasureSpec.AT_MOST) {
        widthSize = Math.min(desiredWidth, widthSize);
    }
    if (heightMode == MeasureSpec.AT_MOST) {
        heightSize = Math.min(desiredHeight, heightSize);
    }

    setMeasuredDimension(widthSize, heightSize);
}

阶段五:ViewGroup 的 measure 过程

5.1 ViewGroup.measureChildren()

// 文件:ViewGroup.java
// ★★★ 遍历测量所有子 View ★★★
protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
    final int size = mChildrenCount;
    final View[] children = mChildren;
    for (int i = 0; i < size; ++i) {
        final View child = children[i];
        if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
        }
    }
}

5.2 ViewGroup.measureChild()

// 文件:ViewGroup.java
// ★★★ 测量单个子 View(不考虑 margin) ★★★
protected void measureChild(View child, int parentWidthMeasureSpec,
        int parentHeightMeasureSpec) {
    final LayoutParams lp = child.getLayoutParams();

    final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
            mPaddingLeft + mPaddingRight, lp.width);
    final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
            mPaddingTop + mPaddingBottom, lp.height);

    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}

5.3 ViewGroup.measureChildWithMargins()

// 文件:ViewGroup.java
// ★★★ 测量单个子 View(考虑 margin) ★★★
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec,
        int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
    final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

    final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
            mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed,
            lp.width);
    final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
            mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + heightUsed,
            lp.height);

    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}

5.4 getChildMeasureSpec() —— 核心方法

// 文件:ViewGroup.java
// ★★★ 核心:根据父容器 MeasureSpec 和子 View 的 LayoutParams 计算子 View 的 MeasureSpec ★★★
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
    int specMode = MeasureSpec.getMode(spec);
    int specSize = MeasureSpec.getSize(spec);

    // 父容器可用大小 = 父容器总大小 - 已占用的 padding
    int size = Math.max(0, specSize - padding);

    int resultSize = 0;
    int resultMode = 0;

    switch (specMode) {
        // 父容器是精确模式
        case MeasureSpec.EXACTLY:
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                resultSize = size;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // 父容器是最大模式
        case MeasureSpec.AT_MOST:
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // 父容器无限制(系统内部使用)
        case MeasureSpec.UNSPECIFIED:
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                resultSize = 0;
                resultMode = MeasureSpec.UNSPECIFIED;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                resultSize = 0;
                resultMode = MeasureSpec.UNSPECIFIED;
            }
            break;
    }

    return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}

getChildMeasureSpec 规则表

父容器模式子 View LayoutParams子 View 测量模式子 View 测量大小
EXACTLY固定值EXACTLYchildDimension
EXACTLYMATCH_PARENTEXACTLYparentSize
EXACTLYWRAP_CONTENTAT_MOSTparentSize
AT_MOST固定值EXACTLYchildDimension
AT_MOSTMATCH_PARENTAT_MOSTparentSize
AT_MOSTWRAP_CONTENTAT_MOSTparentSize
UNSPECIFIED固定值EXACTLYchildDimension
UNSPECIFIEDMATCH_PARENTUNSPECIFIED0
UNSPECIFIEDWRAP_CONTENTUNSPECIFIED0

阶段六:LinearLayout 的 measure 过程

6.1 LinearLayout.onMeasure()

// 文件:LinearLayout.java
// ★★★ LinearLayout 测量入口 ★★★
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (mOrientation == VERTICAL) {
        measureVertical(widthMeasureSpec, heightMeasureSpec);
    } else {
        measureHorizontal(widthMeasureSpec, heightMeasureSpec);
    }
}

6.2 measureVertical() 核心逻辑

// 文件:LinearLayout.java
// ★★★ 竖直方向测量 ★★★
void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
    mTotalLength = 0;
    int maxWidth = 0;

    // 1. ★ 遍历所有子 View 进行测量 ★
    for (int i = 0; i < count; ++i) {
        final View child = getVirtualChildAt(i);
        if (child == null || child.getVisibility() == GONE) {
            continue;
        }

        // 测量子 View(考虑权重)
        measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
                heightMeasureSpec, totalWeight == 0 ? mTotalLength : 0);

        // 累加高度
        final int childHeight = child.getMeasuredHeight();
        mTotalLength = Math.max(mTotalLength, mTotalLength + childHeight + lp.topMargin + lp.bottomMargin);
    }

    // 2. ★ 加上 padding ★
    mTotalLength += mPaddingTop + mPaddingBottom;

    // 3. ★ 处理最小高度 ★
    int heightSize = Math.max(mTotalLength, getSuggestedMinimumHeight());

    // 4. ★★★ resolveSizeAndState ★★★
    int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);
    heightSize = heightSizeAndState & MEASURED_SIZE_MASK;

    setMeasuredDimension(
        resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
        heightSizeAndState
    );
}

6.3 resolveSizeAndState()

// 文件:View.java
// ★★★ 处理 AT_MOST 模式下的尺寸冲突 ★★★
public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
    int result = size;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);

    switch (specMode) {
        case MeasureSpec.UNSPECIFIED:
            result = size;
            break;
        case MeasureSpec.AT_MOST:
            // ★ 如果期望大小超过了父容器限制,则限制为 specSize ★
            if (specSize < size) {
                result = specSize | MEASURED_STATE_TOO_SMALL;
            } else {
                result = size;
            }
            break;
        case MeasureSpec.EXACTLY:
            result = specSize;
            break;
    }
    return result | (childMeasuredState & MEASURED_STATE_MASK);
}

如果布局中高度采用的是 match_parent 或者具体数值,那么它的测量过程和 View 一致,即高度为 specSize;如果它的布局中高度采用的是 wrap_content,那么它的高度是所有子元素所占用的高度总和,但是仍然不能超过它的父容器的剩余空间。

阶段七:layout 过程

7.1 View.layout()

// 文件:View.java
// ★★★ 布局入口:确定 View 的位置 ★★★
public void layout(int l, int t, int r, int b) {
    // 如果需要重新测量,则先调用 onMeasure
    if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
        onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
        mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
    }

    int oldL = mLeft;
    int oldT = mTop;
    int oldB = mBottom;
    int oldR = mRight;

    // ★ 1. setFrame:设置四个顶点的位置 ★
    boolean changed = setFrame(l, t, r, b);

    if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
        // ★ 2. ★ 调用 onLayout ★
        onLayout(changed, l, t, r, b);
        mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
    }
}

7.2 setFrame() —— 四个顶点赋值

// 文件:View.java
// ★★★ 设置 View 的四个顶点 ★★★
protected boolean setFrame(int left, int top, int right, int bottom) {
    if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
        mLeft = left;
        mTop = top;
        mRight = right;
        mBottom = bottom;
        return true;
    }
    return false;
}

7.3 LinearLayout.onLayout()

// 文件:LinearLayout.java
// ★★★ LinearLayout 布局 ★★★
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    if (mOrientation == VERTICAL) {
        layoutVertical(l, t, r, b);
    } else {
        layoutHorizontal(l, t, r, b);
    }
}

// ★★★ 竖直方向布局 ★★★
void layoutVertical(int left, int top, int right, int bottom) {
    final int count = getVirtualChildCount();
    int childTop = mPaddingTop;

    for (int i = 0; i < count; i++) {
        final View child = getVirtualChildAt(i);
        if (child == null || child.getVisibility() == GONE) {
            continue;
        }

        final int childWidth = child.getMeasuredWidth();
        final int childHeight = child.getMeasuredHeight();

        // ★ 调用 setChildFrame 设置子 View 的位置 ★
        setChildFrame(child, childLeft, childTop + getLocationOffset(child),
                childWidth, childHeight);

        childTop += childHeight + lp.topMargin + lp.bottomMargin;
    }
}

7.4 setChildFrame()

// 文件:LinearLayout.java
// ★★★ 调用子 View 的 layout 方法设置位置 ★★★
private void setChildFrame(View child, int left, int top, int width, int height) {
    child.layout(left, top, left + width, top + height);
}

7.5 getWidth() / getHeight()

// 文件:View.java
// ★★★ 获取最终宽/高 ★★★
public final int getWidth() {
    return mRight - mLeft;
}

public final int getHeight() {
    return mBottom - mTop;
}

7.6 测量宽高 vs 最终宽高的区别

对比项测量宽/高最终宽/高
获取方法getMeasuredWidth() / getMeasuredHeight()getWidth() / getHeight()
赋值时机measure 阶段layout 阶段
值是否相等默认情况下相等默认情况下相等

在几乎所有的情况下,View 的测量大小和最终大小是相等的,但是特殊情况除外。特殊情况:如果在 layout 阶段 View 被重新布局,或者父容器强制改变子 View 的大小,可能导致测量值和最终值不一致。

阶段八:draw 过程

View.draw() 按顺序执行 6 个绘制步骤:

// 文件:View.java
// ★★★ 绘制流程 ★★★
public void draw(Canvas canvas) {
    /*
     * 绘制步骤必须按顺序执行:
     * 1. 绘制背景 (drawBackground)
     * 2. 如果需要,保存画布图层
     * 3. 绘制内容 (onDraw)
     * 4. 绘制子 View (dispatchDraw)
     * 5. 如果需要,绘制渐变边缘并恢复图层
     * 6. 绘制装饰(滚动条等)(onDrawScrollBars)
     */

    final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE
            && (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);

    // ★ Step 1: 绘制背景 ★
    if (!dirtyOpaque) {
        drawBackground(canvas);
    }

    // ★ Step 3: 绘制内容 ★
    if (!dirtyOpaque) onDraw(canvas);

    // ★ Step 4: 绘制子 View ★
    dispatchDraw(canvas);

    // ★ Step 6: 绘制滚动条 ★
    onDrawScrollBars(canvas);

    if (mOverlay != null && !mOverlay.isEmpty()) {
        mOverlay.getOverlayView().dispatchDraw(canvas);
    }
}

dirtyOpaque 的作用: 如果 View 是不透明的且没有重叠,系统可以跳过 drawBackground 和 onDraw的某些步骤进行优化。

阶段九:setWillNotDraw —— 优化标记位

// 文件:View.java
/**
 * 如果这个 View 不需要绘制任何内容,设置这个标记位为 true 后,
 * 系统会进行相应的优化。
 *
 * 默认情况下,View 没有启用这个优化标记位,
 * 但是 ViewGroup 会默认启用这个优化标记位。
 *
 * 当自定义控件继承于 ViewGroup 并且本身不具备绘制功能时,
 * 可以开启这个标记位便于系统进行优化。
 *
 * 当明确知道一个 ViewGroup 需要通过 onDraw 绘制内容时,
 * 需要显式地关闭 WILL_NOT_DRAW 标记位。
 */
public void setWillNotDraw(boolean willNotDraw) {
    setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);
}


// 文件:ViewGroup.java
// ★ ViewGroup 默认开启 WILL_NOT_DRAW ★
public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    setFlags(WILL_NOT_DRAW, DRAW_MASK);
}

阶段十:获取 View 宽高的 4 种方法

由于 View 的 measure 过程和 Activity 的生命周期方法不同步,在 onCreateonStartonResume中无法正确获取 View 的宽高。

在 Activity 已启动的时候就做一件任务,但是这一件任务需要获取某个 View 的宽高,可能会说,这很简单啊,在 onCreate 或者 onResume 里面去获取这个 View 的宽高就行了?读者可以自行试一下,实际上在 onCreate、onStart、onResume 中均无法正确获取到 View 的宽高信息,这是因为 View 的 measure 过程和 Activity 的生命周期方法不是独立的。

方法一:onWindowFocusChanged

// ★ 当窗口获得焦点时获取宽高 ★
// 注意:会多次调用(获得焦点和失去焦点时各一次)
@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus) {
        int width = view.getMeasuredWidth();
        int height = view.getMeasuredHeight();
    }
}

需要注意的是,onWindowFocusChanged 方法会多次调用,当 Activity 的窗口得到焦点和失去焦点时均会被调用一次。具体来说,当 Activity 继续执行和暂停执行时,onWindowFocusChanged 均会被调用,如果频繁地进行 onPause 和 onResume,那么 onWindowFocusChanged 也会被频繁地调用。

方法二:view.post(Runnable)

// ★ 通过 post 投递到消息队列尾部 ★
// 当 Looper 调用此 runnable 时,View 已经初始化好了
view.post(new Runnable() {
    @Override
    public void run() {
        int width = view.getMeasuredWidth();
        int height = view.getMeasuredHeight();
    }
});

通过 post 可以将一个 runnable 投递到消息队列的尾部,然后等待 Looper 调用此 runnable 的时候,View 也已经初始化好了。

注意嗷:这里如果在runnable里面使用activity会内存泄漏,需要使用weakrefrence

方法三:ViewTreeObserver

// ★ 使用 OnGlobalLayoutListener ★
// 注意:会多次调用,需及时移除
ViewTreeObserver observer = view.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        int width = view.getMeasuredWidth();
        int height = view.getMeasuredHeight();
        // 获取后移除监听
        view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }
});

使用 ViewTreeObserver 的众多回调可以完成这个功能,比如使用 OnGlobalLayoutListener 这个接口,当 View 树的状态发生改变或者 View 树内部的 View 的可见性发现改变时,onGlobalLayout 方法将被回调,因此这是获取 View 的宽/高一个很好的时机。需要注意的是,伴随着 View 树的状态改变等,onGlobalLayout 会被调用多次。

这里常用来当作首帧耗时的首帧尾部时间戳。当然也可以用Choreographer。但是一般普通应用还是用这个。

用户点击 → onCreate/onResume 
    → 测量(measure) → 布局(layout) → 绘制(draw) 
        → onGlobalLayout 回调 ← 这里!
            → 真正渲染到屏幕(GPU 合成、送显)
                → 用户看到首帧

方法四:手动 measure

// ★★★ 手动测量 ★★★

// 固定值(100px)
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY);
view.measure(widthMeasureSpec, heightMeasureSpec);

// wrap_content
int widthMeasureSpec = MeasureSpec.makeMeasureSpec((1 << 30) - 1, MeasureSpec.AT_MOST);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec((1 << 30) - 1, MeasureSpec.AT_MOST);
view.measure(widthMeasureSpec, heightMeasureSpec);

错误用法:

// ❌ 错误用法一:specSize 为 -1 无法得出合法 SpecMode
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(-1, MeasureSpec.UNSPECIFIED);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(-1, MeasureSpec.UNSPECIFIED);
view.measure(widthMeasureSpec, heightMeasureSpec);

// ❌ 错误用法二:需要父容器约束才能正确测量
view.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

关于 View 的 measure,网络上有两个错误的用法。为什么说是错误的,首先其违背了系统的内部实现规范(因为无法通过错误的 MeasureSpec 去得出合法的 SpecMode,从而导致 measure 过程出错),其次不能保证一定能 measure 出正确的结果。

10.渲染阶段-surfaceflinger/choregrapher/vsync/renderthread

好,刚刚view调了draw来绘制,那怎么将这些代码转换成图像,在屏幕上展示,展示过程中有什么操作呢?这块就是渲染。

在app启动阶段如下:

用户点击图标 → PMS (包管理) 校验 → Zygote fork 进程 → ActivityThread.main() 初始化主线程消息队列。
Application 创建: 执行 attach() 和 onCreate()。
AMS 调度: AMS 通过 startActivity 启动目标 Activity。
视图构建与初始化阶段

performLaunchActivity() → Activity.onCreate() → setContentView() (解析 XML,挂载 View 树)。
handleResumeActivity() → Activity.makeVisible() → WindowManager.addView() (这一步会将 DecorView 挂载到 WindowManager)。
渲染准备阶段(性能关键)

ViewRootImpl.setView():UI 渲染的起点,在这里会触发第一次 layout 请求。
创建 RenderProxy: 在此阶段会初始化 RenderThread,这是 Android 硬件加速开启的标志。
渲染流程执行阶段(核心讲解区)

ViewRootImpl.performTraversals()
├── ① performMeasure() → 确定 View 大小
├── ② performLayout() → 确定 View 位置
└── ③ performDraw() ← 当前讲解阶段
→ 生成 DisplayList (记录指令)
→ 调用 RenderThread (异步交接)
→ Skia 引擎处理 (GPU 命令解析)
→ GPU 执行光栅化
送显阶段

BufferQueue 交换: 图像数据进入缓冲区。
SurfaceFlinger 合成: 结合 VSync 信号,通过 HWC 将 Buffer 送入屏幕显示。

核心节点在于 ViewRootImpl.performTraversals(),这是 App 启动后 UI 真正开始‘动起来’的地方。它会先通过 performMeasure 和 performLayout 确定坐标,接着在 performDraw 中不再是简单的 Java 层绘图,而是将 UI 指令存入 DisplayList,通过 RenderThread 交给 Skia 引擎处理,最后在 GPU 完成光栅化,并由 SurfaceFlinger 合成后送显。

一、整体流程概览

  • 输入: 触发信号(VSync)。

  • UI 准备: 主线程进行 measure/layout/draw,生成 DisplayList(绘制指令集)。

  • 渲染: RenderThread 接管 DisplayList,利用 Skia 作为渲染后端,通过 OpenGL/Vulkan 驱动 GPU 进行光栅化。

  • 合成: SurfaceFlinger 接收渲染好的 Buffer,通过 HWC (Hardware Composer) 合成到屏幕。

二、图形图像制作的“流水线”(重点更新)

3.1 指令分发与渲染后端

  • Canvas(Java层): 并不直接绘图,而是将 UI 绘制命令(如 drawCircle)记录在 DisplayList 中。

  • RenderThread(渲染管家): 从主线程接手 DisplayList,独立于主线程执行,防止渲染卡顿。

  • Skia(2D 渲染引擎): 它是 RenderThread 的核心引擎,负责解析 DisplayList,将其转化为 GPU 能理解的绘制操作。

  • OpenGL / Vulkan(底层接口): Skia 最终通过这些图形 API 调度 GPU。GPU 负责将指令转化为像素点(光栅化)。

3.2 CPU 与 GPU 的极致分工

全屏复制

角色

核心任务

CPU (主线程)

处理业务逻辑、测量布局、生成 DisplayList

RenderThread

消费 DisplayList,调度 Skia,管理渲染时序。

GPU

并行计算,将绘图指令**光栅化(Rasterization)**为像素数据存入 Buffer。

三、渲染数据的“运输”:BufferQueue

  • 生产者-消费者模型:

    • 生产者(App): RenderThread 将绘制好的图像写入 GraphicBuffer

    • 消费者(SurfaceFlinger): 通过 BufferQueue 获取图像数据,进行合成。

    • VSync: 保证生产和消费的节奏一致,彻底杜绝撕裂。

这是俺遇到的第5个生产者消费者模型了,messageQueue、MediaCodec编解码、流式ai会话、rabbitMQ。

四、整体调用链(由“入门”转为“专家视角”)

  1. Choreographer: 接收 VSync 信号,触发 ViewRootImpl.doTraversal()

  2. DisplayList 记录: UI 线程在 draw() 过程中,把复杂的绘制操作变为一条条“绘制指令”存入 DisplayList

  3. 渲染指令交换: UI 线程将 DisplayList 提交给 RenderThread

  4. Skia 介入: RenderThread 调用 Skia 引擎解析指令,通过 OpenGL/Vulkan 驱动 GPU 绘制。

  5. 送显: 图像数据放入 Buffer,SurfaceFlinger 收到 VSync,将数据通过 HWC 送入屏幕驱动。

  6. 为什么要有 RenderThread?

因为 UI 绘制如果全在主线程,复杂的动画和复杂的 View 会直接撑爆主线程,导致丢帧。RenderThread 把渲染压力从主线程卸载下来了。

  1. Skia 和 OpenGL 是什么关系?

Skia 是软件层面的“指挥官”(解析 2D 绘图逻辑),OpenGL/Vulkan 是软件与硬件(GPU)之间的“协议标准”。Skia 是用这些标准来指挥 GPU 的。

  1. 什么是光栅化(Rasterization)?

把“画个圆”这种数学指令,变成屏幕上具体的红、绿、蓝像素点的过程。

Android 渲染机制笔记

一、整体流程概览

AMS → ActivityThread → Activity → onCreate → onResume → setContentView → XML 加载 → 图形图像制作(Canvas → DisplayList → RenderThread → Skia/OpenGL → GPU) → 刷新过程(VSync 信号 → SurfaceFlinger 调度 → 屏幕展示)

核心分为2个步骤:

图形图像制作(Canvas → DisplayList → RenderThread → Skia/OpenGL → GPU)

刷新过程(VSync 信号 → SurfaceFlinger 调度 → 屏幕展示)

二、Activity 与 XML 加载

  • AMS 控制 Activity 的生命周期调度。

  • ActivityThread 管理主线程消息循环,负责 Activity 的创建和启动。

  • onCreate 中调用 setContentView:系统将 APK 中预编译的二进制 XML 读取并解析,通过反射实例化 View 对象,构建内存中的 View 树结构(而非存入磁盘)。

三、图形图像制作过程

3.1 整体调用链路
Canvas (Java层) → 记录 DisplayList (指令集) → RenderThread (C++) → Skia/OpenGL → GPU 运算 → 生成图像数据 → 存储到帧缓冲区。

3.2 Canvas 的作用
Canvas 是 Java 层提供的绘图 API。在硬件加速下,Canvas 不直接绘图,而是将绘制指令记录为 DisplayList

3.3 Skia 与 OpenGL/Vulkan
Skia 是 Android 的 2D 渲染引擎,负责处理 DisplayList 的解析。OpenGL/Vulkan 是底层接口,负责将解析后的指令传给 GPU 执行光栅化。

3.4 CPU 与 GPU 的职责分工

  • CPU: 负责 UI 逻辑、测量布局、生成 DisplayList 指令。

  • GPU: 负责大规模并行计算、图形学渲染、像素处理。

3.5 数据流向
App (UI 线程) → 生成 DisplayList → RenderThread (渲染线程) → Skia/OpenGL → GPU 驱动 → GPU 计算 → 图像数据写入帧缓冲区 (Back Buffer) → SurfaceFlinger 合成 → 屏幕显示。

四、刷新过程与屏幕驱动

4.1 双缓冲机制
驱动维护两个缓冲区:

  • 当前帧 (Front Buffer): 屏幕正在显示的画面。

  • 预备帧 (Back Buffer): 下一帧正在渲染的数据。

  • 工作流程: 当 Back Buffer 渲染完成,VSync 信号到来时,系统交换缓冲区,让屏幕展示最新帧,避免画面撕裂。

4.2 屏幕转换控制
屏幕的刷新由 VSync 信号驱动,确保 App 的渲染节奏与屏幕刷新节奏保持同步。

五、帧率与刷新率

5.1 核心概念

  • 帧率 (FPS): 图像生成速度,即每秒生成的帧数。

  • 刷新率 (Hz): 屏幕物理刷新速度,即每秒刷新的次数。

5.2 两种异常情况

  • 情况一 (帧率 > 刷新率): App 生成速度超过屏幕刷新能力,导致跳帧、卡顿。

  • 情况二 (帧率 < 刷新率): App 生成速度跟不上屏幕刷新,导致显示画面延迟、撕裂或掉帧。

六、Android 渲染机制解决方案

6.1 总体思路
统一通过 VSync 信号对齐 App 的绘制节奏与屏幕的刷新节奏。

6.2 SurfaceFlinger
负责将各个 App 提交的 Buffer 合成后,送往屏幕显示。它不仅仅是 16.66ms 刷新一次,而是由 VSync 信号驱动。

6.3 VSYNC (垂直同步信号)
VSync 是由硬件产生的脉冲信号,协调 App 渲染与 SurfaceFlinger 合成。它防止了因渲染与显示不同步而产生的画面撕裂。

6.4 控制图像制作速度 —— Choreographer
Choreographer 是渲染的调度中心,它监听 VSync 信号,在信号到达时通知 App 开始绘制。

七、整体调用链总结

用户操作/动画触发 → ViewRootImpl.scheduleTraversals() → Choreographer (接收 VSync 信号) → ViewRootImpl.doTraversal() → performTraversals() → measure/layout/draw → 生成 DisplayList → RenderThread 执行渲染 (Skia/OpenGL/GPU) → 图像数据放入 Back Buffer → VSync 触发 SurfaceFlinger 合成 → 屏幕刷新显示。

名词

帧率 (FPS)

每秒生成的帧数。

刷新率 (Hz)

每秒刷新的次数。

帧率 > 刷新率

跳帧、卡顿。

帧率 < 刷新率

画面撕裂、掉帧。

理想状态

帧率 = 刷新率。

VSYNC 的作用

协调 App 渲染与屏幕刷新,避免撕裂。

Choreographer

根据 VSync 信号调度 doTraversal,保证绘制节奏。

双缓冲

Front Buffer (显示) + Back Buffer (渲染),解决撕裂。

渲染核心

Canvas 记录 DisplayList -> RenderThread -> Skia/OpenGL -> GPU。

hhhhhh,渲染烂尾了,因为俺还没有学完,这部分和fps检测等俺学完了再讲一下吧(画饼)

4. 异常场景

4.2 资源加载失败

4.1 启动闪退异常汇总

5. 耗时操作有哪些

耗时操作:

高概率:rpc、网络请求、数据库操作、文件读写、IO、file、进程间通信、编解码

低概率:sp(commit同步耗时,apply异步大数据频繁读取耗时)、图片加载、嵌套布局、复杂布局、动态计算也有可能、线程切换、锁等待、死锁、解析大型数据、AB开关、注册kmp、短时间生成大量对象

表现:

高概率一般在主线程就噶了

低概率的运气好不会直接噶,但是会被线上用户/低端机/手机性能不好的时候跑出来,或者界面一卡一卡的、其他数据渲染慢

解决方法:

不同问题有不同的解决方式,一般是放子线程/异步调用,动画铺平,框架解,mkkv减少一次内存切换,减少页面布局层级或者xml的布局写到java代码里面放首帧后,有一点点耗时但是不是很耗时的更改调用时机放首帧后,

之前遇到过:

偶现肉眼可见的动画抖动,低内存车机,主线程new file。

低端车机煲机多媒体应用8小时,视频播放卡顿严重,音视频不同步。煲机后资源损耗太多带不起来音视频应用😅

网络请求(弱网)。

应用启动的时候切线程去用bitmapfactory加载了一次image,导致冷启时用户肉眼可见的空白了几百毫秒,还是高端机。。。其实这里放主线程比较好,因为这里不是大图加载,切线程对用户的影响可能更大一些。

这里不得提一嘴ios,安卓发现整个问题的时候,同一个业务ios在冷启的时候去加载了400多次image。。。优化后稳定优化了200ms启动时间,这么多年竟然都没发现,ios的性能真是优秀,我要转ios(bushi)

AB开关,组件化的时候在类似于应用启动时高性能静态加载资源的地方使用了AB开关,启动耗时劣化了400ms被框架拎出来了

下游业务使用kmp,注册下游业务的时候启动耗时又增加了,拎到首帧后线上又出来anr,因为kmp链接到了tecal。。。然后又被框架拎出来

给xml里面多加了一层布局,首帧耗时增加几十ms。。。

为了实现复杂动画,动态计算css,导致安卓大部分中/低端机动画掉帧非常严重。。。公司的跨端组件跑不起来复杂动画。为什么要动态计算而不是帧动画?当然是动画太复杂只能根据业务规则来计算。。。

跟手滑的时候使用translateX,整个页面掉帧。。。

日志打印,一些常调用遍历调用的地方加日志多了容易卡。

5.2 首帧耗时

埋点时机:

5.3 白屏检测

跟fragment搞个fake的fragment,真实的fragment创建销毁的时候就去调一下fake的这个。后面发现假的这个fragment一直没有销毁,重复创建,就是有问题,如果没有掉到oncreate就调了ondestroy就表示白屏了。

6. 优化

6.1 框架侧优化

没学过,估计得用到hook,我看框架经常把类改来改去的,这块估计得学点calssloader类加载机制。

6.2 业务侧优化

生命周期编排、任务编排,耗时的往后稍稍,优先级高的提前、线程池管控、启动时抑制gc、减少view层级、view标签使用merge减少view层级、懒加载非启动必须用到的东西、xml使用java代码动态加载view。这几个是最管用最稳定的,几乎不会引入额外的问题。

6.3 业务防劣化

7. 常用的技术

Hook Instrumentation、AMS、ClassLoader

热修复啥的。

也没学,后面有空再学吧

7.4 风险

8. 总结

8.1 流程回顾

以为会写很多优化方向,结果没学会,以为能解决我开头提出的哪些问题,抽丝剥茧找到点原因,结果也没有。倒是借助ai理清楚了启动这块核心组件原理,hhhhhh。不错,安卓源码这块代码看了好久,看了忘完了看。没想到理了一下启动这块把核心组件全串起来了,通畅!从今往后俺也是会aosp的人了!

8.2 优化取舍

8.3 后续方向

这里是讲启动,除了还需要补充的东西以外。这一块整体还是属于性能优化方向的,另外2篇也比较有意思偏原理+应用结合可以看看。之前一直以为不需要学原理当个api ui仔也挺好的,直到把俺扔到启动这个业务干了大半年,要命

JVM&内存分析_jvm内存分析-CSDN博客

进程&线程_线程 alu-CSDN博客

9.参考链接

Android应用启动流程:从启动到可交互的过程解析_android 应用启动流程-CSDN博客

深入研究Android启动速度优化(上)- 看完这些启动优化已经完成80%了_android 分析app的启动流程跟启动时间-CSDN博客

https://developer.android.google.cn/topic/performance/vitals/launch-time?hl=zh-cn

《Android开发艺术探索》、《Android源码设计模式解析与实战第2版》

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值