| /* |
| * Copyright (C) 2019 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.wm; |
| |
| import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; |
| import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; |
| import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS; |
| import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader; |
| import static android.view.Display.DEFAULT_DISPLAY; |
| |
| import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; |
| |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.nullable; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; |
| |
| import static org.mockito.Mockito.CALLS_REAL_METHODS; |
| import static org.mockito.Mockito.withSettings; |
| |
| import android.app.ActivityManagerInternal; |
| import android.app.AppOpsManager; |
| import android.app.IApplicationThread; |
| import android.app.usage.UsageStatsManagerInternal; |
| import android.content.BroadcastReceiver; |
| import android.content.ComponentName; |
| import android.content.ContentResolver; |
| import android.content.Context; |
| import android.content.IntentFilter; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.IPackageManager; |
| import android.content.pm.PackageManagerInternal; |
| import android.database.ContentObserver; |
| import android.hardware.devicestate.DeviceStateManager; |
| import android.hardware.display.DisplayManager; |
| import android.hardware.display.DisplayManagerInternal; |
| import android.net.Uri; |
| import android.os.Handler; |
| import android.os.Looper; |
| import android.os.PowerManager; |
| import android.os.PowerManagerInternal; |
| import android.os.PowerSaveState; |
| import android.os.StrictMode; |
| import android.os.UserHandle; |
| import android.provider.DeviceConfig; |
| import android.util.Log; |
| import android.view.InputChannel; |
| import android.view.SurfaceControl; |
| |
| import com.android.dx.mockito.inline.extended.StaticMockitoSession; |
| import com.android.server.AnimationThread; |
| import com.android.server.DisplayThread; |
| import com.android.server.LocalServices; |
| import com.android.server.LockGuard; |
| import com.android.server.UiThread; |
| import com.android.server.Watchdog; |
| import com.android.server.am.ActivityManagerService; |
| import com.android.server.display.color.ColorDisplayService; |
| import com.android.server.firewall.IntentFirewall; |
| import com.android.server.input.InputManagerService; |
| import com.android.server.pm.UserManagerService; |
| import com.android.server.policy.PermissionPolicyInternal; |
| import com.android.server.policy.WindowManagerPolicy; |
| import com.android.server.statusbar.StatusBarManagerInternal; |
| import com.android.server.uri.UriGrantsManagerInternal; |
| |
| import org.junit.rules.TestRule; |
| import org.junit.runner.Description; |
| import org.junit.runners.model.Statement; |
| import org.mockito.MockSettings; |
| import org.mockito.Mockito; |
| import org.mockito.quality.Strictness; |
| |
| import java.util.ArrayList; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| /** |
| * JUnit test rule to correctly setting up system services like {@link WindowManagerService} |
| * and {@link ActivityTaskManagerService} for tests. |
| */ |
| public class SystemServicesTestRule implements TestRule { |
| |
| private static final String TAG = SystemServicesTestRule.class.getSimpleName(); |
| |
| static int sNextDisplayId = DEFAULT_DISPLAY + 100; |
| |
| private static final int[] TEST_USER_PROFILE_IDS = {}; |
| /** Use a real static object so there won't be NPE in finalize() after clearInlineMocks(). */ |
| private static final PowerManager.WakeLock sWakeLock = getInstrumentation().getContext() |
| .getSystemService(PowerManager.class).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); |
| private PowerManager.WakeLock mStubbedWakeLock; |
| |
| /** |
| * The captured listeners will be unregistered in {@link #tearDown()} to avoid keeping static |
| * references of test instances from DeviceConfig. |
| */ |
| private final ArrayList<DeviceConfig.OnPropertiesChangedListener> mDeviceConfigListeners = |
| new ArrayList<>(); |
| |
| private Description mDescription; |
| private Context mContext; |
| private StaticMockitoSession mMockitoSession; |
| private ActivityTaskManagerService mAtmService; |
| private WindowManagerService mWmService; |
| private WindowState.PowerManagerWrapper mPowerManagerWrapper; |
| private InputManagerService mImService; |
| private InputChannel mInputChannel; |
| /** |
| * Spied {@link SurfaceControl.Transaction} class than can be used to verify calls. |
| */ |
| SurfaceControl.Transaction mTransaction; |
| |
| @Override |
| public Statement apply(Statement base, Description description) { |
| return new Statement() { |
| @Override |
| public void evaluate() throws Throwable { |
| mDescription = description; |
| Throwable throwable = null; |
| try { |
| runWithDexmakerShareClassLoader(SystemServicesTestRule.this::setUp); |
| base.evaluate(); |
| } catch (Throwable t) { |
| throwable = t; |
| } finally { |
| try { |
| tearDown(); |
| } catch (Throwable t) { |
| if (throwable != null) { |
| Log.e("SystemServicesTestRule", "Suppressed: ", throwable); |
| t.addSuppressed(throwable); |
| } |
| throwable = t; |
| } |
| } |
| if (throwable != null) throw throwable; |
| } |
| }; |
| } |
| |
| private void setUp() { |
| // Use stubOnly() to reduce memory usage if it doesn't need verification. |
| final MockSettings spyStubOnly = withSettings().stubOnly() |
| .defaultAnswer(CALLS_REAL_METHODS); |
| final MockSettings mockStubOnly = withSettings().stubOnly(); |
| // Return mocked services: LocalServices.getService |
| // Avoid real operation: SurfaceControl.mirrorSurface |
| // Avoid leakage: DeviceConfig.addOnPropertiesChangedListener, LockGuard.installLock |
| // Watchdog.getInstance/addMonitor |
| mMockitoSession = mockitoSession() |
| .mockStatic(LocalServices.class, spyStubOnly) |
| .mockStatic(DeviceConfig.class, spyStubOnly) |
| .mockStatic(SurfaceControl.class, mockStubOnly) |
| .mockStatic(LockGuard.class, mockStubOnly) |
| .mockStatic(Watchdog.class, mockStubOnly) |
| .strictness(Strictness.LENIENT) |
| .startMocking(); |
| |
| setUpSystemCore(); |
| setUpLocalServices(); |
| setUpActivityTaskManagerService(); |
| setUpWindowManagerService(); |
| } |
| |
| private void setUpSystemCore() { |
| doReturn(mock(Watchdog.class)).when(Watchdog::getInstance); |
| doAnswer(invocation -> { |
| // Exclude CONSTRAIN_DISPLAY_APIS because ActivityRecord#sConstrainDisplayApisConfig |
| // only registers once and it doesn't reference to outside. |
| if (!NAMESPACE_CONSTRAIN_DISPLAY_APIS.equals(invocation.getArgument(0))) { |
| mDeviceConfigListeners.add(invocation.getArgument(2)); |
| } |
| // SizeCompatTests uses setNeverConstrainDisplayApisFlag, and ActivityRecordTests |
| // uses splash_screen_exception_list. So still execute real registration. |
| return invocation.callRealMethod(); |
| }).when(() -> DeviceConfig.addOnPropertiesChangedListener(anyString(), any(), any())); |
| |
| mContext = getInstrumentation().getTargetContext(); |
| spyOn(mContext); |
| |
| doReturn(null).when(mContext) |
| .registerReceiver(nullable(BroadcastReceiver.class), any(IntentFilter.class)); |
| doReturn(null).when(mContext) |
| .registerReceiverAsUser(any(BroadcastReceiver.class), any(UserHandle.class), |
| any(IntentFilter.class), nullable(String.class), nullable(Handler.class)); |
| |
| final ContentResolver contentResolver = mContext.getContentResolver(); |
| spyOn(contentResolver); |
| doNothing().when(contentResolver) |
| .registerContentObserver(any(Uri.class), anyBoolean(), any(ContentObserver.class), |
| anyInt()); |
| } |
| |
| private void setUpLocalServices() { |
| // Tear down any local services just in case. |
| tearDownLocalServices(); |
| |
| // UriGrantsManagerInternal |
| final UriGrantsManagerInternal ugmi = mock(UriGrantsManagerInternal.class); |
| LocalServices.addService(UriGrantsManagerInternal.class, ugmi); |
| |
| // AppOpsManager |
| final AppOpsManager aom = mock(AppOpsManager.class); |
| doReturn(aom).when(mContext).getSystemService(eq(Context.APP_OPS_SERVICE)); |
| |
| // DeviceStateManager |
| final DeviceStateManager dsm = mock(DeviceStateManager.class); |
| doReturn(dsm).when(mContext).getSystemService(eq(Context.DEVICE_STATE_SERVICE)); |
| |
| // Prevent "WakeLock finalized while still held: SCREEN_FROZEN". |
| final PowerManager pm = mock(PowerManager.class); |
| doReturn(pm).when(mContext).getSystemService(eq(Context.POWER_SERVICE)); |
| mStubbedWakeLock = createStubbedWakeLock(false /* needVerification */); |
| doReturn(mStubbedWakeLock).when(pm).newWakeLock(anyInt(), anyString()); |
| doReturn(mStubbedWakeLock).when(pm).newWakeLock(anyInt(), anyString(), anyInt()); |
| |
| // DisplayManagerInternal |
| final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class); |
| doReturn(dmi).when(() -> LocalServices.getService(eq(DisplayManagerInternal.class))); |
| |
| // ColorDisplayServiceInternal |
| final ColorDisplayService.ColorDisplayServiceInternal cds = |
| mock(ColorDisplayService.ColorDisplayServiceInternal.class); |
| doReturn(cds).when(() -> LocalServices.getService( |
| eq(ColorDisplayService.ColorDisplayServiceInternal.class))); |
| |
| final UsageStatsManagerInternal usmi = mock(UsageStatsManagerInternal.class); |
| LocalServices.addService(UsageStatsManagerInternal.class, usmi); |
| |
| // PackageManagerInternal |
| final PackageManagerInternal packageManagerInternal = mock(PackageManagerInternal.class); |
| LocalServices.addService(PackageManagerInternal.class, packageManagerInternal); |
| doReturn(false).when(packageManagerInternal).isPermissionsReviewRequired( |
| anyString(), anyInt()); |
| doReturn(null).when(packageManagerInternal).getDefaultHomeActivity(anyInt()); |
| |
| ComponentName systemServiceComponent = new ComponentName("android.test.system.service", ""); |
| doReturn(systemServiceComponent).when(packageManagerInternal).getSystemUiServiceComponent(); |
| |
| // PowerManagerInternal |
| final PowerManagerInternal pmi = mock(PowerManagerInternal.class); |
| final PowerSaveState state = new PowerSaveState.Builder().build(); |
| doReturn(state).when(pmi).getLowPowerState(anyInt()); |
| doReturn(pmi).when(() -> LocalServices.getService(eq(PowerManagerInternal.class))); |
| |
| // PermissionPolicyInternal |
| final PermissionPolicyInternal ppi = mock(PermissionPolicyInternal.class); |
| LocalServices.addService(PermissionPolicyInternal.class, ppi); |
| doReturn(true).when(ppi).checkStartActivity(any(), anyInt(), any()); |
| |
| // InputManagerService |
| mImService = mock(InputManagerService.class); |
| // InputChannel cannot be mocked because it may pass to InputEventReceiver. |
| final InputChannel[] inputChannels = InputChannel.openInputChannelPair(TAG); |
| inputChannels[0].dispose(); |
| mInputChannel = inputChannels[1]; |
| doReturn(mInputChannel).when(mImService).monitorInput(anyString(), anyInt()); |
| doReturn(mInputChannel).when(mImService).createInputChannel(anyString()); |
| |
| // StatusBarManagerInternal |
| final StatusBarManagerInternal sbmi = mock(StatusBarManagerInternal.class); |
| doReturn(sbmi).when(() -> LocalServices.getService(eq(StatusBarManagerInternal.class))); |
| } |
| |
| private void setUpActivityTaskManagerService() { |
| // ActivityManagerInternal |
| final ActivityManagerInternal amInternal = |
| mock(ActivityManagerInternal.class, withSettings().stubOnly()); |
| doReturn(UserHandle.USER_SYSTEM).when(amInternal).getCurrentUserId(); |
| doReturn(TEST_USER_PROFILE_IDS).when(amInternal).getCurrentProfileIds(); |
| doReturn(true).when(amInternal).isUserRunning(anyInt(), anyInt()); |
| doReturn(true).when(amInternal).hasStartedUserState(anyInt()); |
| doReturn(false).when(amInternal).shouldConfirmCredentials(anyInt()); |
| doReturn(false).when(amInternal).isActivityStartsLoggingEnabled(); |
| LocalServices.addService(ActivityManagerInternal.class, amInternal); |
| |
| final ActivityManagerService amService = |
| mock(ActivityManagerService.class, withSettings().stubOnly()); |
| mAtmService = new TestActivityTaskManagerService(mContext, amService); |
| LocalServices.addService(ActivityTaskManagerInternal.class, mAtmService.getAtmInternal()); |
| } |
| |
| private void setUpWindowManagerService() { |
| mPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class); |
| TestWindowManagerPolicy wmPolicy = new TestWindowManagerPolicy(); |
| TestDisplayWindowSettingsProvider testDisplayWindowSettingsProvider = |
| new TestDisplayWindowSettingsProvider(); |
| // Suppress StrictMode violation (DisplayWindowSettings) to avoid log flood. |
| DisplayThread.getHandler().post(StrictMode::allowThreadDiskWritesMask); |
| mWmService = WindowManagerService.main( |
| mContext, mImService, false, false, wmPolicy, mAtmService, |
| testDisplayWindowSettingsProvider, StubTransaction::new, |
| (unused) -> new MockSurfaceControlBuilder()); |
| spyOn(mWmService); |
| spyOn(mWmService.mRoot); |
| // Invoked during {@link ActivityStack} creation. |
| doNothing().when(mWmService.mRoot).updateUIDsPresentOnDisplay(); |
| // Always keep things awake. |
| doReturn(true).when(mWmService.mRoot).hasAwakeDisplay(); |
| // Called when moving activity to pinned stack. |
| doNothing().when(mWmService.mRoot).ensureActivitiesVisible(any(), |
| anyInt(), anyBoolean(), anyBoolean()); |
| spyOn(mWmService.mDisplayWindowSettings); |
| spyOn(mWmService.mDisplayWindowSettingsProvider); |
| |
| // Setup factory classes to prevent calls to native code. |
| mTransaction = spy(StubTransaction.class); |
| // Return a spied Transaction class than can be used to verify calls. |
| mWmService.mTransactionFactory = () -> mTransaction; |
| mWmService.mSurfaceAnimationRunner = new SurfaceAnimationRunner( |
| null, null, mTransaction, mWmService.mPowerManagerInternal); |
| |
| mWmService.onInitReady(); |
| mAtmService.setWindowManager(mWmService); |
| mWmService.mDisplayEnabled = true; |
| mWmService.mDisplayReady = true; |
| // Set configuration for default display |
| mWmService.getDefaultDisplayContentLocked().reconfigureDisplayLocked(); |
| |
| // Mock default display, and home stack. |
| final DisplayContent display = mAtmService.mRootWindowContainer.getDefaultDisplay(); |
| // Set default display to be in fullscreen mode. Devices with PC feature may start their |
| // default display in freeform mode but some of tests in WmTests have implicit assumption on |
| // that the default display is in fullscreen mode. |
| display.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FULLSCREEN); |
| spyOn(display); |
| final TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea(); |
| |
| // Set the default focused TDA. |
| display.onLastFocusedTaskDisplayAreaChanged(taskDisplayArea); |
| spyOn(taskDisplayArea); |
| final Task homeStack = taskDisplayArea.getRootTask( |
| WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); |
| spyOn(homeStack); |
| } |
| |
| private void tearDown() { |
| mWmService.mRoot.forAllDisplayPolicies(DisplayPolicy::release); |
| |
| // Unregister display listener from root to avoid issues with subsequent tests. |
| mContext.getSystemService(DisplayManager.class) |
| .unregisterDisplayListener(mAtmService.mRootWindowContainer); |
| |
| for (int i = mDeviceConfigListeners.size() - 1; i >= 0; i--) { |
| DeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigListeners.get(i)); |
| } |
| |
| // This makes sure the posted messages without delay are processed, e.g. |
| // DisplayPolicy#release, WindowManagerService#setAnimationScale. |
| waitUntilWindowManagerHandlersIdle(); |
| // Clear all posted messages with delay, so they don't be executed at unexpected times. |
| cleanupWindowManagerHandlers(); |
| // Needs to explicitly dispose current static threads because there could be messages |
| // scheduled at a later time, and all mocks are invalid when it's executed. |
| DisplayThread.dispose(); |
| // Dispose SurfaceAnimationThread before AnimationThread does, so it won't create a new |
| // AnimationThread after AnimationThread disposed, see {@link |
| // AnimatorListenerAdapter#onAnimationEnd()} |
| SurfaceAnimationThread.dispose(); |
| AnimationThread.dispose(); |
| UiThread.dispose(); |
| mInputChannel.dispose(); |
| |
| tearDownLocalServices(); |
| // Reset priority booster because animation thread has been changed. |
| WindowManagerService.sThreadPriorityBooster = new WindowManagerThreadPriorityBooster(); |
| |
| mMockitoSession.finishMocking(); |
| Mockito.framework().clearInlineMocks(); |
| } |
| |
| private static void tearDownLocalServices() { |
| LocalServices.removeServiceForTest(DisplayManagerInternal.class); |
| LocalServices.removeServiceForTest(PowerManagerInternal.class); |
| LocalServices.removeServiceForTest(ActivityManagerInternal.class); |
| LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class); |
| LocalServices.removeServiceForTest(WindowManagerInternal.class); |
| LocalServices.removeServiceForTest(WindowManagerPolicy.class); |
| LocalServices.removeServiceForTest(PackageManagerInternal.class); |
| LocalServices.removeServiceForTest(UriGrantsManagerInternal.class); |
| LocalServices.removeServiceForTest(PermissionPolicyInternal.class); |
| LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class); |
| LocalServices.removeServiceForTest(UsageStatsManagerInternal.class); |
| LocalServices.removeServiceForTest(StatusBarManagerInternal.class); |
| } |
| |
| Description getDescription() { |
| return mDescription; |
| } |
| |
| WindowManagerService getWindowManagerService() { |
| return mWmService; |
| } |
| |
| ActivityTaskManagerService getActivityTaskManagerService() { |
| return mAtmService; |
| } |
| |
| WindowState.PowerManagerWrapper getPowerManagerWrapper() { |
| return mPowerManagerWrapper; |
| } |
| |
| /** Creates a no-op wakelock object. */ |
| PowerManager.WakeLock createStubbedWakeLock(boolean needVerification) { |
| if (needVerification) { |
| return mock(PowerManager.WakeLock.class, Mockito.withSettings() |
| .spiedInstance(sWakeLock).defaultAnswer(Mockito.RETURNS_DEFAULTS)); |
| } |
| return mock(PowerManager.WakeLock.class, Mockito.withSettings() |
| .spiedInstance(sWakeLock).stubOnly()); |
| } |
| |
| WindowProcessController addProcess(String pkgName, String procName, int pid, int uid) { |
| return addProcess(mAtmService, pkgName, procName, pid, uid); |
| } |
| |
| static WindowProcessController addProcess(ActivityTaskManagerService atmService, String pkgName, |
| String procName, int pid, int uid) { |
| final ApplicationInfo info = new ApplicationInfo(); |
| info.uid = uid; |
| info.packageName = pkgName; |
| return addProcess(atmService, info, procName, pid); |
| } |
| |
| static WindowProcessController addProcess(ActivityTaskManagerService atmService, |
| ApplicationInfo info, String procName, int pid) { |
| final WindowProcessListener mockListener = mock(WindowProcessListener.class, |
| withSettings().stubOnly()); |
| final int uid = info.uid; |
| final WindowProcessController proc = new WindowProcessController(atmService, |
| info, procName, uid, UserHandle.getUserId(uid), mockListener, mockListener); |
| proc.setThread(mock(IApplicationThread.class, withSettings().stubOnly())); |
| atmService.mProcessNames.put(procName, uid, proc); |
| if (pid > 0) { |
| proc.setPid(pid); |
| atmService.mProcessMap.put(pid, proc); |
| } |
| return proc; |
| } |
| |
| void cleanupWindowManagerHandlers() { |
| final WindowManagerService wm = getWindowManagerService(); |
| if (wm == null) { |
| return; |
| } |
| wm.mH.removeCallbacksAndMessages(null); |
| wm.mAnimationHandler.removeCallbacksAndMessages(null); |
| // This is a different handler object than the wm.mAnimationHandler above. |
| AnimationThread.getHandler().removeCallbacksAndMessages(null); |
| SurfaceAnimationThread.getHandler().removeCallbacksAndMessages(null); |
| } |
| |
| void waitUntilWindowManagerHandlersIdle() { |
| final WindowManagerService wm = getWindowManagerService(); |
| if (wm == null) { |
| return; |
| } |
| waitHandlerIdle(wm.mH); |
| waitHandlerIdle(wm.mAnimationHandler); |
| // This is a different handler object than the wm.mAnimationHandler above. |
| waitHandlerIdle(AnimationThread.getHandler()); |
| waitHandlerIdle(SurfaceAnimationThread.getHandler()); |
| } |
| |
| static void waitHandlerIdle(Handler handler) { |
| handler.runWithScissors(() -> { }, 0 /* timeout */); |
| } |
| |
| void waitUntilWindowAnimatorIdle() { |
| final WindowManagerService wm = getWindowManagerService(); |
| if (wm == null) { |
| return; |
| } |
| // Add a message to the handler queue and make sure it is fully processed before we move on. |
| // This makes sure all previous messages in the handler are fully processed vs. just popping |
| // them from the message queue. |
| final AtomicBoolean currentMessagesProcessed = new AtomicBoolean(false); |
| wm.mAnimator.getChoreographer().postFrameCallback(time -> { |
| synchronized (currentMessagesProcessed) { |
| currentMessagesProcessed.set(true); |
| currentMessagesProcessed.notifyAll(); |
| } |
| }); |
| while (!currentMessagesProcessed.get()) { |
| synchronized (currentMessagesProcessed) { |
| try { |
| currentMessagesProcessed.wait(); |
| } catch (InterruptedException e) { |
| } |
| } |
| } |
| } |
| |
| /** |
| * Throws if caller doesn't hold the given lock. |
| * @param lock the lock |
| */ |
| static void checkHoldsLock(Object lock) { |
| if (!Thread.holdsLock(lock)) { |
| throw new IllegalStateException("Caller doesn't hold global lock."); |
| } |
| } |
| |
| protected class TestActivityTaskManagerService extends ActivityTaskManagerService { |
| // ActivityTaskSupervisor may be created more than once while setting up AMS and ATMS. |
| // We keep the reference in order to prevent creating it twice. |
| ActivityTaskSupervisor mTestTaskSupervisor; |
| |
| TestActivityTaskManagerService(Context context, ActivityManagerService ams) { |
| super(context); |
| spyOn(this); |
| |
| mSupportsMultiWindow = true; |
| mSupportsMultiDisplay = true; |
| mSupportsSplitScreenMultiWindow = true; |
| mSupportsFreeformWindowManagement = true; |
| mSupportsPictureInPicture = true; |
| mDevEnableNonResizableMultiWindow = false; |
| mMinPercentageMultiWindowSupportHeight = 0.3f; |
| mMinPercentageMultiWindowSupportWidth = 0.5f; |
| mLargeScreenSmallestScreenWidthDp = 600; |
| mSupportsNonResizableMultiWindow = 0; |
| mRespectsActivityMinWidthHeightMultiWindow = 0; |
| mForceResizableActivities = false; |
| |
| doReturn(mock(IPackageManager.class)).when(this).getPackageManager(); |
| // allow background activity starts by default |
| doReturn(true).when(this).isBackgroundActivityStartsEnabled(); |
| doNothing().when(this).updateCpuStats(); |
| |
| // AppOpsService |
| final AppOpsManager aos = mock(AppOpsManager.class); |
| doReturn(aos).when(this).getAppOpsManager(); |
| // Make sure permission checks aren't overridden. |
| doReturn(AppOpsManager.MODE_DEFAULT).when(aos).noteOpNoThrow(anyInt(), anyInt(), |
| anyString(), nullable(String.class), nullable(String.class)); |
| |
| // UserManagerService |
| final UserManagerService ums = mock(UserManagerService.class); |
| doReturn(ums).when(this).getUserManager(); |
| doReturn(TEST_USER_PROFILE_IDS).when(ums).getProfileIds(anyInt(), eq(true)); |
| |
| setUsageStatsManager(LocalServices.getService(UsageStatsManagerInternal.class)); |
| ams.mActivityTaskManager = this; |
| ams.mAtmInternal = mInternal; |
| onActivityManagerInternalAdded(); |
| |
| final IntentFirewall intentFirewall = mock(IntentFirewall.class); |
| doReturn(true).when(intentFirewall).checkStartActivity( |
| any(), anyInt(), anyInt(), nullable(String.class), any()); |
| initialize(intentFirewall, null /* intentController */, |
| DisplayThread.getHandler().getLooper()); |
| spyOn(getLifecycleManager()); |
| spyOn(getLockTaskController()); |
| spyOn(getTaskChangeNotificationController()); |
| |
| AppWarnings appWarnings = getAppWarningsLocked(); |
| spyOn(appWarnings); |
| doNothing().when(appWarnings).onStartActivity(any()); |
| } |
| |
| @Override |
| int handleIncomingUser(int callingPid, int callingUid, int userId, String name) { |
| return userId; |
| } |
| |
| @Override |
| protected ActivityTaskSupervisor createTaskSupervisor() { |
| if (mTestTaskSupervisor == null) { |
| mTestTaskSupervisor = new TestActivityTaskSupervisor(this, mH.getLooper()); |
| } |
| return mTestTaskSupervisor; |
| } |
| } |
| |
| /** |
| * An {@link ActivityTaskSupervisor} which stubs out certain methods that depend on |
| * setup not available in the test environment. Also specifies an injector for |
| */ |
| protected class TestActivityTaskSupervisor extends ActivityTaskSupervisor { |
| |
| TestActivityTaskSupervisor(ActivityTaskManagerService service, Looper looper) { |
| super(service, looper); |
| spyOn(this); |
| |
| // Do not schedule idle that may touch methods outside the scope of the test. |
| doNothing().when(this).scheduleIdle(); |
| doNothing().when(this).scheduleIdleTimeout(any()); |
| // unit test version does not handle launch wake lock |
| doNothing().when(this).acquireLaunchWakelock(); |
| |
| mLaunchingActivityWakeLock = mStubbedWakeLock; |
| |
| initialize(); |
| |
| final KeyguardController controller = getKeyguardController(); |
| spyOn(controller); |
| doReturn(true).when(controller).checkKeyguardVisibility(any()); |
| } |
| } |
| } |