Android系统启动流程(四)Launcher启动过程与系统启动流程

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;

if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {

mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;

mService.updateSleepIfNeededLocked();

}

result = resumeTopActivityInnerLocked(prev, options);//1

} finally {

mStackSupervisor.inResumeTopActivity = false;

}

return result;

}

注释1调用了resumeTopActivityInnerLocked函数:

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {

return isOnHomeDisplay() &&

mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, “prevFinished”);

}

resumeTopActivityInnerLocked函数的代码很长,我们截取我们要分析的关键的一句:调用ActivityStackSupervisor的resumeHomeStackTask函数,代码如下所示。

frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

boolean resumeHomeStackTask(int homeStackTaskType, ActivityRecord prev, String reason) {

if (r != null && !r.finishing) {

mService.setFocusedActivityLocked(r, myReason);

return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);

}

return mService.startHomeActivityLocked(mCurrentUser, myReason);//1

}

在注释1处调用了ActivityManagerService的startHomeActivityLocked函数,如下所示。

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

boolean startHomeActivityLocked(int userId, String reason) {

if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL

&& mTopAction == null) {//1

return false;

}

Intent intent = getHomeIntent();//2

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.instrumentationClass == null) {//3

intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);

mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);//4

}

} else {

Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());

}

return true;

}

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

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;

}

getHomeIntent函数中创建了Intent,并将mTopAction和mTopData传入。mTopAction的值为Intent.ACTION_MAIN,并且如果系统运行模式不是低级工厂模式则将intent的Category设置为Intent.CATEGORY_HOME。我们再回到ActivityManagerService的startHomeActivityLocked函数,假设系统的运行模式不是低级工厂模式,在注释3处判断符合Action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_HOME的应用程序是否已经启动,如果没启动则调用注释4的方法启动该应用程序。

这个被启动的应用程序就是Launcher,因为Launcher的Manifest文件中的intent-filter标签匹配了Action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_HOME。Launcher的Manifest文件如下所示。

packages/apps/Launcher3/AndroidManifest.xml

<manifest

xmlns:android=“http://schemas.android.com/apk/res/android”

package=“com.android.launcher3”>

<application

<activity

android:name=“com.android.launcher3.Launcher”

android:launchMode=“singleTask”

android:clearTaskOnLaunch=“true”

android:stateNotNeeded=“true”

android:theme=“@style/Theme”

android:windowSoftInputMode=“adjustPan”

android:screenOrientation=“nosensor”

android:configChanges=“keyboard|keyboardHidden|navigation”

android:resumeWhilePausing=“true”

android:taskAffinity=“”

android:enabled=“true”>

这样,应用程序Launcher就会被启动起来,并执行它的onCreate函数。

3.Launcher中应用图标显示流程

Launcher的onCreate函数如下所示。

packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

@Override

protected void onCreate(Bundle savedInstanceState) {

LauncherAppState app = LauncherAppState.getInstance();//1

mDeviceProfile = getResources().getConfiguration().orientation

== Configuration.ORIENTATION_LANDSCAPE ?

app.getInvariantDeviceProfile().landscapeProfile
app.getInvariantDeviceProfile().portraitProfile;

mSharedPrefs = Utilities.getPrefs(this);

mIsSafeModeEnabled = getPackageManager().isSafeMode();

mModel = app.setLauncher(this);//2

if (!mRestoring) {

if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE) {

mModel.startLoader(PagedView.INVALID_RESTORE_PAGE);//2

} else {

mModel.startLoader(mWorkspace.getRestorePage());

}

}

}

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

packages/apps/Launcher3/src/com/android/launcher3/LauncherAppState.java

LauncherModel setLauncher(Launcher launcher) {

getLauncherProvider().setLauncherProviderChangeListener(launcher);

mModel.initialize(launcher);//1

mAccessibilityDelegate = ((launcher != null) && Utilities.ATLEAST_LOLLIPOP) ?

new LauncherAccessibilityDelegate(launcher) : null;

return mModel;

}

注释1处会调用LauncherModel的initialize函数:

public void initialize(Callbacks callbacks) {

synchronized (mLock) {

unbindItemInfosAndClearQueuedBindRunnables();

mCallbacks = new WeakReference(callbacks);

}

}

在initialize函数中会将Callbacks,也就是传入的Launcher 封装成一个弱引用对象。因此我们得知mCallbacks变量指的就是封装成弱引用对象的Launcher,这个mCallbacks后文会用到它。

再回到Launcher的onCreate函数,在注释2处调用了LauncherModel的startLoader函数:

packages/apps/Launcher3/src/com/android/launcher3/LauncherModel.java

@Thunk static final HandlerThread sWorkerThread = new HandlerThread(“launcher-loader”);//1

static {

sWorkerThread.start();

}

@Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());//2

public void startLoader(int synchronousBindPage, int loadFlags) {s

InstallShortcutReceiver.enableInstallQueue();

synchronized (mLock) {

synchronized (mDeferredBindRunnables) {

mDeferredBindRunnables.clear();

}

if (mCallbacks != null && mCallbacks.get() != null) {

stopLoaderLocked();

mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags);//3

if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE

&& mAllAppsLoaded && mWorkspaceLoaded && !mIsLoaderTaskRunning) {

mLoaderTask.runBindSynchronousPage(synchronousBindPage);

} else {

sWorkerThread.setPriority(Thread.NORM_PRIORITY);

sWorker.post(mLoaderTask);//4

}

}

}

}

注释1处创建了具有消息循环的线程HandlerThread对象。注释2处创建了Handler,并且传入HandlerThread的Looper。Hander的作用就是向HandlerThread发送消息。在注释3处创建LoaderTask,在注释4处将LoaderTask作为消息发送给HandlerThread 。

LoaderTask类实现了Runnable接口,当LoaderTask所描述的消息被处理时则会调用它的run函数,代码如下所示

private class LoaderTask implements Runnable {

public void run() {

synchronized (mLock) {

if (mStopped) {

return;

}

mIsLoaderTaskRunning = true;

}

keep_running: {

if (DEBUG_LOADERS) Log.d(TAG, “step 1: loading workspace”);

loadAndBindWorkspace();//1

if (mStopped) {

break keep_running;

}

waitForIdle();

if (DEBUG_LOADERS) Log.d(TAG, “step 2: loading all apps”);

loadAndBindAllApps();//2

}

mContext = null;

synchronized (mLock) {

if (mLoaderTask == this) {

mLoaderTask = null;

}

mIsLoaderTaskRunning = false;

mHasLoaderCompletedOnce = true;

}

}

}

Launcher是用工作区的形式来显示系统安装的应用程序的快捷图标,每一个工作区都是来描述一个抽象桌面的,它由n个屏幕组成,每个屏幕又分n个单元格,每个单元格用来显示一个应用程序的快捷图标。注释1处调用loadAndBindWorkspace函数用来加载工作区信息,注释2处的loadAndBindAllApps函数是用来加载系统已经安装的应用程序信息,loadAndBindAllApps函数代码如下所示。

private void loadAndBindAllApps() {

if (DEBUG_LOADERS) {

Log.d(TAG, “loadAndBindAllApps mAllAppsLoaded=” + mAllAppsLoaded);

}

if (!mAllAppsLoaded) {

loadAllApps();//1

synchronized (LoaderTask.this) {

if (mStopped) {

return;

}

}

updateIconCache();

synchronized (LoaderTask.this) {

if (mStopped) {

return;

}

mAllAppsLoaded = true;

}

} else {

onlyBindAllApps();

}

}

如果系统没有加载已经安装的应用程序信息,则会调用注释1处的loadAllApps函数:

private void loadAllApps() {

mHandler.post(new Runnable() {

public void run() {

final long bindTime = SystemClock.uptimeMillis();

final Callbacks callbacks = tryGetCallbacks(oldCallbacks);

if (callbacks != null) {

callbacks.bindAllApplications(added);//1

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函数,在前面我们得知这个callbacks实际是指向Launcher的,因此我们来查看Launcher的bindAllApplications函数,代码如下所示。

packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

public void bindAllApplications(final ArrayList apps) {

if (waitUntilResume(mBindAllApplicationsRunnable, true)) {

mTmpAppsList =
apps;

return;

}

if (mAppsView != null) {

mAppsView.setApps(apps);//1

}

if (mLauncherCallbacks != null) {

mLauncherCallbacks.bindAllApplications(apps);

}

}

在注释1处会调用AllAppsContainerView的setApps函数,并将包含应用信息的列表apps传进去,AllAppsContainerView的setApps函数如下所示。

packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java

public void setApps(List apps) {

mApps.setApps(apps);

}

包含应用信息的列表apps已经传给了AllAppsContainerView,查看AllAppsContainerView的onFinishInflate函数:

@Override

protected void onFinishInflate() {

super.onFinishInflate();

// Load the all apps recycler view

mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);//1

mAppsRecyclerView.setApps(mApps);//2

mAppsRecyclerView.setLayoutManager(mLayoutManager);

mAppsRecyclerView.setAdapter(mAdapter);//3

mAppsRecyclerView.setHasFixedSize(true);

mAppsRecyclerView.addOnScrollListener(mElevationController);

mAppsRecyclerView.setElevationController(mElevationController);

}

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

如果你需要这些资料, ⬅ 专栏获取
mAppsRecyclerView.setHasFixedSize(true);

mAppsRecyclerView.addOnScrollListener(mElevationController);

mAppsRecyclerView.setElevationController(mElevationController);

}

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

[外链图片转存中…(img-yOFOVGhy-1719178793172)]

[外链图片转存中…(img-KBBRyqZe-1719178793172)]

[外链图片转存中…(img-OzGsxKUO-1719178793173)]

[外链图片转存中…(img-6UTdk9xv-1719178793173)]

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

如果你需要这些资料, ⬅ 专栏获取

  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值