Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 89f43fc5 authored by Louis Chang's avatar Louis Chang
Browse files

Start home activities for all displays on boot

We were only starting home activity on default display when
system boot up. After system booted, home activities would be
started when new displays added. But in some cases, there
are more than one displays being ready before boot completed.
So it ended up with no home activities on secondary displays.

Making sure home activities can be launched on all displays
on boot now.

Also checks finishing booting when all resumed activities
on all displays are idle.

Bug: 111363427
Test: Manual
Test: atest ActivityStackSupervisorTests

Change-Id: I2291ce967bc6f2f03ca7f680c3d6a2d8e8f3cd08
parent 78ecd34d
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -129,7 +129,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
@@ -8380,7 +8379,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                    throw e.rethrowAsRuntimeException();
                }
            }
            mAtmInternal.startHomeActivity(currentUserId, "systemReady");
            mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
            mAtmInternal.showSystemReadyErrorDialogsIfNeeded();
+100 −10
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
import static android.app.WindowConfiguration.windowingModeToString;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static android.content.pm.PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY;
@@ -115,8 +116,8 @@ import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.IApplicationThread;
import android.app.ProfilerInfo;
import android.app.ResultInfo;
import android.app.WaitResult;
@@ -146,6 +147,7 @@ import android.hardware.power.V1_0.PowerHint;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
import android.os.FactoryTest;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -786,10 +788,24 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            r.moveFocusableActivityToTop(myReason);
            return resumeFocusedStacksTopActivitiesLocked(r.getStack(), prev, null);
        }
        return mService.startHomeActivityLocked(mCurrentUser, myReason, displayId);
        return startHomeOnDisplay(mCurrentUser, myReason, displayId);
    }

    boolean canStartHomeOnDisplay(ActivityInfo homeInfo, int displayId) {
        if (mService.mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                && mService.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;
        }

        final WindowProcessController app =
                mService.getProcessController(homeInfo.processName, homeInfo.applicationInfo.uid);
        if (app != null && app.isInstrumenting()) {
            // Don't do this if the home app is currently being instrumented.
            return false;
        }

    boolean canStartHomeOnDisplay(ActivityInfo homeActivity, int displayId) {
        if (displayId == DEFAULT_DISPLAY || (displayId != INVALID_DISPLAY
                && displayId == mService.mVr2dDisplayId)) {
            // No restrictions to default display or vr 2d display.
@@ -802,8 +818,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            return false;
        }

        final boolean supportMultipleInstance = homeActivity.launchMode != LAUNCH_SINGLE_TASK
                && homeActivity.launchMode != LAUNCH_SINGLE_INSTANCE;
        final boolean supportMultipleInstance = homeInfo.launchMode != LAUNCH_SINGLE_TASK
                && homeInfo.launchMode != LAUNCH_SINGLE_INSTANCE;
        if (!supportMultipleInstance) {
            // Can't launch home on other displays if it requested to be single instance.
            return false;
@@ -1037,12 +1053,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
                // We cannot only check the top stack on each display since there might have
                // always-on-top stacks (e.g. pinned stack).
                final ActivityStack stack = display.getChildAt(stackNdx);
                if (!isTopDisplayFocusedStack(stack) || stack.numActivities() == 0) {
                if (stack.numActivities() == 0) {
                    continue;
                }
                final ActivityRecord resumedActivity = stack.getResumedActivity();
                if (resumedActivity == null || !resumedActivity.idle) {
                if (resumedActivity != null && !resumedActivity.idle) {
                    if (DEBUG_STATES) Slog.d(TAG_STATES, "allResumedActivitiesIdle: stack="
                             + stack.mStackId + " " + resumedActivity + " not idle");
                    return false;
@@ -1895,7 +1913,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
    }

    /**
     * Called when the frontmost task is idle.
     * Called when all resumed tasks/stacks are idle.
     * @return the state of mService.mAm.mBooting before this was called.
     */
    @GuardedBy("mService")
@@ -1950,7 +1968,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            r.idle = true;

            //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
            if (isTopDisplayFocusedStack(r.getStack()) || fromTimeout) {

            // Make sure we can finish booting when all resumed activities are idle.
            if ((!mService.isBooted() && allResumedActivitiesIdle()) || fromTimeout) {
                booting = checkFinishBootingLocked();
            }

@@ -4107,7 +4127,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId);
        synchronized (mService.mGlobalLock) {
            getActivityDisplayOrCreateLocked(displayId);
            mService.startHomeActivityLocked(mCurrentUser, "displayAdded", displayId);
            startHomeOnDisplay(mCurrentUser, "displayAdded", displayId);
        }
    }

@@ -4185,6 +4205,76 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        return activityDisplay;
    }

    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;
            homeStarted |= startHomeOnDisplay(userId, reason, displayId);
        }
        return homeStarted;
    }

    /**
     * This starts home activity on displays that can have system decorations and only if the
     * home activity can have multiple instances.
     */
    boolean startHomeOnDisplay(int userId, String reason, int displayId) {
        final Intent homeIntent = mService.getHomeIntent();
        final ActivityInfo aInfo = resolveHomeActivity(userId, homeIntent);
        if (aInfo == null) {
            return false;
        }

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

        // 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);
        mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
                displayId);
        return true;
    }

    /**
     * This resolves the home activity info and updates the home component of the given intent.
     * @return the home activity info if any.
     */
    private ActivityInfo resolveHomeActivity(int userId, Intent homeIntent) {
        final int flags = ActivityManagerService.STOCK_PM_FLAGS;
        final ComponentName comp = homeIntent.getComponent();
        ActivityInfo aInfo = null;
        try {
            if (comp != null) {
                // Factory test.
                aInfo = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
            } else {
                final String resolvedType =
                        homeIntent.resolveTypeIfNeeded(mService.mContext.getContentResolver());
                final ResolveInfo info = AppGlobals.getPackageManager()
                        .resolveIntent(homeIntent, resolvedType, flags, userId);
                if (info != null) {
                    aInfo = info.activityInfo;
                }
            }
        } catch (RemoteException e) {
            // ignore
        }

        if (aInfo == null) {
            Slog.wtf(TAG, "No home screen found for " + homeIntent, new Throwable());
            return null;
        }

        homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
        aInfo = new ActivityInfo(aInfo);
        aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId);
        homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
        return aInfo;
    }

    @VisibleForTesting
    void addChild(ActivityDisplay activityDisplay, int position) {
        positionChildAt(activityDisplay, position);
+1 −6
Original line number Diff line number Diff line
@@ -20,8 +20,8 @@ import static android.app.ActivityManager.START_SUCCESS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;

import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL;

import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;

@@ -35,7 +35,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Binder;
import android.os.FactoryTest;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -167,10 +166,6 @@ public class ActivityStartController {
    }

    void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, int displayId) {
        if (!mSupervisor.canStartHomeOnDisplay(aInfo, displayId)) {
            return;
        }

        final ActivityOptions options = ActivityOptions.makeBasic();
        options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
        options.setLaunchActivityType(ACTIVITY_TYPE_HOME);
+11 −66
Original line number Diff line number Diff line
@@ -85,13 +85,10 @@ import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.HEA
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.HOME_PROC;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.LAUNCHING_ACTIVITY;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto
        .PREVIOUS_PROC_VISIBLE_TIME_MS;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage
        .MODE;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage
        .PACKAGE;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE;
import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_ONLY;
@@ -5353,65 +5350,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
        return intent;
    }

    /**
     * This starts home activity on displays that can have system decorations and only if the
     * home activity can have multiple instances.
     */
    boolean startHomeActivityLocked(int userId, String reason, int displayId) {
        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;
        }

        final 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);
            WindowProcessController app =
                    getProcessController(aInfo.processName, aInfo.applicationInfo.uid);
            if (app == null || !app.isInstrumenting()) {
                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;
                getActivityStartController().startHomeActivity(intent, aInfo, myReason, displayId);
            }
        } else {
            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
        }

        return true;
    }

    private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
        ActivityInfo ai = null;
        final ComponentName comp = intent.getComponent();
        try {
            if (comp != null) {
                // Factory test.
                ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
            } else {
                ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
                        intent,
                        intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                        flags, userId);

                if (info != null) {
                    ai = info.activityInfo;
                }
            }
        } catch (RemoteException e) {
            // ignore
        }

        return ai;
    }

    ApplicationInfo getAppInfoForUser(ApplicationInfo info, int userId) {
        if (info == null) return null;
        ApplicationInfo newInfo = new ApplicationInfo(info);
@@ -6127,7 +6065,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
        @Override
        public boolean startHomeActivity(int userId, String reason) {
            synchronized (mGlobalLock) {
                return startHomeActivityLocked(userId, reason, DEFAULT_DISPLAY);
                return mStackSupervisor.startHomeOnDisplay(userId, reason, DEFAULT_DISPLAY);
            }
        }

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

+3 −2
Original line number Diff line number Diff line
@@ -33,8 +33,8 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.service.voice.IVoiceInteractionSession;
import android.util.SparseIntArray;

import android.util.proto.ProtoOutputStream;

import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.ActivityServiceConnectionsHolder;
import com.android.server.am.PendingIntentRecord;
@@ -48,7 +48,6 @@ import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;

/**
 * Activity Task manager local system service interface.
@@ -348,6 +347,8 @@ public abstract class ActivityTaskManagerInternal {
    /** @return The intent used to launch the home activity. */
    public abstract Intent getHomeIntent();
    public abstract boolean startHomeActivity(int userId, String reason);
    /** Start home activities on all displays that support system decorations. */
    public abstract boolean startHomeOnAllDisplays(int userId, String reason);
    /** @return true if the given process is the factory test process. */
    public abstract boolean isFactoryTestProcess(WindowProcessController wpc);
    public abstract void updateTopComponentForFactoryTest();
Loading