注:以下代码分析基于android-10.0.0_r30)
一 概述
之前介绍Zygote进程启动的时候说到了Zygote会启动SystemServer,然后在SystemServer启动的最后会调用到ActivityManagerService的systemReady,在这个systemReady中,就会执行桌面启动的逻辑,接下来,就来看看桌面是如何启动的,并且又是如何将系统安装的应用显示在桌面上的
源码目录
frameworks/base/services/java/com/android/server/SystemServer.java
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
frameworks/base/services/core/java/com/android/server/wm/RootActivityContainer.java
frameworks/base/services/core/java/com/android/server/wm/ActivityStartController.java
packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
packages/apps/Launcher3/src/com/android/launcher3/LauncherModel.java
packages/apps/Launcher3/src/com/android/launcher3/model/LoaderTask.java
packages/apps/Launcher3/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
packages/apps/Launcher3/src/com/android/launcher3/model/BaseLoaderResults.java
packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java
二 ActivityManagerService启动Launch
2.1 mAtmInternal
在ActivityManagerService的systemReady中,会做一些准备工作,然后执行外部传入的Runnable,最后通过一个mAtmInternal.startHomeOnAllDisplays的方法来启动桌面
这个mAtmInternal,它是一个ActivityTaskManagerInternal对象,这个类是一个抽象类,它的实现类是ActivityTaskManagerService,所以在systemReady的方法中,最终启动桌面是通过调用ActivityTaskManagerService的startHomeOnAllDisplays来完成的
[ActivityManagerService.java]
LocalServices.getService(ActivityTaskManagerInternal.class)
2.2 systemReady
[ActivityManagerService.java]
public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
traceLog.traceBegin("PhaseActivityManagerReady");
synchronized(this) {
//第一次是false
if (mSystemReady) {
// 如何调用完所有的receivers,就进入下一个阶段
if (goingCallback != null) {
goingCallback.run();
}
return;
}
mLocalDeviceIdleController
= LocalServices.getService(DeviceIdleController.LocalService.class);
mActivityTaskManager.onSystemReady();
// 确认配置信息
mUserController.onSystemReady();
mAppOpsService.systemReady();
mSystemReady = true;
}
try {
sTheRealBuildSerial = IDeviceIdentifiersPolicyService.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE))
.getSerial();
} catch (RemoteException e) {}
ArrayList<ProcessRecord> procsToKill = null;
synchronized(mPidsSelfLocked) {
for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
ProcessRecord proc = mPidsSelfLocked.valueAt(i);
if (!isAllowedWhileBooting(proc.info)){
if (procsToKill == null) {
procsToKill = new ArrayList<ProcessRecord>();
}
procsToKill.add(proc);
}
}
}
synchronized(this) {
if (procsToKill != null) {
for (int i=procsToKill.size()-1; i>=0; i--) {
ProcessRecord proc = procsToKill.get(i);
Slog.i(TAG, "Removing system update proc: " + proc);
mProcessList.removeProcessLocked(proc, true, false, "system update done");
}
}
// 处理完毕系统更新的一些工作
mProcessesReady = true;
}
//前面都是做的一些准备工作,下面正式启动
Slog.i(TAG, "System now ready");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY, SystemClock.uptimeMillis());
mAtmInternal.updateTopComponentForFactoryTest();
mAtmInternal.getLaunchObserverRegistry().registerLaunchObserver(mActivityLaunchObserver);
//设置一些系统属性
watchDeviceProvisioning(mContext);
retrieveSettings();
mUgmInternal.onSystemReady();
final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
if (pmi != null) {
pmi.registerLowPowerModeObserver(ServiceType.FORCE_BACKGROUND_CHECK,
state -> updateForceBackgroundCheck(state.batterySaverEnabled));
updateForceBackgroundCheck(
pmi.getLowPowerState(ServiceType.FORCE_BACKGROUND_CHECK).batterySaverEnabled);
} else {
Slog.wtf(TAG, "PowerManagerInternal not found.");
}
if (goingCallback != null) goingCallback.run();
//在此处检查当前UserId
if (currentUserId != UserHandle.USER_SYSTEM && !mUserController.isSystemUserStarted()) {
//不是USER_SYSTEM
throw new RuntimeException("System user not started while current user is:"
+ currentUserId);
}
traceLog.traceBegin("ActivityManagerStartApps");
mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
Integer.toString(currentUserId), currentUserId);
mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,
Integer.toString(currentUserId), currentUserId);
//是USER_SYSTEM
final boolean bootingSystemUser = currentUserId == UserHandle.USER_SYSTEM;
if (bootingSystemUser) {
//设置UserId
mSystemServiceManager.startUser(currentUserId);
}
synchronized (this) {
//只启动支持加密的持久性的应用程序
startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
mBooting = true;
if (UserManager.isSplitSystemUser() &&
Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0) != 0) {
ComponentName cName = new ComponentName(mContext, SystemUserHomeActivity.class);
try {
AppGlobals.getPackageManager().setComponentEnabledSetting(cName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0,
UserHandle.USER_SYSTEM);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
if (bootingSystemUser) {
//启动Launch桌面
mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
}
...
}
}
三 RootActivityContainer
3.1 startHomeOnAllDisplays
通过mAtmInternal.startHomeOnAllDisplays,实际调用的是ActivityTaskManagerService的startHomeOnAllDisplays
[ActivityTaskManagerService.java]
public boolean startHomeOnAllDisplays(int userId, String reason) {
synchronized (mGlobalLock) {
return mRootActivityContainer.startHomeOnAllDisplays(userId, reason);
}
}
这里的mRootActivityContainer就是RootActivityContainer,它会经过一系列的调用,最后调用到startHomeOnDisplay
[RootActivityContainer.java]
boolean startHomeOnAllDisplays(int userId, String reason) {
boolean homeStarted = false;
for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
final int displayId = mActivityDisplays.get(i).mDisplayId;
//步骤1
homeStarted |= startHomeOnDisplay(userId, reason, displayId);
}
return homeStarted;
}
boolean startHomeOnDisplay(int userId, String reason, int displayId) {
//步骤2
return startHomeOnDisplay(userId, reason, displayId, false /* allowInstrumenting */,
false /* fromHomeKey */);
}
接下来,就具体看看这个做了那些事
3.2 startHomeOnDisplay
这里的启动方式,也是系统中比较常见的一种方式,就是构建出一个ActivityInfo,然后启动
- 这里的mService是一个ActivityTaskManagerService
- mService.getActivityStartController获得的是一个ActivityStartController,这个类是一个和的Activity启动相关的类
- 最后调用的startHomeActivity就是ActivityStartController.startHomeActivity
[RootActivityContainer.java]
boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting,
boolean fromHomeKey) {
// 异常情况
if (displayId == INVALID_DISPLAY) {
displayId = getTopDisplayFocusedStack().mDisplayId;
}
//构造一个ActivityInfo和Intent
Intent homeIntent = null;
ActivityInfo aInfo = null;
if (displayId == DEFAULT_DISPLAY) {
//关键点:构建一个Launch的intent
homeIntent = mService.getHomeIntent();
aInfo = resolveHomeActivity(userId, homeIntent);
} else if (shouldPlaceSecondaryHomeOnDisplay(displayId)) {
Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, displayId);
aInfo = info.first;
homeIntent = info.second;
}
if (aInfo == null || homeIntent == null) {
return false;
}
if (!canStartHomeOnDisplay(aInfo, displayId, allowInstrumenting)) {
return false;
}
// 设置参数
homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
if (fromHomeKey) {
homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
}
//正式启动
final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
aInfo.applicationInfo.uid) + ":" + displayId;
mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
displayId);
return true;
}
3.3 getHomeIntent
在RootActivityContainer的startHomeOnDisplay中,有着非常关键是一步,就是mService.getHomeIntent,它会构造一个隐式跳转的intent,拿到这个intent之后,就会通过startHomeActivity进行启动桌面Activity了
[ActivityTaskManagerService.java]
String mTopAction = Intent.ACTION_MAIN;
Intent getHomeIntent() {
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;
}
到这里,我们桌面的启动的第一部分就算是完成了,当然,关于ActivityStartController之后是如何启动Activity的,这里就不深究了,放到以后Activity的启动流程详细说明,关于Activity的启动,又涉及到进程的启动,Activity的启动,AMS的通信等等,本篇的重心主要在桌面的启动和安装的应用是如何显示上
四 Launcher
4.1 Launch的AndroidManifest
现在开始是桌面启动的第二部分,经过AMS的一系列调用,最终通过隐士启动的方式,启动了Launcher,他是在packages/apps/Launcher3目录下的一个android项目,这个项目也只定义了一个Activity,就是Launch
[AndroidManifest.xml]
<manifest
...
<application
...
<activity
android:name="com.android.launcher3.Launcher"
android:launchMode="singleTask"
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="unspecified"
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
android:enabled="true">
<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"/>
<category android:name="android.intent.category.LAUNCHER_APP" />
</intent-filter>
<meta-data
android:name="com.android.launcher3.grid.control"
android:value="${packageName}.grid_control" />
</activity>
</application>
</manifest>
4.2 Launch.java
Launch是一个Activity,它继承自BaseDraggingActivity,在Launch的onCreate方法如下
- 创建一个LauncherAppState对象
- 创建一个mModel
- 加载一个mLauncherView
- 通过model加载桌面数据
- 将mLauncherView设置给ContentView
protected void onCreate(Bundle savedInstanceState) {
...
super.onCreate(savedInstanceState);
TraceHelper.partitionSection("Launcher-onCreate", "super call");
//1 LauncherAppState对象,和app数据相关
LauncherAppState app = LauncherAppState.getInstance(this);
mOldConfig = new Configuration(getResources().getConfiguration());
//2 通过这个app对象拿到一个model
mModel = app.setLauncher(this);
...
//3 初始化一个view
mLauncherView = LayoutInflater.from(this).inflate(R.layout.launcher, null);
...
//4 加载桌面数据
if (!mModel.startLoader(currentScreen)) {
if (!internalStateHandled) {
// If we are not binding synchronously, show a fade in animation when
// the first page bind completes.
mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).setValue(0);
}
} else {
// Pages bound synchronously.
mWorkspace.setCurrentPage(currentScreen);
setWorkspaceLoading(true);
}
// For handling default keys
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
//设置界面视图
setContentView(mLauncherView);
getRootView().dispatchInsets();
...//注册其他事件
}
显然,这个Launch使用的是MVVM的设计,在onCreate方法中构建了view和model,那么按照MVVK的逻辑,真正的数据肯定是通过model加载的,然后通过bindData进行数据绑定,首先我们先看这个model是如何加载数据的
4.3 LauncherModel.java
Launch中的model是LauncherModel
[LauncherModel.java]
public boolean startLoader(int synchronousBindPage) {
...
synchronized (mLock) {
if (mCallbacks != null && mCallbacks.get() != null) {
final Callbacks oldCallbacks = mCallbacks.get();
MAIN_EXECUTOR.execute(oldCallbacks::clearPendingBinds);
// If there is already one running, tell it to stop.
stopLoader();
LoaderResults loaderResults = new LoaderResults(mApp, sBgDataModel,
mBgAllAppsList, synchronousBindPage, mCallbacks);
if (mModelLoaded && !mIsLoaderTaskRunning) {
//如何加载了,就绑定数据
loaderResults.bindWorkspace();
loaderResults.bindAllApps();
loaderResults.bindDeepShortcuts();
loaderResults.bindWidgets();
return true;
} else {
//如果没有加载,就加载数据
startLoaderForResults(loaderResults);
}
}
}
return false;
}
显然,如果是加载过数据,那么通过几行bind逻辑进行绑定数据,如何没有加载过数据,那么通过startLoaderForResults加载数据,我们第一次加载没有加载过数据,所以我们看startLoaderForResults的逻辑
4.4 LoaderTask
根据这个名字,我们都能猜到这是一个继承Runnable的类,那么它的关键逻辑就肯定在run中
[LoaderTask.java]
public void run() {
synchronized (this) {
// Skip fast if we are already stopped.
if (mStopped) {
return;
}
}
TraceHelper.beginSection(TAG);
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
TraceHelper.partitionSection(TAG, "step 1.1: loading workspace");
//加载工作区
loadWorkspace();
//绑定工作区
mResults.bindWorkspace();
...
// 加载安装的app
List<LauncherActivityInfo> allActivityList = loadAllApps();
//绑定安装的app
mResults.bindAllApps();
...
transaction.commit();
} ...
}
在这个run方法中,会加载很多数据,这里我们只看加载安装app的逻辑,其他的地方略去,这个加载安装app的逻辑是loadAllApps,
[LoaderTask.java]
private List<LauncherActivityInfo> loadAllApps() {
final List<UserHandle> profiles = mUserManager.getUserProfiles();
List<LauncherActivityInfo> allActivityList = new ArrayList<>();
mBgAllAppsList.clear();
for (UserHandle user : profiles) {
//查询app list
final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
if (apps == null || apps.isEmpty()) {
//没有app,一般不会走
return allActivityList;
}
boolean quietMode = mUserManager.isQuietModeEnabled(user);
// 创建对应的ActivityInfo,我们点击图标的时候会用到
for (int i = 0; i < apps.size(); i++) {
LauncherActivityInfo app = apps.get(i);
mBgAllAppsList.add(new AppInfo(app, user, quietMode), app);
}
//添加进集合
allActivityList.addAll(apps);
}
...
return allActivityList;
}
这里又出现了一个mLauncherApps,这是一个LauncherAppsCompat,它是一个抽象类,有三个实现类,getActivityList这个方法就在它的实现类LauncherAppsCompatVL中
4.5 LauncherAppsCompatVL
[LauncherAppsCompatVL.java]
public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
return mLauncherApps.getActivityList(packageName, user);
}
这里有一个mLauncherApps,它是一个LauncherApps,这个LauncherApps他是LauncherAppsService的binder对象在client端的封装对象,通过LauncherApps,我们就可以进行进程间的通信,调用到LauncherAppsService
//mLauncherApps的创建
mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
[LauncherApps.java]
public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
logErrorForInvalidProfileAccess(user);
try {
return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
packageName, user), user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
这里的mService.getLauncherActivities就会调用到LauncherAppsService的getLauncherActivities
五 LauncherAppsService
5.1 getLauncherActivities
在LauncherAppsService的getLauncherActivities中,会调用queryActivitiesForUser,然后在这个方法中,通过getService拿到一个PackageManagerService的通信对象,然后通过这个对象调用PMS的queryIntentActivities
[LauncherAppsService.java]
@Override
public ParceledListSlice<ResolveInfo> getLauncherActivities(String callingPackage,
String packageName, UserHandle user) throws RemoteException {
ParceledListSlice<ResolveInfo> launcherActivities = queryActivitiesForUser(
callingPackage,
//创建一个查询用的intent
new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
.setPackage(packageName),
user);
...
}
private ParceledListSlice<ResolveInfo> queryActivitiesForUser(String callingPackage,
Intent intent, UserHandle user) {
...
try {
final PackageManagerInternal pmInt =
LocalServices.getService(PackageManagerInternal.class);
//通过传入的intent,获取安装的app
List<ResolveInfo> apps = pmInt.queryIntentActivities(intent,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
callingUid, user.getIdentifier());
return new ParceledListSlice<>(apps);
} finally {
injectRestoreCallingIdentity(ident);
}
}
通过LauncherAppsService和PackageManagerService的调用,最后拿到了一个安装app的数据列表,接下来看LoaderTask中是如何进行数据绑定的
六 BaseLoaderResults
在LoaderTask的loadAllApps之后,是mResults.bindAllApps。这个mResults是一个LoaderResults,它是一个继承自BaseLoaderResults的子类
[BaseLoaderResults.java]
public void bindAllApps() {
AppInfo[] apps = mBgAllAppsList.copyData();
executeCallbacksTask(c -> c.bindAllApplications(apps), mUiExecutor);
}
在这里拿到了数据之后,会通过回调调用bindAllApplications,这个接口是Launch实现的
4.4 BaseLoaderResults
这里的LoaderResults是BaseLoaderResults的一个子类,它的bindAllApps逻辑是在父类中的
[Launch.java]
AllAppsContainerView mAppsView;
public void bindAllApplications(AppInfo[] apps) {
mAppsView.getAppsStore().setApps(apps);
}
[AllAppsContainerView.java]
public AllAppsStore getAppsStore() {
return mAllAppsStore;
}
private void onAppsUpdated() {
if (FeatureFlags.ALL_APPS_TABS_ENABLED) {
...
rebindAdapters(hasWorkApps);
}
}
所以调用setApps实际上会调用到AllAppsStore中,然后通过AllAppsStore.setApps时的回调,又调用到AllAppsContainerView的onAppsUpdated,然后根据一系列的调用,最后调用到replaceRVContainer
[AllAppsContainerView.java]
private void rebindAdapters(boolean showTabs, boolean force) {
if (showTabs == mUsingTabs && !force) {
return;
}
replaceRVContainer(showTabs);
...
}
显然,根据这个方法的名字,也知道这里是一个刷新RecyclerView的方法
[AllAppsContainerView.java]
rivate void replaceRVContainer(boolean showTabs) {
for (int i = 0; i < mAH.length; i++) {
if (mAH[i].recyclerView != null) {
mAH[i].recyclerView.setLayoutManager(null);
}
}
View oldView = getRecyclerViewContainer();
int index = indexOfChild(oldView);
removeView(oldView);
int layout = showTabs ? R.layout.all_apps_tabs : R.layout.all_apps_rv_layout;
View newView = LayoutInflater.from(getContext()).inflate(layout, this, false);
addView(newView, index);
if (showTabs) {
mViewPager = (AllAppsPagedView) newView;
mViewPager.initParentViews(this);
mViewPager.getPageIndicator().setContainerView(this);
} else {
mViewPager = null;
}
}
到此,Launch的启动也算是完成了
总结
终于,从系统的启动,init进程,Zygote进程,SystemServer,Launch的一系列的启动过程终于是串联起来了,
- 在Launch的启动过程中,首先是通过SystemServer启动Launch来启动Activity,这里是通过隐式启动来完成的
- 然后在Launch中加载安装的应用信息,这里又使用的MVVM架构
- 在model中加载完数据后通过bindData进行显示
- 而加载数据又涉及到了LauncherAppsService和PackageManagerService
- 最后通过PackageManagerService拿到安装的apk数据
- 在AllAppsStore通过观察者的模式通知View刷新数据
- 最后就是View中replaceRVContainer刷新RecyclerView的数据