Android 源码分析 Launcher 启动
Posted 小图包
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 源码分析 Launcher 启动相关的知识,希望对你有一定的参考价值。
通过进阶解密学习 记录 Launcher 启动过程,记录加深理解后续其他android版本的启动流程
系统启动的最后一步时启动一个应用程序用来显示系统中已经安装的应用程序,这个应用程序就叫做Launcher。Launcher在启动过程中会请求PackageManagerService返回系统中已经安装的应用程序的信息,并将这些信息封装成一个快捷图标列表显示在系统屏幕上,这样用户可以通过点击这些快捷图标来启动相应的应用程序。
时序图如下
Launcher的启动过程
Launcher 的入口为 AMS 的 systemRead 函数,它在 SystemServer 的 startOtherServices 函数中被调用
//com.android.server SystemServer.java
public void startOtherServices(){
...
mActivityManagerService.systemReady(() -> {
...
}
}
在AMS 的 systemRead 函数实现
//com.android.server.am ActivityManagerService.java
public void systemReady(final Runnable goingCallback, BootTimingsTraceLog traceLog) {
...
synchronized(this) {
...
1.
mStackSupervisor.resumeFocusedStackTopActivityLocked();
mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
}
}
//package com.android.server.am; ActivityStackSupervisor.java
boolean resumeFocusedStackTopActivityLocked() {
return resumeFocusedStackTopActivityLocked(null, null, null);
}
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
需要启动的目标栈不为空,并且启动的栈跟需要启动栈一样就执行
if (targetStack != null && isFocusedStack(targetStack)) {
2
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
...
return false;
}
//com.android.server.am ActivityStack.java
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mStackSupervisor.inResumeTopActivity) {
// Don't even start recursing.
return false;
}
boolean result = false;
try {
// Protect against recursion.
mStackSupervisor.inResumeTopActivity = true;
3
result = resumeTopActivityInnerLocked(prev, options);
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
mStackSupervisor.checkReadyForSleepLocked();
return result;
}
//com.android.server.am; ActivityStack.java
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
...
return isOnHomeDisplay() &&
4
mStackSupervisor.resumeHomeStackTask(prev, "prevFinished");
}
...
}
//com.android.server.am; ActivityStackSupervisor.java
boolean resumeHomeStackTask(ActivityRecord prev, String reason) {
...
if (prev != null) {
prev.getTask().setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
}
mHomeStack.moveHomeStackTaskToTop();
获取 HomeActivity
ActivityRecord r = getHomeActivity();
final String myReason = reason + " resumeHomeStackTask";
// Only resume home activity if isn't finishing.
if (r != null && !r.finishing) {
moveFocusableActivityStackToFrontLocked(r, myReason);
return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
}
//调用 AMS startHomeActivityLocked 函数
5
return mService.startHomeActivityLocked(mCurrentUser, myReason);
}
从上述的代码中主要 通过中AMS 的 systemRead .调resumeFocusedStackTopActivityLocked(); 1至5 处 层层调用,最后通过ActivityManagerService 创建Laucncher启动的所需的Intent
//com.android.server.am; ActivityManagerService.java
boolean startHomeActivityLocked(int userId, String reason) {
1 判断mFactoryTest的工厂模式 和mTopAction 的值
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
&& mTopAction == null) {
return false;
}
2. 创建 Launcher 所需要的 Intent
Intent intent = getHomeIntent();
ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
if (aInfo != null) {
intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
aInfo = new ActivityInfo(aInfo);
aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
ProcessRecord app = getProcessRecordLocked(aInfo.processName,
aInfo.applicationInfo.uid, true);
if (app == null || app.instr == null) { 3
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
// For ANR debugging to verify if the user activity is the one that actually
// launched.
final String myReason = reason + ":" + userId + ":" + resolvedUserId;
4 启动的应用程序就是 Launcher,
mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);
}
} else {
Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
}
return true;
}
上面代码主要做了一下几件事:
1 FactoryTest: 代表启动的运行模式:非工厂模式、低级工厂模式、高级工厂模式 , mTopAction: 则描述第一个被启动 Activity 组件的 Action,默认是 Intent.ACTION_MAIN.
判断当前FactoryTest 为低级工厂模式 并且 mTopAction 为空的时候 返回 false
2 创建 Launcher 所需要的 Intent
3 判断符合 action 为 Intent.ACTION_MAIN、Category 为 Intent.CATEGORY_HOME 的应用程序是否已经启动
4 如果没有启动,则启动应用
回头在看 getHomeIntent() 怎么设置 Launcher 的 Intent
//com.android.server.am; ActivityManagerService.java
Intent getHomeIntent() {
//传入第一个启动的 action 和 启动的 mTopData
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
//设置主页面
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
intent.addCategory(Intent.CATEGORY_HOME);
}
return intent;
}
getHomeIntent() 获取到的就是 Launcher.java 启动 Intent
//android-8.0.0_r1/packages/apps/Launcher3/AndroidManifest.xml
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.launcher3">
<uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
....
1. 手机启动的主页面
<activity
android:name="com.android.launcher3.Launcher"
android:launchMode="singleTask"
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan|stateUnchanged"
android:screenOrientation="nosensor"
android:configChanges="keyboard|keyboardHidden|navigation"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
android:enabled="true">
2. 设置了 android.intent.action.MAIN 属性就是主启动
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY"/>
</intent-filter>
</activity>
...
</manifest>
这里看到清单文件中 Launcher 中 intent-filter action配置android.intent.action.MAIN 属性,这样Launcher 的 Activity 也就成了主 Activity
接着上述代码中 ActivityManagerService中startHomeActivityLocked函数标记4处
调用 startActivityLocked 来启动 Launcher Activity
//com.android.server.am; ActivityStarter.java
void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
mSupervisor.moveHomeStackTaskToTop(reason);
1 Launcher 的 onCreate 函数
mLastHomeActivityStartResult = startActivityLocked(null /*caller*/, intent,
null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/,
null /*voiceSession*/, null /*voiceInteractor*/, null /*resultTo*/,
null /*resultWho*/, 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/,
null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/,
0 /*startFlags*/, null /*options*/, false /*ignoreTargetSecurity*/,
false /*componentSpecified*/, mLastHomeActivityStartRecord /*outActivity*/,
null /*container*/, null /*inTask*/, "startHomeActivity: " + reason);
if (mSupervisor.inResumeTopActivity) {
mSupervisor.scheduleResumeTopActivities();
}
}
// package com.android.launcher3; Launcher.java
public class Launcher extends BaseActivity implements LauncherExterns, View.OnClickListener, OnLongClickListener,LauncherModel.Callbacks, View.OnTouchListener, LauncherProviderChangeListener, AccessibilityManager.AccessibilityStateChangeListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
...
1 加载布局 R.layout.launcher
mLauncherView = getLayoutInflater().inflate(R.layout.launcher, null);
...
2 设置布局底层解析
setContentView(mLauncherView);
...
}
}
至此startActivityLocked 来启动 Launcher Activity,Activity 启动,终进入到 Launcher 的 onCreate 生命周期函数中.
Launcher 应用图标显示
Launcher onCreate 生命周期函数
//com.android.launcher3; Launcher.java
public class Launcher extends BaseActivity
implements LauncherExterns, View.OnClickListener, OnLongClickListener,
LauncherModel.Callbacks, View.OnTouchListener, LauncherProviderChangeListener,
AccessibilityManager.AccessibilityStateChangeListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
...
super.onCreate(savedInstanceState);
1 获取 LauncherAppState 实例
LauncherAppState app = LauncherAppState.getInstance(this);
2 将 Launcer 与 LauncherAppState 对象绑定
mModel = app.setLauncher(this);
...
mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
mAppWidgetHost.startListening();
mPaused = false;
mLauncherView = getLayoutInflater().inflate(R.layout.launcher, null);
.....
lockAllApps();
3 调用 LauncherModel 的 startLoader 函数
if (!mModel.startLoader(currentScreen)) {
mDragLayer.setAlpha(0);
} else {
...
}
setContentView(mLauncherView);
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onCreate(savedInstanceState);
}
}
}
我们先来看 LauncherAppState 的 setLauncher 方法实现
//com.android.launcher3; LauncherAppState.java
LauncherModel setLauncher(Launcher launcher) {
getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
LauncherModel initialize 初始化工作
mModel.initialize(launcher);
return mModel;
}
LauncherModel initialize 具体实现
//com.android.launcher3; LauncherModel.java
public void initialize(Callbacks callbacks) {
synchronized (mLock) {
Preconditions.assertUIThread();
// Remove any queued UI runnables
mHandler.cancelAll();
1 Callbacks ,也就是传入的 Launcher
mCallbacks = new WeakReference<>(callbacks);
}
}
我们得知 mCallBack 的成员变量指的就是封装成弱引用对象 Launcher 这个mCallback会在Launcher 的onCreate 3 处调用 ,我们看注释 3 的 LauncherModel 调用 startLoader 函数实现:
//com.android.launcher3; LauncherModel.java
public class LauncherModel extends BroadcastReceiver
implements LauncherAppsCompat.OnAppsChangedCallbackCompat {
1. 创建了消息循环的线程
@Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
static {
//启动
sWorkerThread.start();
}
2.创建 Hander并且传入HanderThread的Looper
@Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());
//Launcher 的弱引用
@Thunk WeakReference<Callbacks> mCallbacks;
public boolean startLoader(int synchronousBindPage) {
InstallShortcutReceiver.enableInstallQueue();
synchronized (mLock) {
if (mCallbacks != null && mCallbacks.get() != null) {
final Callbacks oldCallbacks = mCallbacks.get();
runOnMainThread(new Runnable() {
public void run() {
oldCallbacks.clearPendingBinds();
}
});
// If there is already one running, tell it to stop.
stopLoaderLocked();
3. 创建 LoaderTask
mLoaderTask = new LoaderTask(mApp.getContext(), synchronousBindPage);
if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE
&& mModelLoaded && !mIsLoaderTaskRunning) {
mLoaderTask.runBindSynchronousPage(synchronousBindPage);
return true;
} else {
sWorkerThread.setPriority(Thread.NORM_PRIORITY);
4. 将mLoaderTask 作为消息发送给 HandlerThread
sWorker.post(mLoaderTask);
}
}
}
return false;
}
...//省略部分代码
}
由上LauncherModel可知做了如下操作
1 创建具有消息循环的线程HanderThread的对象
2 创建Hander并且传入了HandlerThread的Looper,Hander向HandlerThread发消息
3 创建 LoaderTask 实例,它实现了 Runnable 接口
4 LoaderTask 作为消息发送给了 HandlerThread 的 Looper 来处理,最后 在 LoaderTask 的 run 函数回调
看下 LoaderTask run的 方法
private class LoaderTask implements Runnable {
...
public void run() {
synchronized (mLock) {
if (mStopped) {
return;
}
mIsLoaderTaskRunning = true;
}
try {
if (DEBUG_LOADERS) Log.d(TAG, "step 1.1: loading workspace");
// Set to false in bindWorkspace()
mIsLoadingAndBindingWorkspace = true;
1. 加载工作区信息
loadWorkspace();
2. 绑定工作区信息
bindWorkspace(mPageToBindFirst);
...
3. 加载系统以及安装额应用程序信息
loadAllApps();
...
} catch (CancellationException e) {
}
...
}
Launcher 是工作区的形式来显示系统安装的应用程序的快捷图标的,每一个工作区都是用来描述一个抽象桌面的,它有 n 个屏幕组成,每一个屏幕又分为 n 个单元格,每个单元格用来显示一个应用程序的快捷图标。在 1 、2 处分别调用了 bindWorkspace 函数来加载和绑定工作区信息。
我们看下3处的实现
//com.android.launcher3 LauncherModel.java
private void loadAllApps() {
...
mHandler.post(new Runnable() {
public void run() {
final long bindTime = SystemClock.uptimeMillis();
final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
if (callbacks != null) {
1.callbacks 实际指向的 Launcher 的,
callbacks.bindAllApplications(added);
if (DEBUG_LOADERS) {
Log.d(TAG, "bound " + added.size() + " apps in "
+ (SystemClock.uptimeMillis() - bindTime) + "ms");
}
} else {
Log.i(TAG, "not binding apps: no Launcher activity");
}
}
});
...
}
在一处 callbacks 实际指向的 Launcher 的,所以 Launcher.java 类中看它具体实现 bindAllApplications
//com.android.launcher3; Launcher.java
public void bindAllApplications(final ArrayList<AppInfo> apps) {
if (waitUntilResume(mBindAllApplicationsRunnable, true)) {
mTmpAppsList = apps;
return;
}
if (mAppsView != null) {
1. 将包含应用信息的列表 apps 传入 mAppsView 中
mAppsView.setApps(apps);
}
if (mLauncherCallbacks != null) {
mLauncherCallbacks.bindAllApplications(apps);
}
}
//com.android.launcher3.allapps; AllAppsContainerView.java
public void setApps(List<AppInfo> apps) {
mApps.setApps(apps);
}
mApps 成员变量是 AlphabeticalAppsList 里面的函数,接着在跟
//com.android.launcher3.allapps; AlphabeticalAppsList.java
public void setApps(List<AppInfo> apps) {
mComponentToAppMap.clear();
1. 添加 APP
addApps(apps);
}
public void addApps(List<AppInfo> apps) {
2. 更新 APP
updateApps(apps);
}
/**
* Updates existing apps in the list
*/
public void updateApps(List<AppInfo> apps) {
for (AppInfo app : apps) {
mComponentToAppMap.put(app.toComponentKey(), app);
}
onAppsUpdated();
}
private void updateAdapterItems() {
refillAdapterItems();
refreshRecyclerView();
}
private void refreshRecyclerView() {
if (mAdapter != null) {
//刷新 RecyclerView.Adapter
mAdapter.notifyDataSetChanged();
}
}
}
我们在看初始化Adapter的地方在 就在 AllAppsContainerView 布局对象加载完成之后的回调 onFinishInflate 中
//com.android.launcher3.allapps; AllAppsContainerView.java
@Override
protected void onFinishInflate() {
super.onFinishInflate();
....
mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);
mAppsRecyclerView.setApps(mApps);
mAppsRecyclerView.setLayoutManager(mLayoutManager);
得到RecyclerView并且设置加载适配器
mAppsRecyclerView.setAdapter(mAdapter);
mAppsRecyclerView.setHasFixedSize(true);
mAppsRecyclerView.addOnScrollListener(mElevationController);
mAppsRecyclerView.setElevationController(mElevationController);
}
launcher 启动流程分析完了,我们来总结一下
Android系统启动流程总结
1 启动电源及系统启动。当电源按下时引导芯片代码从预定义的地方(固化在ROM)开始执行。加载引导程序BootLoader到RAM,然后执行;
2 引导程序BootLoader。引导程序BootLoader是在Android操作系统开始运行前的一个小程序,它的主要作用是把OS拉起来并运行;
3 Linux内核启动。当内核启动时,设置缓存、被保护存储器、计划列表、加载驱动。当内核完成系统设置时,它首先在系统文件中寻找init.rc文件,并启动init进程;
4 init进程启动。初始化合启动属性服务,并且启动Zygote进程;
5 Zygote进程启动。创建Java虚拟机并为Java虚拟机注册JNI方法,创建服务端Socket,启动SystemServer进程;
6 SystemServer进程启动。启动Binder线程池和SystemServiceManager,并且启动各种系统服务;
7 Launcher启动。被SystemServer进程启动的AMS会启动Launcher,Launcher启动后会将已安装应用的快捷图标显示到界面上。
以上是关于Android 源码分析 Launcher 启动的主要内容,如果未能解决你的问题,请参考以下文章
Android 4.0 Launcher2源码分析——启动过程分析
LaucherActivity的源码分析和应用(非launcher桌面应用)
LaucherActivity的源码分析和应用(非launcher桌面应用)