Android桌面Launcher3的启动

QuibblerQuibbler 2020-06-21 约 41 分钟 2985 次阅读

Android桌面Launcher3的启动

SystemServer启动会在startBootstrapServices()方法中启动引导带服务,其中就包括PackageManagerService(这里判断了手机是否是工厂模式)。而包管理服务和接下来要分析的Launcher启动有很大关系。SystemServer启动流程参考《SystemServer系统服务启动》。

private void startBootstrapServices() {
    	...
         try {
            Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
            mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
        } finally {
            Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
        }
        mFirstBoot = mPackageManagerService.isFirstBoot();
        mPackageManager = mSystemContext.getPackageManager();
        ...
    }

startOtherServices

接着在SystemServer的run()方法中调用startOtherServices(),单个方法目前见到比较长的总共1300余行。Android系统为了尽可能的提高执行速度,不会考虑各种方法的差分,代码简洁。毕竟是系统,效率优先。

/**
     * Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
     */
    private void startOtherServices() {
        	...
    	    traceBeginAndSlog("InstallSystemProviders");
            mActivityManagerService.installSystemProviders();
            // Now that SettingsProvider is ready, reactivate SQLiteCompatibilityWalFlags
            SQLiteCompatibilityWalFlags.reset();
            traceEnd();
            ...
            mActivityManagerService.systemReady(() -> {...}, BOOT_TIMINGS_TRACE_LOG)
            ...
    }

在该方法中调用了ActivityManagerService的systemReady(Runnable , TimingsTraceLog)方法,用的是Lambda表达式(低API系统源码还没有,看来Google与时俱进,重构源码),其实展开又有200多行代码,主要执行:

mActivityManagerService.systemReady(() -> {
        mSystemServiceManager.startBootPhase(
                SystemService.PHASE_ACTIVITY_MANAGER_READY);
        try {
            mActivityManagerService.startObservingNativeCrashes();
        } catch (Throwable e) {
            reportWtf("observing native crashes", e);
        }
        try {
            //看来从这个时候开始Android开始监控NE异常
            mActivityManagerService.startObservingNativeCrashes();
        } catch (Throwable e) {
            reportWtf("observing native crashes", e);
        }
        ...
    }

给SystemServiceManager设置一个标记:为到目前为止已启动所有系统服务指定的引导阶段。

/**
     * Starts the specified boot phase for all system services that have been started up to
     * this point.
     *
     * @param phase The boot phase to start.
     */
    public void startBootPhase(final int phase) {
        if (phase <= mCurrentPhase) {
            throw new IllegalArgumentException("Next phase must be larger than previous");
        }
        mCurrentPhase = phase;
        ...
    }

标记值定义在SystemService中:

/**
     * After receiving this boot phase, services can broadcast Intents.
     */
    public static final int PHASE_ACTIVITY_MANAGER_READY = 550;

systemReady

回到systemReady(Runnable , TimingsTraceLog)方法继续,定义在ActivityManagerService中:

public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
        traceLog.traceBegin("PhaseActivityManagerReady");
        synchronized(this) {
            if (mSystemReady) {
                // If we're done calling all the receivers, run the next "boot phase" passed in
                // by the SystemServer
                if (goingCallback != null) {
                    goingCallback.run();
                }
                return;
            }
            ...
        }
        ...
        mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
        mUserController.sendUserSwitchBroadcasts(-1, currentUserId);
        ...
    }

除了执行传入的Runnable类型的Lambda表达式,还有两部重要的方法调用(参考《Android进阶解密》)。

resumeTopActivities

先来看第一个方法,mAtmInternal是ActivityTaskManagerInternal类型,ActivityTaskManagerInternal是抽象类型,真正的实现类是ActivityTaskManagerService中的静态内部类LocalService。实现了resumeTopActivities(boolean scheduleIdle)方法:

@Override
    public void resumeTopActivities(boolean scheduleIdle) {
        synchronized (mGlobalLock) {
            mRootActivityContainer.resumeFocusedStacksTopActivities();
            if (scheduleIdle) {
                mStackSupervisor.scheduleIdleLocked();
            }
        }
    }

相比之前的源码有所变化,这部分代码本来是直接放在ActivityManagerService中的systemReady(Runnable , TimingsTraceLog)方法中调用。

mRootActivityContainer对象是RootActivityContainer类型,resumeFocusedStacksTopActivities()定义:

boolean resumeFocusedStacksTopActivities() {
        return resumeFocusedStacksTopActivities(null, null, null);
    }

继续追resumeFocusedStacksTopActivities(null, null, null)方法,该方法的完整定义如下:

boolean resumeFocusedStacksTopActivities(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
        if (!mStackSupervisor.readyToResume()) {
            return false;
        }
        boolean result = false;
        //由于传入的是null,在新的系统版本中不会执行这里
        if (targetStack != null && (targetStack.isTopStackOnDisplay()
                || getTopDisplayFocusedStack() == targetStack)) {
            result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            boolean resumedOnDisplay = false;
            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = display.getChildAt(stackNdx);
                final ActivityRecord topRunningActivity = stack.topRunningActivityLocked();
                if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
                    continue;
                }
                if (stack == targetStack) {
                    // Simply update the result for targetStack because the targetStack had
                    // already resumed in above. We don't want to resume it again, especially in
                    // some cases, it would cause a second launch failure if app process was dead.
                    resumedOnDisplay |= result;
                    continue;
                }
                if (display.isTopStack(stack) && topRunningActivity.isState(RESUMED)) {
                    // Kick off any lingering app transitions form the MoveTaskToFront operation,
                    // but only consider the top task and stack on that display.
                    stack.executeAppTransition(targetOptions);
                } else {
                    resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target);
                }
            }
            if (!resumedOnDisplay) {
                // In cases when there are no valid activities (e.g. device just booted or launcher
                // crashed) it's possible that nothing was resumed on a display. Requesting resume
                // of top activity in focused stack explicitly will make sure that at least home
                // activity is started and resumed, and no recursion occurs.
                final ActivityStack focusedStack = display.getFocusedStack();
                if (focusedStack != null) {
                    //执行这里
                    focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
                }
            }
        }
        return result;
    }

注意,源码重构之后与以往的代码流程不同,之前是调用resumeFocusedStacksTopActivities(null, null, null)方法,传入的参数均为null,不会执行老版系统的逻辑,而是走下面的新增的代码段:

...
        if (focusedStack != null) {
            //执行这里
            focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
    ...

focusedStack是ActivityStack类型,用来描述Activity堆栈,resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options)方法

/**
     * 确保堆栈中的置顶Activity已恢复resumed。
     *
     * @param prev 在暂停过程中先前恢复的活动; 可以为null,以从其他地方调用。
     * @param options Activity 选项。
     *
     * @return 如果正在恢复某些操作,则返回true;否则,则返回false。
     *
     * NOTE: 直接调用此方法并不安全,因为它可能导致非焦点堆栈中的活动恢复。 使用
     * RootActivityContainer#resumeFocusedStacksTopActivities恢复当前系统状态的正确活动。
     */
    @GuardedBy("mService")
    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        if (mInResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }
        boolean result = false;
        try {
            mInResumeTopActivity = true;
            result = resumeTopActivityInnerLocked(prev, options);
            final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
            if (next == null || !next.canTurnScreenOn()) {
                checkReadyForSleep();
            }
        } finally {
            mInResumeTopActivity = false;
        }
        return result;
    }

方法中调又用了resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options)方法,该方法定义如下:

@GuardedBy("mService")
    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        if (!mService.isBooting() && !mService.isBooted()) {
            // Not ready yet!
            return false;
        }
        // Find the next top-most activity to resume in this stack that is not finishing and is
        // focusable. If it is not focusable, we will fall into the case below to resume the
        // top activity in the next focusable task.
        ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
        final boolean hasRunningActivity = next != null;
        // TODO: Maybe this entire condition can get removed?
        if (hasRunningActivity && !isAttached()) {
            return false;
        }
        ...
        if (!hasRunningActivity) {
            // There are no activities left in the stack, let's look somewhere else.
            return resumeNextFocusableActivityWhenStackIsEmpty(prev, options);
        }
        ...
    }

这里查看的是Android Q的系统源码,和以往的源码有很大不同,稍有不慎就追踪方法丢了。hasRunningActivity为false,表示已经没有Activity活动,也就是需要返回到桌面Launcher了,这里走的是resumeNextFocusableActivityWhenStackIsEmpty(...)方法:

private boolean resumeNextFocusableActivityWhenStackIsEmpty(ActivityRecord prev,
            ActivityOptions options) {
        final String reason = "noMoreActivities";
        if (!isActivityTypeHome()) {
            final ActivityStack nextFocusedStack = adjustFocusToNextFocusableStack(reason);
            if (nextFocusedStack != null) {
                // Try to move focus to the next visible stack with a running activity if this
                // stack is not covering the entire screen or is on a secondary display with no home
                // stack.
                return mRootActivityContainer.resumeFocusedStacksTopActivities(nextFocusedStack,
                        prev, null /* targetOptions */);
            }
        }
        // If the current stack is a home stack, or if focus didn't switch to a different stack -
        // just start up the Launcher...
        ActivityOptions.abort(options);
        if (DEBUG_STATES) Slog.d(TAG_STATES,
                "resumeNextFocusableActivityWhenStackIsEmpty: " + reason + ", go home");
        return mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId);
    }

在方法最后调用mRootActivityContainer对象,也就是RootActivityContainer 类中的resumeHomeActivity(...)方法

boolean resumeHomeActivity(ActivityRecord prev, String reason, int displayId) {
        if (!mService.isBooting() && !mService.isBooted()) {
            // Not ready yet!
            return false;
        }
        if (displayId == INVALID_DISPLAY) {
            displayId = DEFAULT_DISPLAY;
        }
        final ActivityRecord r = getActivityDisplay(displayId).getHomeActivity();
        final String myReason = reason + " resumeHomeActivity";
        // Only resume home activity if isn't finishing.
        if (r != null && !r.finishing) {
            r.moveFocusableActivityToTop(myReason);
            return resumeFocusedStacksTopActivities(r.getActivityStack(), prev, null);
        }
        return startHomeOnDisplay(mCurrentUser, myReason, displayId);
    }

调用链->startHomeOnDisplay(int userId, String reason, int displayId)

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

调用链->startHomeOnDisplay(...)

boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting,
            boolean fromHomeKey) {
        // Fallback to top focused display if the displayId is invalid.
        if (displayId == INVALID_DISPLAY) {
            displayId = getTopDisplayFocusedStack().mDisplayId;
        }
        Intent homeIntent = null;
        ActivityInfo aInfo = null;
        if (displayId == DEFAULT_DISPLAY) {
            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;
        }
        // Updates the home component of the intent.
        homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
        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);
        }
        // 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) + ":" + displayId;
        mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
                displayId);
        return true;
    }

通过调用mService的getHomeIntent()方法获取桌面启动的Intent并且设置各种参数、flag。这里明显和之前的不同,之前该方法是在当前类中,现在移动到了ActivityTaskManagerService中去获取桌面的Intent。

最后通过调用mService的getActivityStartController()方法获取ActivityStartController对象mActivityStartController,调用ActivityStartController的startHomeActivity(...)方法启动桌面:

void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, int displayId) {
        final ActivityOptions options = ActivityOptions.makeBasic();
        options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
        if (!ActivityRecord.isResolverActivity(aInfo.name)) {
            // The resolver activity shouldn't be put in home stack because when the foreground is
            // standard type activity, the resolver activity should be put on the top of current
            // foreground instead of bring home stack to front.
            options.setLaunchActivityType(ACTIVITY_TYPE_HOME);
        }
        options.setLaunchDisplayId(displayId);
        mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
                .setOutActivity(tmpOutRecord)
                .setCallingUid(0)
                .setActivityInfo(aInfo)
                .setActivityOptions(options.toBundle())
                .execute();
        mLastHomeActivityStartRecord = tmpOutRecord[0];
        final ActivityDisplay display =
                mService.mRootActivityContainer.getActivityDisplay(displayId);
        final ActivityStack homeStack = display != null ? display.getHomeStack() : null;
        if (homeStack != null && homeStack.mInResumeTopActivity) {
            // 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();
        }
    }

接下来就和启动普通的应用一样,通过Intent启动桌面应用。桌面到此随着系统的启动而启动完成!Launcher3系统APP启动加载桌面图标见《Launcher加载APP图标流程》

参考资料:

        Android高级进阶>第二章 Android系统启动

        Android的Launcher启动过程分析

        Activity相关学习-启动-resumeTopActivityInnerLocked

        APP启动流程

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w