声明: 图片本来是有的 涉及到有些代码不能示人没有贴上,不过仅文字说也足够了,请广大老爷们自行下载源码参看流程分析阅读。
目录
一、认识Launcher: 1
1、功能 1
2、样式 2
3、Android.mk文件 3
3、AndroidManifest文件 5
①权限: 5
②应用程序组件配置: 6
二、启动流程 7
1.从Systemserver到AMS 7
2.将SystemServer进程加到AMS中调度管理 10
3.AMS systemReady过程 11
4.启动HomeActivity 11
三、加载流程 14
1.重要类认识 14
2.流程 15
①加载绑定Workspace上的内容 18
②加载绑定Allapps中的内容 23
③总结 25
一、 认识Launcher:
① Launcher是Android系统的启动器
② 应用程序的管理器
③ Android系统的桌面
① 原生Launcher3经典的四种UI模式
从Launcher桌面元素的角度来看,组件包括应用程序的快捷方式、文件夹、桌面小部件及相关组件,称这类组件为桌面组件。
以上我们认识了其从功能到界面的了解,下面就是我们程序员上场的时候了
LOCAL_MODULE_TAGS := optional
// 编译选项为何种模式编译,optional为在任种模式下均可编译(User、eng、test三种模式)
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-java-files-under, WallpaperPicker/src) \
$(call all-proto-files-under, protos)
//需要编译的资源文件
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/WallpaperPicker/res $(LOCAL_PATH)/res
//需要编译的资源文件的路径
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
//用于混淆代码的脚本文件名该处为proguard.flags(出于代码安全考虑的混淆工具可配置)
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 android-support-v7-recyclerview
//需要依赖的Java库
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/
LOCAL_AAPT_FLAGS := --auto-add-overlay
//应用程序打包标示变量,设置为自动添加并覆盖
#LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := Launcher3
LOCAL_PRIVILEGED_MODULE := true
#LOCAL_CERTIFICATE := shared
LOCAL_OVERRIDES_PACKAGES := Home Launcher2
//编译Launcher3时Launcher2不会被加入编译系统
include $(BUILD_PACKAGE)
//当完成了本地编译环境变量的设置以后,通过该语句启动编译,生成目标
#
# Protocol Buffer Debug Utility in Java
#配置工具库依赖编译
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, util) \
$(call all-proto-files-under, protos)
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := launcher_protoutil_lib
LOCAL_IS_HOST_MODULE := true
LOCAL_JAR_MANIFEST := util/etc/manifest.txt
include $(BUILD_HOST_JAVA_LIBRARY)
#
# Protocol Buffer Debug Utility Wrapper Script
# Protocol Buffer的测试工具
include $(CLEAR_VARS)
LOCAL_IS_HOST_MODULE := true
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := launcher_protoutil
include $(BUILD_SYSTEM)/base_rules.mk
$(LOCAL_BUILT_MODULE): | $(HOST_OUT_JAVA_LIBRARIES)/launcher_protoutil_lib.jar
$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/util/etc/launcher_protoutil | $(ACP)
@echo "Copy: $(PRIVATE_MODULE) ($@)"
$(copy-file-to-new-target)
$(hide) chmod 755 $@
INTERNAL_DALVIK_MODULES += $(LOCAL_INSTALLED_MODULE)
include $(call all-makefiles-under,$(LOCAL_PATH))
//这是一个递归的调用,意思是搜索Launcher3目录下是否还有其他的Android.mk文件,如果有则启动一次编译
<permission
android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
//安装快捷方式
android:name="com.android.launcher3.permission.READ_SETTINGS"
android:name="com.android.launcher3.permission.WRITE_SETTINGS"
android:name="com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS"
//Launcher3对外提供一个内容提供者,应用程序可以通过鉴权信息来访问数据,为此读写这些数据时会申请该权限
android:name="com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST"
//当Launcher3第一次加载的时候会向系统发一次广播,如果对此感兴趣则需要申请该权限。
Launcher3主Activity配置
声明Launcher是一个单任务模式的Activity
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
两句尤为重要,体现了Launcher的特殊地位,说明这是桌面
壁纸桌面选择模块的配置
二、 启动流程
先从SystemServer开始。
systemserver最主要的作用:
1) 就是初始化framework层各种service和其对应的特定servicemanager,并将他们注册到全局servicemanager类,以便其他地方只需要通过servicemanager. getService(String servicename)就可以取得该service的实例。
2) 2)调用各service的systemready接口,启动service。 这些service基本都是单例类,所以这种注册也是方便全局调用。
SystemServer.Java
路径:/frameworks/base/services/java/com/android/server/SystemServer.java
之后在
方法中检查时间、地区、语言环境,首先判断系统当前时间,若当前时间小于1970年1月1日,则一些初始化操作可能会处所,所以当系统的当前时间小于1970年1月1日的时候,设置系统当前时间为该时间点。
······
上面的主要是设置虚拟机运行内存,加载运行库,设置SystemServer的异步消息
可知可以看到在SystemServer进程中也存在着Context对象,然后通过SystemServiceManager的构造方法创建了一个新的SystemServiceManager对象,我们知道SystemServer进程主要是用来构建系统各种service服务的,而SystemServiceManager就是这些服务的管理对象。
里面主要涉及了是三个方法:
startBootstrapServices() 主要用于启动系统Boot级服务
startCoreServices() 主要用于启动系统核心的服务
startOtherServices() 主要用于启动一些非紧要或者是非需要及时启动的服务
1、BootstrapServices为引导服务,启动的service包括:
Installer 系统安装apk时的一个服务类,启动完成Installer服务之后才能启动其他的系统服务
ActivityManagerService 负责四大组件的启动、切换、调度。
PowerManagerService 计算系统中和Power相关的计算,然后决策系统应该如何反应
LightsService 管理和显示背光LED
DisplayManagerService 用来管理所有显示设备
UserManagerService 多用户模式管理
SensorService 为系统提供各种感应器服务
PackageManagerService 用来对apk进行安装、解析、删除、卸载等等操作
2、 CoreServices为核心服务,包括:
BatteryService 管理电池相关的服务
UsageStatsService 收集用户使用每一个APP的频率、使用时常
WebViewUpdateService WebView更新服务
3、OtherServices其他服务,包括很多服务,比如:
CameraService 摄像头相关服务
AlarmManagerService 全局定时器管理服务
InputManagerService 管理输入事件
WindowManagerService 窗口管理服务
VrManagerService VR模式管理服务
BluetoothService 蓝牙管理服务
NotificationManagerService 通知管理服务
DeviceStorageMonitorService 存储相关管理服务
LocationManagerService 定位管理服务
AudioService 音频相关管理服务
······
模块SystemUI启动···
接下来我们转移战地到ActivityManagerService中
ActivityManagerService.java
/frameworks /base/services/core/java/com/android/server/am/ActivityManagerService.java
······
· setSystemProcess意义:
这一步就是给SystemServer进程创建ProcessRecord,adj值,就是将SystemServer进程加入到AMS进程管理机制中,跟应用进程一致;
······
······
getHomeIntent函数中创建了Intent,并将mTopAction和mTopData传入。mTopAction的值为Intent.ACTION_MAIN,并且如果系统运行模式不是低级工厂模式则将intent的Category设置为Intent.CATEGORY_HOME。我们再回到ActivityManagerService的startHomeActivityLocked函数,假设系统的运行模式不是低级工厂模式,符合Action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_HOME的应用程序是否已经启动
这个被启动的应用程序就是Launcher,因为Launcher的Manifest文件中的intent-filter标签匹配了Action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_HOME。这样,应用程序Launcher就会被启动起来,并执行它的onCreate函数。
/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
ActivityStackSupervisor.java
一张图总结Launcher启动流程:
三、 加载流程
在上述的Launcher启动流程已经理清之后,我们接下来就可以进行对Launcher的加载捋捋了。
1.重要类认识
首先对一些文件进行认识。
Launcher:主界面Activity,最核心且唯一的Activity。
LauncherAppState:单例对象,构造方法中初始化对象、注册应用安装、卸载、更新,配置变化等广播。这些广播用来实时更新桌面图标等,其receiver的实现在LauncherModel类中,LauncherModel也在这里初始化。
LauncherModel:数据处理类,保存桌面状态,提供读写数据库的API,内部类LoaderTask用来初始化桌面。
InvariantDeviceProfile:一些不变的设备相关参数管理类,其内部包涵了横竖屏模式的DeviceProfile。
WidgetPreviewLoader:存储Widget信息的数据库,内部创建了数据库widgetpreviews.db。
LauncherAppsCompat:获取已安装App列表信息的兼容抽象基类,子类依据不同版本API进行兼容性处理。
AppWidgetManagerCompat:获取AppWidget列表的兼容抽象基类,子类依据不同版本API进行兼容性处理。
LauncherStateTransitionAnimation:各类动画总管处理执行类,负责各种情况下的各种动画效果处理。
IconCache:图标缓存类,应用程序icon和title的缓存,内部类创建了数据库app_icons.db。
LauncherProvider:核心数据库类,负责launcher.db的创建与维护。
LauncherAppWidgetHost:AppWidgetHost子类,是桌面插件宿主,为了方便托拽等才继承处理的。
LauncherAppWidgetHostView:AppWidgetHostView子类,配合LauncherAppWidgetHost得到HostView。
LauncherRootView:竖屏模式下根布局,继承了InsettableFrameLayout,控制是否显示在状态栏等下面。
DragLayer:一个用来负责分发事件的ViewGroup。
DragController:DragLayer只是一个ViewGroup,具体的拖拽的处理都放到了DragController中。
BubblTextView:图标都基于他,继承自TextView。
DragView:拖动图标时跟随手指移动的View。
Folder:打开文件夹展示的View。
FolderIcon:文件夹图标。
DragSource/DropTarget:拖拽接口,DragSource表示图标从哪开始拖,DropTarget表示图标被拖到哪去。
ItemInfo:桌面上每个Item的信息数据结构,包括在第几屏、第几行、第几列、宽高等信息;该对象与数据库中记录一一对应;该类有多个子类,譬如FolderIcon的FolderInfo、BubbleTextView的ShortcutInfo等。
App的启动是从Application开始的,但是我们最新的Launcher3中,谷歌工程师把这个类移除,再次之前的版本都是有这个类的
我们手头的LauncherApplication了,现在讲解的是基于最新的Launcher3代码,因此我们这个Launcher中没有Application,所以程序启动最开始的是ContentProvider的onCreate方法,代码如下:
/alps/packages/apps/Launcher3/src/com/android/launcher3/LauncherProvider.java
LauncherProvider.java
严苛模式:
1. 启用严苛模式,StrictMode可以用于捕捉发生在应用程序主线程 中耗时的磁盘、网络访问或函数调用,
2. 可以帮助开发者使其改进程序,使主线程处理UI和动画在磁盘读写和网络操作时变得更平滑,避免主线程被阻塞,导致ANR窗口的发生。
代码中处理的事情不多,主要是启动严苛模式和创建数据库。
接下来就是启动Launcher,我么看一下Launcher中的onCreate方法中的代码:
/alps/packages/apps /Launcher3/src/com/android/launcher3/Launcher.java
Launcher.java
······
······
这一段代码是用来异步加载桌面的应用快捷图标、小部件和所有应用图标,是最重要的一步。
./Launcher3/src/com/android/launcher3/LauncherModel.java
LauncherModel.java
执行run方法。
① 加载绑定Workspace上的内容
并没有直接进行加载,只是对一些状态进行了更新和条件判断,loadWorkspace和bindWorkspace才是实际操作。
我们看真正的加载WorkSpace。代码敲长的~
初始化后面要用到的对象实例
······
/Launcher3/src/com/android/launcher3/LauncherProvider.java
如果数据库还没有创建,就会加载默认的配置(default_workspace_xxx.xml),并保存到数据库中。
······
在加载过后就要开始绑定了。
先是各种初始化以及各对象的实例化
······
执行runnable里面回调在Launcher中的方法准备进行绑定
然后是真正的绑定
和startBinding类似
·······
······
同样调用Launcher的回调
以及类似的bindWorkspaceItems、bindAddScreens、bindFolders、bindAppWidget是运用的同样的套路。加载文件夹、item、空白页等有大量的细节,感兴趣可以跟踪代码。(不行了,累死了,不想写了···)
最后通知其绑定完成。
这样整个loadAndBindWorkspace过程就结束了,接着下一步。
② 加载绑定Allapps中的内容
第二步:loadAndBindAllApps
······
······
依旧是回调Launcher.Java中的回调方法
小结:
1.获取需要显示到Launcher中的app列表,创建app图标 |
2.绑定app—bindAllApplications
至此 Allapps也加载绑定结束。
接着会执行onPackagesUpdated,package的更新操作,就不再展开了。Widget也是类似的。这样加载allapp的过程就结束了。
回到launcher的Oncreate方法。
在这里执行第一次开机的用户向导(可定制化)
③ 总结
最后,借用一张图来总结其从Oncreate以来的执行步骤。