SystemServer

 public static void main(String[] args) {
        new SystemServer().run();
    }

    public SystemServer() {
        // Check for factory test mode.
        mFactoryTestMode = FactoryTest.getMode();
        // Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
        mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));

        mRuntimeStartElapsedTime = SystemClock.elapsedRealtime();
        mRuntimeStartUptime = SystemClock.uptimeMillis();
    }
Copy the code

The main function does the initialization, setting whether to boot after the flag bit.

Now look at the run method:

private void run() { try { //1. Record the vm parameters of native... Looper.prepareMainLooper(); Looper.getMainLooper().setSlowLogThresholdMs( SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS); // Android_servers. so contains a large number of native Android services system. loadLibrary("android_servers"); // Check whether we failed to shut down last time we tried. // This call may not return. performPendingShutdown(); // Initialize the system context. createSystemContext(); // Create the system service manager. mSystemServiceManager = new SystemServiceManager(mSystemContext); mSystemServiceManager.setStartInfo(mRuntimeRestart, mRuntimeStartElapsedTime, mRuntimeStartUptime); LocalServices.addService(SystemServiceManager.class, mSystemServiceManager); // Prepare the thread pool for init tasks that can be parallelized SystemServerInitThreadPool.get(); } finally { traceEnd(); // InitBeforeStartServices } // Start services. try { traceBeginAndSlog("StartServices"); startBootstrapServices(); startCoreServices(); startOtherServices(); SystemServerInitThreadPool.shutdown(); } catch (Throwable ex) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting system services", ex); throw ex; } finally { traceEnd(); } StrictMode.initVmDefaults(null); . // Loop forever. Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }Copy the code

There are four initial steps:

1. Record runtime parameters such as VMS from Zygote. Initialize android_server’s so library. Android_server initializes the native layer of important system services

2. Set Looper for SystemServer and enter the loop. Wait for another application to call

3. Initialize the SystemServer context and SystemServiceManager

4. Start major system services.

Initialize SystemServer and SystemServiceManager

Look at the context in which SystemServer created the entire process:

    private void createSystemContext() {
        ActivityThread activityThread = ActivityThread.systemMain();
        mSystemContext = activityThread.getSystemContext();
        mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);

        final Context systemUiContext = activityThread.getSystemUiContext();
        systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
    }
Copy the code

You can see here that I’m going to use the ActivityThread class,

1. The systemMain method was called to initialize the ActivityThread

2. Set a default theme for the system

Initialize SystemServicemanager

 mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setStartInfo(mRuntimeRestart,
                    mRuntimeStartElapsedTime, mRuntimeStartUptime);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
Copy the code

SystemServiceManager starts and joins LocalServices as the initiator and controller of all Android services.

The role of LocalServices is actually very similar to that of SystemServiceManager. LocalService has an ArrayMap inside, which holds instances of the corresponding service directly.

SystemServiceManager usually calls the constructor with the Context argument directly through reflection.

Start various services

try {
            traceBeginAndSlog("StartServices");
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            traceEnd();
        }
Copy the code

There are three steps:

The first step is to start the services that you need immediately after Android starts up

Step 2: Start the core service

Step 3: Start other services

private void startBootstrapServices() { ... Installer installer = mSystemServiceManager.startService(Installer.class); mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class); mActivityManagerService = mSystemServiceManager.startService( ActivityManagerService.Lifecycle.class).getService(); mActivityManagerService.setSystemServiceManager(mSystemServiceManager); mActivityManagerService.setInstaller(installer); mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class); mActivityManagerService.initPowerManagement(); mSystemServiceManager.startService(RecoverySystemService.class); mSystemServiceManager.startService(LightsService.class); if (SystemProperties.getBoolean("config.enable_sidekick_graphics", false)) { mSystemServiceManager.startService(WEAR_SIDEKICK_SERVICE_CLASS); } mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class); mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY); traceEnd(); mPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode ! = FactoryTest.FACTORY_TEST_OFF, mOnlyCore); mFirstBoot = mPackageManagerService.isFirstBoot(); mPackageManager = mSystemContext.getPackageManager(); if (! mRuntimeRestart && ! isFirstBootOrUpgrade()) { if (! mOnlyCore) { boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt", false); if (! disableOtaDexopt) { traceBeginAndSlog("StartOtaDexOptService"); try { OtaDexoptService.main(mSystemContext, mPackageManagerService); } catch (Throwable e) { reportWtf("starting OtaDexOptService", e); } finally { traceEnd(); } } } mSystemServiceManager.startService(UserManagerService.LifeCycle.class); AttributeCache.init(mSystemContext); mActivityManagerService.setSystemProcess(); mDisplayManagerService.setupSchedulerPolicies(); mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer)); mSensorServiceStart = SystemServerInitThreadPool.get().submit(() -> { TimingsTraceLog traceLog = new TimingsTraceLog( SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER); traceLog.traceBegin(START_SENSOR_SERVICE); startSensorService(); }, START_SENSOR_SERVICE); }Copy the code

From here, it is clear that our Android system immediately needs the following services:

1. The Installer is installed on the SystemServer and waits for the Installd service to connect to Binder. Explain that installd generates an InstalLD process by reading a script from installd. Rc. The purpose of this process is to install software.

2. DeviceIdentifiersPolicyService the service is in order to verify the equipment status.

ActivityManagerService This is the AMS that we are most familiar with. It is the service that runs through the entire APP, and it can be said that the familiar can not be more familiar. The main function in charge is to manage and start application activities. Also load the install service.

PowerManagerService This is a service that helps manage power supplies

5.RecoverySystemService This service is responsible for system recovery. You can communicate with the underlying uncrypt decryption process through the socket, and read the system upgrade package under /data/cache. Finally, the system enters the reset mode through the /recovery partition, and starts to install or reset the Android system.

6.LightsService A device that controls the light of a mobile phone.

7.DisplayManagerService This is a service that has been displayed as mobile management since 4.2.

8.PackageManagerService This is also an important class and is extremely important when I analyze the plug-in framework. Manage the package information of the app application.

UserManagerService is also an important class. In the early days Android was a single-user system, but now Android has become a multi-user system, and multi-users are managed through this class

10. Initialize the SensorService sensor.

The preceding services need to be started immediately when the Android system starts.

Start core services

    private void startCoreServices() {
       
        mSystemServiceManager.startService(BatteryService.class);
        mSystemServiceManager.startService(UsageStatsService.class);
        mActivityManagerService.setUsageStatsManager(
                LocalServices.getService(UsageStatsManagerInternal.class));
      
        // Tracks whether the updatable WebView is in a ready state and watches for update installs.
        if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
            traceBeginAndSlog("StartWebViewUpdateService");
            mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
            traceEnd();
        }

        BinderCallsStatsService.start();
    }
Copy the code

There are three core services that Are considered by Android:

1.BatteryService MONITORS battery information

2.UsageStatsService Monitors application services, such as checking the application usage time.

3. If the WebView flag is enabled, the WebView update service is enabled

Start auxiliary services

Private void startOtherServices() {try {// Start system core services... // Wait until ActivityManagerService has started, Progress in processing various service mActivityManagerService. SystemReady (() - > {Slog i. (TAG, "Making services ready"); traceBeginAndSlog("StartActivityManagerReadyPhase"); mSystemServiceManager.startBootPhase( SystemService.PHASE_ACTIVITY_MANAGER_READY); traceEnd(); traceBeginAndSlog("StartObservingNativeCrashes"); try { mActivityManagerService.startObservingNativeCrashes(); } catch (Throwable e) { reportWtf("observing native crashes", e); } traceEnd(); // No dependency on Webview preparation in system server. But this should // be completed before allowing 3rd party final String WEBVIEW_PREPARATION = "WebViewFactoryPreparation"; Future<? > webviewPrep = null; if (! mOnlyCore && mWebViewUpdateService ! = null) { webviewPrep = SystemServerInitThreadPool.get().submit(() -> { Slog.i(TAG, WEBVIEW_PREPARATION); TimingsTraceLog traceLog = new TimingsTraceLog( SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER); traceLog.traceBegin(WEBVIEW_PREPARATION); ConcurrentUtils.waitForFutureNoInterrupt(mZygotePreload, "Zygote preload"); mZygotePreload = null; mWebViewUpdateService.prepareWebViewInSystemServer(); traceLog.traceEnd(); }, WEBVIEW_PREPARATION); } if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { traceBeginAndSlog("StartCarServiceHelperService"); mSystemServiceManager.startService(CAR_SERVICE_HELPER_SERVICE_CLASS); traceEnd(); } traceBeginAndSlog("StartSystemUI"); try { startSystemUi(context, windowManagerF); } catch (Throwable e) { reportWtf("starting System UI", e); } traceEnd(); traceBeginAndSlog("MakeNetworkManagementServiceReady"); try { if (networkManagementF ! = null) networkManagementF.systemReady(); } catch (Throwable e) { reportWtf("making Network Managment Service ready", e); } CountDownLatch networkPolicyInitReadySignal = null; if (networkPolicyF ! = null) { networkPolicyInitReadySignal = networkPolicyF .networkScoreAndNetworkManagementServiceReady(); } traceEnd(); traceBeginAndSlog("MakeIpSecServiceReady"); try { if (ipSecServiceF ! = null) ipSecServiceF.systemReady(); } catch (Throwable e) { reportWtf("making IpSec Service ready", e); } traceEnd(); traceBeginAndSlog("MakeNetworkStatsServiceReady"); try { if (networkStatsF ! = null) networkStatsF.systemReady(); } catch (Throwable e) { reportWtf("making Network Stats Service ready", e); } traceEnd(); traceBeginAndSlog("MakeConnectivityServiceReady"); try { if (connectivityF ! = null) connectivityF.systemReady(); } catch (Throwable e) { reportWtf("making Connectivity Service ready", e); } traceEnd(); traceBeginAndSlog("MakeNetworkPolicyServiceReady"); try { if (networkPolicyF ! = null) { networkPolicyF.systemReady(networkPolicyInitReadySignal); } } catch (Throwable e) { reportWtf("making Network Policy Service ready", e); } traceEnd(); traceBeginAndSlog("StartWatchdog"); Watchdog.getInstance().start(); traceEnd(); . }, BOOT_TIMINGS_TRACE_LOG); }Copy the code

At this time, many services are initialized, such as inputManager, network and so on. The rest of the system’s invoked services will be implemented here.

ActivityManagerService.systemReady

The services that need to be initialized are then initialized in the AMS systemReady callback. SystemReady has changed a lot, with only three lines in version 7.0, and now some of the most important functions are in systemReady.

  public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {


        synchronized (this) {
            // Only start up encryption-aware persistent apps; once user is
            // unlocked we'll come back around and start unaware apps
            startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);

            // Start up initial activity.
            mBooting = true;
            // Enable home activity for system user, so that the system can always boot. We don't
            // do this when the system user is not setup since the setup wizard should be the one
            // to handle home activity in this case.
            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();
                }
            }
            startHomeActivityLocked(currentUserId, "systemReady");
          }
...
}
Copy the code

The systemReady method configures the current process into the AMS process list, initializes the PMS, and prepares for the subsequent launch of the Home screen to read the interface App in the Launcher directory. Finally, it obtains the UserController to obtain the current user ID. Start creating the Home interface with startHomeActivityLocked.

ActivityManagerService.startHomeActivityLocked

boolean startHomeActivityLocked(int userId, String reason) { ... 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); 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) { intent.setFlags(intent.getFlags() | 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; mActivityStartController.startHomeActivity(intent, aInfo, myReason); } } else { Slog.wtf(TAG, "No home screen found for " + intent, new Throwable()); } return true; }Copy the code

From here, we can clearly know that there are two main things to do:

1. In the first step, use getHomeIntent to obtain the package set to the interface using PackageManagerService. And get the corresponding ActivityInfo.

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; }Copy the code

HomeIntent principle explanation to add an Intent. CATEGORY_HOME identification, through the PMS to find, add android. The Intent. The category. The HOME AndroidManifest. The XML packages.

<category android:name="android.intent.category.HOME" />
Copy the code

2. Step 2, start the Home screen by assigning ProcessRecord and using the ActivityStartController.

This new class, starting with Android 9.0, separates the responsibilities of ActivityStack and gives them to the ActivityStartController. After that, I’ll walk you through the entire Android 9.0 Activity startup, removing the core message center mH (a Handler) in the ActivityThread and handing over each lifecycle to a state machine.

The ActivityStartController startHomeActivity

    void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason) {
        mSupervisor.moveHomeStackTaskToTop(reason);

        mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
                .setOutActivity(tmpOutRecord)
                .setCallingUid(0)
                .setActivityInfo(aInfo)
                .execute();
        mLastHomeActivityStartRecord = tmpOutRecord[0];
        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();
        }
Copy the code

The key method for two moveHomeStackTaskToTop and scheduleResumeTopActivities

1. moveHomeStackTaskToTop

    void moveHomeStackTaskToTop() {
        if (!isActivityTypeHome()) {
            throw new IllegalStateException("Calling moveHomeStackTaskToTop() on non-home stack: "
                    + this);
        }
        final int top = mTaskHistory.size() - 1;
        if (top >= 0) {
            final TaskRecord task = mTaskHistory.get(top);
            if (DEBUG_TASKS || DEBUG_STACK) Slog.d(TAG_STACK,
                    "moveHomeStackTaskToTop: moving " + task);
            mTaskHistory.remove(top);
            mTaskHistory.add(top, task);
            updateTaskMovement(task, true);
        }
    }
Copy the code

If there is an Activity in the Activity stack, update the Home Activity to the top.

2.scheduleResumeTopActivities

    final void scheduleResumeTopActivities() {
        if (!mHandler.hasMessages(RESUME_TOP_ACTIVITY_MSG)) {
            mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
        }
    }
Copy the code

This is handled by the AMS internal Handler

private final class ActivityStackSupervisorHandler extends Handler 
Copy the code

This Handler is passed in as looper generated in SystemServer. Including RESUME_TOP_ACTIVITY_MSG resumeFocusedStackTopActivityLocked branch will call.

boolean resumeFocusedStackTopActivityLocked( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) { if (! readyToResume()) { return false; } if (targetStack ! = null && isFocusedStack(targetStack)) { return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); } final ActivityRecord r = mFocusedStack.topRunningActivityLocked(); if (r == null || ! r.isState(RESUMED)) { mFocusedStack.resumeTopActivityUncheckedLocked(null, null); } else if (r.isState(RESUMED)) { // Kick off any lingering app transitions form the MoveTaskToFront operation. mFocusedStack.executeAppTransition(targetOptions); } return false; }Copy the code

It will determine if the ActivityRecord corresponding to the current stack exists. So at this moment right now is the first open ActivityRecord has not generated, resumeTopActivityUncheckedLocked will go.

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { ... if (prev ! = null && prev ! = next) { ... } else { // Whoops, need to restart this activity! if (! next.hasBeenLaunched) { next.hasBeenLaunched = true; } else { if (SHOW_APP_STARTING_PREVIEW) { next.showStartingWindow(null /* prev */, false /* newTask */, false /* taskSwich */); } if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next); } if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next); mStackSupervisor.startSpecificActivityLocked(next, true, true); } if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; }Copy the code

Because at this time will surely there is no Activity, must start by ActivityStackSupervisor startSpecificActivityLocked at this time.

To start the Activity by startSpecificActivityLocked at this time.

Launcher

The way Home reads App data is a bit complicated, but here’s how it works, along with a few key classes.

1.LauncherModel manages the data in the Launcher interface, and comprehensively manages the reading of apps, Appwidgets, etc

2.AllAppList Stores AppInfo objects

3.LoaderResults This is the result object after reading the data

4.LoaderTask Asynchronously loads the App information class

5.AllAppsContainerView Container of the App icon

Let’s start by looking at some of the key loading data in the Launcher and the location of the initialized View:

@Override protected void onCreate(Bundle savedInstanceState) { ... super.onCreate(savedInstanceState); . LauncherAppState app = LauncherAppState.getInstance(this); mOldConfig = new Configuration(getResources().getConfiguration()); mModel = app.setLauncher(this); mAllAppsController = new AllAppsTransitionController(this); mStateManager = new LauncherStateManager(this); UiFactory.onCreate(this); mLauncherView = LayoutInflater.from(this).inflate(R.layout.launcher, null); . setupViews(); . mAppTransitionManager = LauncherAppTransitionManager.newInstance(this); . 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(); . }Copy the code

The rest is the core approach we need to focus on. We will start to analyze the principle of Google’s Home interface with the onCreate method as the core.

Initialization can be roughly divided into three steps:

1. Initialize LauncherModel

2. Initialize AllAppContainer

3. Call startLoader to start loading

Let’s start by looking at the setLauncher method of LauncherAppState

    LauncherModel setLauncher(Launcher launcher) {
        getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
        mModel.initialize(launcher);
        return mModel;
    }
Copy the code

Now the Launcher initializes the Model, the core of the entire interface, and Laucher initializes it through the init method. Initialize AllAppList.

2. Initialize the view container of app Icon

private void setupViews() {
...

        // Setup Apps
        mAppsView = findViewById(R.id.apps_view);

        // Setup the drag controller (drop targets have to be added in reverse order in priority)
        mDragController.setMoveTarget(mWorkspace);
        mDropTargetBar.setup(mDragController);

        mAllAppsController.setupViews(mAppsView);
    }
Copy the code

With the basic data container ready, the next step is to initialize the View.

MAppsView is our App icon to load the container, the view through AllAppsTransitionController to control the class.

3.LauncherModel. startLoader

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) { ... } else { startLoaderForResults(loaderResults); } } } return false; }Copy the code
public void startLoaderForResults(LoaderResults results) { synchronized (mLock) { stopLoader(); mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results); runOnWorkerThread(mLoaderTask); }}Copy the code

Since Home has not been loaded at this point, the method below will be called to start the LoadTask method, start the thread, and load the app data.

LoadTask

public void run() { synchronized (this) { // Skip fast if we are already stopped. if (mStopped) { return; }}... try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { ... loadAllApps(); mResults.bindAllApps(); . } catch (CancellationException e) { // Loader stopped, ignore TraceHelper.partitionSection(TAG, "Cancelled"); }}Copy the code

Here, we’re just going to focus on the method of reading App information.

    private void loadAllApps() {
        final List<UserHandle> profiles = mUserManager.getUserProfiles();

        // Clear the list of apps
        mBgAllAppsList.clear();
        for (UserHandle user : profiles) {
            // Query for the set of apps
            final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
            // Fail if we don't have any apps
            // TODO: Fix this. Only fail for the current user.
            if (apps == null || apps.isEmpty()) {
                return;
            }
            boolean quietMode = mUserManager.isQuietModeEnabled(user);
            // Create the ApplicationInfos
            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);
            }
        }

        if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {
            // get all active sessions and add them to the all apps list
            for (PackageInstaller.SessionInfo info :
                    mPackageInstaller.getAllVerifiedSessions()) {
                mBgAllAppsList.addPromiseApp(mApp.getContext(),
                        PackageInstallerCompat.PackageInstallInfo.fromInstallingState(info));
            }
        }

        mBgAllAppsList.added = new ArrayList<>();
    }
Copy the code

The mBgAllAppsList is actually the AllAppList object I mentioned above, stored in which app-related data is read by mLauncherApps (this is via context.launcher_service).

AllAppContainer

Once the data is ready, call back to the upper layer using the bindApp method of LoadResult to refresh the AllAppContainer.

public AllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); . mAH = new AdapterHolder[2]; mAH[AdapterHolder.MAIN] = new AdapterHolder(false /* isWork */); mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */); mAllAppsStore.addUpdateListener(this::onAppsUpdated); . }Copy the code

The AdapterHolder object is very important in this container, which can be seen as a page that we normally display App ICONS.

Remember the bindApp function above. This method will go back to the Launcher and bind the data to the AppStore in AllAppContainer using the bindApplication. Once updated it wakes up the onAppsUpdated method in the AppStore.

    private void onAppsUpdated() {
        if (FeatureFlags.ALL_APPS_TABS_ENABLED) {
            boolean hasWorkApps = false;
            for (AppInfo app : mAllAppsStore.getApps()) {
                if (mWorkMatcher.matches(app, null)) {
                    hasWorkApps = true;
                    break;
                }
            }
            rebindAdapters(hasWorkApps);
}
      
Copy the code

At this point, just like our normal functions, the data is bound to the RecyclerView in the AdapterHolder.

private void rebindAdapters(boolean showTabs, boolean force) { if (showTabs == mUsingTabs && ! force) { return; } replaceRVContainer(showTabs); mUsingTabs = showTabs; mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.MAIN].recyclerView); mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.WORK].recyclerView); if (mUsingTabs) { mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher); mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher); onTabChanged(mViewPager.getNextPage()); } else { mAH[AdapterHolder.MAIN].setup(findViewById(R.id.apps_list_view), null); mAH[AdapterHolder.WORK].recyclerView = null; } setupHeader(); mAllAppsStore.registerIconContainer(mAH[AdapterHolder.MAIN].recyclerView); mAllAppsStore.registerIconContainer(mAH[AdapterHolder.WORK].recyclerView); }Copy the code

Now let’s look at the adapterholder.setup method.

        void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
            appsList.updateItemFilter(matcher);
            recyclerView = (AllAppsRecyclerView) rv;
            recyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
            recyclerView.setApps(appsList, mUsingTabs);
            recyclerView.setLayoutManager(layoutManager);
            recyclerView.setAdapter(adapter);
            recyclerView.setHasFixedSize(true);
            // No animations will occur when changes occur to the items in this RecyclerView.
            recyclerView.setItemAnimator(null);
            FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(recyclerView);
            recyclerView.addItemDecoration(focusedItemDecorator);
            adapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
            applyVerticalFadingEdgeEnabled(verticalFadingEdge);
            applyPadding();
        }
Copy the code

At this point, readers who have done Android will immediately know where to start with the next source code. Let’s go straight to the Adapter and see how the click event in the adapter actually works.

AllAppsGridAdapter

@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case VIEW_TYPE_ICON: BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate( R.layout.all_apps_icon, parent, false); icon.setOnClickListener(ItemClickHandler.INSTANCE); icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_ALL_APPS); icon.setLongPressTimeout(ViewConfiguration.getLongPressTimeout()); icon.setOnFocusChangeListener(mIconFocusListener); // Ensure the all apps icon height matches the workspace icons in portrait mode. icon.getLayoutParams().height = mLauncher.getDeviceProfile().allAppsCellHeightPx; return new ViewHolder(icon); . }Copy the code

ItemClickHandler here. The INSTANCE is the core:

public static final OnClickListener INSTANCE = ItemClickHandler::onClick; private static void onClick(View v) { // Make sure that rogue clicks don't get through while allapps is launching, or after the // view has detached (it's possible for this to happen if the view is removed mid touch). if (v.getWindowToken() == null) { return; } Launcher launcher = Launcher.getLauncher(v.getContext()); if (! launcher.getWorkspace().isFinishedSwitchingState()) { return; } Object tag = v.getTag(); if (tag instanceof ShortcutInfo) { onClickAppShortcut(v, (ShortcutInfo) tag, launcher); } else if (tag instanceof FolderInfo) { if (v instanceof FolderIcon) { onClickFolderIcon(v); } } else if (tag instanceof AppInfo) { startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher); } else if (tag instanceof LauncherAppWidgetInfo) { if (v instanceof PendingAppWidgetHostView) { onClickPendingWidget((PendingAppWidgetHostView) v, launcher); }}}Copy the code

This is the core method for handling various click events. And our tag must be AppInfo, so if we look at this method,

private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
        ...
        launcher.startActivitySafely(v, intent, item);
    }
Copy the code

Here’s how you know that the startActivitySafely method on the Launcher will be called back. Finally, call startActivitySafely.

public boolean startActivitySafely(View v, Intent intent, ItemInfo item) { if (mIsSafeModeEnabled && ! Utilities.isSystemApp(this, intent)) { Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show(); return false; } // Only launch using the new animation if the shortcut has not opted out (this is a // private contract between launcher and may be ignored in the future). boolean useLaunchAnimation = (v ! = null) && ! intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION); Bundle optsBundle = useLaunchAnimation ? getActivityLaunchOptionsAsBundle(v) : null; UserHandle user = item == null ? null : item.user; // Prepare intent intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (v ! = null) { intent.setSourceBounds(getViewBounds(v)); } try { boolean isShortcut = Utilities.ATLEAST_MARSHMALLOW && (item instanceof ShortcutInfo) && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) && ! ((ShortcutInfo) item).isPromise(); if (isShortcut) { // Shortcuts need some special checks due to legacy reasons. startShortcutIntentSafely(intent, optsBundle, item); } else if (user == null || user.equals(Process.myUserHandle())) { // Could be launching some bookkeeping activity startActivity(intent, optsBundle); } else { LauncherAppsCompat.getInstance(this).startActivityForProfile( intent.getComponent(), user, intent.getSourceBounds(), optsBundle); } getUserEventDispatcher().logAppLaunch(v, intent); return true; } catch (ActivityNotFoundException|SecurityException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e); } return false; }Copy the code

When the core point is concerned, startActivity(Intent, optsBundle) is called; Start the Activity.

What about detecting androidmanifest.xml? Not said good call this method must be checked once, otherwise will report an exception?

Remember that this is done implicitly by calling the package name +category to MAIN, and the PMS will be further resolved in LauncherActivityInfo. So there are no worries in plug-in framework analysis.

conclusion

Sequence diagram of Home App button clicks