This series mainly introduces the init, Zygote, SystemServer, and Launcher involved in the startup process of Android8.0. In the previous three articles, the following process was explained:

  • Initialization: Power on the power supply and load the BootLoader program. Start init. CPP and parse the init.rc configuration file.
  • Start the Zygote process: Start the VM and register the JNI method. Register Socket server, preload resources; Execute the runSelectLoop() method to wait for other processes to register;
  • Start the SystemServer process with Zygote, create a Binder thread pool and execute the main method. Enable three system services (boot, core, and others).

After completing the above three processes, our system starts to load the application Launcher. Looking at the source code, you can find that the Launcher is executed as an APP application, which is usually located in the system’s Packages /apps directory. You can use this application to launch other applications in the system and provide quick access ICONS.

Start the Launcher

1.1 Preparations for Startup

When the SystemServer is started, boot services, including PackageManagerService (PMS) and ActivityManagerService (AMS), are started. PMS parses and installs APK in the system. AMS is used to launch and manage the four major components, so LauncherActivity starts with AMS. After the boot service is started, start other services. The entry point to start the Launcher is AMS ‘systemReady method,

frameworks\base\services\java\com\android\server\SystemServer.java
 private void startOtherServices() {... // A lot of work is done before this, including AMS, PMS, NetworkScoreService and other services. Said the activity manager can run mActivityManagerService. SystemReady (() - > {Slog i. (TAG,"Making services ready");
            traceBeginAndSlog("StartActivityManagerReadyPhase"); mSystemServiceManager.startBootPhase( SystemService.PHASE_ACTIVITY_MANAGER_READY); . }... . }Copy the code
frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
 public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
        traceLog.traceBegin("PhaseActivityManagerReady"); synchronized(this) { ... mStackSupervisor.resumeFocusedStackTopActivityLocked(); mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId); . }}Copy the code

1.2 Finding the Activity Launcher

AMS manages the Activity object in the stack by calling ActivityStack. Our ultimate goal is to find out how the Activity Launcher application is called. The process is as follows: ActivityStackSuperior#resumeFocusedStackTopActivityLocked() – > ActivityStack# resumeTopActivityUncheckedLocked () – > resumeTopActivityInnerLocked in resumeTopActivityInnerLocked (), Start the Activty that starts the Launcher by calling startHomeActivityLocked.

frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
 boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
            
 if(targetStack ! = null && isFocusedStack(targetStack)) {returntargetStack.resumeTopActivityUncheckedLocked(target, targetOptions); }...return false;
        
Copy the code
frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mStackSupervisor.inResumeTopActivity) {
            return false;
        }
         boolean result = false;
        try {
            mStackSupervisor.inResumeTopActivity = true;
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
        }
        final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
        if(next == null || ! next.canTurnScreenOn()) { checkReadyForSleep(); }return result;
}
Copy the code
frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
 private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
 ...
returnisOnHomeDisplay() && mStackSupervisor.resumeHomeStackTask(prev, reason); .if(r ! = null && ! r.finishing) { moveFocusableActivityStackToFrontLocked(r, myReason);return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
        }
        returnmService.startHomeActivityLocked(mCurrentUser, myReason); . }Copy the code

1.3 start the Launcher

frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java boolean startHomeActivityLocked(int UserId, String Reason) {//1 Determine factory mode and topActionif (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                && mTopAction == null) {
            return false; 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) {
                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid); 
                final String myReason = reason + ":" + userId + ":"+ resolvedUserId; / / 3 start Launcdr mActivityStarter. StartHomeActivityLocked (intent, aInfo myReason); }}else {
            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
        }
        return true;
}
Copy the code

At note 1 is the determination of the operation mode and Action, where the operation mode includes: non-factory mode, low-level factory mode, and advanced factory mode. ACTION_MAIN (intent.action_main, intent.action_main, intent.action_main, intent.action_main, intent.action_main, intent.action_main, intent.action_main, intent.action_main, intent.action_main, intent.action_main, intent.action_main) For the desktop application, can increase the Intent. The HOME, if we want to customize the desktop applications, can start the Activity in the application of AndroidMainfest Action to add android. Intent. Action. HOME, as shown below:

 <application
       ...
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.HOME"/>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
Copy the code

Launching Launer is done in ActivityStarter’s Starhome ActivityLocked method, The Intent is moved to the top of HomeStack(the variable used to store the Launcher) with the ActivityStackSupervisor, and startActivityLocked is called to launch Intnet and launch Launcer.

void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) { mSupervisor.moveHomeStackTaskToTop(reason); . }Copy the code

Launcher desktop icon display

After Launcer is launched, the APP Launcher performs the loading of your application and the display of desktop ICONS as a standalone APP.

2.1 loading APP

packages\apps\Launcher3\src\com\android\launcher3\Launcher.java protected void onCreate(Bundle savedInstanceState) { ...  / / load the desktop color information and listening topic change WallpaperColorInfo WallpaperColorInfo = WallpaperColorInfo. GetInstance (this); wallpaperColorInfo.setOnThemeChangeListener(this); . / / load the desktop application information LauncherAppState app = LauncherAppState. GetInstance (this); . mModel = app.setLauncher(this); . MLauncherView = Layoutinflater.from (this).inflate(r.layout.launcher, null); setupViews(); .if(! mModel.startLoader(currentScreen)) { mDragLayer.setAlpha(0); }else {
            mWorkspace.setCurrentPage(currentScreen);
            setWorkspaceLoading(true); }}Copy the code
// Set the launcher listener and initialize model packages\apps\Launcher3\ SRC \com\ Android \Launcher3\ LauncherAppState LauncherModelsetLauncher(Launcher launcher) { getLocalProvider(mContext).setLauncherProviderChangeListener(launcher); mModel.initialize(launcher); // Pass in the Launcher objectreturn mModel;
    }
Copy the code

When setting up a listener, the incoming Callbacks are sent with a Launcher object so that when the APP is finished loading, the value is returned in the form of an interface callback. Let’s start loading the APP.

packages\apps\Launcher3\src\com\android\launcher3\LauncherModel public void initialize(Callbacks callbacks) { synchronized (mLock) { Preconditions.assertUIThread(); mCallbacks = new WeakReference<>(callbacks); }} // The Callbacks interface contains the following contents, which are mainly usedbindAllApplications
public interface Callbacks extends LauncherAppWidgetHost.ProviderChangedListener {
      ...
        public void bindAllApplications(ArrayList<AppInfo> apps);
        public void bindAppsAddedOrUpdated(ArrayList<AppInfo> apps);
        public void bindAppsAdded(ArrayList<Long> newScreens,
                                  ArrayList<ItemInfo> addNotAnimated,
                                  ArrayList<ItemInfo> addAnimated);
        public void bindPromiseAppProgressUpdated(PromiseAppInfo app);
        public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated, UserHandle user);
        public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);
        public void bindRestoreItemsChange(HashSet<ItemInfo> updates);
        public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher);
        public void bindAppInfosRemoved(ArrayList<AppInfo> appInfos);
        public void bindAllWidgets(MultiHashMap<PackageItemInfo, WidgetItem> widgets); . }Copy the code

The loaded Task is analyzed as follows

. Packages \apps\Launcher3\ SRC \com\android\ Launcher3\ LauncherModel // Start loading public Boolean startLoader(int synchronousBindPage) { ... Synchronized (mLock) {// Clears the previous callback cacheif(mCallbacks ! = null && mCallbacks.get() ! = null) { final Callbacks oldCallbacks = mCallbacks.get(); // Clear any pendingbind-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); // contains the Callbacks objectif(mModelLoaded && ! MIsLoaderTaskRunning) {/ / has loaded and not being loaded / / after completion of loading, began to look at the results back to the Launcher loaderResults. BindWorkspace (); loaderResults.bindAllApps(); / / load callback loaderResults bindDeepShortcuts (); loaderResults.bindWidgets();return true;
                } elseStartLoaderForResults (loaderResults); }}}return false; } packages\apps\Launcher3\src\com\android\launcher3\LauncherModel public void startLoaderForResults(LoaderResults Results) {synchronized (mLock) {// stop loading stopLoader(); MLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results); RunOnWorkerThread (mLoaderTask); }} the threads involved in loading initialize packages\apps\Launcher3\ SRC \com\ Android \Launcher3\ LauncherModel @thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
    static {
        sWorkerThread.start();
    }
@Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());
Copy the code

2.2 Loading callback processing

The LauncherModel loading thread obtains the information of all the apps in the system, and at the same time passes the results conveniently through its Callbacks interface.

packages\apps\Launcher3\src\com\android\launcher3\Launcher.java
public void bindAllApplications(final ArrayList<AppInfo> apps) {
        Runnable r = new RunnableWithId(RUNNABLE_ID_BIND_APPS) {
            public void run() {
                bindAllApplications(apps); }}; . Mappsview.setapps (apps); }if (mLauncherCallbacks != null) {
            mLauncherCallbacks.bindAllApplications(apps);
        }
    }
Copy the code

The bindAllApplications for the AllAppsContainerView screen start setting up the data for the AllAppsContainerView screen. The control is AlphabeticalAppsList Use AlphabeticalAppsList to set up your data. The process is similar to Recycleview.

packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsContainerView.java
 public void setApps(List<AppInfo> apps) { mApps.setApps(apps); } / / data transfer control controls packages \ apps \ Launcher3 \ SRC \ com \ android \ Launcher3 \ allapps \ AlphabeticalAppsList Java public voidsetApps(List<AppInfo> apps) {
        mComponentToAppMap.clear();
        addOrUpdateApps(apps);
    }

packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsContainerView.java
 @Override
    protected void onFinishInflate() {... mAppsRecyclerView = findViewById(R.id.apps_list_view); / / you can see the desktop application part of the interface for RecyclerView mAppsRecyclerView. SetApps (mApps); mAppsRecyclerView.setLayoutManager(mLayoutManager); mAppsRecyclerView.setAdapter(mAdapter); mAppsRecyclerView.setHasFixedSize(true); . }Copy the code

The AllAppsContainerView calls the onFinishInflate method after the XML layout file is loaded so that the loaded data is finally displayed on the desktop. Form the desktop ICONS we see.

2.3 Tap the desktop icon to go to the application

After setting adapter in AllAppsContainerView, RecyclerView does not contain setOnItemClickListener method, so it is generally customized in Adapter, can pass click events in the form of callback. The execution process of the Launcher is as follows:

//packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsContainerView.java public AllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) { ... MAdapter = new AllAppsGridAdapter(mLauncher, mApps, mLauncher, this); mSpringAnimationHandler = mAdapter.getSpringAnimationHandler(); mApps.setAdapter(mAdapter); . }Copy the code

Set the listener callback for clicks

//packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsGridAdapter.java public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps, View.OnClickListener iconClickListener, View.OnLongClickListener iconLongClickListener) { ... mIconClickListener = iconClickListener; . }Copy the code

Click event handling

packages\apps\Launcher3\src\com\android\launcher3\Launcher.java
 public void onClick(View v) {
...
 Object tag = v.getTag();
        if (tag instanceof ShortcutInfo) {
            onClickAppShortcut(v);
        } else if (tag instanceof FolderInfo) {
            if(v instanceof FolderIcon) { onClickFolderIcon(v); }}else if((v instanceof PageIndicator) || (v == mAllAppsButton && mAllAppsButton ! = null)) { onClickAllAppsButton(v); }else if (tag instanceof AppInfo) {
            startAppShortcutOrInfoActivity(v);
        } else if (tag instanceof LauncherAppWidgetInfo) {
            if(v instanceof PendingAppWidgetHostView) { onClickPendingWidget((PendingAppWidgetHostView) v); Protected void onClickAppShortcut(Final View V) {... startAppShortcutOrInfoActivity(v); . } private void startAppShortcutOrInfoActivity(View v) { ItemInfo item = (ItemInfo) v.getTag(); Intent intent;if (item instanceof PromiseAppInfo) {
            PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
            intent = promiseAppInfo.getMarketIntent();
        } else{ intent = item.getIntent(); }... Boolean success = startActivitySafely(v, intent, item); . }Copy the code

Now the startup process of the Launcher is analyzed and summarized as follows:

  1. Start: SystemServer starts PMS and AMS and starts loading via AMS systemReady;
  2. Looking for: Lookup process following ActivityStackSuperior# resumeFocusedStackTopActivityLocked () – > ActivityStack# resumeTopActivityUncheckedLocked () – > resumeTopActivityInnerLocked ();
  3. Display: By calling in resumeTopActivityInnerLocked startHomeActivityLocked method, start the Launcher Activty, through the LauncherModel loading thread processing, access to information to all Apps, Send the data back to the Launcher in the form of Callbacks, and then assign the data to AllAppsContainerView so that the desktop ICONS of Apps are displayed on the desktop.
  4. Jump: Set the callback processing for click events. After clicking the desktop icon, use startActivitySafely to jump to the Main screen of the application.