前言
我们熟知一般 Android 工程师都是在应用层上开发,不会涉及系统源码,但是如果你想往底层发展,或者深入插件化、Framework 系统层等开发工作,如果不了解 Android 源码可是不行的,那么接下来我基于自己的理解跟学习来记录跟 Android 开发息息相关的源码分析,大概从 Android 中的 SystemServer 启动、四大组件启动、AMS、PMS 等几个维度来介绍,下面是我的计划,当然在未来也有可能改变。
介绍
上面一章介绍了 Android 中 SystemServer 启动和一些其它服务的启动,那么系统服务启动完了之后,就该显示 Android 系统桌面了,在显示之前会请求 PMS 返回系统中已经安装的应用程序信息,并将这些信息封装成一个快捷图标列表显示在系统屏幕上,这样用户就可以通过点击桌面上的图标来启动相应的应用程序了,在 Android 中用于显示桌面的 Activity 是 Launcher.java 下面我们就分析
Launcher 启动过程。
Launcher 的启动分析
SystemServer 进程在启动过程中会启动 PMS ,PMS 启动后会将系统中的应用程序安装完成。在此前已经启动的 AMS 会将 Launcher 启动起来。可以看下执行的时序图
启动 Launcher 的入口为 AMS 的 systemRead 函数,它在 SystemServer 的 startOtherServices 函数中被调用,如下代码所示:
//com.android.server SystemServer.java
public void startOtherServices(){
...
//1. 这里是 lambda 语法
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);
}
}
systemReady 函数中调用了 ActivityStackSupervisor 的 resumeFocusedStackTopActivityLocked() 函数,如下代码所示
//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)) {
/**
* ActivityStack 描述堆栈的
*/
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
...
return false;
}
根据上面的代码,首先判断启动的 Activity 堆栈是否为空,并且是需要的栈,那么久执行 targetStack.resumeTopActivityUncheckedLocked 函数
//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;
/**
* 1.
*/
result = resumeTopActivityInnerLocked(prev, options);
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
mStackSupervisor.checkReadyForSleepLocked();
return result;
}
执行到 resumeTopActivityInnerLocked 函数,具体看代码
//com.android.server.am; ActivityStack.java
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
...
return isOnHomeDisplay() &&
mStackSupervisor.resumeHomeStackTask(prev, "prevFinished");
}
...
}
调用 ActivityStackSupervisor 的 resumeHomeStackTask 函数,代码如下:
//com.android.server.am; ActivityStackSupervisor.java
boolean resumeHomeStackTask(ActivityRecord prev, String reason) {
...
if (prev != null) {
prev.getTask().setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
}
//将 home 移动到栈顶
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 函数
return mService.startHomeActivityLocked(mCurrentUser, myReason);
}
上面代码先把 home 移动到栈顶,然后通过 AMS startHomeActivityLocked 来启动 Launcher ,看下面代码
//com.android.server.am; ActivityManagerService.java
boolean startHomeActivityLocked(int userId, String reason) {
/**
* 1. 判断值是否符合要求--> 判断当前启动的运行模式是否是低级工厂模式并且 mTopAction 为空的时候
*
* @mFactoryTest: 代表启动的运行模式:非工厂模式、低级工厂模式、高级工厂模式、
* @mTopAction: 则描述第一个被启动 Activity 组件的 Action,默认是 Intent.ACTION_MAIN.
*/
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);
/**
* 3. 判断符合 action 为 Intent.ACTION_MAIN、Category 为 Intent.CATEGORY_HOME 的应用程序是否已经启动
*/
if (app == null || app.instr == null) {
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;
/**
* 3.1. 这个被启动的应用程序就是 Launcher,
*/
mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);
}
} else {
Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
}
return true;
}
上面代码主要做了一下几件事:
-
1.判断 mFactoryTest、mTopAction 是否符合要求--> 判断当前启动的运行模式是否是低级工厂模式并且 mTopAction 为空的时候
-
2.创建 Launcher 所需要的 Intent
-
3.判断符合 action 为 Intent.ACTION_MAIN、Category 为 Intent.CATEGORY_HOME 的应用程序是否已经启动
3.1 如果没有启动调用 ActivityStarter 的 startHomeActivityLocked 函数
接着我们看下 getHomeIntent() 是怎么生成的 Launcher 的 Intent
//com.android.server.am; ActivityManagerService.java
Intent getHomeIntent() {
//传入第一个启动的 action 和 启动的 mTopData
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
//传入组件 ComponentName(app.packageName,ai.name);
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, 我们可以看下它的清单文件 Activity 的注册
//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 的 内部配置了 android.intent.action.MAIN 属性,那么这样 Launcher 的 Activity 也就成了主 Activity。回到 AMS 的 startHomeActivityLocked 函数中,看注释 3.1 如果没有启动过 Launcher 那么就执行 ActivityStarter 的 startHomeActivityLocked 函数来启动 Launcher,看下面代码:
//com.android.server.am; ActivityStarter.java
void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
/**
* 1. 将 home 放入 HomeStack 中
*/
mSupervisor.moveHomeStackTaskToTop(reason);
/**
* 2. 会执行到 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();
}
}
在注释 1 中将 Launcher 放入 HomeStack 中,HomeStack 是在 ActivityStackSupervisor 中定义的用于存储 Launcher 的变量。接着调用 startActivityLocked 来启动 Launcher Activity,Activity 启动我们后面单独会写一篇介绍,这里不做过多说明。最终进入到 Launcher 的 onCreate 生命周期函数中
// 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 路径在 android-8.0.0_r1/packages/apps/Launcher3/res/layout-port/launcher.xml
mLauncherView = getLayoutInflater().inflate(R.layout.launcher, null);
...
//2. 设置布局底层解析 xml2View 并添加到 ViewGroup 中
setContentView(mLauncherView);
...
}
}
接下来我们就分析 Launcher 中应用图标的显示。
Launcher 应用图标显示
上一小节我们讲到了 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);
mDeviceProfile = app.getInvariantDeviceProfile().getDeviceProfile(this);
if (isInMultiWindowModeCompat()) {
Display display = getWindowManager().getDefaultDisplay();
Point mwSize = new Point();
display.getSize(mwSize);
mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
}
mSharedPrefs = Utilities.getPrefs(this);
mIsSafeModeEnabled = getPackageManager().isSafeMode();
/**
* 2. 将 Launcer 与 LauncherAppState 对象绑定
*/
mModel = app.setLauncher(this);
mModelWriter = mModel.getWriter(mDeviceProfile.isVerticalBarLayout());
mIconCache = app.getIconCache();
mAccessibilityDelegate = new LauncherAccessibilityDelegate(this);
mDragController = new DragController(this);
mAllAppsController = new AllAppsTransitionController(this);
mStateTransitionAnimation = new LauncherStateTransitionAnimation(this, mAllAppsController);
mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
mAppWidgetHost.startListening();
// If we are getting an onCreate, we can actually preempt onResume and unset mPaused here,
// this also ensures that any synchronous binding below doesn't re-trigger another
// LauncherModel load.
mPaused = false;
//通过打气筒解析 xml 布局转化成 View 的过程
mLauncherView = getLayoutInflater().inflate(R.layout.launcher, null);
setupViews();
mDeviceProfile.layout(this, false /* notifyListeners */);
mExtractedColors = new ExtractedColors();
loadExtractedColorsAndColorItems();
mPopupDataProvider = new PopupDataProvider(this);
((AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE))
.addAccessibilityStateChangeListener(this);
lockAllApps();
restoreState(savedInstanceState);
if (LauncherAppState.PROFILE_STARTUP) {
Trace.endSection();
}
//获取意外退出 Activity 保存的属于新兴
if (savedInstanceState != null) {
currentScreen = savedInstanceState.getInt(RUNTIME_STATE_CURRENT_SCREEN, currentScreen);
}
/**
* 3.调用 LauncherModel 的 startLoader 函数
*/
if (!mModel.startLoader(currentScreen)) {
mDragLayer.setAlpha(0);
} else {
...
}
...
//设置当前 Activity 显示方向
setOrientation();
//设置布局底层解析 xml2View 并添加到 ViewGroup 中
setContentView(mLauncherView);
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onCreate(savedInstanceState);
}
}
}
通过上面代码我们可以知道主要是进行一些对象初始化的绑定,还有解析 xml 文件的过程,我们先来看 LauncherAppState 的 setLauncher 函数实现:
//com.android.launcher3; LauncherAppState.java
LauncherModel setLauncher(Launcher launcher) {
getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
//1. 调用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
/**
* 1. 取消队列里面所有的 Runnable
*/
mHandler.cancelAll();
/**
* 2. 使用 弱引用添加 callbacks 避免内存泄漏
*/
mCallbacks = new WeakReference<>(callbacks);
}
}
在 initialize 函数中会将 Callbacks ,也就是传入的 Launcher,封装成一个弱引用对象。因此我们得知 mCallBack 的成员变量指的就是封装成弱引用对象 Launcher,这个 mCallbacks 在 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. 向 HanderThread 发送消息
*/
@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;
}
...//省略部分代码
}
通过上面代码跟注释我们总结下主要做了哪些事
-
1.在当前 LauncherModel 的成员声明了 HandlerThread 具有消息循环的线程
-
2.在当前 LauncherModel 的成员声明了 Handler 并把 HandlerThread 的 Looper 作为参数传递给了 Handler,那么 Handler 这里就是把消息指向了 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();
verifyNotStopped();
...
} catch (CancellationException e) {
}
...
}
Launcher 是工作区的形式来显示系统安装的应用程序的快捷图标的,每一个工作区都是用来描述一个抽象桌面的,它有 n 个屏幕组成,每一个屏幕又分为 n 个单元格,每个单元格用来显示一个应用程序的快捷图标。在注释 1 、2 处分别调用了 bindWorkspace 函数来加载和绑定工作区信息。注释 3 处的 loadAllApps 函数用来加载系统已经安装的应用程序信息,我们来看下注释 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.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");
}
}
});
...
}
在注释 1 处会调用 callbacks 的 bindAllApplications 函数,从之前 Launcher 的 onCreate 函数注释 3 处我们得知这个 callbacks 实际指向的 Launcher 的。所以我们回到 Launcher.java 类中看它具体实现 bindAllApplications 做了什么,如下代码所示:
//com.android.launcher3; Launcher.java
/**
* 在 LauncherModel 中调用
*/
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);
}
}
在注释 1 处会调用 AllAppsContainerView 的成员变量 mAppsView 的 setApps 函数, 它会把所有 APP 信息传递进去。
//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 onAppsUpdated() {
...//添加逻辑省略
//更新 Adapter 中的对象数据
updateAdapterItems();
}
private void updateAdapterItems() {
refillAdapterItems();
refreshRecyclerView();
}
private void refreshRecyclerView() {
if (mAdapter != null) {
//刷新 RecyclerView.Adapter
mAdapter.notifyDataSetChanged();
}
}
刷新 APP 信息我们找到了,init Adapter 的地方其实就在 AllAppsContainerView 布局对象加载完成之后的回调 onFinishInflate 中,我们看下具体实现:
//com.android.launcher3.allapps; AllAppsContainerView.java
@Override
protected void onFinishInflate() {
super.onFinishInflate();
....
//找到主页面搜索按钮
mSearchContainer = findViewById(R.id.search_container);
//输入扩展 View
mSearchInput = (ExtendedEditText) findViewById(R.id.search_box_input);
/**
* 1. 得到 AllAppsRecyclerView 继承的是 RecyclerView
*/
mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);
/**
* 2. 设置 mApps
*/
mAppsRecyclerView.setApps(mApps);
mAppsRecyclerView.setLayoutManager(mLayoutManager);
/**
* 3. 设置加载适配器
*/
mAppsRecyclerView.setAdapter(mAdapter);
mAppsRecyclerView.setHasFixedSize(true);
mAppsRecyclerView.addOnScrollListener(mElevationController);
mAppsRecyclerView.setElevationController(mElevationController);
}
在注释 1 处得到 AllAppsRecyclerView 对象用来显示 APP 列表,并在注释 2 处将此前的 mAPPs 设置进去,在注释 3 处设置 RecyclerView 的 Apdapter 适配器,这样 APP 就显示在屏幕上了。
到这里 Launcher 中应用图标显示过程以及 launcher 启动流程就将完了,下一篇将为带来应用程序的启动流程,还没有关注的小伙伴可以先关注一波...
总结
这里我就以一张图来总结 Launcher 的启动流程吧。
网友评论