diff options
7 files changed, 175 insertions, 104 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e8c6365b38cb..c6fdf15d67e2 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -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(); diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 17454b42524c..87226bf15ecf 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -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 homeActivity, int 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; + } + 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); diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java index 20d5ab201307..3151ec9c1b83 100644 --- a/services/core/java/com/android/server/am/ActivityStartController.java +++ b/services/core/java/com/android/server/am/ActivityStartController.java @@ -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); diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java index 5b0a4a9b0596..5e3c1da2310b 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java @@ -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); } } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index b011da60b210..caa2da3f5125 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -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(); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java index bdceec79eb29..8ab22105c3ae 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java @@ -26,16 +26,21 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; +import static com.android.server.am.ActivityDisplay.POSITION_TOP; import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.contains; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -427,4 +432,32 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { verify(targetStack, times(1)).resumeTopActivityUncheckedLocked( eq(activity), eq(null /* targetOptions */)); } + + + /** + * Tests that home activities can be started on the displays that supports system decorations. + */ + @Test + public void testStartHomeOnAllDisplays() throws Exception { + // Create secondary displays. + final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay()); + mSupervisor.addChild(secondDisplay, POSITION_TOP); + doReturn(true).when(secondDisplay).supportsSystemDecorations(); + + // Create mock tasks and other necessary mocks. + TaskBuilder taskBuilder = new TaskBuilder(mService.mStackSupervisor).setCreateStack(false); + final TaskRecord.TaskRecordFactory factory = mock(TaskRecord.TaskRecordFactory.class); + TaskRecord.setTaskRecordFactory(factory); + doAnswer(i -> taskBuilder.build()).when(factory) + .create(any(), anyInt(), any(), any(), any(), any()); + doReturn(true).when(mService.mStackSupervisor) + .ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean()); + doReturn(true).when(mSupervisor).canStartHomeOnDisplay(any(), anyInt()); + + mSupervisor.startHomeOnAllDisplays(0, "testStartHome"); + + assertTrue(mSupervisor.getDefaultDisplay().getTopStack().isActivityTypeHome()); + assertNotNull(secondDisplay.getTopStack()); + assertTrue(secondDisplay.getTopStack().isActivityTypeHome()); + } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java index adf861b8d936..57960efee3c7 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -170,6 +170,7 @@ public class ActivityTestsBase { // Makes sure the supervisor is using with the spy object. atm.mStackSupervisor.setService(atm); doReturn(mock(IPackageManager.class)).when(am).getPackageManager(); + doReturn(mock(IPackageManager.class)).when(atm).getPackageManager(); PackageManagerInternal mockPackageManager = mock(PackageManagerInternal.class); doReturn(mockPackageManager).when(am).getPackageManagerInternalLocked(); doReturn(null).when(mockPackageManager).getDefaultHomeActivity(anyInt()); @@ -417,6 +418,10 @@ public class ActivityTestsBase { private ActivityTaskManagerInternal mInternal; private PackageManagerInternal mPmInternal; + // ActivityStackSupervisor may be created more than once while setting up AMS and ATMS. + // We keep the reference in order to prevent creating it twice. + private ActivityStackSupervisor mTestStackSupervisor; + TestActivityTaskManagerService(Context context) { super(context); mSupportsMultiWindow = true; @@ -447,24 +452,27 @@ public class ActivityTestsBase { @Override final protected ActivityStackSupervisor createStackSupervisor() { - final ActivityStackSupervisor supervisor = spy(createTestSupervisor()); - final KeyguardController keyguardController = mock(KeyguardController.class); - - // Invoked during {@link ActivityStack} creation. - doNothing().when(supervisor).updateUIDsPresentOnDisplay(); - // Always keep things awake. - doReturn(true).when(supervisor).hasAwakeDisplay(); - // Called when moving activity to pinned stack. - doNothing().when(supervisor).ensureActivitiesVisibleLocked(any(), anyInt(), anyBoolean()); - // Do not schedule idle timeouts - doNothing().when(supervisor).scheduleIdleTimeoutLocked(any()); - // unit test version does not handle launch wake lock - doNothing().when(supervisor).acquireLaunchWakelock(); - doReturn(keyguardController).when(supervisor).getKeyguardController(); - - supervisor.initialize(); - - return supervisor; + if (mTestStackSupervisor == null) { + final ActivityStackSupervisor supervisor = spy(createTestSupervisor()); + final KeyguardController keyguardController = mock(KeyguardController.class); + + // Invoked during {@link ActivityStack} creation. + doNothing().when(supervisor).updateUIDsPresentOnDisplay(); + // Always keep things awake. + doReturn(true).when(supervisor).hasAwakeDisplay(); + // Called when moving activity to pinned stack. + doNothing().when(supervisor).ensureActivitiesVisibleLocked(any(), anyInt(), + anyBoolean()); + // Do not schedule idle timeouts + doNothing().when(supervisor).scheduleIdleTimeoutLocked(any()); + // unit test version does not handle launch wake lock + doNothing().when(supervisor).acquireLaunchWakelock(); + doReturn(keyguardController).when(supervisor).getKeyguardController(); + + supervisor.initialize(); + mTestStackSupervisor = supervisor; + } + return mTestStackSupervisor; } protected ActivityStackSupervisor createTestSupervisor() { |