Changes AM.startUserInBgOnSecondaryDisplay() to check if display is valid.
Also adds APIs to list the valid displays: - @TestApi AM getSecondaryDisplayIdsForStartingBackgroundUsers() - cmd activity list-secondary-displays-for-starting-users - system property (fw.secondary_display_for_starting_users_for_testing_purposes) to override it for testing purposes Test: m -j update-api Test: adb shell cmd activity list-secondary-displays-for-starting-users Test: atest MultipleUsersOnMultipleDisplaysTest # CTS Test: atest ActivityManagerServiceTest ActivityManagerServiceInjectorTest # unit Bug: 239982558 Change-Id: Iaf5c83344075cce9985885a3f9359ebbd0174d41
This commit is contained in:
@@ -121,6 +121,7 @@ package android.app {
|
||||
public class ActivityManager {
|
||||
method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
|
||||
method public void alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName);
|
||||
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public int[] getSecondaryDisplayIdsForStartingBackgroundUsers();
|
||||
method public long getTotalRam();
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.PACKAGE_USAGE_STATS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional=true) public int getUidProcessCapabilities(int);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.PACKAGE_USAGE_STATS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional=true) public int getUidProcessState(int);
|
||||
|
||||
@@ -4387,13 +4387,15 @@ public class ActivityManager {
|
||||
* a profile, the {@link #getCurrentUser()}, the {@link UserHandle#SYSTEM system user}, or
|
||||
* does not exist.
|
||||
*
|
||||
* @param displayId id of the display, it must exist.
|
||||
* @param displayId id of the display.
|
||||
*
|
||||
* @return whether the operation succeeded. Notice that if the user was already started in such
|
||||
* display before, it will return {@code false}.
|
||||
*
|
||||
* @throws UnsupportedOperationException if the device does not support background users on
|
||||
* secondary displays.
|
||||
* @throws IllegalArgumentException if the display doesn't exist or is not a valid display to
|
||||
* start secondary users on.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@@ -4413,6 +4415,24 @@ public class ActivityManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id of displays that can be used by
|
||||
* {@link #startUserInBackgroundOnSecondaryDisplay(int, int)}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
@Nullable
|
||||
@RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
|
||||
android.Manifest.permission.INTERACT_ACROSS_USERS})
|
||||
public int[] getSecondaryDisplayIdsForStartingBackgroundUsers() {
|
||||
try {
|
||||
return getService().getSecondaryDisplayIdsForStartingBackgroundUsers();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the message that is shown when a user is switched from.
|
||||
*
|
||||
|
||||
@@ -770,4 +770,10 @@ interface IActivityManager {
|
||||
"@android.annotation.RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional = true)")
|
||||
boolean startUserInBackgroundOnSecondaryDisplay(int userid, int displayId);
|
||||
|
||||
/**
|
||||
* Gets the ids of displays that can be used on {@link #startUserInBackgroundOnSecondaryDisplay(int userId, int displayId)}.
|
||||
*
|
||||
* <p>Typically used only by automotive builds when the vehicle has multiple displays.
|
||||
*/
|
||||
@nullable int[] getSecondaryDisplayIdsForStartingBackgroundUsers();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import static android.Manifest.permission.FILTER_EVENTS;
|
||||
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
|
||||
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
|
||||
import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
|
||||
import static android.Manifest.permission.MANAGE_USERS;
|
||||
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
|
||||
import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
|
||||
import static android.app.ActivityManager.INSTR_FLAG_ALWAYS_CHECK_SIGNATURE;
|
||||
@@ -258,6 +259,7 @@ import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
import android.media.audiofx.AudioEffect;
|
||||
import android.net.ConnectivityManager;
|
||||
@@ -332,6 +334,7 @@ import android.util.SparseIntArray;
|
||||
import android.util.TimeUtils;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.util.proto.ProtoUtils;
|
||||
import android.view.Display;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -2366,6 +2369,7 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
mUiHandler = injector.getUiHandler(null /* service */);
|
||||
mUidObserverController = new UidObserverController(mUiHandler);
|
||||
mUserController = new UserController(this);
|
||||
mInjector.mUserController = mUserController;
|
||||
mPendingIntentController =
|
||||
new PendingIntentController(handlerThread.getLooper(), mUserController, mConstants);
|
||||
mAppRestrictionController = new AppRestrictionController(mContext, this);
|
||||
@@ -2480,6 +2484,7 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
|
||||
|
||||
mUserController = new UserController(this);
|
||||
mInjector.mUserController = mUserController;
|
||||
|
||||
mPendingIntentController = new PendingIntentController(
|
||||
mHandlerThread.getLooper(), mUserController, mConstants);
|
||||
@@ -6057,6 +6062,24 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
* This can be called with or without the global lock held.
|
||||
*/
|
||||
@PermissionMethod
|
||||
private void enforceCallingHasAtLeastOnePermission(String func, String... permissions) {
|
||||
for (String permission : permissions) {
|
||||
if (checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String msg = "Permission Denial: " + func + " from pid="
|
||||
+ Binder.getCallingPid()
|
||||
+ ", uid=" + Binder.getCallingUid()
|
||||
+ " requires one of " + Arrays.toString(permissions);
|
||||
Slog.w(TAG, msg);
|
||||
throw new SecurityException(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* This can be called with or without the global lock held.
|
||||
*/
|
||||
void enforcePermission(String permission, int pid, int uid, String func) {
|
||||
if (checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED) {
|
||||
return;
|
||||
@@ -16333,8 +16356,34 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
|
||||
@Override
|
||||
public boolean startUserInBackgroundOnSecondaryDisplay(int userId, int displayId) {
|
||||
int[] displayIds = getSecondaryDisplayIdsForStartingBackgroundUsers();
|
||||
boolean validDisplay = false;
|
||||
if (displayIds != null) {
|
||||
for (int i = 0; i < displayIds.length; i++) {
|
||||
if (displayId == displayIds[i]) {
|
||||
validDisplay = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!validDisplay) {
|
||||
throw new IllegalArgumentException("Invalid display (" + displayId + ") to start user. "
|
||||
+ "Valid options are: " + Arrays.toString(displayIds));
|
||||
}
|
||||
|
||||
if (DEBUG_MU) {
|
||||
Slogf.d(TAG_MU, "Calling startUserOnSecondaryDisplay(%d, %d) using injector %s", userId,
|
||||
displayId, mInjector);
|
||||
}
|
||||
// Permission check done inside UserController.
|
||||
return mUserController.startUserOnSecondaryDisplay(userId, displayId);
|
||||
return mInjector.startUserOnSecondaryDisplay(userId, displayId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSecondaryDisplayIdsForStartingBackgroundUsers() {
|
||||
enforceCallingHasAtLeastOnePermission("getSecondaryDisplayIdsForStartingBackgroundUsers()",
|
||||
MANAGE_USERS, INTERACT_ACROSS_USERS);
|
||||
return mInjector.getSecondaryDisplayIdsForStartingBackgroundUsers();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -18343,8 +18392,10 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
|
||||
@VisibleForTesting
|
||||
public static class Injector {
|
||||
private final Context mContext;
|
||||
private NetworkManagementInternal mNmi;
|
||||
private Context mContext;
|
||||
|
||||
private UserController mUserController;
|
||||
|
||||
public Injector(Context context) {
|
||||
mContext = context;
|
||||
@@ -18369,6 +18420,103 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@code AMS.getSecondaryDisplayIdsForStartingBackgroundUsers()}.
|
||||
*/
|
||||
// NOTE: ideally Injector should have no complex logic, but if this logic was moved to AMS,
|
||||
// it could not be tested with the existing ActivityManagerServiceTest (as DisplayManager,
|
||||
// DisplayInfo, etc... are final and UserManager.isUsersOnSecondaryDisplaysEnabled is
|
||||
// static).
|
||||
// So, the logic was added here, and tested on ActivityManagerServiceInjectorTest (which
|
||||
// was added on FrameworksMockingServicesTests and hence uses Extended Mockito to mock
|
||||
// final and static stuff)
|
||||
@Nullable
|
||||
public int[] getSecondaryDisplayIdsForStartingBackgroundUsers() {
|
||||
if (!UserManager.isUsersOnSecondaryDisplaysEnabled()) {
|
||||
Slogf.w(TAG, "getSecondaryDisplayIdsForStartingBackgroundUsers(): not supported");
|
||||
return null;
|
||||
}
|
||||
|
||||
// NOTE: DisplayManagerInternal doesn't have a method to list all displays
|
||||
DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
|
||||
|
||||
Display[] allDisplays = displayManager.getDisplays();
|
||||
|
||||
// allDisplays should contain at least Display.DEFAULT_DISPLAY, but it's better to
|
||||
// double check, just in case...
|
||||
if (allDisplays == null || allDisplays.length == 0) {
|
||||
Slogf.wtf(TAG, "displayManager (%s) returned no displays", displayManager);
|
||||
return null;
|
||||
}
|
||||
boolean hasDefaultDisplay = false;
|
||||
for (Display display : allDisplays) {
|
||||
if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
|
||||
hasDefaultDisplay = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasDefaultDisplay) {
|
||||
Slogf.wtf(TAG, "displayManager (%s) has %d displays (%s), but none has id "
|
||||
+ "DEFAULT_DISPLAY (%d)", displayManager, allDisplays.length,
|
||||
Arrays.toString(allDisplays), Display.DEFAULT_DISPLAY);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Starts with all displays but DEFAULT_DISPLAY
|
||||
int[] displayIds = new int[allDisplays.length - 1];
|
||||
|
||||
// TODO(b/247592632): check for other properties like isSecure or proper display type
|
||||
int numberValidDisplays = 0;
|
||||
for (Display display : allDisplays) {
|
||||
int displayId = display.getDisplayId();
|
||||
if (display.isValid() && displayId != Display.DEFAULT_DISPLAY) {
|
||||
displayIds[numberValidDisplays++] = displayId;
|
||||
}
|
||||
}
|
||||
|
||||
if (numberValidDisplays == 0) {
|
||||
// TODO(b/247580038): remove this workaround once a virtual display on Car's
|
||||
// KitchenSink (or other app) can be used while running CTS tests on devices that
|
||||
// don't have a real display.
|
||||
// STOPSHIP: if not removed, it should at least be unit tested
|
||||
String testingProp = "fw.secondary_display_for_starting_users_for_testing_purposes";
|
||||
int displayId = SystemProperties.getInt(testingProp, Display.DEFAULT_DISPLAY);
|
||||
if (displayId != Display.DEFAULT_DISPLAY && displayId > 0) {
|
||||
Slogf.w(TAG, "getSecondaryDisplayIdsForStartingBackgroundUsers(): no valid "
|
||||
+ "display found, but returning %d as set by property %s", displayId,
|
||||
testingProp);
|
||||
return new int[] { displayId };
|
||||
}
|
||||
Slogf.e(TAG, "getSecondaryDisplayIdsForStartingBackgroundUsers(): no valid display"
|
||||
+ " on %s", Arrays.toString(allDisplays));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (numberValidDisplays != displayIds.length) {
|
||||
int[] validDisplayIds = new int[numberValidDisplays];
|
||||
System.arraycopy(displayIds, 0, validDisplayIds, 0, numberValidDisplays);
|
||||
if (DEBUG_MU) {
|
||||
Slogf.d(TAG, "getSecondaryDisplayIdsForStartingBackgroundUsers(): returning "
|
||||
+ "only valid displays (%d instead of %d): %s", numberValidDisplays,
|
||||
displayIds.length, Arrays.toString(validDisplayIds));
|
||||
}
|
||||
return validDisplayIds;
|
||||
}
|
||||
|
||||
if (DEBUG_MU) {
|
||||
Slogf.d(TAG, "getSecondaryDisplayIdsForStartingBackgroundUsers(): returning all "
|
||||
+ "(but DEFAULT_DISPLAY) displays : %s", Arrays.toString(displayIds));
|
||||
}
|
||||
return displayIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@code AMS.startUserOnSecondaryDisplay()}.
|
||||
*/
|
||||
public boolean startUserOnSecondaryDisplay(int userId, int displayId) {
|
||||
return mUserController.startUserOnSecondaryDisplay(userId, displayId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the process list instance
|
||||
*/
|
||||
|
||||
@@ -367,6 +367,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
|
||||
return runGetCurrentForegroundProcess(pw, mInternal, mTaskInterface);
|
||||
case "reset-dropbox-rate-limiter":
|
||||
return runResetDropboxRateLimiter();
|
||||
case "list-secondary-displays-for-starting-users":
|
||||
return runListSecondaryDisplaysForStartingUsers(pw);
|
||||
default:
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
@@ -2068,6 +2070,10 @@ final class ActivityManagerShellCommand extends ShellCommand {
|
||||
success = mInterface.startUserInBackgroundWithListener(userId, waiter);
|
||||
displaySuffix = "";
|
||||
} else {
|
||||
if (!UserManager.isUsersOnSecondaryDisplaysEnabled()) {
|
||||
pw.println("Not supported");
|
||||
return -1;
|
||||
}
|
||||
success = mInterface.startUserInBackgroundOnSecondaryDisplay(userId, displayId);
|
||||
displaySuffix = " on display " + displayId;
|
||||
}
|
||||
@@ -3591,6 +3597,14 @@ final class ActivityManagerShellCommand extends ShellCommand {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int runListSecondaryDisplaysForStartingUsers(PrintWriter pw) throws RemoteException {
|
||||
int[] displayIds = mInterface.getSecondaryDisplayIdsForStartingBackgroundUsers();
|
||||
pw.println(displayIds == null || displayIds.length == 0
|
||||
? "none"
|
||||
: Arrays.toString(displayIds));
|
||||
return 0;
|
||||
}
|
||||
|
||||
private Resources getResources(PrintWriter pw) throws RemoteException {
|
||||
// system resources does not contain all the device configuration, construct it manually.
|
||||
Configuration config = mInterface.getConfiguration();
|
||||
@@ -3951,6 +3965,9 @@ final class ActivityManagerShellCommand extends ShellCommand {
|
||||
pw.println(" Set an app's background restriction level which in turn map to a app standby bucket.");
|
||||
pw.println(" get-bg-restriction-level [--user <USER_ID>] <PACKAGE>");
|
||||
pw.println(" Get an app's background restriction level.");
|
||||
pw.println(" list-secondary-displays-for-starting-users");
|
||||
pw.println(" Lists the id of displays that can be used to start users on "
|
||||
+ "background.");
|
||||
pw.println();
|
||||
Intent.printIntentArgsHelp(pw, "");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.am;
|
||||
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.os.UserManager;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
|
||||
import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
|
||||
import com.android.server.ExtendedMockitoTestCase;
|
||||
import com.android.server.am.ActivityManagerService.Injector;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Run as {@code atest
|
||||
* FrameworksMockingServicesTests:com.android.server.am.ActivityManagerServiceInjectorTest}
|
||||
*/
|
||||
public final class ActivityManagerServiceInjectorTest extends ExtendedMockitoTestCase {
|
||||
|
||||
private static final String TAG = ActivityManagerServiceInjectorTest.class.getSimpleName();
|
||||
|
||||
private final Display mDefaultDisplay = validDisplay(DEFAULT_DISPLAY);
|
||||
|
||||
@Mock private Context mContext;
|
||||
@Mock private DisplayManager mDisplayManager;
|
||||
|
||||
private Injector mInjector;
|
||||
|
||||
@Before
|
||||
public void setFixture() {
|
||||
mInjector = new Injector(mContext);
|
||||
|
||||
when(mContext.getSystemService(DisplayManager.class)).thenReturn(mDisplayManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeSession(StaticMockitoSessionBuilder builder) {
|
||||
builder.spyStatic(UserManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSecondaryDisplayIdsForStartingBackgroundUsers_notSupported() {
|
||||
mockUmIsUsersOnSecondaryDisplaysEnabled(false);
|
||||
|
||||
int [] displayIds = mInjector.getSecondaryDisplayIdsForStartingBackgroundUsers();
|
||||
|
||||
assertWithMessage("mAms.getSecondaryDisplayIdsForStartingBackgroundUsers()")
|
||||
.that(displayIds).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSecondaryDisplayIdsForStartingBackgroundUsers_noDisplaysAtAll() {
|
||||
mockUmIsUsersOnSecondaryDisplaysEnabled(true);
|
||||
mockGetDisplays();
|
||||
|
||||
int[] displayIds = mInjector.getSecondaryDisplayIdsForStartingBackgroundUsers();
|
||||
|
||||
assertWithMessage("mAms.getSecondaryDisplayIdsForStartingBackgroundUsers()")
|
||||
.that(displayIds).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSecondaryDisplayIdsForStartingBackgroundUsers_defaultDisplayOnly() {
|
||||
mockUmIsUsersOnSecondaryDisplaysEnabled(true);
|
||||
mockGetDisplays(mDefaultDisplay);
|
||||
|
||||
int[] displayIds = mInjector.getSecondaryDisplayIdsForStartingBackgroundUsers();
|
||||
|
||||
assertWithMessage("mAms.getSecondaryDisplayIdsForStartingBackgroundUsers()")
|
||||
.that(displayIds).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSecondaryDisplayIdsForStartingBackgroundUsers_noDefaultDisplay() {
|
||||
mockUmIsUsersOnSecondaryDisplaysEnabled(true);
|
||||
mockGetDisplays(validDisplay(42));
|
||||
|
||||
int[] displayIds = mInjector.getSecondaryDisplayIdsForStartingBackgroundUsers();
|
||||
|
||||
assertWithMessage("mAms.getSecondaryDisplayIdsForStartingBackgroundUsers()")
|
||||
.that(displayIds).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSecondaryDisplayIdsForStartingBackgroundUsers_mixed() {
|
||||
mockUmIsUsersOnSecondaryDisplaysEnabled(true);
|
||||
mockGetDisplays(mDefaultDisplay, validDisplay(42), invalidDisplay(108));
|
||||
|
||||
int[] displayIds = mInjector.getSecondaryDisplayIdsForStartingBackgroundUsers();
|
||||
|
||||
assertWithMessage("mAms.getSecondaryDisplayIdsForStartingBackgroundUsers()")
|
||||
.that(displayIds).isNotNull();
|
||||
assertWithMessage("mAms.getSecondaryDisplayIdsForStartingBackgroundUsers()")
|
||||
.that(displayIds).asList().containsExactly(42);
|
||||
}
|
||||
|
||||
// Extra test to make sure the array is properly copied...
|
||||
@Test
|
||||
public void testGetSecondaryDisplayIdsForStartingBackgroundUsers_mixed_invalidFirst() {
|
||||
mockUmIsUsersOnSecondaryDisplaysEnabled(true);
|
||||
mockGetDisplays(invalidDisplay(108), mDefaultDisplay, validDisplay(42));
|
||||
|
||||
int[] displayIds = mInjector.getSecondaryDisplayIdsForStartingBackgroundUsers();
|
||||
|
||||
assertWithMessage("mAms.getSecondaryDisplayIdsForStartingBackgroundUsers()")
|
||||
.that(displayIds).asList().containsExactly(42);
|
||||
}
|
||||
|
||||
private Display validDisplay(int displayId) {
|
||||
return mockDisplay(displayId, /* valid= */ true);
|
||||
}
|
||||
|
||||
private Display invalidDisplay(int displayId) {
|
||||
return mockDisplay(displayId, /* valid= */ false);
|
||||
}
|
||||
|
||||
private Display mockDisplay(int displayId, boolean valid) {
|
||||
Display display = mock(Display.class);
|
||||
|
||||
when(display.getDisplayId()).thenReturn(displayId);
|
||||
when(display.isValid()).thenReturn(valid);
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
private void mockGetDisplays(Display... displays) {
|
||||
Log.d(TAG, "mockGetDisplays(): " + Arrays.toString(displays));
|
||||
when(mDisplayManager.getDisplays()).thenReturn(displays);
|
||||
}
|
||||
|
||||
private void mockUmIsUsersOnSecondaryDisplaysEnabled(boolean enabled) {
|
||||
Log.d(TAG, "Mocking UserManager.isUsersOnSecondaryDisplaysEnabled() to return " + enabled);
|
||||
doReturn(enabled).when(() -> UserManager.isUsersOnSecondaryDisplaysEnabled());
|
||||
}
|
||||
}
|
||||
@@ -37,11 +37,14 @@ import static com.android.server.am.ProcessList.NETWORK_STATE_BLOCK;
|
||||
import static com.android.server.am.ProcessList.NETWORK_STATE_NO_CHANGE;
|
||||
import static com.android.server.am.ProcessList.NETWORK_STATE_UNBLOCK;
|
||||
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@@ -62,7 +65,6 @@ import android.app.SyncNotedAppOp;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
@@ -74,6 +76,8 @@ import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.util.IntArray;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.test.filters.MediumTest;
|
||||
import androidx.test.filters.SmallTest;
|
||||
@@ -116,6 +120,7 @@ public class ActivityManagerServiceTest {
|
||||
private static final String TAG = ActivityManagerServiceTest.class.getSimpleName();
|
||||
|
||||
private static final int TEST_UID = 11111;
|
||||
private static final int USER_ID = 666;
|
||||
|
||||
private static final long TEST_PROC_STATE_SEQ1 = 555;
|
||||
private static final long TEST_PROC_STATE_SEQ2 = 556;
|
||||
@@ -147,8 +152,8 @@ public class ActivityManagerServiceTest {
|
||||
@Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
|
||||
|
||||
private Context mContext = getInstrumentation().getTargetContext();
|
||||
|
||||
@Mock private AppOpsService mAppOpsService;
|
||||
@Mock private PackageManager mPackageManager;
|
||||
|
||||
private TestInjector mInjector;
|
||||
private ActivityManagerService mAms;
|
||||
@@ -828,6 +833,57 @@ public class ActivityManagerServiceTest {
|
||||
true); // expectWait
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSecondaryDisplayIdsForStartingBackgroundUsers() {
|
||||
mInjector.secondaryDisplayIdsForStartingBackgroundUsers = new int[]{4, 8, 15, 16, 23, 42};
|
||||
|
||||
int [] displayIds = mAms.getSecondaryDisplayIdsForStartingBackgroundUsers();
|
||||
|
||||
assertWithMessage("mAms.getSecondaryDisplayIdsForStartingBackgroundUsers()")
|
||||
.that(displayIds).asList().containsExactly(4, 8, 15, 16, 23, 42);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartUserInBackgroundOnSecondaryDisplay_invalidDisplay() {
|
||||
mInjector.secondaryDisplayIdsForStartingBackgroundUsers = new int[]{4, 8, 15, 16, 23, 42};
|
||||
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> mAms.startUserInBackgroundOnSecondaryDisplay(USER_ID, 666));
|
||||
|
||||
assertWithMessage("UserController.startUserOnSecondaryDisplay() calls")
|
||||
.that(mInjector.usersStartedOnSecondaryDisplays).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartUserInBackgroundOnSecondaryDisplay_validDisplay_failed() {
|
||||
mInjector.secondaryDisplayIdsForStartingBackgroundUsers = new int[]{ 4, 8, 15, 16, 23, 42 };
|
||||
mInjector.returnValueForstartUserOnSecondaryDisplay = false;
|
||||
|
||||
boolean started = mAms.startUserInBackgroundOnSecondaryDisplay(USER_ID, 42);
|
||||
Log.v(TAG, "Started: " + started);
|
||||
|
||||
assertWithMessage("mAms.startUserInBackgroundOnSecondaryDisplay(%s, 42)", USER_ID)
|
||||
.that(started).isFalse();
|
||||
assertWithMessage("UserController.startUserOnSecondaryDisplay() calls")
|
||||
.that(mInjector.usersStartedOnSecondaryDisplays)
|
||||
.containsExactly(new Pair<>(USER_ID, 42));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartUserInBackgroundOnSecondaryDisplay_validDisplay_success() {
|
||||
mInjector.secondaryDisplayIdsForStartingBackgroundUsers = new int[]{ 4, 8, 15, 16, 23, 42 };
|
||||
mInjector.returnValueForstartUserOnSecondaryDisplay = true;
|
||||
|
||||
boolean started = mAms.startUserInBackgroundOnSecondaryDisplay(USER_ID, 42);
|
||||
Log.v(TAG, "Started: " + started);
|
||||
|
||||
assertWithMessage("mAms.startUserInBackgroundOnSecondaryDisplay(%s, 42)", USER_ID)
|
||||
.that(started).isTrue();
|
||||
assertWithMessage("UserController.startUserOnSecondaryDisplay() calls")
|
||||
.that(mInjector.usersStartedOnSecondaryDisplays)
|
||||
.containsExactly(new Pair<>(USER_ID, 42));
|
||||
}
|
||||
|
||||
private void verifyWaitingForNetworkStateUpdate(long curProcStateSeq,
|
||||
long lastNetworkUpdatedProcStateSeq,
|
||||
final long procStateSeqToWait, boolean expectWait) throws Exception {
|
||||
@@ -922,7 +978,11 @@ public class ActivityManagerServiceTest {
|
||||
}
|
||||
|
||||
private class TestInjector extends Injector {
|
||||
private boolean mRestricted = true;
|
||||
public boolean restricted = true;
|
||||
public int[] secondaryDisplayIdsForStartingBackgroundUsers;
|
||||
|
||||
public boolean returnValueForstartUserOnSecondaryDisplay;
|
||||
public List<Pair<Integer, Integer>> usersStartedOnSecondaryDisplays = new ArrayList<>();
|
||||
|
||||
TestInjector(Context context) {
|
||||
super(context);
|
||||
@@ -940,11 +1000,18 @@ public class ActivityManagerServiceTest {
|
||||
|
||||
@Override
|
||||
public boolean isNetworkRestrictedForUid(int uid) {
|
||||
return mRestricted;
|
||||
return restricted;
|
||||
}
|
||||
|
||||
public void setNetworkRestrictedForUid(boolean restricted) {
|
||||
mRestricted = restricted;
|
||||
@Override
|
||||
public int[] getSecondaryDisplayIdsForStartingBackgroundUsers() {
|
||||
return secondaryDisplayIdsForStartingBackgroundUsers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startUserOnSecondaryDisplay(int userId, int displayId) {
|
||||
usersStartedOnSecondaryDisplays.add(new Pair<>(userId, displayId));
|
||||
return returnValueForstartUserOnSecondaryDisplay;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user