Launch的启动

1,596 阅读8分钟

android源码分析目录

注:以下代码分析基于android-10.0.0_r30)

一 概述

之前介绍Zygote进程启动的时候说到了Zygote会启动SystemServer,然后在SystemServer启动的最后会调用到ActivityManagerService的systemReady,在这个systemReady中,就会执行桌面启动的逻辑,接下来,就来看看桌面是如何启动的,并且又是如何将系统安装的应用显示在桌面上的

源码目录

frameworks/base/services/java/com/android/server/SystemServer.java
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
frameworks/base/services/core/java/com/android/server/wm/RootActivityContainer.java
frameworks/base/services/core/java/com/android/server/wm/ActivityStartController.java
packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
packages/apps/Launcher3/src/com/android/launcher3/LauncherModel.java
packages/apps/Launcher3/src/com/android/launcher3/model/LoaderTask.java
packages/apps/Launcher3/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
packages/apps/Launcher3/src/com/android/launcher3/model/BaseLoaderResults.java
packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java

二 ActivityManagerService启动Launch

2.1 mAtmInternal

在ActivityManagerService的systemReady中,会做一些准备工作,然后执行外部传入的Runnable,最后通过一个mAtmInternal.startHomeOnAllDisplays的方法来启动桌面

这个mAtmInternal,它是一个ActivityTaskManagerInternal对象,这个类是一个抽象类,它的实现类是ActivityTaskManagerService,所以在systemReady的方法中,最终启动桌面是通过调用ActivityTaskManagerService的startHomeOnAllDisplays来完成的

[ActivityManagerService.java]

LocalServices.getService(ActivityTaskManagerInternal.class)

2.2 systemReady

[ActivityManagerService.java]

public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
    traceLog.traceBegin("PhaseActivityManagerReady");
    synchronized(this) {
        //第一次是false
        if (mSystemReady) {
            // 如何调用完所有的receivers,就进入下一个阶段
            if (goingCallback != null) {
                goingCallback.run();
            }
            return;
        }

        mLocalDeviceIdleController
                = LocalServices.getService(DeviceIdleController.LocalService.class);
        mActivityTaskManager.onSystemReady();
        // 确认配置信息
        mUserController.onSystemReady();
        mAppOpsService.systemReady();
        mSystemReady = true;
    }

    try {
        sTheRealBuildSerial = IDeviceIdentifiersPolicyService.Stub.asInterface(
                ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE))
                .getSerial();
    } catch (RemoteException e) {}

    ArrayList<ProcessRecord> procsToKill = null;
    synchronized(mPidsSelfLocked) {
        for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
            ProcessRecord proc = mPidsSelfLocked.valueAt(i);
            if (!isAllowedWhileBooting(proc.info)){
                if (procsToKill == null) {
                    procsToKill = new ArrayList<ProcessRecord>();
                }
                procsToKill.add(proc);
            }
        }
    }

    synchronized(this) {
        if (procsToKill != null) {
            for (int i=procsToKill.size()-1; i>=0; i--) {
                ProcessRecord proc = procsToKill.get(i);
                Slog.i(TAG, "Removing system update proc: " + proc);
                mProcessList.removeProcessLocked(proc, true, false, "system update done");
            }
        }

        // 处理完毕系统更新的一些工作
        mProcessesReady = true;
    }

    //前面都是做的一些准备工作,下面正式启动
    Slog.i(TAG, "System now ready");
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY, SystemClock.uptimeMillis());

    mAtmInternal.updateTopComponentForFactoryTest();
    mAtmInternal.getLaunchObserverRegistry().registerLaunchObserver(mActivityLaunchObserver);

    //设置一些系统属性
    watchDeviceProvisioning(mContext);

    retrieveSettings();
    mUgmInternal.onSystemReady();

    final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
    if (pmi != null) {
        pmi.registerLowPowerModeObserver(ServiceType.FORCE_BACKGROUND_CHECK,
                state -> updateForceBackgroundCheck(state.batterySaverEnabled));
        updateForceBackgroundCheck(
                pmi.getLowPowerState(ServiceType.FORCE_BACKGROUND_CHECK).batterySaverEnabled);
    } else {
        Slog.wtf(TAG, "PowerManagerInternal not found.");
    }

    if (goingCallback != null) goingCallback.run();
    //在此处检查当前UserId

    if (currentUserId != UserHandle.USER_SYSTEM && !mUserController.isSystemUserStarted()) {
        //不是USER_SYSTEM
        throw new RuntimeException("System user not started while current user is:"
                + currentUserId);
    }
    traceLog.traceBegin("ActivityManagerStartApps");
    mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
            Integer.toString(currentUserId), currentUserId);
    mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,
            Integer.toString(currentUserId), currentUserId);

    //是USER_SYSTEM 
    final boolean bootingSystemUser = currentUserId == UserHandle.USER_SYSTEM;

    if (bootingSystemUser) {
        //设置UserId
        mSystemServiceManager.startUser(currentUserId);
    }

    synchronized (this) {
        //只启动支持加密的持久性的应用程序
        startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);

        mBooting = true;
        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();
            }
        }

        if (bootingSystemUser) {
            //启动Launch桌面
            mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
        }

        ...
    }
}

三 RootActivityContainer

3.1 startHomeOnAllDisplays

通过mAtmInternal.startHomeOnAllDisplays,实际调用的是ActivityTaskManagerService的startHomeOnAllDisplays

[ActivityTaskManagerService.java]

public boolean startHomeOnAllDisplays(int userId, String reason) {
    synchronized (mGlobalLock) {
        return mRootActivityContainer.startHomeOnAllDisplays(userId, reason);
    }
}

这里的mRootActivityContainer就是RootActivityContainer,它会经过一系列的调用,最后调用到startHomeOnDisplay

[RootActivityContainer.java]

boolean startHomeOnAllDisplays(int userId, String reason) {
    boolean homeStarted = false;
    for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
        final int displayId = mActivityDisplays.get(i).mDisplayId;
        //步骤1
        homeStarted |= startHomeOnDisplay(userId, reason, displayId);
    }
    return homeStarted;
}

boolean startHomeOnDisplay(int userId, String reason, int displayId) {
    //步骤2
    return startHomeOnDisplay(userId, reason, displayId, false /* allowInstrumenting */,
            false /* fromHomeKey */);
}

接下来,就具体看看这个做了那些事

3.2 startHomeOnDisplay

这里的启动方式,也是系统中比较常见的一种方式,就是构建出一个ActivityInfo,然后启动

  • 这里的mService是一个ActivityTaskManagerService
  • mService.getActivityStartController获得的是一个ActivityStartController,这个类是一个和的Activity启动相关的类
  • 最后调用的startHomeActivity就是ActivityStartController.startHomeActivity

[RootActivityContainer.java]

boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting,
        boolean fromHomeKey) {
    // 异常情况
    if (displayId == INVALID_DISPLAY) {
        displayId = getTopDisplayFocusedStack().mDisplayId;
    }

    //构造一个ActivityInfo和Intent
    Intent homeIntent = null;
    ActivityInfo aInfo = null;
    if (displayId == DEFAULT_DISPLAY) {
        //关键点:构建一个Launch的intent
        homeIntent = mService.getHomeIntent();
        aInfo = resolveHomeActivity(userId, homeIntent);
    } else if (shouldPlaceSecondaryHomeOnDisplay(displayId)) {
        Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, displayId);
        aInfo = info.first;
        homeIntent = info.second;
    }
    if (aInfo == null || homeIntent == null) {
        return false;
    }

    if (!canStartHomeOnDisplay(aInfo, displayId, allowInstrumenting)) {
        return false;
    }

    // 设置参数
    homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
    homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);

    if (fromHomeKey) {
        homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
    }
    //正式启动
    final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
            aInfo.applicationInfo.uid) + ":" + displayId;
    mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
            displayId);
    return true;
}

3.3 getHomeIntent

在RootActivityContainer的startHomeOnDisplay中,有着非常关键是一步,就是mService.getHomeIntent,它会构造一个隐式跳转的intent,拿到这个intent之后,就会通过startHomeActivity进行启动桌面Activity了

[ActivityTaskManagerService.java]

String mTopAction = Intent.ACTION_MAIN;

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;
}

到这里,我们桌面的启动的第一部分就算是完成了,当然,关于ActivityStartController之后是如何启动Activity的,这里就不深究了,放到以后Activity的启动流程详细说明,关于Activity的启动,又涉及到进程的启动,Activity的启动,AMS的通信等等,本篇的重心主要在桌面的启动和安装的应用是如何显示上

四 Launcher

4.1 Launch的AndroidManifest

现在开始是桌面启动的第二部分,经过AMS的一系列调用,最终通过隐士启动的方式,启动了Launcher,他是在packages/apps/Launcher3目录下的一个android项目,这个项目也只定义了一个Activity,就是Launch

[AndroidManifest.xml]

<manifest
    ...
    <application 
        ...
        <activity
            android:name="com.android.launcher3.Launcher"
            android:launchMode="singleTask"
            android:clearTaskOnLaunch="true"
            android:stateNotNeeded="true"
            android:windowSoftInputMode="adjustPan"
            android:screenOrientation="unspecified"
            android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
            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>
            <meta-data
                android:name="com.android.launcher3.grid.control"
                android:value="${packageName}.grid_control" />
        </activity>

    </application>
</manifest>

4.2 Launch.java

Launch是一个Activity,它继承自BaseDraggingActivity,在Launch的onCreate方法如下

  1. 创建一个LauncherAppState对象
  2. 创建一个mModel
  3. 加载一个mLauncherView
  4. 通过model加载桌面数据
  5. 将mLauncherView设置给ContentView
protected void onCreate(Bundle savedInstanceState) {
    ...

    super.onCreate(savedInstanceState);
    TraceHelper.partitionSection("Launcher-onCreate", "super call");
    //1 LauncherAppState对象,和app数据相关
    LauncherAppState app = LauncherAppState.getInstance(this);
    mOldConfig = new Configuration(getResources().getConfiguration());

    //2 通过这个app对象拿到一个model
    mModel = app.setLauncher(this);
    ...

    //3 初始化一个view
    mLauncherView = LayoutInflater.from(this).inflate(R.layout.launcher, null);

    ...

    //4 加载桌面数据
    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();

    ...//注册其他事件
}

显然,这个Launch使用的是MVVM的设计,在onCreate方法中构建了view和model,那么按照MVVK的逻辑,真正的数据肯定是通过model加载的,然后通过bindData进行数据绑定,首先我们先看这个model是如何加载数据的

4.3 LauncherModel.java

Launch中的model是LauncherModel

[LauncherModel.java]

public boolean startLoader(int synchronousBindPage) {
    ...
    synchronized (mLock) {

        if (mCallbacks != null && mCallbacks.get() != null) {
            final Callbacks oldCallbacks = mCallbacks.get();

            MAIN_EXECUTOR.execute(oldCallbacks::clearPendingBinds);

            // If there is already one running, tell it to stop.
            stopLoader();
            LoaderResults loaderResults = new LoaderResults(mApp, sBgDataModel,
                    mBgAllAppsList, synchronousBindPage, mCallbacks);
            if (mModelLoaded && !mIsLoaderTaskRunning) {
                //如何加载了,就绑定数据
                loaderResults.bindWorkspace();

                loaderResults.bindAllApps();
                loaderResults.bindDeepShortcuts();
                loaderResults.bindWidgets();
                return true;
            } else {
                //如果没有加载,就加载数据
                startLoaderForResults(loaderResults);
            }
        }
    }
    return false;
}

显然,如果是加载过数据,那么通过几行bind逻辑进行绑定数据,如何没有加载过数据,那么通过startLoaderForResults加载数据,我们第一次加载没有加载过数据,所以我们看startLoaderForResults的逻辑

4.4 LoaderTask

根据这个名字,我们都能猜到这是一个继承Runnable的类,那么它的关键逻辑就肯定在run中

[LoaderTask.java]

public void run() {
    synchronized (this) {
        // Skip fast if we are already stopped.
        if (mStopped) {
            return;
        }
    }

    TraceHelper.beginSection(TAG);
    try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
        TraceHelper.partitionSection(TAG, "step 1.1: loading workspace");
        //加载工作区
        loadWorkspace();

        //绑定工作区
        mResults.bindWorkspace();

        ...

        // 加载安装的app
        List<LauncherActivityInfo> allActivityList = loadAllApps();

        //绑定安装的app
        mResults.bindAllApps();

        ...

        transaction.commit();
    } ...
}

在这个run方法中,会加载很多数据,这里我们只看加载安装app的逻辑,其他的地方略去,这个加载安装app的逻辑是loadAllApps,

[LoaderTask.java]

private List<LauncherActivityInfo> loadAllApps() {
    final List<UserHandle> profiles = mUserManager.getUserProfiles();
    List<LauncherActivityInfo> allActivityList = new ArrayList<>();

    mBgAllAppsList.clear();
    for (UserHandle user : profiles) {
        //查询app list
        final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);

        if (apps == null || apps.isEmpty()) {
            //没有app,一般不会走
            return allActivityList;
        }

        boolean quietMode = mUserManager.isQuietModeEnabled(user);
        // 创建对应的ActivityInfo,我们点击图标的时候会用到
        for (int i = 0; i < apps.size(); i++) {
            LauncherActivityInfo app = apps.get(i);
            mBgAllAppsList.add(new AppInfo(app, user, quietMode), app);
        }
        //添加进集合
        allActivityList.addAll(apps);
    }

    ...
    return allActivityList;
}

这里又出现了一个mLauncherApps,这是一个LauncherAppsCompat,它是一个抽象类,有三个实现类,getActivityList这个方法就在它的实现类LauncherAppsCompatVL中

4.5 LauncherAppsCompatVL

[LauncherAppsCompatVL.java]

public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
    return mLauncherApps.getActivityList(packageName, user);
}

这里有一个mLauncherApps,它是一个LauncherApps,这个LauncherApps他是LauncherAppsService的binder对象在client端的封装对象,通过LauncherApps,我们就可以进行进程间的通信,调用到LauncherAppsService

//mLauncherApps的创建
mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);

[LauncherApps.java]

public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
    logErrorForInvalidProfileAccess(user);
    try {
        return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
                packageName, user), user);
    } catch (RemoteException re) {
        throw re.rethrowFromSystemServer();
    }
}

这里的mService.getLauncherActivities就会调用到LauncherAppsService的getLauncherActivities

五 LauncherAppsService

5.1 getLauncherActivities

在LauncherAppsService的getLauncherActivities中,会调用queryActivitiesForUser,然后在这个方法中,通过getService拿到一个PackageManagerService的通信对象,然后通过这个对象调用PMS的queryIntentActivities

[LauncherAppsService.java]

@Override
public ParceledListSlice<ResolveInfo> getLauncherActivities(String callingPackage,
        String packageName, UserHandle user) throws RemoteException {
    ParceledListSlice<ResolveInfo> launcherActivities = queryActivitiesForUser(
            callingPackage,
            //创建一个查询用的intent
            new Intent(Intent.ACTION_MAIN)
                    .addCategory(Intent.CATEGORY_LAUNCHER)
                    .setPackage(packageName),
            user);
    ...
}

private ParceledListSlice<ResolveInfo> queryActivitiesForUser(String callingPackage,
        Intent intent, UserHandle user) {
    ...
    try {
        final PackageManagerInternal pmInt =
                LocalServices.getService(PackageManagerInternal.class);

        //通过传入的intent,获取安装的app
        List<ResolveInfo> apps = pmInt.queryIntentActivities(intent,
                PackageManager.MATCH_DIRECT_BOOT_AWARE
                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                callingUid, user.getIdentifier());
        return new ParceledListSlice<>(apps);
    } finally {
        injectRestoreCallingIdentity(ident);
    }
}

通过LauncherAppsService和PackageManagerService的调用,最后拿到了一个安装app的数据列表,接下来看LoaderTask中是如何进行数据绑定的

六 BaseLoaderResults

在LoaderTask的loadAllApps之后,是mResults.bindAllApps。这个mResults是一个LoaderResults,它是一个继承自BaseLoaderResults的子类

[BaseLoaderResults.java]

public void bindAllApps() {
    AppInfo[] apps = mBgAllAppsList.copyData();
    executeCallbacksTask(c -> c.bindAllApplications(apps), mUiExecutor);
}

在这里拿到了数据之后,会通过回调调用bindAllApplications,这个接口是Launch实现的

4.4 BaseLoaderResults

这里的LoaderResults是BaseLoaderResults的一个子类,它的bindAllApps逻辑是在父类中的

[Launch.java]

AllAppsContainerView mAppsView;

public void bindAllApplications(AppInfo[] apps) {
    mAppsView.getAppsStore().setApps(apps);
}

[AllAppsContainerView.java]

public AllAppsStore getAppsStore() {
    return mAllAppsStore;
}

private void onAppsUpdated() {
    if (FeatureFlags.ALL_APPS_TABS_ENABLED) {
        ...
        rebindAdapters(hasWorkApps);
    }
}

所以调用setApps实际上会调用到AllAppsStore中,然后通过AllAppsStore.setApps时的回调,又调用到AllAppsContainerView的onAppsUpdated,然后根据一系列的调用,最后调用到replaceRVContainer

[AllAppsContainerView.java]

private void rebindAdapters(boolean showTabs, boolean force) {
    if (showTabs == mUsingTabs && !force) {
        return;
    }
    replaceRVContainer(showTabs);
    ...
}

显然,根据这个方法的名字,也知道这里是一个刷新RecyclerView的方法

[AllAppsContainerView.java]

rivate void replaceRVContainer(boolean showTabs) {
    for (int i = 0; i < mAH.length; i++) {
        if (mAH[i].recyclerView != null) {
            mAH[i].recyclerView.setLayoutManager(null);
        }
    }
    View oldView = getRecyclerViewContainer();
    int index = indexOfChild(oldView);
    removeView(oldView);
    int layout = showTabs ? R.layout.all_apps_tabs : R.layout.all_apps_rv_layout;
    View newView = LayoutInflater.from(getContext()).inflate(layout, this, false);
    addView(newView, index);
    if (showTabs) {
        mViewPager = (AllAppsPagedView) newView;
        mViewPager.initParentViews(this);
        mViewPager.getPageIndicator().setContainerView(this);
    } else {
        mViewPager = null;
    }
}

到此,Launch的启动也算是完成了

总结

终于,从系统的启动,init进程,Zygote进程,SystemServer,Launch的一系列的启动过程终于是串联起来了,

  1. 在Launch的启动过程中,首先是通过SystemServer启动Launch来启动Activity,这里是通过隐式启动来完成的
  2. 然后在Launch中加载安装的应用信息,这里又使用的MVVM架构
  3. 在model中加载完数据后通过bindData进行显示
  4. 而加载数据又涉及到了LauncherAppsService和PackageManagerService
  5. 最后通过PackageManagerService拿到安装的apk数据
  6. 在AllAppsStore通过观察者的模式通知View刷新数据
  7. 最后就是View中replaceRVContainer刷新RecyclerView的数据