
2.4 Launcher启动过程
此前已经学习了Android系统启动流程的init进程、Zygote进程和SystemServer进程,最后我们来学习Launcher的启动过程。
2.4.1 Launcher概述
系统启动的最后一步是启动一个应用程序用来显示系统中已经安装的应用程序,这个应用程序就叫作Launcher。Launcher在启动过程中会请求PackageManagerService返回系统中已经安装的应用程序的信息,并将这些信息封装成一个快捷图标列表显示在系统屏幕上,这样用户可以通过点击这些快捷图标来启动相应的应用程序。
通俗来讲Launcher就是Android系统的桌面,它的作用主要有以下两点:
(1)作为Android系统的启动器,用于启动应用程序。
(2)作为Android系统的桌面,用于显示和管理应用程序的快捷图标或者其他桌面组件。
2.4.2 Launcher启动过程介绍
SystemServer进程在启动的过程中会启动PackageManagerService,PackageManagerService启动后会将系统中的应用程序安装完成。在此前已经启动的AMS会将Launcher启动起来。Launcher启动过程的时序图如图2-3所示。

图2-3 Launcher启动过程时序图
启动Launcher的入口为AMS的systemReady方法,它在SystemServer的startOtherServices方法中被调用,如下所示:

与Android 7.1.2源码不同的是,Android 8.0的部分源码引入了Java Lambda表达式,比如注释1处。下面来查看AMS的systemReady方法做了什么:

systemReady方法中调用了ActivityStackSupervisor的resumeFocusedStackTopActivityLocked方法:

在注释1处调用ActivityStack的resumeTopActivityUncheckedLocked方法,ActivityStack对象是用来描述Activity堆栈的,resumeTopActivityUncheckedLocked方法如下所示:


在注释1处调用了resumeTopActivityInnerLocked方法,如下所示:

resumeTopActivityInnerLocked方法的代码很长,在此仅截取我们要分析的关键的部分,调用ActivityStackSupervisor的resumeHomeStackTask方法,代码如下所示:

在resumeHomeStackTask方法中调用了AMS的startHomeActivityLocked方法,如下所示:


注释1处的mFactoryTest代表系统的运行模式,系统的运行模式分为三种,分别是非工厂模式、低级工厂模式和高级工厂模式,mTopAction 则用来描述第一个被启动Activity组件的Action,它的默认值为Intent.ACTION_MAIN。因此注释1处的代码的意思就是mFactoryTest 为FactoryTest.FACTORY_TEST_LOW_LEVEL (低级工厂模式)并且mTopAction等于null时,直接返回false。注释2处的getHomeIntent方法如下所示:

在getHomeIntent方法中创建了Intent,并将mTopAction和mTopData传入。mTopAction的值为Intent.ACTION_MAIN,并且如果系统运行模式不是低级工厂模式,则将intent的Category 设置为Intent.CATEGORY_HOME,最后返回该Intent,再回到AMS的startHomeActivityLocked 方法,假设系统的运行模式不是低级工厂模式,在注释3处判断符合Action为Intent.ACTION_MAIN、Category为Intent.CATEGORY_HOME的应用程序是否已经启动,如果没启动则调用注释4处的方法启动该应用程序。这个被启动的应用程序就是Launcher,因为Launcher的AndroidManifest文件中的intent-filter标签匹配了Action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_HOME。
Launcher的AndroidManifest文件如下所示:

可以看到intent-filter设置了android.intent.category.HOME属性,这样名称为com.android.launcher3.Launcher的Activity 就成为了主Activity。从前面AMS的startHomeActivityLocked 方法的注释4处,我们得知如果Launcher没有启动就会调用ActivityStarter的startHomeActivityLocked方法来启动Launcher,如下所示:


在注释1处将Launcher放入HomeStack中,HomeStack是在ActivityStackSupervisor中定义的用于存储Launcher的变量。接着调用startActivityLocked方法来启动Launcher,剩余的过程会和Activity的启动过程类似,本书将在第4章介绍该知识点。最终进入Launcher的onCreate方法中,到这里Launcher就完成了启动。
2.4.3 Launcher中应用图标显示过程
Launcher 完成启动后会做很多的工作,作为桌面它会显示应用程序图标,这与应用程序开发有所关联,应用程序图标是用户进入应用程序的入口,因此我们有必要了解Launcher是如何显示应用程序图标的。
我们先从Launcher的onCreate方法入手,代码如下所示:


在注释1处获取LauncherAppState的实例,在注释2处调用它的setLauncher方法并将Launcher对象传入,LauncherAppState的setLauncher方法如下所示:

在注释1处会调用LauncherModel的initialize方法:

在initialize方法中会将Callbacks,也就是传入的Launcher,封装成一个弱引用对象。因此我们得知mCallbacks变量指的就是封装成弱引用对象的Launcher,这个mCallbacks③后面会用到它。
再回到Launcher的onCreate方法,在注释3处调用了LauncherModel的startLoader方法,如下所示:


在注释1处创建了具有消息循环的线程HandlerThread对象。在注释2处创建了Handler,并且传入HandlerThread的Looper,这里Hander的作用就是向HandlerThread发送消息。在注释3处创建LoaderTask,在注释4处将LoaderTask作为消息发送给HandlerThread。
LoaderTask类实现了Runnable接口,当LoaderTask所描述的消息被处理时,则会调用它的run方法,LoaderTask是LauncherModel的内部类,代码如下所示:


Launcher 是用工作区的形式来显示系统安装的应用程序的快捷图标的,每一个工作区都是用来描述一个抽象桌面的,它由n个屏幕组成,每个屏幕又分为n个单元格,每个单元格用来显示一个应用程序的快捷图标。在注释1处和注释2处分别调用loadWorkspace方法和bindWorkspace方法来加载和绑定工作区信息。注释3处的loadAllApps方法用来加载系统已经安装的应用程序信息,代码如下所示:

在注释1处会调用callbacks的bindAllApplications 方法,从之前的标注③处我们得知这个callbacks实际是指向Launcher的,下面我们来查看Launcher的bindAllApplications方法:

在注释1处会调用AllAppsContainerView类型的mAppsView对象的setApps方法,并将包含应用信息的列表apps传进去,AllAppsContainerView的setApps方法如下所示:

setApps 方法会将包含应用信息的列表apps设置给mApps,这个mApps是AlphabeticalAppsList类型的对象。接着查看AllAppsContainerView的onFinishInflate方法如下所示:

onFinishInflate方法会在AllAppsContainerView加载完XML布局时调用,在注释1处得到AllAppsRecyclerView用来显示App列表,并在注释2处将此前的mApps设置进去,在注释3处为AllAppsRecyclerView设置Adapter。这样显示应用程序快捷图标的列表就会显示在屏幕上。
到这里Launcher中应用图标显示过程以及Launcher启动流程就讲解完了,接下来介绍Android系统启动流程。