美文网首页
Launcher 是什么时候启动的(基于Android 14)

Launcher 是什么时候启动的(基于Android 14)

作者: smart_dev | 来源:发表于2023-10-14 13:39 被阅读0次

问题背景

  • 我们知道系统并没有直接提供启动进程的方式,总是有人发起调用(启动activity的时候会去判断相关进程在不在等流程)

  • Launcher 桌面本身是一个APP,当然也遵循普通APP进程的启动方式

  • 通常分析普通进程都是从Launcher桌面上点击一个图标开始,那桌面是什么时候启动的呢?谁来启动的呢?

问题结论

SystemServer进程启动后,会去调用AMS中的systemReady进而启动 Launcher

在这里我们只梳理:从哪里开始触发 到 如何找到launcher的activity 即可,因为后续的流程相当于是走的普通activity启动流程。

过程分析

  1. SystemServer 进程起来后,会去启动 AMS 等相关服务

  2. 其中在 startOtherServices() 方法中,会去调用AMS#systemReady

  3. AMS#systemReady 调用 ATMS#startHomeOnAllDisplays

  4. RootWindowContainer#startHomeOnDisplay 在这个方法中找到homeIntent,最终调用atms去启动这个intent

发起Launcher启动的时序图
/**
 * Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
 */
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    ...

    // We now tell the activity manager it is okay to run third party
    // code.  It will call back into us once it has gotten to the state
    // where third party code can really run (but before it has actually
    // started launching the initial applications), for us to complete our
    // initialization.
    mActivityManagerService.systemReady(() -> {
        ...
    }, t);
    ....
}
/**
 * Ready. Set. Go!
 */
public void systemReady(final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) {
    ....
    synchronized (this) {
        ....
        // 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 (SystemProperties.getBoolean(SYSTEM_USER_HOME_NEEDED, false)) {
            t.traceBegin("enableHomeActivity");

            ComponentName cName = new ComponentName(mContext, SystemUserHomeActivity.class);
            try {
                AppGlobals.getPackageManager().setComponentEnabledSetting(cName,
                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0,
                        UserHandle.USER_SYSTEM, "am");
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            }
            t.traceEnd();
        }

        boolean isBootingSystemUser = currentUserId == UserHandle.USER_SYSTEM;

        // Some systems - like automotive - will explicitly unlock system user then switch
        // to a secondary user.
        // TODO(b/266158156): this workaround shouldn't be necessary once we move
        // the headless-user start logic to UserManager-land.
        if (isBootingSystemUser && !UserManager.isHeadlessSystemUserMode()) {
            t.traceBegin("startHomeOnAllDisplays");
            mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
            t.traceEnd();
        }
        ....
    }

}
@Override
public boolean startHomeOnAllDisplays(int userId, String reason) {
    synchronized (mGlobalLock) {
        return mRootWindowContainer.startHomeOnAllDisplays(userId, reason);
    }
}
boolean startHomeOnAllDisplays(int userId, String reason) {
    boolean homeStarted = false;
    for (int i = getChildCount() - 1; i >= 0; i--) {
        final int displayId = getChildAt(i).mDisplayId;
        homeStarted |= startHomeOnDisplay(userId, reason, displayId);
    }
    return homeStarted;
}

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

boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea,
                                   boolean allowInstrumenting, boolean fromHomeKey) {
    // Fallback to top focused display area if the provided one is invalid.
    if (taskDisplayArea == null) {
        final Task rootTask = getTopDisplayFocusedRootTask();
        taskDisplayArea = rootTask != null ? rootTask.getDisplayArea()
                : getDefaultTaskDisplayArea();
    }

    Intent homeIntent = null;
    ActivityInfo aInfo = null;
    if (taskDisplayArea == getDefaultTaskDisplayArea()
            || mWmService.shouldPlacePrimaryHomeOnDisplay(
            taskDisplayArea.getDisplayId(), userId)) {
        // 去寻找 桌面的 intent
        homeIntent = mService.getHomeIntent();
        // 解析桌面activity的信息
        aInfo = resolveHomeActivity(userId, homeIntent);
    } else if (shouldPlaceSecondaryHomeOnDisplayArea(taskDisplayArea)) {
        Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, taskDisplayArea);
        aInfo = info.first;
        homeIntent = info.second;
    }
    if (aInfo == null || homeIntent == null) {
        return false;
    }

    if (!canStartHomeOnDisplayArea(aInfo, taskDisplayArea, allowInstrumenting)) {
        return false;
    }

    // Updates the home component of the intent.
    homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
    // 添加标志 FLAG_ACTIVITY_NEW_TASK
    homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
    // Updates the extra information of the intent.
    if (fromHomeKey) {
        homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
        if (mWindowManager.getRecentsAnimationController() != null) {
            mWindowManager.getRecentsAnimationController().cancelAnimationForHomeStart();
        }
    }
    homeIntent.putExtra(WindowManagerPolicy.EXTRA_START_REASON, reason);

    // Update the reason for ANR debugging to verify if the user activity is the one that
    // actually launched.
    final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
            aInfo.applicationInfo.uid) + ":" + taskDisplayArea.getDisplayId();
    // 到这里就要去正常的调用 atms 去启动Activity流程
    mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
            taskDisplayArea);
    return true;
}

相关文章

网友评论

      本文标题:Launcher 是什么时候启动的(基于Android 14)

      本文链接:https://www.haomeiwen.com/subject/ovdzbdtx.html