赞
踩
相关文章
Android系统启动流程(1) —— 解析init进程启动过程
Android系统启动流程(2) —— 解析Zygote进程启动过程
Android系统启动流程(3) —— 解析SystemServer进程启动过程
系统启动的最后一步是启动一个应用程序用来显示系统中已经安装的应用程序,也就是我们手机看到的桌面,这个应用程序就叫作 Launcher。Launcher 在启动过程中会请求 PackageManagerService 返回系统中已经安装的应用程序的信息,并将这些信息封装成一个快捷图标列表显示在系统屏幕上, 这样用户可以通过点击这些快捷图标来启动相应的应用程序。
通俗来讲 Launcher 就是 Android 系统的桌面,它的作用主要有以下两点:
SystemServer 进程在启动的过程中会启动ActivityManagerServer、PackageManagerService服务, PackageManagerService启动之后会将系统中的应用程序安装完成。AMS(ActivityManagerServer) 会将 Launcher 启动起来。
启动Launcher的入口为AMS的sytemReady方法,它在SystemServer的startOtherServices方法中被调用,代码如下所示:
frameworks/base/services/java/com/android/server/SystemServer.java
- private void startOtherServices() {
-
- mActivityManagerService.systemReady(() -> {
- Slog.i(TAG, "Making services ready");
- traceBeginAndSlog("StartActivityManagerReadyPhase");
- mSystemServiceManager.startBootPhase(
- SystemService.PHASE_ACTIVITY_MANAGER_READY);
-
- ...
-
- }, BOOT_TIMINGS_TRACE_LOG);
- }
在Android8.0开始在源码中引入了Java Lambda表达式,接下来分析AMS的systemReady方法做了什么,代码如下:
- public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
- ...
-
- synchronized (this) {
-
- ...
-
- startHomeActivityLocked(currentUserId, "systemReady"); // ... 1
-
- ...
-
- mStackSupervisor.resumeFocusedStackTopActivityLocked();// ... 2
- mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
- }
- }
- boolean startHomeActivityLocked(int userId, String reason) {
-
- Slog.wtf("ActivityManagerService", "reason = " + reason +
- " ; mFactoryTest =" + mFactoryTest
- + " ; mTopAction = " + mTopAction
- + " ; userId = " + userId); // ... 1
-
- if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
- && mTopAction == null) {
- // We are running in factory test mode, but unable to find
- // the factory test app, so just sit around displaying the
- // error message and don't try to start anything.
- return false;
- }
- Intent intent = getHomeIntent();
- ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
- Slog.wtf("ActivityManagerService", "reason = " + reason
- + " ; aInfo = " + aInfo); // ... 2
- if (aInfo != null) {
- intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
- Slog.wtf("ActivityManagerService", "reason = " + reason
- + " ; aInfo.applicationInfo.packageName = " + aInfo.applicationInfo.packageName); // ... 3
- // Don't do this if the home app is currently being
- // instrumented.
- 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) {
- intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
- mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
- }
- } else {
- Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
- }
-
- return true;
- }
Direct Boot模式下,仅限于运行一些关键的、紧急的APP,比如:
在Android 7.0以后,在启动Launcher之前会先启动一个FallbackHome; FallbackHome是Settings里的一个activity,Settings的android:directBootAware为true,而且FallbackHome在category中配置了Home属性;而Launcher的android:directBootAware为false,所以在DirectBoot模式下,只有FallbackHome可以启动。即先启动com.android.tv.settings/.FallbackHome(或者是com.android.settings/.FallbackHome ) ,待用户解锁后再启动com.android.launcher3/.Launcher。想更深入了解Direct Boot模式和FallbackHome所做的工作的同学可以去阅读源码研究,这里就不做深入说明,下面我们继续分享Lancher的启动过程。
- boolean resumeFocusedStackTopActivityLocked() {
- return resumeFocusedStackTopActivityLocked(null, null, null);
- }
-
- boolean resumeFocusedStackTopActivityLocked(
- ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
-
- if (!readyToResume()) {
- return false;
- }
-
- if (targetStack != null && isFocusedStack(targetStack)) {
- return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); // ... 1
- }
-
- final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
- if (r == null || r.state != RESUMED) {
- mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
- } else if (r.state == RESUMED) {
- // Kick off any lingering app transitions form the MoveTaskToFront operation.
- mFocusedStack.executeAppTransition(targetOptions);
- }
-
- return false;
- }
- 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;
- result = resumeTopActivityInnerLocked(prev, options); // ... 1
- } finally {
- mStackSupervisor.inResumeTopActivity = false;
- }
-
- // When resuming the top activity, it may be necessary to pause the top activity (for
- // example, returning to the lock screen. We suppress the normal pause logic in
- // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the end.
- // We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here to ensure
- // any necessary pause logic occurs. In the case where the Activity will be shown regardless
- // of the lock screen, the call to {@link ActivityStackSupervisor#checkReadyForSleepLocked}
- // is skipped.
- final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
- if (next == null || !next.canTurnScreenOn()) {
- checkReadyForSleep();
- }
-
- return result;
- }
-
- private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
-
- ...
- if (!hasRunningActivity) {
- // There are no activities left in the stack, let's look somewhere else.
- return resumeTopActivityInNextFocusableStack(prev, options, "noMoreActivities"); // ... 1
- }
-
-
- ...
- }
- private boolean resumeTopActivityInNextFocusableStack(ActivityRecord prev,
- ActivityOptions options, String reason) {
-
- ...
- return isOnHomeDisplay() &&
- mStackSupervisor.resumeHomeStackTask(prev, reason); // ... 1
- }
在注释1处调用 ActivityStackSupervisor 的resumeHomeStackTask 方法并且传入的reason参数就是"noMoreActivities",代码如下所示:
-
- boolean resumeHomeStackTask(ActivityRecord prev, String reason) {
-
- ...
-
- // reason 的值为noMoreActivities
- final String myReason = reason + " resumeHomeStackTask"; // ... 1
-
- // Only resume home activity if isn't finishing.
- if (r != null && !r.finishing) {
- moveFocusableActivityStackToFrontLocked(r, myReason);
- return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
- }
- return mService.startHomeActivityLocked(mCurrentUser, myReason); // ... 2
- }
- boolean startHomeActivityLocked(int userId, String reason) {
- // 判断工厂模式和mTopAction的值
- if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
- && mTopAction == null) { // ... 1
- // We are running in factory test mode, but unable to find
- // the factory test app, so just sit around displaying the
- // error message and don't try to start anything.
- return false;
- }
- // 创建Launcher启动所需的Intent
- Intent intent = getHomeIntent(); // ... 2
- ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId); // ... 3
- if (aInfo != null) {
- intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
- // Don't do this if the home app is currently being
- // instrumented.
- 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) { // ... 4
- 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;
- mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason); // ... 5
- }
- } else {
- Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
- }
-
- return true;
- }
- 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;
- }
- private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
- ActivityInfo ai = null;
- ComponentName comp = intent.getComponent();
- try {
- if (comp != null) {
- // Factory test.
- ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
- } else {
- ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
- intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- flags, userId);
-
- if (info != null) {
- ai = info.activityInfo;
- }
- }
- } catch (RemoteException e) {
- // ignore
- }
-
- return ai;
- }
- <manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.launcher3">
- <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
- ...
-
- <application
- android:backupAgent="com.android.launcher3.LauncherBackupAgent"
- android:fullBackupOnly="true"
- android:fullBackupContent="@xml/backupscheme"
- android:hardwareAccelerated="true"
- android:icon="@drawable/ic_launcher_home"
- android:label="@string/derived_app_name"
- android:theme="@style/LauncherTheme"
- android:largeHeap="@bool/config_largeHeap"
- android:restoreAnyVersion="true"
- android:supportsRtl="true" >
-
- <!--
- Main launcher activity. When extending only change the name, and keep all the
- attributes and intent filters the same
- -->
- <activity
- android:name="com.android.launcher3.Launcher"
- android:launchMode="singleTask"
- android:clearTaskOnLaunch="true"
- android:stateNotNeeded="true"
- android:windowSoftInputMode="adjustPan"
- android:screenOrientation="nosensor"
- android:configChanges="keyboard|keyboardHidden|navigation"
- 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>
- </activity>
- ...
-
- </application>
- </manifest>
可以看到intent-filter设置了<category android:name="android.intent.category.HOME" /> 属性,这样名称为com.android.launcher3.Launcher的Activity 就成为了主 Activity。 从前面 AMS的startHomeActivityLocked方法的注释5处,我们知如 Launcher 没有启动就会调用ActivityStarter的startHomeActivityLocked 方法来启动Launcher ,如下所示:
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java
- void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
- // 将Launcher放入HomeStack中
- mSupervisor.moveHomeStackTaskToTop(reason); // ... 1
- 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 /*inTask*/, "startHomeActivity: " + reason); // ... 2
- if (mSupervisor.inResumeTopActivity) {
- // If we are in resume section already, home activity will be initialized, but not
- // resumed (to avoid recursive resume) and will stay that way until something pokes it
- // again. We need to schedule another resume.
- mSupervisor.scheduleResumeTopActivities();
- }
- }
在注释1处将 Launcher放入HomeStack 中,HomeStack 是在 ActivityStackSupervisor 中定义的用于存储Launcher的变量 。接着调用注释2处的startActivityLocked方法来启动Launcher, 剩余的过程会和普通Activity 启动过程类似,后面会出Activity启动过程相关文章,这里就先不做讲解。最终进Launcher的onCreate 方注中,到这里 Launcher就启动完成了。
Launcher 完成启动后会做很多的工作,作为桌面它会显示应用程序图标, 这与应用程序开发有所关联,应用程序图标是用户进入应用程的入口,因此我们有必要了解 Launcher 是如何显示应用程序图标的。
- @Override
- protected void onCreate(Bundle savedInstanceState) {
-
- ...
-
- LauncherAppState app = LauncherAppState.getInstance(this); // ... 1
-
- // Load configuration-specific DeviceProfile
- mDeviceProfile = app.getInvariantDeviceProfile().getDeviceProfile(this);
- if (isInMultiWindowModeCompat()) {
- Display display = getWindowManager().getDefaultDisplay();
- Point mwSize = new Point();
- display.getSize(mwSize);
- mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
- }
-
- mOrientation = getResources().getConfiguration().orientation;
- mSharedPrefs = Utilities.getPrefs(this);
- mIsSafeModeEnabled = getPackageManager().isSafeMode();
-
- mModel = app.setLauncher(this); // ...2
-
- ...
-
- if (!mModel.startLoader(currentScreen)) { // ... 3
- // If we are not binding synchronously, show a fade in animation when
- // the first page bind completes.
- mDragLayer.setAlpha(0);
- } else {
- // Pages bound synchronously.
- mWorkspace.setCurrentPage(currentScreen);
-
- setWorkspaceLoading(true);
- }
-
- ...
-
- }
-
- LauncherModel setLauncher(Launcher launcher) {
- getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
- mModel.initialize(launcher); // ... 1
- return mModel;
- }
- public void initialize(Callbacks callbacks) {
- synchronized (mLock) {
- Preconditions.assertUIThread();
- mCallbacks = new WeakReference<>(callbacks);
- }
- }
- ...
-
- // 创建了具有消息循环的线程HandlerThread对象
- @Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader"); // ... 1
- static {
- sWorkerThread.start();
- }
- @Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper()); // ... 2
-
- ...
-
- public boolean startLoader(int synchronousBindPage) {
- // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
- InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING);
- synchronized (mLock) {
- // Don't bother to start the thread if we know it's not going to do anything
- if (mCallbacks != null && mCallbacks.get() != null) {
- final Callbacks oldCallbacks = mCallbacks.get();
- // Clear any pending bind-runnables from the synchronized load process.
- mUiExecutor.execute(new Runnable() {
- public void run() {
- oldCallbacks.clearPendingBinds();
- }
- });
-
- // If there is already one running, tell it to stop.
- stopLoader();
- LoaderResults loaderResults = new LoaderResults(mApp, sBgDataModel,
- mBgAllAppsList, synchronousBindPage, mCallbacks); // ... 3
- if (mModelLoaded && !mIsLoaderTaskRunning) {
- // Divide the set of loaded items into those that we are binding synchronously,
- // and everything else that is to be bound normally (asynchronously).
- loaderResults.bindWorkspace();
- // For now, continue posting the binding of AllApps as there are other
- // issues that arise from that.
- loaderResults.bindAllApps();
- loaderResults.bindDeepShortcuts();
- loaderResults.bindWidgets();
- return true;
- } else {
- startLoaderForResults(loaderResults); // ... 4
- }
- }
- }
- return false;
- }
- public void startLoaderForResults(LoaderResults results) {
- synchronized (mLock) {
- stopLoader();
- mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results); // ... 1
- runOnWorkerThread(mLoaderTask); // ... 2
- }
- }
在注释1处创建LoaderTask的对象mLoaderTask并将LoaderResult对象传入构造器,后面会用到这个LoaderResult的对象,在注释2处调用runOnWorkerThread方法,代码如下:
packages/apps/Launcher3/src/com/android/launche3/LauncherModel.java
- private static void runOnWorkerThread(Runnable r) {
- if (sWorkerThread.getThreadId() == Process.myTid()) {
- r.run(); // 如果当前线程是工作线程,直接执行run方法
- } else {
- // If we are not on the worker thread, then post to the worker handler
- // 如果当前线程不是工作现在,那么post到工作线程处理。
- sWorker.post(r);
- }
- }
LoaderTask类实现了Runnable接口,当LoaderTask所描述的消息被处理时,则会调用它的run方法,LoaderTask的run方法代码如下所示:
packages/apps/Launcher3/src/com/android/launche3/model/LoaderTask.java
- public void run() {
- synchronized (this) {
- // Skip fast if we are already stopped.
- if (mStopped) {
- return;
- }
- }
-
- try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
- long now = 0;
- if (DEBUG_LOADERS) Log.d(TAG, "step 1.1: loading workspace");
- // 加载工作区信息
- loadWorkspace(); // ... 1
-
- verifyNotStopped();
- if (DEBUG_LOADERS) Log.d(TAG, "step 1.2: bind workspace workspace");
-
- // 绑定工作区信息
- mResults.bindWorkspace(); // ... 2
-
- // Take a break
- if (DEBUG_LOADERS) {
- Log.d(TAG, "step 1 completed, wait for idle");
- now = SystemClock.uptimeMillis();
- }
- waitForIdle();
- if (DEBUG_LOADERS) Log.d(TAG, "Waited " + (SystemClock.uptimeMillis() - now) + "ms");
- verifyNotStopped();
-
- // second step
- if (DEBUG_LOADERS) Log.d(TAG, "step 2.1: loading all apps");
-
- // 加载系统已经安装的应用程序信息
- loadAllApps(); // ... 3
-
- if (DEBUG_LOADERS) Log.d(TAG, "step 2.2: Binding all apps");
- verifyNotStopped();
-
- // 绑定Appinfo
- mResults.bindAllApps(); // ... 4
-
- ...
-
- } catch (CancellationException e) {
- // Loader stopped, ignore
- if (DEBUG_LOADERS) {
- Log.d(TAG, "Loader cancelled", e);
- }
- }
- }
- private void loadAllApps() {
-
- ...
-
- // Clear the list of apps
- mBgAllAppsList.clear();
- for (UserHandle user : profiles) {
-
- ...
-
- final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
- ...
-
- for (int i = 0; i < apps.size(); i++) {
- LauncherActivityInfo app = apps.get(i);
- // This builds the icon bitmaps.
- mBgAllAppsList.add(new AppInfo(app, user, quietMode), app); // ... 1
- }
-
- ManagedProfileHeuristic.onAllAppsLoaded(mApp.getContext(), apps, user);
- }
-
- ...
- }
在注释1处创建AppInfo信息并添加到mBgAllAppsList列表中。
在回到LoaderTask的run方法,在注释4处的mResult就是构造LoaderTask时传入的LoaderResult对象,调用LoaderResult的bindAllApps方法绑定App信息,代码如下:
packages/apps/Launcher3/src/com/android/launche3/model/LoaderResult.java
- public void bindAllApps() {
- // shallow copy
- // 将mBgAllAppList中的data属性克隆一份
- @SuppressWarnings("unchecked")
- final ArrayList<AppInfo> list = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();
-
- Runnable r = new Runnable() {
- public void run() {
- Callbacks callbacks = mCallbacks.get();
- if (callbacks != null) {
- // 这里的callbacks就是Launcher的对象
- callbacks.bindAllApplications(list); // ... 1
- }
- }
- };
- mUiExecutor.execute(r);
- }
在注释1处调用callbacks的bindAllApplications方法实质上就是调用Launcher的bindAllApplications方法,接下里分析Launcher中的bindAllApplications方法,代码如下:
packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
- public void bindAllApplications(final ArrayList<AppInfo> apps) {
-
- ...
-
- if (mAppsView != null) {
- Executor pendingExecutor = getPendingExecutor();
- if (pendingExecutor != null && mState != State.APPS) {
- // Wait until the fade in animation has finished before setting all apps list.
- pendingExecutor.execute(r);
- return;
- }
-
- mAppsView.setApps(apps); // ... 1
- }
-
- ...
- }
- public void setApps(List<AppInfo> apps) {
- mApps.setApps(apps);
- }
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- ...
-
- mAppsRecyclerView = findViewById(R.id.apps_list_view); // ... 1
- mAppsRecyclerView.setApps(mApps); // ... 2
- mAppsRecyclerView.setLayoutManager(mLayoutManager);
- mAppsRecyclerView.setAdapter(mAdapter); // ... 3
-
- ...
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。