Migrate PowerManagerTests to PowerServiceTests
- Migrate power tests within servicestests/ to correct module
- Add permissions and libraries needed for these tests.
Bug: 290764236
Test: atest PowerServiceTests
Change-Id: Ib63768225b39024153497d11cd4cb9bfef46617e
diff --git a/services/tests/powerservicetests/Android.bp b/services/tests/powerservicetests/Android.bp
index 236f90c..f6714a8 100644
--- a/services/tests/powerservicetests/Android.bp
+++ b/services/tests/powerservicetests/Android.bp
@@ -12,9 +12,15 @@
static_libs: [
"frameworks-base-testutils",
+ "platform-compat-test-rules",
"platform-test-annotations",
"services.core",
"servicestests-utils",
+ "testables",
+ ],
+
+ libs: [
+ "android.test.mock",
],
platform_apis: true,
diff --git a/services/tests/powerservicetests/AndroidManifest.xml b/services/tests/powerservicetests/AndroidManifest.xml
index 3ace9d5..26d9eec 100644
--- a/services/tests/powerservicetests/AndroidManifest.xml
+++ b/services/tests/powerservicetests/AndroidManifest.xml
@@ -17,10 +17,19 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.powerservicetests">
- <!--
- Insert permissions here. eg:
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
- -->
+ <!-- Permissions -->
+ <uses-permission android:name="android.permission.DEVICE_POWER"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
+ <uses-permission android:name="android.permission.READ_DREAM_STATE"/>
+ <uses-permission android:name="android.permission.READ_DREAM_SUPPRESSION"/>
+ <uses-permission android:name="android.permission.STATUS_BAR_SERVICE"/>
+ <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
+ <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
+
<application android:debuggable="true"
android:testOnly="true">
<uses-library android:name="android.test.mock" android:required="true" />
diff --git a/services/tests/powerservicetests/src/com/android/server/power/LowPowerStandbyControllerTest.java b/services/tests/powerservicetests/src/com/android/server/power/LowPowerStandbyControllerTest.java
new file mode 100644
index 0000000..d3c0e35
--- /dev/null
+++ b/services/tests/powerservicetests/src/com/android/server/power/LowPowerStandbyControllerTest.java
@@ -0,0 +1,899 @@
+/*
+ * Copyright (C) 2021 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.power;
+
+import static android.os.PowerManager.FEATURE_WAKE_ON_LAN_IN_LOW_POWER_STANDBY;
+import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL;
+import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST;
+import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION;
+import static android.os.PowerManager.LowPowerStandbyPortDescription.MATCH_PORT_LOCAL;
+import static android.os.PowerManager.LowPowerStandbyPortDescription.PROTOCOL_TCP;
+import static android.os.PowerManager.LowPowerStandbyPortDescription.PROTOCOL_UDP;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.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.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManagerInternal;
+import android.app.AlarmManager;
+import android.app.IActivityManager;
+import android.app.IForegroundServiceObserver;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.IPowerManager;
+import android.os.PowerManager;
+import android.os.PowerManager.LowPowerStandbyPolicy;
+import android.os.PowerManager.LowPowerStandbyPortDescription;
+import android.os.PowerManagerInternal;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.test.TestLooper;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
+import android.util.ArraySet;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.util.test.BroadcastInterceptingContext;
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.LocalServices;
+import com.android.server.PowerAllowlistInternal;
+import com.android.server.PowerAllowlistInternal.TempAllowlistChangeListener;
+import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.power.LowPowerStandbyController.DeviceConfigWrapper;
+import com.android.server.testutils.OffsettableClock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for {@link com.android.server.power.LowPowerStandbyController}.
+ *
+ * Build/Install/Run:
+ * atest LowPowerStandbyControllerTest
+ */
+public class LowPowerStandbyControllerTest {
+ private static final int STANDBY_TIMEOUT = 5000;
+ private static final String TEST_PKG1 = "PKG1";
+ private static final String TEST_PKG2 = "PKG2";
+ private static final int TEST_PKG1_APP_ID = 123;
+ private static final int TEST_PKG2_APP_ID = 456;
+ private static final int USER_ID_1 = 0;
+ private static final int USER_ID_2 = 10;
+ private static final LowPowerStandbyPolicy EMPTY_POLICY = new LowPowerStandbyPolicy(
+ "Test policy", Collections.emptySet(), 0, Collections.emptySet());
+ private static final LowPowerStandbyPortDescription PORT_DESC_1 =
+ new LowPowerStandbyPortDescription(PROTOCOL_UDP, MATCH_PORT_LOCAL, 5353);
+ private static final LowPowerStandbyPortDescription PORT_DESC_2 =
+ new LowPowerStandbyPortDescription(PROTOCOL_TCP, MATCH_PORT_LOCAL, 8008);
+
+ private LowPowerStandbyController mController;
+ private BroadcastInterceptingContext mContextSpy;
+ private Resources mResourcesSpy;
+ private OffsettableClock mClock;
+ private TestLooper mTestLooper;
+ private File mTestPolicyFile;
+
+ @Mock
+ private DeviceConfigWrapper mDeviceConfigWrapperMock;
+ @Mock
+ private IActivityManager mIActivityManagerMock;
+ @Mock
+ private AlarmManager mAlarmManagerMock;
+ @Mock
+ private PackageManager mPackageManagerMock;
+ @Mock
+ private UserManager mUserManagerMock;
+ @Mock
+ private IPowerManager mIPowerManagerMock;
+ @Mock
+ private PowerManagerInternal mPowerManagerInternalMock;
+ @Mock
+ private NetworkPolicyManagerInternal mNetworkPolicyManagerInternalMock;
+ @Mock
+ private PowerAllowlistInternal mPowerAllowlistInternalMock;
+ @Mock
+ private ActivityManagerInternal mActivityManagerInternalMock;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mContextSpy = spy(new BroadcastInterceptingContext(InstrumentationRegistry.getContext()));
+ when(mContextSpy.getPackageManager()).thenReturn(mPackageManagerMock);
+ when(mContextSpy.getSystemService(AlarmManager.class)).thenReturn(mAlarmManagerMock);
+ when(mContextSpy.getSystemService(UserManager.class)).thenReturn(mUserManagerMock);
+ PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock, null, null);
+ when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
+ addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock);
+ addLocalServiceMock(NetworkPolicyManagerInternal.class, mNetworkPolicyManagerInternalMock);
+ addLocalServiceMock(PowerAllowlistInternal.class, mPowerAllowlistInternalMock);
+ addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock);
+
+ when(mIPowerManagerMock.isInteractive()).thenReturn(true);
+
+ when(mDeviceConfigWrapperMock.enableCustomPolicy()).thenReturn(true);
+ when(mDeviceConfigWrapperMock.enableStandbyPorts()).thenReturn(true);
+ mResourcesSpy = spy(mContextSpy.getResources());
+ when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
+ when(mResourcesSpy.getBoolean(
+ com.android.internal.R.bool.config_lowPowerStandbySupported))
+ .thenReturn(true);
+ when(mResourcesSpy.getInteger(
+ com.android.internal.R.integer.config_lowPowerStandbyNonInteractiveTimeout))
+ .thenReturn(STANDBY_TIMEOUT);
+ when(mResourcesSpy.getBoolean(
+ com.android.internal.R.bool.config_lowPowerStandbyEnabledByDefault))
+ .thenReturn(false);
+
+ FakeSettingsProvider.clearSettingsProvider();
+ MockContentResolver cr = new MockContentResolver(mContextSpy);
+ cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ when(mContextSpy.getContentResolver()).thenReturn(cr);
+
+ when(mUserManagerMock.getUserHandles(true)).thenReturn(List.of(
+ UserHandle.of(USER_ID_1), UserHandle.of(USER_ID_2)));
+ when(mPackageManagerMock.getPackageUid(eq(TEST_PKG1), any())).thenReturn(TEST_PKG1_APP_ID);
+ when(mPackageManagerMock.getPackageUid(eq(TEST_PKG2), any())).thenReturn(TEST_PKG2_APP_ID);
+ when(mPackageManagerMock.getPackageUidAsUser(eq(TEST_PKG1), eq(USER_ID_1)))
+ .thenReturn(TEST_PKG1_APP_ID);
+ when(mPackageManagerMock.getPackageUidAsUser(eq(TEST_PKG2), eq(USER_ID_1)))
+ .thenReturn(TEST_PKG2_APP_ID);
+
+ mClock = new OffsettableClock.Stopped();
+ mTestLooper = new TestLooper(mClock::now);
+
+ mTestPolicyFile = new File(mContextSpy.getCacheDir(), "lps_policy.xml");
+ mController = new LowPowerStandbyController(mContextSpy, mTestLooper.getLooper(),
+ () -> mClock.now(), mDeviceConfigWrapperMock, () -> mIActivityManagerMock,
+ mTestPolicyFile);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ LocalServices.removeServiceForTest(PowerManagerInternal.class);
+ LocalServices.removeServiceForTest(LowPowerStandbyControllerInternal.class);
+ LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
+ LocalServices.removeServiceForTest(PowerAllowlistInternal.class);
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+
+ mTestPolicyFile.delete();
+ }
+
+ @Test
+ public void testOnSystemReady_isInactivate() {
+ setLowPowerStandbySupportedConfig(true);
+ mController.systemReady();
+
+ assertThat(mController.isActive()).isFalse();
+ verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
+ verify(mNetworkPolicyManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
+ }
+
+ @Test
+ public void testActivate() throws Exception {
+ setLowPowerStandbySupportedConfig(true);
+ mController.systemReady();
+ mController.setEnabled(true);
+ setNonInteractive();
+ setDeviceIdleMode(true);
+ awaitStandbyTimeoutAlarm();
+ assertThat(mController.isActive()).isTrue();
+ verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(true);
+ verify(mNetworkPolicyManagerInternalMock, times(1)).setLowPowerStandbyActive(true);
+ }
+
+ private void awaitStandbyTimeoutAlarm() {
+ ArgumentCaptor<Long> timeArg = ArgumentCaptor.forClass(Long.class);
+ ArgumentCaptor<AlarmManager.OnAlarmListener> listenerArg =
+ ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+ verify(mAlarmManagerMock).setExact(
+ eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+ timeArg.capture(), anyString(),
+ listenerArg.capture(), any());
+ mClock.reset();
+ mClock.fastForward(timeArg.getValue());
+ listenerArg.getValue().onAlarm();
+ mTestLooper.dispatchAll();
+ }
+
+ @Test
+ public void testOnNonInteractive_notImmediatelyActive() throws Exception {
+ setLowPowerStandbySupportedConfig(true);
+ mController.systemReady();
+ mController.setEnabled(true);
+
+ setNonInteractive();
+ mTestLooper.dispatchAll();
+
+ assertThat(mController.isActive()).isFalse();
+ verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
+ verify(mNetworkPolicyManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
+ }
+
+ @Test
+ public void testOnNonInteractive_activateAfterStandbyTimeout() throws Exception {
+ setLowPowerStandbySupportedConfig(true);
+ mController.systemReady();
+ mController.setEnabled(true);
+
+ setNonInteractive();
+ awaitStandbyTimeoutAlarm();
+
+ assertThat(mController.isActive()).isTrue();
+ verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(true);
+ verify(mNetworkPolicyManagerInternalMock, times(1)).setLowPowerStandbyActive(true);
+ }
+
+ @Test
+ public void testOnNonInteractive_doesNotActivateWhenBecomingInteractive() throws Exception {
+ setLowPowerStandbySupportedConfig(true);
+ mController.systemReady();
+ mController.setEnabled(true);
+
+ setNonInteractive();
+ advanceTime(STANDBY_TIMEOUT / 2);
+ setInteractive();
+ verifyStandbyAlarmCancelled();
+
+ assertThat(mController.isActive()).isFalse();
+ verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
+ verify(mNetworkPolicyManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
+ }
+
+ private void verifyStandbyAlarmCancelled() {
+ InOrder inOrder = inOrder(mAlarmManagerMock);
+ inOrder.verify(mAlarmManagerMock, atLeast(0)).setExact(anyInt(), anyLong(), anyString(),
+ any(), any());
+ inOrder.verify(mAlarmManagerMock).cancel((AlarmManager.OnAlarmListener) any());
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void testOnInteractive_deactivate() throws Exception {
+ setLowPowerStandbySupportedConfig(true);
+ mController.systemReady();
+ mController.setEnabled(true);
+ setNonInteractive();
+ setDeviceIdleMode(true);
+ awaitStandbyTimeoutAlarm();
+
+ setInteractive();
+ mTestLooper.dispatchAll();
+
+ assertThat(mController.isActive()).isFalse();
+ verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(false);
+ verify(mNetworkPolicyManagerInternalMock, times(1)).setLowPowerStandbyActive(false);
+ }
+
+ @Test
+ public void testOnDozeMaintenance_deactivate() throws Exception {
+ setLowPowerStandbySupportedConfig(true);
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setActiveDuringMaintenance(false);
+ setNonInteractive();
+ setDeviceIdleMode(true);
+ awaitStandbyTimeoutAlarm();
+
+ setDeviceIdleMode(false);
+ mTestLooper.dispatchAll();
+
+ assertThat(mController.isActive()).isFalse();
+ verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(false);
+ verify(mNetworkPolicyManagerInternalMock, times(1)).setLowPowerStandbyActive(false);
+ }
+
+ @Test
+ public void testOnDozeMaintenance_activeDuringMaintenance_staysActive() throws Exception {
+ setLowPowerStandbySupportedConfig(true);
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setActiveDuringMaintenance(true);
+ setNonInteractive();
+ setDeviceIdleMode(true);
+ awaitStandbyTimeoutAlarm();
+
+ setDeviceIdleMode(false);
+ mTestLooper.dispatchAll();
+
+ assertThat(mController.isActive()).isTrue();
+ verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(false);
+ verify(mNetworkPolicyManagerInternalMock, never()).setLowPowerStandbyActive(false);
+ }
+
+ @Test
+ public void testOnDozeMaintenanceEnds_activate() throws Exception {
+ setLowPowerStandbySupportedConfig(true);
+ mController.systemReady();
+ mController.setEnabled(true);
+ setNonInteractive();
+ setDeviceIdleMode(true);
+ awaitStandbyTimeoutAlarm();
+
+ setDeviceIdleMode(false);
+ advanceTime(1000);
+ setDeviceIdleMode(true);
+ mTestLooper.dispatchAll();
+
+ assertThat(mController.isActive()).isTrue();
+ verify(mPowerManagerInternalMock, times(2)).setLowPowerStandbyActive(true);
+ verify(mNetworkPolicyManagerInternalMock, times(2)).setLowPowerStandbyActive(true);
+ }
+
+ @Test
+ public void testLowPowerStandbyDisabled_doesNotActivate() throws Exception {
+ setLowPowerStandbySupportedConfig(true);
+ mController.systemReady();
+ mController.setEnabled(false);
+ setNonInteractive();
+
+ assertThat(mController.isActive()).isFalse();
+ verify(mAlarmManagerMock, never()).setExact(anyInt(), anyLong(), anyString(), any(), any());
+ verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
+ verify(mNetworkPolicyManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
+ }
+
+ @Test
+ public void testLowPowerStandbyEnabled_EnabledChangedBroadcastsAreSent() throws Exception {
+ setLowPowerStandbySupportedConfig(true);
+ mController.systemReady();
+
+ BroadcastInterceptingContext.FutureIntent futureIntent = mContextSpy.nextBroadcastIntent(
+ PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED);
+ mController.setEnabled(false);
+ futureIntent.assertNotReceived();
+
+ futureIntent = mContextSpy.nextBroadcastIntent(
+ PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED);
+ mController.setEnabled(true);
+ assertThat(futureIntent.get(1, TimeUnit.SECONDS)).isNotNull();
+
+ futureIntent = mContextSpy.nextBroadcastIntent(
+ PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED);
+ mController.setEnabled(true);
+ futureIntent.assertNotReceived();
+
+ futureIntent = mContextSpy.nextBroadcastIntent(
+ PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED);
+
+ mController.setEnabled(false);
+ assertThat(futureIntent.get(1, TimeUnit.SECONDS)).isNotNull();
+ }
+
+ @Test
+ public void testSetEnabled_WhenNotSupported_DoesNotEnable() throws Exception {
+ setLowPowerStandbySupportedConfig(false);
+ mController.systemReady();
+
+ mController.setEnabled(true);
+
+ assertThat(mController.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void testIsSupported_WhenSupported() throws Exception {
+ setLowPowerStandbySupportedConfig(true);
+ mController.systemReady();
+
+ assertThat(mController.isSupported()).isTrue();
+ }
+
+ @Test
+ public void testIsSupported_WhenNotSupported() throws Exception {
+ setLowPowerStandbySupportedConfig(false);
+ mController.systemReady();
+
+ assertThat(mController.isSupported()).isFalse();
+ }
+
+ @Test
+ public void testForceActive() throws Exception {
+ setLowPowerStandbySupportedConfig(false);
+ mController.systemReady();
+
+ mController.forceActive(true);
+ mTestLooper.dispatchAll();
+
+ assertThat(mController.isActive()).isTrue();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyActive(true);
+ verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyActive(true);
+
+ mController.forceActive(false);
+ mTestLooper.dispatchAll();
+
+ assertThat(mController.isActive()).isFalse();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyActive(false);
+ verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyActive(false);
+ }
+
+ private void setLowPowerStandbySupportedConfig(boolean supported) {
+ when(mResourcesSpy.getBoolean(
+ com.android.internal.R.bool.config_lowPowerStandbySupported))
+ .thenReturn(supported);
+ }
+
+ @Test
+ public void testSetPolicy() throws Exception {
+ mController.systemReady();
+ mController.setPolicy(EMPTY_POLICY);
+ assertThat(mController.getPolicy()).isEqualTo(EMPTY_POLICY);
+ }
+
+ @Test
+ public void testSetDefaultPolicy() throws Exception {
+ mController.systemReady();
+ mController.setPolicy(EMPTY_POLICY);
+ mController.setPolicy(null);
+ assertThat(mController.getPolicy()).isNotNull();
+ assertThat(mController.getPolicy()).isEqualTo(LowPowerStandbyController.DEFAULT_POLICY);
+ }
+
+ @Test
+ public void testAddToAllowlist_ReasonIsAllowed_servicesAreNotified() throws Exception {
+ mController.systemReady();
+ mController.setPolicy(
+ policyWithAllowedReasons(LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION));
+
+ LowPowerStandbyControllerInternal service = LocalServices.getService(
+ LowPowerStandbyControllerInternal.class);
+ service.addToAllowlist(10, LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{10});
+ verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{10});
+
+ service.removeFromAllowlist(10, LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{});
+ verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{});
+ }
+
+ @Test
+ public void testRemoveFromAllowlist_ReasonIsAllowed_servicesAreNotified() throws Exception {
+ mController.systemReady();
+ mController.setPolicy(
+ policyWithAllowedReasons(LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION));
+
+ LowPowerStandbyControllerInternal service = LocalServices.getService(
+ LowPowerStandbyControllerInternal.class);
+ service.addToAllowlist(10, LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION);
+ mTestLooper.dispatchAll();
+
+ service.removeFromAllowlist(10, LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{});
+ verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{});
+ }
+
+ @Test
+ public void testSetAllowReasons_ActiveExemptionsNoLongerAllowed_servicesAreNotified() {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(
+ policyWithAllowedReasons(LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION));
+
+ LowPowerStandbyControllerInternal service = LocalServices.getService(
+ LowPowerStandbyControllerInternal.class);
+ service.addToAllowlist(10, LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION);
+ mTestLooper.dispatchAll();
+
+ mController.setPolicy(EMPTY_POLICY);
+ mTestLooper.dispatchAll();
+
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{});
+ verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{});
+ }
+
+ @Test
+ public void testSetAllowReasons_ReasonBecomesAllowed_servicesAreNotified() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(EMPTY_POLICY);
+
+ LowPowerStandbyControllerInternal service = LocalServices.getService(
+ LowPowerStandbyControllerInternal.class);
+ service.addToAllowlist(10, LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION);
+ mTestLooper.dispatchAll();
+
+ verify(mPowerManagerInternalMock, never()).setLowPowerStandbyAllowlist(any());
+ verify(mNetworkPolicyManagerInternalMock, never()).setLowPowerStandbyAllowlist(any());
+
+ mController.setPolicy(
+ policyWithAllowedReasons(LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION));
+ mTestLooper.dispatchAll();
+
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{10});
+ verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{10});
+ }
+
+ @Test
+ public void testSetAllowReasons_NoActiveExemptions_servicesAreNotNotified() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(
+ policyWithAllowedReasons(LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION));
+ mController.setPolicy(EMPTY_POLICY);
+ mTestLooper.dispatchAll();
+
+ verify(mPowerManagerInternalMock, never()).setLowPowerStandbyAllowlist(any());
+ verify(mNetworkPolicyManagerInternalMock, never()).setLowPowerStandbyAllowlist(any());
+ }
+
+ @Test
+ public void testSetAllowedFeatures_isAllowedIfDisabled() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(false);
+ mTestLooper.dispatchAll();
+
+ assertTrue(mController.isAllowed(FEATURE_WAKE_ON_LAN_IN_LOW_POWER_STANDBY));
+ }
+
+ @Test
+ public void testSetAllowedFeatures_isAllowedWhenEnabled() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithAllowedFeatures(FEATURE_WAKE_ON_LAN_IN_LOW_POWER_STANDBY));
+ mTestLooper.dispatchAll();
+
+ assertTrue(mController.isAllowed(FEATURE_WAKE_ON_LAN_IN_LOW_POWER_STANDBY));
+ }
+
+ @Test
+ public void testSetAllowedFeatures_isNotAllowed() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mTestLooper.dispatchAll();
+
+ assertFalse(mController.isAllowed(FEATURE_WAKE_ON_LAN_IN_LOW_POWER_STANDBY));
+ }
+
+ @Test
+ public void testSetExemptPackages_uidPerUserIsExempt() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG1, TEST_PKG2));
+ mTestLooper.dispatchAll();
+
+ int[] expectedUidAllowlist = {
+ UserHandle.getUid(USER_ID_1, TEST_PKG1_APP_ID),
+ UserHandle.getUid(USER_ID_1, TEST_PKG2_APP_ID),
+ UserHandle.getUid(USER_ID_2, TEST_PKG1_APP_ID),
+ UserHandle.getUid(USER_ID_2, TEST_PKG2_APP_ID)
+ };
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(expectedUidAllowlist);
+ verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(expectedUidAllowlist);
+ }
+
+ @Test
+ public void testExemptPackageIsRemoved_servicesAreNotified() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
+ mTestLooper.dispatchAll();
+
+ int[] expectedUidAllowlist = {
+ UserHandle.getUid(USER_ID_1, TEST_PKG1_APP_ID),
+ UserHandle.getUid(USER_ID_2, TEST_PKG1_APP_ID),
+ };
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(expectedUidAllowlist);
+ verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(expectedUidAllowlist);
+ verifyNoMoreInteractions(mPowerManagerInternalMock, mNetworkPolicyManagerInternalMock);
+
+ reset(mPackageManagerMock);
+ when(mPackageManagerMock.getPackageUid(eq(TEST_PKG1), any()))
+ .thenThrow(PackageManager.NameNotFoundException.class);
+
+ Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
+ intent.setData(Uri.fromParts(IntentFilter.SCHEME_PACKAGE, TEST_PKG1, null));
+ intent.putExtra(Intent.EXTRA_REPLACING, false);
+ mContextSpy.sendBroadcast(intent);
+ mTestLooper.dispatchAll();
+
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]);
+ verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]);
+ }
+
+ @Test
+ public void testUsersChanged_packagesExemptForNewUser() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
+ mTestLooper.dispatchAll();
+
+ InOrder inOrder = inOrder(mPowerManagerInternalMock);
+
+ inOrder.verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{
+ UserHandle.getUid(USER_ID_1, TEST_PKG1_APP_ID),
+ UserHandle.getUid(USER_ID_2, TEST_PKG1_APP_ID),
+ });
+ inOrder.verifyNoMoreInteractions();
+
+ when(mUserManagerMock.getUserHandles(true)).thenReturn(List.of(UserHandle.of(USER_ID_1)));
+ Intent intent = new Intent(Intent.ACTION_USER_REMOVED);
+ intent.putExtra(Intent.EXTRA_USER, UserHandle.of(USER_ID_2));
+ mContextSpy.sendBroadcast(intent);
+ mTestLooper.dispatchAll();
+
+ inOrder.verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{
+ UserHandle.getUid(USER_ID_1, TEST_PKG1_APP_ID)
+ });
+ inOrder.verifyNoMoreInteractions();
+
+ when(mUserManagerMock.getUserHandles(true)).thenReturn(
+ List.of(UserHandle.of(USER_ID_1), UserHandle.of(USER_ID_2)));
+ intent = new Intent(Intent.ACTION_USER_ADDED);
+ intent.putExtra(Intent.EXTRA_USER, UserHandle.of(USER_ID_2));
+ mContextSpy.sendBroadcast(intent);
+ mTestLooper.dispatchAll();
+
+ inOrder.verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{
+ UserHandle.getUid(USER_ID_1, TEST_PKG1_APP_ID),
+ UserHandle.getUid(USER_ID_2, TEST_PKG1_APP_ID)
+ });
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void testIsExempt_exemptIfDisabled() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(false);
+ mTestLooper.dispatchAll();
+
+ assertTrue(mController.isPackageExempt(TEST_PKG1_APP_ID));
+ }
+
+ @Test
+ public void testIsExempt_notExemptIfEnabled() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mTestLooper.dispatchAll();
+
+ assertFalse(mController.isPackageExempt(TEST_PKG1_APP_ID));
+ }
+
+ @Test
+ public void testAllowReason_tempPowerSaveAllowlist() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithAllowedReasons(
+ LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST));
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor<TempAllowlistChangeListener> tempAllowlistChangeListenerArgumentCaptor =
+ ArgumentCaptor.forClass(TempAllowlistChangeListener.class);
+ verify(mPowerAllowlistInternalMock).registerTempAllowlistChangeListener(
+ tempAllowlistChangeListenerArgumentCaptor.capture());
+ TempAllowlistChangeListener tempAllowlistChangeListener =
+ tempAllowlistChangeListenerArgumentCaptor.getValue();
+
+ tempAllowlistChangeListener.onAppAdded(TEST_PKG1_APP_ID);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG1_APP_ID});
+
+ tempAllowlistChangeListener.onAppAdded(TEST_PKG2_APP_ID);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(
+ new int[]{TEST_PKG1_APP_ID, TEST_PKG2_APP_ID});
+
+ tempAllowlistChangeListener.onAppRemoved(TEST_PKG1_APP_ID);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG2_APP_ID});
+
+ mController.setPolicy(EMPTY_POLICY);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]);
+ }
+
+ @Test
+ public void testAllowReason_ongoingPhoneCallService() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithAllowedReasons(
+ LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL));
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor<IForegroundServiceObserver> fgsObserverCapt =
+ ArgumentCaptor.forClass(IForegroundServiceObserver.class);
+ verify(mIActivityManagerMock).registerForegroundServiceObserver(fgsObserverCapt.capture());
+ IForegroundServiceObserver fgsObserver = fgsObserverCapt.getValue();
+
+ when(mActivityManagerInternalMock.hasRunningForegroundService(eq(TEST_PKG1_APP_ID),
+ eq(ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL))).thenReturn(true);
+ fgsObserver.onForegroundStateChanged(null, TEST_PKG1, USER_ID_1, true);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG1_APP_ID});
+
+ when(mActivityManagerInternalMock.hasRunningForegroundService(eq(TEST_PKG2_APP_ID),
+ eq(ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL))).thenReturn(true);
+ fgsObserver.onForegroundStateChanged(null, TEST_PKG2, USER_ID_1, true);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(
+ new int[]{TEST_PKG1_APP_ID, TEST_PKG2_APP_ID});
+
+ when(mActivityManagerInternalMock.hasRunningForegroundService(eq(TEST_PKG1_APP_ID),
+ eq(ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL))).thenReturn(false);
+ fgsObserver.onForegroundStateChanged(null, TEST_PKG1, USER_ID_1, false);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG2_APP_ID});
+
+ mController.setPolicy(EMPTY_POLICY);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]);
+ }
+
+ @Test
+ public void testStandbyPorts_broadcastChangedIfPackageIsExempt() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
+
+ Binder token = new Binder();
+ BroadcastInterceptingContext.FutureIntent futureIntent = mContextSpy.nextBroadcastIntent(
+ PowerManager.ACTION_LOW_POWER_STANDBY_PORTS_CHANGED);
+ mController.acquireStandbyPorts(token, TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
+ mTestLooper.dispatchAll();
+ assertThat(futureIntent.get(1, TimeUnit.SECONDS)).isNotNull();
+
+ futureIntent = mContextSpy.nextBroadcastIntent(
+ PowerManager.ACTION_LOW_POWER_STANDBY_PORTS_CHANGED);
+ mController.releaseStandbyPorts(token);
+ mTestLooper.dispatchAll();
+ assertThat(futureIntent.get(1, TimeUnit.SECONDS)).isNotNull();
+ }
+
+ @Test
+ public void testStandbyPorts_noBroadcastChangedIfPackageIsNotExempt() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
+
+ BroadcastInterceptingContext.FutureIntent futureIntent = mContextSpy.nextBroadcastIntent(
+ PowerManager.ACTION_LOW_POWER_STANDBY_PORTS_CHANGED);
+ mController.acquireStandbyPorts(new Binder(), TEST_PKG2_APP_ID, List.of(PORT_DESC_1));
+ mTestLooper.dispatchAll();
+ futureIntent.assertNotReceived();
+ }
+
+ @Test
+ public void testActiveStandbyPorts_emptyIfDisabled() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(false);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
+
+ mController.acquireStandbyPorts(new Binder(), TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
+ assertThat(mController.getActiveStandbyPorts()).isEmpty();
+ }
+
+ @Test
+ public void testActiveStandbyPorts_emptyIfPackageNotExempt() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG2));
+
+ mController.acquireStandbyPorts(new Binder(), TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
+ assertThat(mController.getActiveStandbyPorts()).isEmpty();
+ }
+
+ @Test
+ public void testActiveStandbyPorts_activeIfPackageExempt() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
+
+ mController.acquireStandbyPorts(new Binder(), TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
+ mController.acquireStandbyPorts(new Binder(), TEST_PKG2_APP_ID, List.of(PORT_DESC_2));
+ assertThat(mController.getActiveStandbyPorts()).containsExactly(PORT_DESC_1);
+ }
+
+ @Test
+ public void testActiveStandbyPorts_removedAfterRelease() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
+ Binder token = new Binder();
+ mController.acquireStandbyPorts(token, TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
+ mController.releaseStandbyPorts(token);
+ assertThat(mController.getActiveStandbyPorts()).isEmpty();
+ }
+
+ private void setInteractive() throws Exception {
+ when(mIPowerManagerMock.isInteractive()).thenReturn(true);
+ mContextSpy.sendBroadcast(new Intent(Intent.ACTION_SCREEN_ON));
+ }
+
+ private void setNonInteractive() throws Exception {
+ when(mIPowerManagerMock.isInteractive()).thenReturn(false);
+ mContextSpy.sendBroadcast(new Intent(Intent.ACTION_SCREEN_OFF));
+ }
+
+ private void setDeviceIdleMode(boolean idle) throws Exception {
+ when(mIPowerManagerMock.isDeviceIdleMode()).thenReturn(idle);
+ mContextSpy.sendBroadcast(new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
+ }
+
+ private LowPowerStandbyPolicy policyWithAllowedReasons(int allowedReasons) {
+ return new LowPowerStandbyPolicy(
+ "Test policy",
+ Collections.emptySet(),
+ allowedReasons,
+ Collections.emptySet()
+ );
+ }
+
+ private LowPowerStandbyPolicy policyWithAllowedFeatures(String... allowedFeatures) {
+ return new LowPowerStandbyPolicy(
+ "Test policy",
+ Collections.emptySet(),
+ 0,
+ new ArraySet<>(allowedFeatures)
+ );
+ }
+
+ private LowPowerStandbyPolicy policyWithExemptPackages(String... exemptPackages) {
+ return new LowPowerStandbyPolicy(
+ "Test policy",
+ new ArraySet<>(exemptPackages),
+ 0,
+ Collections.emptySet()
+ );
+ }
+
+ private void advanceTime(long timeMs) {
+ mClock.fastForward(timeMs);
+ mTestLooper.dispatchAll();
+ }
+
+ /**
+ * Creates a mock and registers it to {@link LocalServices}.
+ */
+ private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+ LocalServices.removeServiceForTest(clazz);
+ LocalServices.addService(clazz, mock);
+ }
+}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
new file mode 100644
index 0000000..2f03965
--- /dev/null
+++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2020 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.power;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.SensorManager;
+import android.hardware.display.AmbientDisplayConfiguration;
+import android.os.BatteryStats;
+import android.os.Handler;
+import android.os.IWakeLockCallback;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.VibrationAttributes;
+import android.os.Vibrator;
+import android.os.test.TestLooper;
+import android.provider.Settings;
+import android.testing.TestableContext;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.server.LocalServices;
+import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.power.batterysaver.BatterySaverController;
+import com.android.server.power.batterysaver.BatterySaverPolicy;
+import com.android.server.power.batterysaver.BatterySavingStats;
+import com.android.server.power.stats.BatteryStatsImpl;
+import com.android.server.statusbar.StatusBarManagerInternal;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Tests for {@link com.android.server.power.Notifier}
+ */
+public class NotifierTest {
+ private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent";
+ private static final int USER_ID = 0;
+
+ @Mock private BatterySaverController mBatterySaverControllerMock;
+ @Mock private BatterySaverPolicy mBatterySaverPolicyMock;
+ @Mock private PowerManagerService.NativeWrapper mNativeWrapperMock;
+ @Mock private Notifier mNotifierMock;
+ @Mock private WirelessChargerDetector mWirelessChargerDetectorMock;
+ @Mock private AmbientDisplayConfiguration mAmbientDisplayConfigurationMock;
+ @Mock private SystemPropertiesWrapper mSystemPropertiesMock;
+ @Mock private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock;
+ @Mock private BatteryStatsImpl mBatteryStats;
+ @Mock private Vibrator mVibrator;
+ @Mock private StatusBarManagerInternal mStatusBarManagerInternal;
+
+ private PowerManagerService mService;
+ private Context mContextSpy;
+ private Resources mResourcesSpy;
+ private TestLooper mTestLooper = new TestLooper();
+ private FakeExecutor mTestExecutor = new FakeExecutor();
+ private Notifier mNotifier;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
+ LocalServices.addService(StatusBarManagerInternal.class, mStatusBarManagerInternal);
+
+ mContextSpy = spy(new TestableContext(InstrumentationRegistry.getContext()));
+ mResourcesSpy = spy(mContextSpy.getResources());
+ when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
+ when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn("");
+ when(mContextSpy.getSystemService(Vibrator.class)).thenReturn(mVibrator);
+
+ mService = new PowerManagerService(mContextSpy, mInjector);
+ }
+
+ @Test
+ public void testVibrateEnabled_wiredCharging() {
+ createNotifier();
+
+ // GIVEN the charging vibration is enabled
+ enableChargingVibration(true);
+
+ // WHEN wired charging starts
+ mNotifier.onWiredChargingStarted(USER_ID);
+ mTestLooper.dispatchAll();
+ mTestExecutor.simulateAsyncExecutionOfLastCommand();
+
+ // THEN the device vibrates once
+ verify(mVibrator, times(1)).vibrate(any(), any(VibrationAttributes.class));
+ }
+
+ @Test
+ public void testVibrateDisabled_wiredCharging() {
+ createNotifier();
+
+ // GIVEN the charging vibration is disabled
+ enableChargingVibration(false);
+
+ // WHEN wired charging starts
+ mNotifier.onWiredChargingStarted(USER_ID);
+ mTestLooper.dispatchAll();
+ mTestExecutor.simulateAsyncExecutionOfLastCommand();
+
+ // THEN the device doesn't vibrate
+ verify(mVibrator, never()).vibrate(any(), any(VibrationAttributes.class));
+ }
+
+ @Test
+ public void testVibrateEnabled_wirelessCharging() {
+ createNotifier();
+
+ // GIVEN the charging vibration is enabled
+ enableChargingVibration(true);
+
+ // WHEN wireless charging starts
+ mNotifier.onWirelessChargingStarted(5, USER_ID);
+ mTestLooper.dispatchAll();
+ mTestExecutor.simulateAsyncExecutionOfLastCommand();
+
+ // THEN the device vibrates once
+ verify(mVibrator, times(1)).vibrate(any(), any(VibrationAttributes.class));
+ }
+
+ @Test
+ public void testVibrateDisabled_wirelessCharging() {
+ createNotifier();
+
+ // GIVEN the charging vibration is disabeld
+ enableChargingVibration(false);
+
+ // WHEN wireless charging starts
+ mNotifier.onWirelessChargingStarted(5, USER_ID);
+ mTestLooper.dispatchAll();
+ mTestExecutor.simulateAsyncExecutionOfLastCommand();
+
+ // THEN the device doesn't vibrate
+ verify(mVibrator, never()).vibrate(any(), any(VibrationAttributes.class));
+ }
+
+ @Test
+ public void testVibrateEnabled_dndOn() {
+ createNotifier();
+
+ // GIVEN the charging vibration is enabled but dnd is on
+ enableChargingVibration(true);
+ enableChargingFeedback(
+ /* chargingFeedbackEnabled */ true,
+ /* dndOn */ true);
+
+ // WHEN wired charging starts
+ mNotifier.onWiredChargingStarted(USER_ID);
+ mTestLooper.dispatchAll();
+ mTestExecutor.simulateAsyncExecutionOfLastCommand();
+
+ // THEN the device doesn't vibrate
+ verify(mVibrator, never()).vibrate(any(), any(VibrationAttributes.class));
+ }
+
+ @Test
+ public void testWirelessAnimationEnabled() {
+ // GIVEN the wireless charging animation is enabled
+ when(mResourcesSpy.getBoolean(
+ com.android.internal.R.bool.config_showBuiltinWirelessChargingAnim))
+ .thenReturn(true);
+ createNotifier();
+
+ // WHEN wireless charging starts
+ mNotifier.onWirelessChargingStarted(5, USER_ID);
+ mTestLooper.dispatchAll();
+ mTestExecutor.simulateAsyncExecutionOfLastCommand();
+
+ // THEN the charging animation is triggered
+ verify(mStatusBarManagerInternal, times(1)).showChargingAnimation(5);
+ }
+
+ @Test
+ public void testWirelessAnimationDisabled() {
+ // GIVEN the wireless charging animation is disabled
+ when(mResourcesSpy.getBoolean(
+ com.android.internal.R.bool.config_showBuiltinWirelessChargingAnim))
+ .thenReturn(false);
+ createNotifier();
+
+ // WHEN wireless charging starts
+ mNotifier.onWirelessChargingStarted(5, USER_ID);
+ mTestLooper.dispatchAll();
+ mTestExecutor.simulateAsyncExecutionOfLastCommand();
+
+ // THEN the charging animation never gets called
+ verify(mStatusBarManagerInternal, never()).showChargingAnimation(anyInt());
+ }
+
+ @Test
+ public void testOnWakeLockListener_RemoteException_NoRethrow() {
+ createNotifier();
+
+ IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
+ @Override public void onStateChanged(boolean enabled) throws RemoteException {
+ throw new RemoteException("Just testing");
+ }
+ };
+
+ final int uid = 1234;
+ final int pid = 5678;
+ mNotifier.onWakeLockReleased(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+ mNotifier.onWakeLockAcquired(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+ mNotifier.onWakeLockChanging(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* newWorkSource= */ null, /* newHistoryTag= */ null,
+ exceptingCallback);
+ mTestLooper.dispatchAll();
+ // If we didn't throw, we're good!
+ }
+
+ private final PowerManagerService.Injector mInjector = new PowerManagerService.Injector() {
+ @Override
+ Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
+ SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
+ FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
+ Executor backgroundExecutor) {
+ return mNotifierMock;
+ }
+
+ @Override
+ SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
+ return super.createSuspendBlocker(service, name);
+ }
+
+ @Override
+ BatterySaverPolicy createBatterySaverPolicy(
+ Object lock, Context context, BatterySavingStats batterySavingStats) {
+ return mBatterySaverPolicyMock;
+ }
+
+ @Override
+ BatterySaverController createBatterySaverController(
+ Object lock, Context context, BatterySaverPolicy batterySaverPolicy,
+ BatterySavingStats batterySavingStats) {
+ return mBatterySaverControllerMock;
+ }
+
+ @Override
+ PowerManagerService.NativeWrapper createNativeWrapper() {
+ return mNativeWrapperMock;
+ }
+
+ @Override
+ WirelessChargerDetector createWirelessChargerDetector(
+ SensorManager sensorManager, SuspendBlocker suspendBlocker, Handler handler) {
+ return mWirelessChargerDetectorMock;
+ }
+
+ @Override
+ AmbientDisplayConfiguration createAmbientDisplayConfiguration(Context context) {
+ return mAmbientDisplayConfigurationMock;
+ }
+
+ @Override
+ InattentiveSleepWarningController createInattentiveSleepWarningController() {
+ return mInattentiveSleepWarningControllerMock;
+ }
+
+ @Override
+ public SystemPropertiesWrapper createSystemPropertiesWrapper() {
+ return mSystemPropertiesMock;
+ }
+
+ @Override
+ void invalidateIsInteractiveCaches() {
+ // Avoids an SELinux denial.
+ }
+ };
+
+ private void enableChargingFeedback(boolean chargingFeedbackEnabled, boolean dndOn) {
+ // enable/disable charging feedback
+ Settings.Secure.putIntForUser(
+ mContextSpy.getContentResolver(),
+ Settings.Secure.CHARGING_SOUNDS_ENABLED,
+ chargingFeedbackEnabled ? 1 : 0,
+ USER_ID);
+
+ // toggle on/off dnd
+ Settings.Global.putInt(
+ mContextSpy.getContentResolver(),
+ Settings.Global.ZEN_MODE,
+ dndOn ? Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ : Settings.Global.ZEN_MODE_OFF);
+ }
+
+ private void enableChargingVibration(boolean enable) {
+ enableChargingFeedback(true, false);
+
+ Settings.Secure.putIntForUser(
+ mContextSpy.getContentResolver(),
+ Settings.Secure.CHARGING_VIBRATION_ENABLED,
+ enable ? 1 : 0,
+ USER_ID);
+ }
+
+ private void createNotifier() {
+ mNotifier = new Notifier(
+ mTestLooper.getLooper(),
+ mContextSpy,
+ IBatteryStats.Stub.asInterface(ServiceManager.getService(
+ BatteryStats.SERVICE_NAME)),
+ mInjector.createSuspendBlocker(mService, "testBlocker"),
+ null,
+ null,
+ null,
+ mTestExecutor);
+ }
+
+ private static class FakeExecutor implements Executor {
+ private Runnable mLastCommand;
+
+ @Override
+ public void execute(Runnable command) {
+ assertNull(mLastCommand);
+ assertNotNull(command);
+ mLastCommand = command;
+ }
+
+ public Runnable getAndResetLastCommand() {
+ Runnable toReturn = mLastCommand;
+ mLastCommand = null;
+ return toReturn;
+ }
+
+ public void simulateAsyncExecutionOfLastCommand() {
+ Runnable toRun = getAndResetLastCommand();
+ if (toRun != null) {
+ toRun.run();
+ }
+ }
+ }
+
+}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/PowerGroupTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerGroupTest.java
new file mode 100644
index 0000000..fe31b9c
--- /dev/null
+++ b/services/tests/powerservicetests/src/com/android/server/power/PowerGroupTest.java
@@ -0,0 +1,574 @@
+/*
+ * 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.power;
+
+
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF;
+import static android.os.PowerManager.GO_TO_SLEEP_REASON_APPLICATION;
+import static android.os.PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN;
+import static android.os.PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD;
+import static android.os.PowerManager.GO_TO_SLEEP_REASON_TIMEOUT;
+import static android.os.PowerManager.WAKE_REASON_GESTURE;
+import static android.os.PowerManager.WAKE_REASON_PLUGGED_IN;
+import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
+import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
+
+import static com.android.server.power.PowerManagerService.USER_ACTIVITY_SCREEN_BRIGHT;
+import static com.android.server.power.PowerManagerService.WAKE_LOCK_DOZE;
+import static com.android.server.power.PowerManagerService.WAKE_LOCK_SCREEN_BRIGHT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.hardware.display.DisplayManagerInternal;
+import android.os.PowerManager;
+import android.os.PowerSaveState;
+import android.view.Display;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.util.LatencyTracker;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link com.android.server.power.PowerGroup}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:PowerManagerServiceTest
+ */
+public class PowerGroupTest {
+
+ private static final int GROUP_ID = 0;
+ private static final int UID = 11;
+ private static final long TIMESTAMP_CREATE = 1;
+ private static final long TIMESTAMP1 = 999;
+ private static final long TIMESTAMP2 = TIMESTAMP1 + 10;
+ private static final long TIMESTAMP3 = TIMESTAMP2 + 10;
+
+ private static final float PRECISION = 0.001f;
+
+ private static final float BRIGHTNESS = 0.99f;
+ private static final float BRIGHTNESS_DOZE = 0.5f;
+
+
+
+ private PowerGroup mPowerGroup;
+ @Mock private PowerGroup.PowerGroupListener mWakefulnessCallbackMock;
+ @Mock private Notifier mNotifier;
+ @Mock private DisplayManagerInternal mDisplayManagerInternal;
+
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mPowerGroup = new PowerGroup(GROUP_ID, mWakefulnessCallbackMock, mNotifier,
+ mDisplayManagerInternal, WAKEFULNESS_AWAKE, /* ready= */ true,
+ /* supportsSandman= */ true, TIMESTAMP_CREATE);
+ }
+
+ @Test
+ public void testWakePowerGroup() {
+ mPowerGroup.sleepLocked(TIMESTAMP1, UID, GO_TO_SLEEP_REASON_APPLICATION);
+ verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+ eq(WAKEFULNESS_ASLEEP), eq(TIMESTAMP1), eq(GO_TO_SLEEP_REASON_APPLICATION),
+ eq(UID), /* opUid= */anyInt(), /* opPackageName= */ isNull(), /* details= */
+ isNull());
+ String details = "wake PowerGroup1";
+ LatencyTracker latencyTracker = LatencyTracker.getInstance(
+ InstrumentationRegistry.getInstrumentation().getContext());
+ mPowerGroup.wakeUpLocked(TIMESTAMP2, WAKE_REASON_PLUGGED_IN, details, UID,
+ /* opPackageName= */ null, /* opUid= */ 0, latencyTracker);
+ verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+ eq(WAKEFULNESS_AWAKE), eq(TIMESTAMP2), eq(WAKE_REASON_PLUGGED_IN), eq(UID),
+ /* opUid= */ anyInt(), /* opPackageName= */ isNull(), eq(details));
+ }
+
+ @Test
+ public void testDreamPowerGroup() {
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ mPowerGroup.dreamLocked(TIMESTAMP1, UID, /* allowWake= */ false);
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ assertThat(mPowerGroup.isSandmanSummonedLocked()).isTrue();
+ verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+ eq(WAKEFULNESS_DREAMING), eq(TIMESTAMP1), eq(GO_TO_SLEEP_REASON_APPLICATION),
+ eq(UID), /* opUid= */anyInt(), /* opPackageName= */ isNull(), /* details= */
+ isNull());
+ }
+
+ @Test
+ public void testDozePowerGroup() {
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ mPowerGroup.dozeLocked(TIMESTAMP1, UID, GO_TO_SLEEP_REASON_TIMEOUT);
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ assertThat(mPowerGroup.isSandmanSummonedLocked()).isTrue();
+ verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+ eq(WAKEFULNESS_DOZING), eq(TIMESTAMP1), eq(GO_TO_SLEEP_REASON_TIMEOUT),
+ eq(UID), /* opUid= */ anyInt(), /* opPackageName= */ isNull(),
+ /* details= */ isNull());
+ }
+
+ @Test
+ public void testDozePowerGroupWhenNonInteractiveHasNoEffect() {
+ mPowerGroup.sleepLocked(TIMESTAMP1, UID, GO_TO_SLEEP_REASON_TIMEOUT);
+ verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+ eq(WAKEFULNESS_ASLEEP), eq(TIMESTAMP1), eq(GO_TO_SLEEP_REASON_TIMEOUT),
+ eq(UID), /* opUid= */ anyInt(), /* opPackageName= */ isNull(),
+ /* details= */ isNull());
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mPowerGroup.dozeLocked(TIMESTAMP2, UID, GO_TO_SLEEP_REASON_TIMEOUT)).isFalse();
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ verify(mWakefulnessCallbackMock, never()).onWakefulnessChangedLocked(
+ eq(GROUP_ID), eq(WAKEFULNESS_DOZING), eq(TIMESTAMP2), /* reason= */ anyInt(),
+ eq(UID), /* opUid= */ anyInt(), /* opPackageName= */ any(), /* details= */ any());
+ }
+
+ @Test
+ public void testSleepPowerGroup() {
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ mPowerGroup.sleepLocked(TIMESTAMP1, UID, GO_TO_SLEEP_REASON_DEVICE_FOLD);
+ assertThat(mPowerGroup.isSandmanSummonedLocked()).isTrue();
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+ eq(WAKEFULNESS_ASLEEP), eq(TIMESTAMP1), eq(GO_TO_SLEEP_REASON_DEVICE_FOLD),
+ eq(UID), /* opUid= */ anyInt(), /* opPackageName= */ isNull(),
+ /* details= */ isNull());
+ }
+
+ @Test
+ public void testDreamPowerGroupWhenNotAwakeHasNoEffect() {
+ mPowerGroup.dozeLocked(TIMESTAMP1, UID, GO_TO_SLEEP_REASON_TIMEOUT);
+ verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+ eq(WAKEFULNESS_DOZING), eq(TIMESTAMP1), eq(GO_TO_SLEEP_REASON_TIMEOUT),
+ eq(UID), /* opUid= */ anyInt(), /* opPackageName= */ isNull(),
+ /* details= */ isNull());
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ assertThat(mPowerGroup.dreamLocked(TIMESTAMP2, UID, /* allowWake= */ false)).isFalse();
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ verify(mWakefulnessCallbackMock, never()).onWakefulnessChangedLocked(
+ eq(GROUP_ID), /* wakefulness= */ eq(WAKEFULNESS_DREAMING), eq(TIMESTAMP2),
+ /* reason= */ anyInt(), eq(UID), /* opUid= */ anyInt(), /* opPackageName= */ any(),
+ /* details= */ any());
+ }
+
+ @Test
+ public void testDreamPowerGroupWhenNotAwakeShouldWake() {
+ mPowerGroup.dozeLocked(TIMESTAMP1, UID, GO_TO_SLEEP_REASON_TIMEOUT);
+ verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+ eq(WAKEFULNESS_DOZING), eq(TIMESTAMP1), eq(GO_TO_SLEEP_REASON_TIMEOUT),
+ eq(UID), /* opUid= */ anyInt(), /* opPackageName= */ isNull(),
+ /* details= */ isNull());
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ assertThat(mPowerGroup.dreamLocked(TIMESTAMP2, UID, /* allowWake= */ true)).isTrue();
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(
+ eq(GROUP_ID), /* wakefulness= */ eq(WAKEFULNESS_DREAMING), eq(TIMESTAMP2),
+ /* reason= */ anyInt(), eq(UID), /* opUid= */ anyInt(), /* opPackageName= */ any(),
+ /* details= */ any());
+ }
+
+ @Test
+ public void testLastWakeAndSleepTimeIsUpdated() {
+ assertThat(mPowerGroup.getLastWakeTimeLocked()).isEqualTo(TIMESTAMP_CREATE);
+ assertThat(mPowerGroup.getLastSleepTimeLocked()).isEqualTo(TIMESTAMP_CREATE);
+
+ // Verify that the transition to WAKEFULNESS_DOZING updates the last sleep time
+ String details = "PowerGroup1 Timeout";
+ mPowerGroup.setWakefulnessLocked(WAKEFULNESS_DOZING, TIMESTAMP1, UID,
+ GO_TO_SLEEP_REASON_TIMEOUT, /* opUid= */ 0, /* opPackageName= */ null, details);
+ assertThat(mPowerGroup.getLastSleepTimeLocked()).isEqualTo(TIMESTAMP1);
+ assertThat(mPowerGroup.getLastWakeTimeLocked()).isEqualTo(TIMESTAMP_CREATE);
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+ eq(WAKEFULNESS_DOZING), eq(TIMESTAMP1), eq(GO_TO_SLEEP_REASON_TIMEOUT),
+ eq(UID), /* opUid= */anyInt(), /* opPackageName= */ isNull(), eq(details));
+
+ // Verify that the transition to WAKEFULNESS_ASLEEP after dozing does not update the last
+ // wake or sleep time
+ mPowerGroup.setWakefulnessLocked(WAKEFULNESS_ASLEEP, TIMESTAMP2, UID,
+ GO_TO_SLEEP_REASON_DEVICE_ADMIN, /* opUid= */ 0, /* opPackageName= */ null,
+ details);
+ assertThat(mPowerGroup.getLastSleepTimeLocked()).isEqualTo(TIMESTAMP1);
+ assertThat(mPowerGroup.getLastWakeTimeLocked()).isEqualTo(TIMESTAMP_CREATE);
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+ eq(WAKEFULNESS_ASLEEP), eq(TIMESTAMP2), eq(GO_TO_SLEEP_REASON_DEVICE_ADMIN),
+ eq(UID), /* opUid= */anyInt(), /* opPackageName= */ isNull(), eq(details));
+
+ // Verify that waking up the power group only updates the last wake time
+ details = "PowerGroup1 Gesture";
+ mPowerGroup.setWakefulnessLocked(WAKEFULNESS_AWAKE, TIMESTAMP2, UID,
+ WAKE_REASON_GESTURE, /* opUid= */ 0, /* opPackageName= */ null, details);
+ assertThat(mPowerGroup.getLastWakeTimeLocked()).isEqualTo(TIMESTAMP2);
+ assertThat(mPowerGroup.getLastSleepTimeLocked()).isEqualTo(TIMESTAMP1);
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+ eq(WAKEFULNESS_AWAKE), eq(TIMESTAMP2), eq(WAKE_REASON_GESTURE),
+ eq(UID), /* opUid= */ anyInt(), /* opPackageName= */ isNull(), eq(details));
+
+ // Verify that a transition to WAKEFULNESS_ASLEEP from an interactive state updates the last
+ // sleep time
+ mPowerGroup.setWakefulnessLocked(WAKEFULNESS_ASLEEP, TIMESTAMP3, UID,
+ GO_TO_SLEEP_REASON_DEVICE_ADMIN, /* opUid= */ 0, /* opPackageName= */ null,
+ details);
+ assertThat(mPowerGroup.getLastSleepTimeLocked()).isEqualTo(TIMESTAMP3);
+ assertThat(mPowerGroup.getLastWakeTimeLocked()).isEqualTo(TIMESTAMP2);
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+ eq(WAKEFULNESS_ASLEEP), eq(TIMESTAMP3), eq(GO_TO_SLEEP_REASON_DEVICE_ADMIN),
+ eq(UID), /* opUid= */anyInt(), /* opPackageName= */ isNull(), eq(details));
+ }
+
+ @Test
+ public void testUpdateWhileAwake_UpdatesDisplayPowerRequest() {
+ final boolean batterySaverEnabled = true;
+ float brightnessFactor = 0.7f;
+ PowerSaveState powerSaveState = new PowerSaveState.Builder()
+ .setBatterySaverEnabled(batterySaverEnabled)
+ .setBrightnessFactor(brightnessFactor)
+ .build();
+
+ mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS,
+ /* useProximitySensor= */ false,
+ /* boostScreenBrightness= */ false,
+ /* dozeScreenStateOverride= */ Display.STATE_ON,
+ /* dozeScreenBrightness= */ BRIGHTNESS_DOZE,
+ /* overrideDrawWakeLock= */ false,
+ powerSaveState,
+ /* quiescent= */ false,
+ /* dozeAfterScreenOff= */ false,
+ /* bootCompleted= */ true,
+ /* screenBrightnessBoostInProgress= */ false,
+ /* waitForNegativeProximity= */ false);
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest =
+ mPowerGroup.mDisplayPowerRequest;
+ assertThat(displayPowerRequest.policy).isEqualTo(POLICY_DIM);
+ assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS);
+ assertThat(displayPowerRequest.useProximitySensor).isEqualTo(false);
+ assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(false);
+ assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN);
+ assertThat(displayPowerRequest.dozeScreenBrightness).isEqualTo(
+ PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ assertThat(displayPowerRequest.lowPowerMode).isEqualTo(batterySaverEnabled);
+ assertThat(displayPowerRequest.screenLowPowerBrightnessFactor).isWithin(PRECISION).of(
+ brightnessFactor);
+ }
+
+ @Test
+ public void testUpdateWhileDozing_UpdatesDisplayPowerRequest() {
+ final boolean batterySaverEnabled = false;
+ float brightnessFactor = 0.3f;
+ PowerSaveState powerSaveState = new PowerSaveState.Builder()
+ .setBatterySaverEnabled(batterySaverEnabled)
+ .setBrightnessFactor(brightnessFactor)
+ .build();
+ mPowerGroup.dozeLocked(TIMESTAMP1, UID, GO_TO_SLEEP_REASON_APPLICATION);
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ mPowerGroup.setWakeLockSummaryLocked(WAKE_LOCK_DOZE);
+
+ mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS,
+ /* useProximitySensor= */ true,
+ /* boostScreenBrightness= */ true,
+ /* dozeScreenStateOverride= */ Display.STATE_ON,
+ /* dozeScreenBrightness= */ BRIGHTNESS_DOZE,
+ /* overrideDrawWakeLock= */ false,
+ powerSaveState,
+ /* quiescent= */ false,
+ /* dozeAfterScreenOff= */ false,
+ /* bootCompleted= */ true,
+ /* screenBrightnessBoostInProgress= */ false,
+ /* waitForNegativeProximity= */ false);
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest =
+ mPowerGroup.mDisplayPowerRequest;
+ assertThat(displayPowerRequest.policy).isEqualTo(POLICY_DOZE);
+ assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS);
+ assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true);
+ assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true);
+ assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_ON);
+ assertThat(displayPowerRequest.dozeScreenBrightness).isWithin(PRECISION).of(
+ BRIGHTNESS_DOZE);
+ assertThat(displayPowerRequest.lowPowerMode).isEqualTo(batterySaverEnabled);
+ assertThat(displayPowerRequest.screenLowPowerBrightnessFactor).isWithin(PRECISION).of(
+ brightnessFactor);
+ }
+
+ @Test
+ public void testUpdateWhileDozing_DozeAfterScreenOff() {
+ final boolean batterySaverEnabled = false;
+ float brightnessFactor = 0.3f;
+ PowerSaveState powerSaveState = new PowerSaveState.Builder()
+ .setBatterySaverEnabled(batterySaverEnabled)
+ .setBrightnessFactor(brightnessFactor)
+ .build();
+ mPowerGroup.dozeLocked(TIMESTAMP1, UID, GO_TO_SLEEP_REASON_APPLICATION);
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+
+ mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS,
+ /* useProximitySensor= */ true,
+ /* boostScreenBrightness= */ true,
+ /* dozeScreenStateOverride= */ Display.STATE_ON,
+ /* dozeScreenBrightness= */ BRIGHTNESS_DOZE,
+ /* overrideDrawWakeLock= */ false,
+ powerSaveState,
+ /* quiescent= */ false,
+ /* dozeAfterScreenOff= */ true,
+ /* bootCompleted= */ true,
+ /* screenBrightnessBoostInProgress= */ false,
+ /* waitForNegativeProximity= */ false);
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest =
+ mPowerGroup.mDisplayPowerRequest;
+ assertThat(displayPowerRequest.policy).isEqualTo(POLICY_OFF);
+ assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS);
+ assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true);
+ assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true);
+ assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN);
+ assertThat(displayPowerRequest.dozeScreenBrightness).isEqualTo(
+ PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ assertThat(displayPowerRequest.lowPowerMode).isEqualTo(batterySaverEnabled);
+ assertThat(displayPowerRequest.screenLowPowerBrightnessFactor).isWithin(PRECISION).of(
+ brightnessFactor);
+ }
+
+ @Test
+ public void testUpdateQuiescent() {
+ final boolean batterySaverEnabled = false;
+ float brightnessFactor = 0.3f;
+ PowerSaveState powerSaveState = new PowerSaveState.Builder()
+ .setBatterySaverEnabled(batterySaverEnabled)
+ .setBrightnessFactor(brightnessFactor)
+ .build();
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS,
+ /* useProximitySensor= */ true,
+ /* boostScreenBrightness= */ true,
+ /* dozeScreenStateOverride= */ Display.STATE_ON,
+ /* dozeScreenBrightness= */ BRIGHTNESS_DOZE,
+ /* overrideDrawWakeLock= */ false,
+ powerSaveState,
+ /* quiescent= */ true,
+ /* dozeAfterScreenOff= */ true,
+ /* bootCompleted= */ true,
+ /* screenBrightnessBoostInProgress= */ false,
+ /* waitForNegativeProximity= */ false);
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest =
+ mPowerGroup.mDisplayPowerRequest;
+ assertThat(displayPowerRequest.policy).isEqualTo(POLICY_OFF);
+ assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS);
+ assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true);
+ assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true);
+ assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN);
+ assertThat(displayPowerRequest.dozeScreenBrightness).isEqualTo(
+ PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ assertThat(displayPowerRequest.lowPowerMode).isEqualTo(batterySaverEnabled);
+ assertThat(displayPowerRequest.screenLowPowerBrightnessFactor).isWithin(PRECISION).of(
+ brightnessFactor);
+ }
+
+ @Test
+ public void testUpdateWhileAsleep_UpdatesDisplayPowerRequest() {
+ final boolean batterySaverEnabled = false;
+ float brightnessFactor = 0.3f;
+ PowerSaveState powerSaveState = new PowerSaveState.Builder()
+ .setBatterySaverEnabled(batterySaverEnabled)
+ .setBrightnessFactor(brightnessFactor)
+ .build();
+ mPowerGroup.sleepLocked(TIMESTAMP1, UID, GO_TO_SLEEP_REASON_TIMEOUT);
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS,
+ /* useProximitySensor= */ true,
+ /* boostScreenBrightness= */ true,
+ /* dozeScreenStateOverride= */ Display.STATE_ON,
+ /* dozeScreenBrightness= */ BRIGHTNESS_DOZE,
+ /* overrideDrawWakeLock= */ false,
+ powerSaveState,
+ /* quiescent= */ false,
+ /* dozeAfterScreenOff= */ false,
+ /* bootCompleted= */ true,
+ /* screenBrightnessBoostInProgress= */ false,
+ /* waitForNegativeProximity= */ false);
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest =
+ mPowerGroup.mDisplayPowerRequest;
+ assertThat(displayPowerRequest.policy).isEqualTo(POLICY_OFF);
+ assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS);
+ assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true);
+ assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true);
+ assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN);
+ assertThat(displayPowerRequest.dozeScreenBrightness).isEqualTo(
+ PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ assertThat(displayPowerRequest.lowPowerMode).isEqualTo(batterySaverEnabled);
+ assertThat(displayPowerRequest.screenLowPowerBrightnessFactor).isWithin(PRECISION).of(
+ brightnessFactor);
+ }
+
+ @Test
+ public void testUpdateWhileDreamingWithScreenBrightWakelock_UpdatesDisplayPowerRequest() {
+ final boolean batterySaverEnabled = false;
+ float brightnessFactor = 0.3f;
+ PowerSaveState powerSaveState = new PowerSaveState.Builder()
+ .setBatterySaverEnabled(batterySaverEnabled)
+ .setBrightnessFactor(brightnessFactor)
+ .build();
+ mPowerGroup.dreamLocked(TIMESTAMP1, UID, /* allowWake= */ false);
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ mPowerGroup.setWakeLockSummaryLocked(WAKE_LOCK_SCREEN_BRIGHT);
+ mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS,
+ /* useProximitySensor= */ true,
+ /* boostScreenBrightness= */ true,
+ /* dozeScreenStateOverride= */ Display.STATE_ON,
+ /* dozeScreenBrightness= */ BRIGHTNESS_DOZE,
+ /* overrideDrawWakeLock= */ false,
+ powerSaveState,
+ /* quiescent= */ false,
+ /* dozeAfterScreenOff= */ false,
+ /* bootCompleted= */ true,
+ /* screenBrightnessBoostInProgress= */ false,
+ /* waitForNegativeProximity= */ false);
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest =
+ mPowerGroup.mDisplayPowerRequest;
+ assertThat(displayPowerRequest.policy).isEqualTo(POLICY_BRIGHT);
+ assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS);
+ assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true);
+ assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true);
+ assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN);
+ assertThat(displayPowerRequest.dozeScreenBrightness).isEqualTo(
+ PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ assertThat(displayPowerRequest.lowPowerMode).isEqualTo(batterySaverEnabled);
+ assertThat(displayPowerRequest.screenLowPowerBrightnessFactor).isWithin(PRECISION).of(
+ brightnessFactor);
+ }
+
+ @Test
+ public void testUpdateWhileAwakeBootNotComplete_UpdatesDisplayPowerRequest() {
+ final boolean batterySaverEnabled = false;
+ float brightnessFactor = 0.3f;
+ PowerSaveState powerSaveState = new PowerSaveState.Builder()
+ .setBatterySaverEnabled(batterySaverEnabled)
+ .setBrightnessFactor(brightnessFactor)
+ .build();
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS,
+ /* useProximitySensor= */ true,
+ /* boostScreenBrightness= */ true,
+ /* dozeScreenStateOverride= */ Display.STATE_ON,
+ /* dozeScreenBrightness= */ BRIGHTNESS_DOZE,
+ /* overrideDrawWakeLock= */ false,
+ powerSaveState,
+ /* quiescent= */ false,
+ /* dozeAfterScreenOff= */ false,
+ /* bootCompleted= */ false,
+ /* screenBrightnessBoostInProgress= */ false,
+ /* waitForNegativeProximity= */ false);
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest =
+ mPowerGroup.mDisplayPowerRequest;
+ assertThat(displayPowerRequest.policy).isEqualTo(POLICY_BRIGHT);
+ assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS);
+ assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true);
+ assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true);
+ assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN);
+ assertThat(displayPowerRequest.dozeScreenBrightness).isEqualTo(
+ PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ assertThat(displayPowerRequest.lowPowerMode).isEqualTo(batterySaverEnabled);
+ assertThat(displayPowerRequest.screenLowPowerBrightnessFactor).isWithin(PRECISION).of(
+ brightnessFactor);
+ }
+
+ @Test
+ public void testUpdateWhileAwakeUserActivityScreenBright_UpdatesDisplayPowerRequest() {
+ final boolean batterySaverEnabled = false;
+ float brightnessFactor = 0.3f;
+ PowerSaveState powerSaveState = new PowerSaveState.Builder()
+ .setBatterySaverEnabled(batterySaverEnabled)
+ .setBrightnessFactor(brightnessFactor)
+ .build();
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ mPowerGroup.setUserActivitySummaryLocked(USER_ACTIVITY_SCREEN_BRIGHT);
+ mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS,
+ /* useProximitySensor= */ true,
+ /* boostScreenBrightness= */ true,
+ /* dozeScreenStateOverride= */ Display.STATE_ON,
+ /* dozeScreenBrightness= */ BRIGHTNESS_DOZE,
+ /* overrideDrawWakeLock= */ false,
+ powerSaveState,
+ /* quiescent= */ false,
+ /* dozeAfterScreenOff= */ false,
+ /* bootCompleted= */ true,
+ /* screenBrightnessBoostInProgress= */ false,
+ /* waitForNegativeProximity= */ false);
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest =
+ mPowerGroup.mDisplayPowerRequest;
+ assertThat(displayPowerRequest.policy).isEqualTo(POLICY_BRIGHT);
+ assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS);
+ assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true);
+ assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true);
+ assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN);
+ assertThat(displayPowerRequest.dozeScreenBrightness).isEqualTo(
+ PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ assertThat(displayPowerRequest.lowPowerMode).isEqualTo(batterySaverEnabled);
+ assertThat(displayPowerRequest.screenLowPowerBrightnessFactor).isWithin(PRECISION).of(
+ brightnessFactor);
+ }
+
+ @Test
+ public void testUpdateWhileAwakeScreenBrightnessBoostInProgress_UpdatesDisplayPowerRequest() {
+ final boolean batterySaverEnabled = false;
+ float brightnessFactor = 0.3f;
+ PowerSaveState powerSaveState = new PowerSaveState.Builder()
+ .setBatterySaverEnabled(batterySaverEnabled)
+ .setBrightnessFactor(brightnessFactor)
+ .build();
+ assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS,
+ /* useProximitySensor= */ true,
+ /* boostScreenBrightness= */ true,
+ /* dozeScreenStateOverride= */ Display.STATE_ON,
+ /* dozeScreenBrightness= */ BRIGHTNESS_DOZE,
+ /* overrideDrawWakeLock= */ false,
+ powerSaveState,
+ /* quiescent= */ false,
+ /* dozeAfterScreenOff= */ false,
+ /* bootCompleted= */ true,
+ /* screenBrightnessBoostInProgress= */ true,
+ /* waitForNegativeProximity= */ false);
+ DisplayManagerInternal.DisplayPowerRequest displayPowerRequest =
+ mPowerGroup.mDisplayPowerRequest;
+ assertThat(displayPowerRequest.policy).isEqualTo(POLICY_BRIGHT);
+ assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS);
+ assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true);
+ assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true);
+ assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN);
+ assertThat(displayPowerRequest.dozeScreenBrightness).isEqualTo(
+ PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ assertThat(displayPowerRequest.lowPowerMode).isEqualTo(batterySaverEnabled);
+ assertThat(displayPowerRequest.screenLowPowerBrightnessFactor).isWithin(PRECISION).of(
+ brightnessFactor);
+ }
+}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
new file mode 100644
index 0000000..c80ff45
--- /dev/null
+++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -0,0 +1,2713 @@
+/*
+ * Copyright (C) 2017 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.power;
+
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
+import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+import static android.os.PowerManager.USER_ACTIVITY_EVENT_BUTTON;
+import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
+import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertFalse;
+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.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManagerInternal;
+import android.attention.AttentionManagerInternal;
+import android.compat.testing.PlatformCompatChangeRule;
+import android.content.AttributionSource;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.PermissionChecker;
+import android.content.res.Resources;
+import android.hardware.SensorManager;
+import android.hardware.display.AmbientDisplayConfiguration;
+import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.hardware.power.Boost;
+import android.hardware.power.Mode;
+import android.os.BatteryManager;
+import android.os.BatteryManagerInternal;
+import android.os.BatterySaverPolicyConfig;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IWakeLockCallback;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.PowerManagerInternal;
+import android.os.PowerSaveState;
+import android.os.UserHandle;
+import android.os.test.TestLooper;
+import android.provider.Settings;
+import android.service.dreams.DreamManagerInternal;
+import android.sysprop.PowerProperties;
+import android.test.mock.MockContentResolver;
+import android.util.IntArray;
+import android.view.Display;
+import android.view.DisplayInfo;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.lights.LightsManager;
+import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.power.PowerManagerService.BatteryReceiver;
+import com.android.server.power.PowerManagerService.BinderService;
+import com.android.server.power.PowerManagerService.NativeWrapper;
+import com.android.server.power.PowerManagerService.UserSwitchedReceiver;
+import com.android.server.power.PowerManagerService.WakeLock;
+import com.android.server.power.batterysaver.BatterySaverController;
+import com.android.server.power.batterysaver.BatterySaverPolicy;
+import com.android.server.power.batterysaver.BatterySaverStateMachine;
+import com.android.server.power.batterysaver.BatterySavingStats;
+import com.android.server.testutils.OffsettableClock;
+
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Tests for {@link com.android.server.power.PowerManagerService}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:PowerManagerServiceTest
+ */
+@SuppressWarnings("GuardedBy")
+public class PowerManagerServiceTest {
+ private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent";
+ private static final String SYSTEM_PROPERTY_REBOOT_REASON = "sys.boot.reason";
+
+ private static final float BRIGHTNESS_FACTOR = 0.7f;
+ private static final boolean BATTERY_SAVER_ENABLED = true;
+
+ @Mock private BatterySaverController mBatterySaverControllerMock;
+ @Mock private BatterySaverPolicy mBatterySaverPolicyMock;
+ @Mock private BatterySaverStateMachine mBatterySaverStateMachineMock;
+ @Mock private LightsManager mLightsManagerMock;
+ @Mock private DisplayManagerInternal mDisplayManagerInternalMock;
+ @Mock private BatteryManagerInternal mBatteryManagerInternalMock;
+ @Mock private ActivityManagerInternal mActivityManagerInternalMock;
+ @Mock private AttentionManagerInternal mAttentionManagerInternalMock;
+ @Mock private DreamManagerInternal mDreamManagerInternalMock;
+ @Mock private PowerManagerService.NativeWrapper mNativeWrapperMock;
+ @Mock private Notifier mNotifierMock;
+ @Mock private WirelessChargerDetector mWirelessChargerDetectorMock;
+ @Mock private AmbientDisplayConfiguration mAmbientDisplayConfigurationMock;
+ @Mock private SystemPropertiesWrapper mSystemPropertiesMock;
+ @Mock private LowPowerStandbyController mLowPowerStandbyControllerMock;
+ @Mock private Callable<Void> mInvalidateInteractiveCachesMock;
+ @Mock private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock;
+ @Mock private PowerManagerService.PermissionCheckerWrapper mPermissionCheckerWrapperMock;
+ @Mock private PowerManagerService.PowerPropertiesWrapper mPowerPropertiesWrapper;
+
+ @Rule public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
+ private PowerManagerService mService;
+ private ContextWrapper mContextSpy;
+ private BatteryReceiver mBatteryReceiver;
+ private UserSwitchedReceiver mUserSwitchedReceiver;
+ private Resources mResourcesSpy;
+ private OffsettableClock mClock;
+ private long mLastElapsedRealtime;
+ private TestLooper mTestLooper;
+
+ private static class IntentFilterMatcher implements ArgumentMatcher<IntentFilter> {
+ private final IntentFilter mFilter;
+
+ IntentFilterMatcher(IntentFilter filter) {
+ mFilter = filter;
+ }
+
+ @Override
+ public boolean matches(IntentFilter other) {
+ if (other.countActions() != mFilter.countActions()) {
+ return false;
+ }
+ for (int i = 0; i < mFilter.countActions(); i++) {
+ if (!mFilter.getAction(i).equals(other.getAction(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ FakeSettingsProvider.clearSettingsProvider();
+
+ PowerSaveState powerSaveState = new PowerSaveState.Builder()
+ .setBatterySaverEnabled(BATTERY_SAVER_ENABLED)
+ .setBrightnessFactor(BRIGHTNESS_FACTOR)
+ .build();
+ when(mBatterySaverPolicyMock.getBatterySaverPolicy(
+ eq(PowerManager.ServiceType.SCREEN_BRIGHTNESS)))
+ .thenReturn(powerSaveState);
+ when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(false);
+ when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(false);
+ when(mDisplayManagerInternalMock.requestPowerState(anyInt(), any(), anyBoolean()))
+ .thenReturn(true);
+ when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn("");
+ when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(true);
+
+ addLocalServiceMock(LightsManager.class, mLightsManagerMock);
+ addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock);
+ addLocalServiceMock(BatteryManagerInternal.class, mBatteryManagerInternalMock);
+ addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock);
+ addLocalServiceMock(AttentionManagerInternal.class, mAttentionManagerInternalMock);
+ addLocalServiceMock(DreamManagerInternal.class, mDreamManagerInternalMock);
+
+ mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
+ mResourcesSpy = spy(mContextSpy.getResources());
+ when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
+
+ MockContentResolver cr = new MockContentResolver(mContextSpy);
+ cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ when(mContextSpy.getContentResolver()).thenReturn(cr);
+
+ Settings.Global.putInt(mContextSpy.getContentResolver(),
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 0);
+
+ mClock = new OffsettableClock.Stopped();
+ mTestLooper = new TestLooper(mClock::now);
+ }
+
+ private PowerManagerService createService() {
+ mService = new PowerManagerService(mContextSpy, new PowerManagerService.Injector() {
+ @Override
+ Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
+ SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
+ FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
+ Executor executor) {
+ return mNotifierMock;
+ }
+
+ @Override
+ SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
+ return super.createSuspendBlocker(service, name);
+ }
+
+ @Override
+ BatterySaverPolicy createBatterySaverPolicy(
+ Object lock, Context context, BatterySavingStats batterySavingStats) {
+ return mBatterySaverPolicyMock;
+ }
+
+ @Override
+ BatterySaverController createBatterySaverController(
+ Object lock, Context context, BatterySaverPolicy batterySaverPolicy,
+ BatterySavingStats batterySavingStats) {
+ return mBatterySaverControllerMock;
+ }
+
+ @Override
+ BatterySaverStateMachine createBatterySaverStateMachine(Object lock, Context context,
+ BatterySaverController batterySaverController) {
+ return mBatterySaverStateMachineMock;
+ }
+
+ @Override
+ NativeWrapper createNativeWrapper() {
+ return mNativeWrapperMock;
+ }
+
+ @Override
+ WirelessChargerDetector createWirelessChargerDetector(
+ SensorManager sensorManager, SuspendBlocker suspendBlocker, Handler handler) {
+ return mWirelessChargerDetectorMock;
+ }
+
+ @Override
+ AmbientDisplayConfiguration createAmbientDisplayConfiguration(Context context) {
+ return mAmbientDisplayConfigurationMock;
+ }
+
+ @Override
+ InattentiveSleepWarningController createInattentiveSleepWarningController() {
+ return mInattentiveSleepWarningControllerMock;
+ }
+
+ @Override
+ public SystemPropertiesWrapper createSystemPropertiesWrapper() {
+ return mSystemPropertiesMock;
+ }
+
+ @Override
+ PowerManagerService.Clock createClock() {
+ return new PowerManagerService.Clock() {
+ @Override
+ public long uptimeMillis() {
+ return mClock.now();
+ }
+
+ @Override
+ public long elapsedRealtime() {
+ mLastElapsedRealtime = mClock.now();
+ return mLastElapsedRealtime;
+ }
+ };
+ }
+
+ @Override
+ Handler createHandler(Looper looper, Handler.Callback callback) {
+ return new Handler(mTestLooper.getLooper(), callback);
+ }
+
+ @Override
+ void invalidateIsInteractiveCaches() {
+ try {
+ mInvalidateInteractiveCachesMock.call();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ LowPowerStandbyController createLowPowerStandbyController(Context context,
+ Looper looper) {
+ return mLowPowerStandbyControllerMock;
+ }
+
+ @Override
+ PowerManagerService.PermissionCheckerWrapper createPermissionCheckerWrapper() {
+ return mPermissionCheckerWrapperMock;
+ }
+
+ @Override
+ PowerManagerService.PowerPropertiesWrapper createPowerPropertiesWrapper() {
+ return mPowerPropertiesWrapper;
+ }
+ });
+ return mService;
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ LocalServices.removeServiceForTest(LightsManager.class);
+ LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+ LocalServices.removeServiceForTest(BatteryManagerInternal.class);
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ FakeSettingsProvider.clearSettingsProvider();
+ }
+
+ /**
+ * Creates a mock and registers it to {@link LocalServices}.
+ */
+ private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+ LocalServices.removeServiceForTest(clazz);
+ LocalServices.addService(clazz, mock);
+ }
+
+ private void startSystem() {
+ mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
+ // Grab the BatteryReceiver
+ ArgumentCaptor<BatteryReceiver> batCaptor = ArgumentCaptor.forClass(BatteryReceiver.class);
+ IntentFilter batFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+ batFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ verify(mContextSpy).registerReceiver(batCaptor.capture(),
+ argThat(new IntentFilterMatcher(batFilter)), isNull(), isA(Handler.class));
+ mBatteryReceiver = batCaptor.getValue();
+
+ // Grab the UserSwitchedReceiver
+ ArgumentCaptor<UserSwitchedReceiver> userSwitchedCaptor =
+ ArgumentCaptor.forClass(UserSwitchedReceiver.class);
+ IntentFilter usFilter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
+ verify(mContextSpy).registerReceiver(userSwitchedCaptor.capture(),
+ argThat(new IntentFilterMatcher(usFilter)), isNull(), isA(Handler.class));
+ mUserSwitchedReceiver = userSwitchedCaptor.getValue();
+
+ mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+ }
+
+ private void forceSleep() {
+ mService.getBinderServiceInstance().goToSleep(mClock.now(),
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+ }
+
+ private void forceDream() {
+ mService.getBinderServiceInstance().nap(mClock.now());
+ }
+
+ private void forceAwake() {
+ mService.getBinderServiceInstance().wakeUp(mClock.now(),
+ PowerManager.WAKE_REASON_UNKNOWN, "testing IPowerManager.wakeUp()", "pkg.name");
+ }
+
+ private void forceDozing() {
+ mService.getBinderServiceInstance().goToSleep(mClock.now(),
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0);
+ }
+
+ private void setPluggedIn(boolean isPluggedIn) {
+ // Set the callback to return the new state
+ when(mBatteryManagerInternalMock.isPowered(anyInt()))
+ .thenReturn(isPluggedIn);
+ // Trigger PowerManager to reread the plug-in state
+ mBatteryReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_BATTERY_CHANGED));
+ }
+
+ private void setBatteryLevel(int batteryLevel) {
+ when(mBatteryManagerInternalMock.getBatteryLevel())
+ .thenReturn(batteryLevel);
+ mBatteryReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_BATTERY_CHANGED));
+ }
+
+ private void setBatteryHealth(int batteryHealth) {
+ when(mBatteryManagerInternalMock.getBatteryHealth())
+ .thenReturn(batteryHealth);
+ mBatteryReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_BATTERY_CHANGED));
+ }
+
+ private void setAttentiveTimeout(int attentiveTimeoutMillis) {
+ Settings.Secure.putInt(
+ mContextSpy.getContentResolver(), Settings.Secure.ATTENTIVE_TIMEOUT,
+ attentiveTimeoutMillis);
+ }
+
+ private void setAttentiveWarningDuration(int attentiveWarningDurationMillis) {
+ when(mResourcesSpy.getInteger(
+ com.android.internal.R.integer.config_attentiveWarningDuration))
+ .thenReturn(attentiveWarningDurationMillis);
+ }
+
+ private void setMinimumScreenOffTimeoutConfig(int minimumScreenOffTimeoutConfigMillis) {
+ when(mResourcesSpy.getInteger(
+ com.android.internal.R.integer.config_minimumScreenOffTimeout))
+ .thenReturn(minimumScreenOffTimeoutConfigMillis);
+ }
+
+ private void setDreamsDisabledByAmbientModeSuppressionConfig(boolean disable) {
+ when(mResourcesSpy.getBoolean(
+ com.android.internal.R.bool.config_dreamsDisabledByAmbientModeSuppressionConfig))
+ .thenReturn(disable);
+ }
+
+ private void setDreamsBatteryLevelDrainConfig(int threshold) {
+ when(mResourcesSpy.getInteger(
+ com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff)).thenReturn(
+ threshold);
+ }
+
+ private void advanceTime(long timeMs) {
+ mClock.fastForward(timeMs);
+ mTestLooper.dispatchAll();
+ }
+
+ @Test
+ public void testCreateService_initializesNativeServiceAndSetsPowerModes() {
+ PowerManagerService service = createService();
+ verify(mNativeWrapperMock).nativeInit(same(service));
+ verify(mNativeWrapperMock).nativeSetPowerMode(eq(Mode.INTERACTIVE), eq(true));
+ verify(mNativeWrapperMock).nativeSetPowerMode(eq(Mode.DOUBLE_TAP_TO_WAKE), eq(false));
+ }
+
+ @Test
+ public void testGetLastShutdownReasonInternal() {
+ when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_REBOOT_REASON), any())).thenReturn(
+ "shutdown,thermal");
+ createService();
+ int reason = mService.getLastShutdownReasonInternal();
+ assertThat(reason).isEqualTo(PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN);
+ }
+
+ @Test
+ public void testWakefulnessAwake_InitialValue() {
+ createService();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @Test
+ public void testWakefulnessSleep_NoDozeSleepFlag() {
+ createService();
+ // Start with AWAKE state
+ startSystem();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ // Take a nap and verify.
+ mService.getBinderServiceInstance().goToSleep(mClock.now(),
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ }
+
+ @Test
+ public void testWakefulnessSleep_SoftSleepFlag_NoWakelocks() {
+ createService();
+ // Start with AWAKE state
+ startSystem();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ // Take a nap and verify we go to sleep.
+ mService.getBinderServiceInstance().goToSleep(mClock.now(),
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION,
+ PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ }
+
+ @Test
+ public void testWakefulnessSleep_SoftSleepFlag_WithPartialWakelock() {
+ createService();
+ // Start with AWAKE state
+ startSystem();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ // Grab a wakelock
+ final String tag = "wakelock1";
+ final String packageName = "pkg.name";
+ final IBinder token = new Binder();
+ final int flags = PowerManager.PARTIAL_WAKE_LOCK;
+ mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY,
+ null /* callback */);
+
+ // Take a nap and verify we stay awake.
+ mService.getBinderServiceInstance().goToSleep(mClock.now(),
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION,
+ PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ }
+
+ @Test
+ public void testWakefulnessSleep_SoftSleepFlag_WithFullWakelock() {
+ createService();
+ // Start with AWAKE state
+ startSystem();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ // Grab a wakelock
+ final String tag = "wakelock1";
+ final String packageName = "pkg.name";
+ final IBinder token = new Binder();
+ final int flags = PowerManager.FULL_WAKE_LOCK;
+ mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY,
+ null /* callback */);
+
+ // Take a nap and verify we stay awake.
+ mService.getBinderServiceInstance().goToSleep(mClock.now(),
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION,
+ PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @Test
+ public void testWakefulnessSleep_SoftSleepFlag_WithScreenBrightWakelock() {
+ createService();
+ // Start with AWAKE state
+ startSystem();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ // Grab a wakelock
+ final String tag = "wakelock1";
+ final String packageName = "pkg.name";
+ final IBinder token = new Binder();
+ final int flags = PowerManager.SCREEN_BRIGHT_WAKE_LOCK;
+ mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY,
+ null /* callback */);
+
+ // Take a nap and verify we stay awake.
+ mService.getBinderServiceInstance().goToSleep(mClock.now(),
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION,
+ PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+ @Test
+ public void testWakefulnessSleep_SoftSleepFlag_WithScreenDimWakelock() {
+ createService();
+ // Start with AWAKE state
+ startSystem();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ // Grab a wakelock
+ final String tag = "wakelock1";
+ final String packageName = "pkg.name";
+ final IBinder token = new Binder();
+ final int flags = PowerManager.SCREEN_DIM_WAKE_LOCK;
+ mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY,
+ null /* callback */);
+
+ // Take a nap and verify we stay awake.
+ mService.getBinderServiceInstance().goToSleep(mClock.now(),
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION,
+ PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @Test
+ @EnableCompatChanges({PowerManagerService.REQUIRE_TURN_SCREEN_ON_PERMISSION})
+ public void testWakefulnessAwake_AcquireCausesWakeup_turnScreenOnAllowed() {
+ createService();
+ startSystem();
+ forceSleep();
+
+ IBinder token = new Binder();
+ String tag = "acq_causes_wakeup";
+ String packageName = "pkg.name";
+ AttributionSource attrSrc = new AttributionSource(Binder.getCallingUid(),
+ packageName, /* attributionTag= */ null);
+
+ doReturn(PermissionChecker.PERMISSION_GRANTED).when(
+ mPermissionCheckerWrapperMock).checkPermissionForDataDelivery(any(),
+ eq(android.Manifest.permission.TURN_SCREEN_ON), anyInt(), eq(attrSrc), anyString());
+
+ // First, ensure that a normal full wake lock does not cause a wakeup
+ int flags = PowerManager.FULL_WAKE_LOCK;
+ mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */);
+
+ // Ensure that the flag does *NOT* work with a partial wake lock.
+ flags = PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP;
+ mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */);
+
+ // Verify that flag forces a wakeup when paired to a FULL_WAKE_LOCK
+ flags = PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP;
+ mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */);
+ }
+
+ @Test
+ @DisableCompatChanges({PowerManagerService.REQUIRE_TURN_SCREEN_ON_PERMISSION})
+ public void testWakefulnessAwake_AcquireCausesWakeupOldSdk_turnScreenOnAllowed() {
+ createService();
+ startSystem();
+ forceSleep();
+
+ IBinder token = new Binder();
+ String tag = "acq_causes_wakeup";
+ String packageName = "pkg.name";
+ AttributionSource attrSrc = new AttributionSource(Binder.getCallingUid(),
+ packageName, /* attributionTag= */ null);
+
+ // verify that the wakeup is allowed for apps targeting older sdks, and therefore won't have
+ // the TURN_SCREEN_ON permission granted
+ doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
+ mPermissionCheckerWrapperMock).checkPermissionForDataDelivery(any(),
+ eq(android.Manifest.permission.TURN_SCREEN_ON), anyInt(), eq(attrSrc), anyString());
+
+ doReturn(false).when(mPowerPropertiesWrapper).waive_target_sdk_check_for_turn_screen_on();
+
+ int flags = PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP;
+ mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */);
+ }
+
+ @Test
+ @EnableCompatChanges({PowerManagerService.REQUIRE_TURN_SCREEN_ON_PERMISSION})
+ public void testWakefulnessAwake_AcquireCausesWakeup_turnScreenOnDenied() {
+ createService();
+ startSystem();
+ forceSleep();
+
+ IBinder token = new Binder();
+ String tag = "acq_causes_wakeup";
+ String packageName = "pkg.name";
+ AttributionSource attrSrc = new AttributionSource(Binder.getCallingUid(),
+ packageName, /* attributionTag= */ null);
+ doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
+ mPermissionCheckerWrapperMock).checkPermissionForDataDelivery(any(),
+ eq(android.Manifest.permission.TURN_SCREEN_ON), anyInt(), eq(attrSrc), anyString());
+
+ doReturn(false).when(mPowerPropertiesWrapper).waive_target_sdk_check_for_turn_screen_on();
+ doReturn(false).when(mPowerPropertiesWrapper).permissionless_turn_screen_on();
+
+ // Verify that flag has no effect when TURN_SCREEN_ON is not allowed for apps targeting U+
+ int flags = PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP;
+ mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */);
+ }
+
+ @Test
+ @EnableCompatChanges({PowerManagerService.REQUIRE_TURN_SCREEN_ON_PERMISSION})
+ public void testWakefulnessAwake_AcquireCausesWakeupOldSdk_turnScreenOnDenied() {
+ createService();
+ startSystem();
+ forceSleep();
+
+ IBinder token = new Binder();
+ String tag = "acq_causes_wakeup";
+ String packageName = "pkg.name";
+ AttributionSource attrSrc = new AttributionSource(Binder.getCallingUid(),
+ packageName, /* attributionTag= */ null);
+ doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
+ mPermissionCheckerWrapperMock).checkPermissionForDataDelivery(any(),
+ eq(android.Manifest.permission.TURN_SCREEN_ON), anyInt(), eq(attrSrc), anyString());
+
+ doReturn(true).when(mPowerPropertiesWrapper).waive_target_sdk_check_for_turn_screen_on();
+
+ // Verify that flag has no effect when TURN_SCREEN_ON is not allowed for apps targeting U+
+ int flags = PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP;
+ mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null);
+ if (PowerProperties.permissionless_turn_screen_on().orElse(false)) {
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ } else {
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ }
+ mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */);
+ }
+
+ @Test
+ public void testWakefulnessAwake_IPowerManagerWakeUp() {
+ createService();
+ startSystem();
+ forceSleep();
+ mService.getBinderServiceInstance().wakeUp(mClock.now(),
+ PowerManager.WAKE_REASON_UNKNOWN, "testing IPowerManager.wakeUp()", "pkg.name");
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ /**
+ * Tests a series of variants that control whether a device wakes-up when it is plugged in
+ * or docked.
+ */
+ @Test
+ public void testWakefulnessAwake_ShouldWakeUpWhenPluggedIn() {
+ createService();
+ startSystem();
+ forceSleep();
+
+ // Test 1:
+ // Set config to prevent it wake up, test, verify, reset config value.
+ when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_unplugTurnsOnScreen))
+ .thenReturn(false);
+ mService.readConfigurationLocked();
+ setPluggedIn(true);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_unplugTurnsOnScreen))
+ .thenReturn(true);
+ mService.readConfigurationLocked();
+
+ // Test 2:
+ // Turn the power off, sleep, then plug into a wireless charger.
+ // Verify that we do not wake up if the phone is being plugged into a wireless charger.
+ setPluggedIn(false);
+ forceSleep();
+ when(mBatteryManagerInternalMock.getPlugType())
+ .thenReturn(BatteryManager.BATTERY_PLUGGED_WIRELESS);
+ when(mWirelessChargerDetectorMock.update(true /* isPowered */,
+ BatteryManager.BATTERY_PLUGGED_WIRELESS)).thenReturn(false);
+ setPluggedIn(true);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+
+ // Test 3:
+ // Do not wake up if the phone is being REMOVED from a wireless charger
+ when(mBatteryManagerInternalMock.getPlugType()).thenReturn(0);
+ setPluggedIn(false);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+
+ // Test 4:
+ // Do not wake if we are dreaming.
+ forceAwake(); // Needs to be awake first before it can dream.
+ forceDream();
+ setPluggedIn(true);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ forceSleep();
+
+ // Test 5:
+ // Don't wake if the device is configured not to wake up in theater mode (and theater
+ // mode is enabled).
+ Settings.Global.putInt(
+ mContextSpy.getContentResolver(), Settings.Global.THEATER_MODE_ON, 1);
+ mUserSwitchedReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_USER_SWITCHED));
+ when(mResourcesSpy.getBoolean(
+ com.android.internal.R.bool.config_allowTheaterModeWakeFromUnplug))
+ .thenReturn(false);
+ setPluggedIn(false);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ Settings.Global.putInt(
+ mContextSpy.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0);
+ mUserSwitchedReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_USER_SWITCHED));
+
+ // Test 6:
+ // Don't wake up if we are Dozing away and always-on is enabled.
+ when(mAmbientDisplayConfigurationMock.alwaysOnEnabled(UserHandle.USER_CURRENT))
+ .thenReturn(true);
+ mUserSwitchedReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_USER_SWITCHED));
+ forceAwake();
+ forceDozing();
+ setPluggedIn(true);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+
+ // Test 7:
+ // Finally, take away all the factors above and ensure the device wakes up!
+ forceAwake();
+ forceSleep();
+ setPluggedIn(false);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ /**
+ * Tests that dreaming stops when undocking and not configured to keep dreaming.
+ */
+ @Test
+ public void testWakefulnessDream_shouldStopDreamingWhenUndocked_whenNotConfigured() {
+ // Make sure "unplug turns on screen" is configured to true.
+ when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_unplugTurnsOnScreen))
+ .thenReturn(true);
+
+ createService();
+ startSystem();
+
+ ArgumentCaptor<DreamManagerInternal.DreamManagerStateListener> dreamManagerStateListener =
+ ArgumentCaptor.forClass(DreamManagerInternal.DreamManagerStateListener.class);
+ verify(mDreamManagerInternalMock).registerDreamManagerStateListener(
+ dreamManagerStateListener.capture());
+ dreamManagerStateListener.getValue().onKeepDreamingWhenUnpluggingChanged(false);
+
+ when(mBatteryManagerInternalMock.getPlugType())
+ .thenReturn(BatteryManager.BATTERY_PLUGGED_DOCK);
+ setPluggedIn(true);
+
+ forceAwake(); // Needs to be awake first before it can dream.
+ forceDream();
+ when(mBatteryManagerInternalMock.getPlugType()).thenReturn(0);
+ setPluggedIn(false);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ /**
+ * Tests that dreaming continues when undocking and configured to do so.
+ */
+ @Test
+ public void testWakefulnessDream_shouldKeepDreamingWhenUndocked_whenConfigured() {
+ // Make sure "unplug turns on screen" is configured to true.
+ when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_unplugTurnsOnScreen))
+ .thenReturn(true);
+
+ createService();
+ startSystem();
+
+ ArgumentCaptor<DreamManagerInternal.DreamManagerStateListener> dreamManagerStateListener =
+ ArgumentCaptor.forClass(DreamManagerInternal.DreamManagerStateListener.class);
+ verify(mDreamManagerInternalMock).registerDreamManagerStateListener(
+ dreamManagerStateListener.capture());
+ dreamManagerStateListener.getValue().onKeepDreamingWhenUnpluggingChanged(true);
+
+ when(mBatteryManagerInternalMock.getPlugType())
+ .thenReturn(BatteryManager.BATTERY_PLUGGED_DOCK);
+ setPluggedIn(true);
+
+ forceAwake(); // Needs to be awake first before it can dream.
+ forceDream();
+ when(mBatteryManagerInternalMock.getPlugType()).thenReturn(0);
+ setPluggedIn(false);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ }
+
+ /**
+ * Tests that dreaming stops when undocking while showing a dream that prevents it.
+ */
+ @Test
+ public void testWakefulnessDream_shouldStopDreamingWhenUndocked_whenDreamPrevents() {
+ // Make sure "unplug turns on screen" is configured to true.
+ when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_unplugTurnsOnScreen))
+ .thenReturn(true);
+
+ createService();
+ startSystem();
+
+ ArgumentCaptor<DreamManagerInternal.DreamManagerStateListener> dreamManagerStateListener =
+ ArgumentCaptor.forClass(DreamManagerInternal.DreamManagerStateListener.class);
+ verify(mDreamManagerInternalMock).registerDreamManagerStateListener(
+ dreamManagerStateListener.capture());
+ dreamManagerStateListener.getValue().onKeepDreamingWhenUnpluggingChanged(true);
+
+ when(mBatteryManagerInternalMock.getPlugType())
+ .thenReturn(BatteryManager.BATTERY_PLUGGED_DOCK);
+ setPluggedIn(true);
+
+ forceAwake(); // Needs to be awake first before it can dream.
+ forceDream();
+ dreamManagerStateListener.getValue().onKeepDreamingWhenUnpluggingChanged(false);
+ when(mBatteryManagerInternalMock.getPlugType()).thenReturn(0);
+ setPluggedIn(false);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @Test
+ public void testWakefulnessDream_shouldStopDreamingWhenUnplugging_whenDreamPrevents() {
+ // Make sure "unplug turns on screen" is configured to true.
+ when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_unplugTurnsOnScreen))
+ .thenReturn(true);
+
+ createService();
+ startSystem();
+
+ ArgumentCaptor<DreamManagerInternal.DreamManagerStateListener> dreamManagerStateListener =
+ ArgumentCaptor.forClass(DreamManagerInternal.DreamManagerStateListener.class);
+ verify(mDreamManagerInternalMock).registerDreamManagerStateListener(
+ dreamManagerStateListener.capture());
+
+ when(mBatteryManagerInternalMock.getPlugType())
+ .thenReturn(BatteryManager.BATTERY_PLUGGED_AC);
+ setPluggedIn(true);
+
+ forceAwake(); // Needs to be awake first before it can dream.
+ forceDream();
+ dreamManagerStateListener.getValue().onKeepDreamingWhenUnpluggingChanged(false);
+ when(mBatteryManagerInternalMock.getPlugType()).thenReturn(0);
+ setPluggedIn(false);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+
+ @Test
+ public void testWakefulnessDoze_goToSleep() {
+ createService();
+ // Start with AWAKE state
+ startSystem();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ // Take a nap and verify.
+ mService.getBinderServiceInstance().goToSleep(mClock.now(),
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ }
+
+ @Test
+ public void testWasDeviceIdleFor_true() {
+ int interval = 1000;
+ createService();
+ startSystem();
+ mService.onUserActivity();
+ advanceTime(interval + 1 /* just a little more */);
+ assertThat(mService.wasDeviceIdleForInternal(interval)).isTrue();
+ }
+
+ @Test
+ public void testWasDeviceIdleFor_false() {
+ int interval = 1000;
+ createService();
+ startSystem();
+ mService.onUserActivity();
+ assertThat(mService.wasDeviceIdleForInternal(interval)).isFalse();
+ }
+
+ @Test
+ public void testForceSuspend_putsDeviceToSleep() {
+ createService();
+ startSystem();
+
+ // Verify that we start awake
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ // Grab the wakefulness value when PowerManager finally calls into the
+ // native component to actually perform the suspend.
+ when(mNativeWrapperMock.nativeForceSuspend()).then(inv -> {
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ return true;
+ });
+
+ boolean retval = mService.getBinderServiceInstance().forceSuspend();
+ assertThat(retval).isTrue();
+
+ // Still asleep when the function returns.
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ }
+
+ @Test
+ public void testForceSuspend_wakeLocksDisabled() {
+ final String tag = "TestWakelockTag_098213";
+ final int flags = PowerManager.PARTIAL_WAKE_LOCK;
+ final String pkg = mContextSpy.getOpPackageName();
+
+ createService();
+
+ // Set up the Notification mock to keep track of the wakelocks that are currently
+ // active or disabled. We'll use this to verify that wakelocks are disabled when
+ // they should be.
+ final Map<String, Integer> wakelockMap = new HashMap<>(1);
+ doAnswer(inv -> {
+ wakelockMap.put((String) inv.getArguments()[1], (int) inv.getArguments()[0]);
+ return null;
+ }).when(mNotifierMock).onWakeLockAcquired(anyInt(), anyString(), anyString(), anyInt(),
+ anyInt(), any(), any(), any());
+ doAnswer(inv -> {
+ wakelockMap.remove((String) inv.getArguments()[1]);
+ return null;
+ }).when(mNotifierMock).onWakeLockReleased(anyInt(), anyString(), anyString(), anyInt(),
+ anyInt(), any(), any(), any());
+
+ //
+ // TEST STARTS HERE
+ //
+ startSystem();
+
+ // Verify that we start awake
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ // Create a wakelock
+ mService.getBinderServiceInstance().acquireWakeLock(new Binder(), flags, tag, pkg,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null);
+ assertThat(wakelockMap.get(tag)).isEqualTo(flags); // Verify wakelock is active.
+
+ // Confirm that the wakelocks have been disabled when the forceSuspend is in flight.
+ when(mNativeWrapperMock.nativeForceSuspend()).then(inv -> {
+ // Verify that the wakelock is disabled by the time we get to the native force
+ // suspend call.
+ assertThat(wakelockMap.containsKey(tag)).isFalse();
+ return true;
+ });
+
+ assertThat(mService.getBinderServiceInstance().forceSuspend()).isTrue();
+ assertThat(wakelockMap.get(tag)).isEqualTo(flags);
+
+ }
+
+ @Test
+ public void testForceSuspend_forceSuspendFailurePropagated() {
+ createService();
+ startSystem();
+ when(mNativeWrapperMock.nativeForceSuspend()).thenReturn(false);
+ assertThat(mService.getBinderServiceInstance().forceSuspend()).isFalse();
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testScreensaverActivateOnSleepDisabled_powered_afterTimeout_goesToDozing() {
+ when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(true);
+
+ doAnswer(inv -> {
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+ return null;
+ }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
+
+ setMinimumScreenOffTimeoutConfig(5);
+ createService();
+ startSystem();
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ advanceTime(15000);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testScreensaverActivateOnSleepEnabled_powered_afterTimeout_goesToDreaming() {
+ when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_dreamsSupported))
+ .thenReturn(true);
+ when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(true);
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ENABLED, 1);
+
+ doAnswer(inv -> {
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+ return null;
+ }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
+
+ setMinimumScreenOffTimeoutConfig(5);
+ createService();
+ startSystem();
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ advanceTime(15000);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testAmbientSuppression_disablesDreamingAndWakesDevice() {
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ENABLED, 1);
+
+ setDreamsDisabledByAmbientModeSuppressionConfig(true);
+ setMinimumScreenOffTimeoutConfig(10000);
+ createService();
+ startSystem();
+
+ doAnswer(inv -> {
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+ return null;
+ }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
+
+ setPluggedIn(true);
+ // Allow asynchronous sandman calls to execute.
+ advanceTime(10000);
+
+ forceDream();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test", true);
+ advanceTime(50);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testAmbientSuppressionDisabled_shouldNotWakeDevice() {
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ENABLED, 1);
+
+ setDreamsDisabledByAmbientModeSuppressionConfig(false);
+ setMinimumScreenOffTimeoutConfig(10000);
+ createService();
+ startSystem();
+
+ doAnswer(inv -> {
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+ return null;
+ }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
+
+ setPluggedIn(true);
+ // Allow asynchronous sandman calls to execute.
+ advanceTime(10000);
+
+ forceDream();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test", true);
+ advanceTime(50);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ }
+
+ @Test
+ public void testAmbientSuppression_doesNotAffectDreamForcing() {
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ENABLED, 1);
+
+ setDreamsDisabledByAmbientModeSuppressionConfig(true);
+ setMinimumScreenOffTimeoutConfig(10000);
+ createService();
+ startSystem();
+
+ doAnswer(inv -> {
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+ return null;
+ }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
+
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test", true);
+ setPluggedIn(true);
+ // Allow asynchronous sandman calls to execute.
+ advanceTime(10000);
+
+ // Verify that forcing dream still works even though ambient display is suppressed
+ forceDream();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ }
+
+ @Test
+ public void testBatteryDrainDuringDream() {
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
+ Settings.Secure.putInt(mContextSpy.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ENABLED, 1);
+
+ setMinimumScreenOffTimeoutConfig(100);
+ setDreamsBatteryLevelDrainConfig(5);
+ createService();
+ startSystem();
+
+ doAnswer(inv -> {
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+ return null;
+ }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
+
+ setBatteryLevel(100);
+ setPluggedIn(true);
+
+ forceAwake(); // Needs to be awake first before it can dream.
+ forceDream();
+ advanceTime(10); // Allow async calls to happen
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ setBatteryLevel(90);
+ advanceTime(10); // Allow async calls to happen
+ assertThat(mService.getDreamsBatteryLevelDrain()).isEqualTo(10);
+
+ // If battery overheat protection is enabled, we shouldn't count battery drain
+ setBatteryHealth(BatteryManager.BATTERY_HEALTH_OVERHEAT);
+ setBatteryLevel(70);
+ advanceTime(10); // Allow async calls to happen
+ assertThat(mService.getDreamsBatteryLevelDrain()).isEqualTo(10);
+ }
+
+ @Test
+ public void testSetDozeOverrideFromDreamManager_triggersSuspendBlocker() {
+ final String suspendBlockerName = "PowerManagerService.Display";
+ final String tag = "acq_causes_wakeup";
+ final String packageName = "pkg.name";
+ final IBinder token = new Binder();
+
+ final boolean[] isAcquired = new boolean[1];
+ doAnswer(inv -> {
+ if (suspendBlockerName.equals(inv.getArguments()[0])) {
+ isAcquired[0] = false;
+ }
+ return null;
+ }).when(mNativeWrapperMock).nativeReleaseSuspendBlocker(any());
+
+ doAnswer(inv -> {
+ if (suspendBlockerName.equals(inv.getArguments()[0])) {
+ isAcquired[0] = true;
+ }
+ return null;
+ }).when(mNativeWrapperMock).nativeAcquireSuspendBlocker(any());
+
+ // Need to create the service after we stub the mocks for this test because some of the
+ // mocks are used during the constructor.
+ createService();
+
+ // Start with AWAKE state
+ startSystem();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertTrue(isAcquired[0]);
+
+ // Take a nap and verify we no longer hold the blocker
+ int flags = PowerManager.DOZE_WAKE_LOCK;
+ mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null);
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+ mService.getBinderServiceInstance().goToSleep(mClock.now(),
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ assertFalse(isAcquired[0]);
+
+ // Override the display state by DreamManager and verify is reacquires the blocker.
+ mService.getLocalServiceInstance()
+ .setDozeOverrideFromDreamManager(Display.STATE_ON, PowerManager.BRIGHTNESS_DEFAULT);
+ assertTrue(isAcquired[0]);
+ }
+
+ @Test
+ public void testSuspendBlockerHeldDuringBoot() {
+ final String suspendBlockerName = "PowerManagerService.Booting";
+
+ final boolean[] isAcquired = new boolean[1];
+ doAnswer(inv -> {
+ isAcquired[0] = false;
+ return null;
+ }).when(mNativeWrapperMock).nativeReleaseSuspendBlocker(eq(suspendBlockerName));
+
+ doAnswer(inv -> {
+ isAcquired[0] = true;
+ return null;
+ }).when(mNativeWrapperMock).nativeAcquireSuspendBlocker(eq(suspendBlockerName));
+
+ // Need to create the service after we stub the mocks for this test because some of the
+ // mocks are used during the constructor.
+ createService();
+ assertTrue(isAcquired[0]);
+
+ mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+ assertTrue(isAcquired[0]);
+
+ mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+ assertFalse(isAcquired[0]);
+ }
+
+ @Test
+ public void testInattentiveSleep_hideWarningIfStayOnIsEnabledAndPluggedIn() {
+ setMinimumScreenOffTimeoutConfig(5);
+ setAttentiveWarningDuration(120);
+ setAttentiveTimeout(100);
+
+ Settings.Global.putInt(mContextSpy.getContentResolver(),
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN, BatteryManager.BATTERY_PLUGGED_AC);
+
+ createService();
+ startSystem();
+
+ verify(mInattentiveSleepWarningControllerMock, times(1)).show();
+ verify(mInattentiveSleepWarningControllerMock, never()).dismiss(anyBoolean());
+ when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(true);
+
+ setPluggedIn(true);
+ verify(mInattentiveSleepWarningControllerMock, atLeastOnce()).dismiss(true);
+ }
+
+ @Test
+ public void testInattentiveSleep_hideWarningIfInattentiveSleepIsDisabled() {
+ setMinimumScreenOffTimeoutConfig(5);
+ setAttentiveWarningDuration(120);
+ setAttentiveTimeout(100);
+
+ createService();
+ startSystem();
+
+ verify(mInattentiveSleepWarningControllerMock, times(1)).show();
+ verify(mInattentiveSleepWarningControllerMock, never()).dismiss(anyBoolean());
+ when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(true);
+
+ setAttentiveTimeout(-1);
+ mService.handleSettingsChangedLocked();
+
+ verify(mInattentiveSleepWarningControllerMock, atLeastOnce()).dismiss(true);
+ }
+
+ @Test
+ public void testInattentiveSleep_userActivityDismissesWarning() {
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+ when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);
+ setMinimumScreenOffTimeoutConfig(5);
+ setAttentiveWarningDuration(1900);
+ setAttentiveTimeout(2000);
+
+ createService();
+ startSystem();
+
+ mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, mClock.now(),
+ PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
+ verify(mInattentiveSleepWarningControllerMock, never()).show();
+
+ advanceTime(150);
+ verify(mInattentiveSleepWarningControllerMock, times(1)).show();
+ verify(mInattentiveSleepWarningControllerMock, never()).dismiss(anyBoolean());
+ when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(true);
+
+ mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, mClock.now(),
+ PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
+ verify(mInattentiveSleepWarningControllerMock, times(1)).dismiss(true);
+ }
+
+ @Test
+ public void testInattentiveSleep_warningHiddenAfterWakingUp() {
+ setMinimumScreenOffTimeoutConfig(5);
+ setAttentiveWarningDuration(70);
+ setAttentiveTimeout(100);
+
+ createService();
+ startSystem();
+ advanceTime(50);
+ verify(mInattentiveSleepWarningControllerMock, atLeastOnce()).show();
+ when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(true);
+ advanceTime(70);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ forceAwake();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ verify(mInattentiveSleepWarningControllerMock, atLeastOnce()).dismiss(false);
+ }
+
+ @Test
+ public void testInattentiveSleep_warningStaysWhenDreaming() {
+ setMinimumScreenOffTimeoutConfig(5);
+ setAttentiveWarningDuration(70);
+ setAttentiveTimeout(100);
+ createService();
+ startSystem();
+ advanceTime(50);
+ verify(mInattentiveSleepWarningControllerMock, atLeastOnce()).show();
+ when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(true);
+
+ forceDream();
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+
+ advanceTime(10);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ verify(mInattentiveSleepWarningControllerMock, never()).dismiss(anyBoolean());
+ }
+
+ @Test
+ public void testInattentiveSleep_warningNotShownWhenSleeping() {
+ setMinimumScreenOffTimeoutConfig(5);
+ setAttentiveWarningDuration(70);
+ setAttentiveTimeout(100);
+ createService();
+ startSystem();
+
+ advanceTime(10);
+ forceSleep();
+
+ advanceTime(50);
+ verify(mInattentiveSleepWarningControllerMock, never()).show();
+ }
+
+ @Test
+ public void testInattentiveSleep_noWarningShownIfInattentiveSleepDisabled() {
+ setAttentiveTimeout(-1);
+ createService();
+ startSystem();
+ verify(mInattentiveSleepWarningControllerMock, never()).show();
+ }
+
+ @Test
+ public void testInattentiveSleep_goesToSleepAfterTimeout() {
+ setMinimumScreenOffTimeoutConfig(5);
+ setAttentiveTimeout(5);
+ createService();
+ startSystem();
+ advanceTime(20);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getBinderServiceInstance().getLastSleepReason()).isEqualTo(
+ PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE);
+ }
+
+ @Test
+ public void testInattentiveSleep_goesToSleepWithWakeLock() {
+ final String pkg = mContextSpy.getOpPackageName();
+ final Binder token = new Binder();
+ final String tag = "testInattentiveSleep_goesToSleepWithWakeLock";
+
+ setMinimumScreenOffTimeoutConfig(5);
+ setAttentiveTimeout(30);
+ createService();
+ startSystem();
+
+ mService.getBinderServiceInstance().acquireWakeLock(token,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ advanceTime(60);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getBinderServiceInstance().getLastSleepReason()).isEqualTo(
+ PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE);
+ }
+
+ @Test
+ public void testInattentiveSleep_dreamEnds_goesToSleepAfterTimeout() {
+ setMinimumScreenOffTimeoutConfig(5);
+ setAttentiveTimeout(30000);
+ createService();
+ startSystem();
+
+ advanceTime(10000);
+ forceDream();
+ advanceTime(10000);
+ final String pkg = mContextSpy.getOpPackageName();
+ mService.getBinderServiceInstance().wakeUp(mClock.now(),
+ PowerManager.WAKE_REASON_DREAM_FINISHED, "PowerManagerServiceTest:DREAM_FINISHED",
+ pkg);
+ advanceTime(10001);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getBinderServiceInstance().getLastSleepReason()).isEqualTo(
+ PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE);
+ }
+
+ @Test
+ public void testInattentiveSleep_wakeLockOnAfterRelease_inattentiveSleepTimeoutNotAffected() {
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+ when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);
+
+ final String pkg = mContextSpy.getOpPackageName();
+ final Binder token = new Binder();
+ final String tag = "testInattentiveSleep_wakeLockOnAfterRelease";
+
+ setMinimumScreenOffTimeoutConfig(5);
+ setAttentiveTimeout(2000);
+ createService();
+ startSystem();
+
+ mService.getBinderServiceInstance().acquireWakeLock(token,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, tag, pkg,
+ null /* workSource */, null /* historyTag */, Display.DEFAULT_DISPLAY, null);
+
+ advanceTime(1500);
+ mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */);
+
+ advanceTime(520);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getBinderServiceInstance().getLastSleepReason()).isEqualTo(
+ PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE);
+ }
+
+ @Test
+ public void testInattentiveSleep_userActivityNoChangeLights_inattentiveSleepTimeoutNotAffected() {
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+ when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);
+
+ setMinimumScreenOffTimeoutConfig(5);
+ setAttentiveTimeout(2000);
+ createService();
+ startSystem();
+
+ advanceTime(1500);
+ mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, mClock.now(),
+ PowerManager.USER_ACTIVITY_EVENT_OTHER,
+ PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS);
+
+ advanceTime(520);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getBinderServiceInstance().getLastSleepReason()).isEqualTo(
+ PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE);
+ }
+
+ @Test
+ public void testInattentiveSleep_userActivity_inattentiveSleepTimeoutExtended() {
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+ when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);
+
+ setMinimumScreenOffTimeoutConfig(5);
+ setAttentiveTimeout(2000);
+ createService();
+ startSystem();
+
+ advanceTime(1500);
+ mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, mClock.now(),
+ PowerManager.USER_ACTIVITY_EVENT_OTHER, 0 /* flags */);
+
+ advanceTime(520);
+ assertThat(mService.getGlobalWakefulnessLocked()).isNotEqualTo(WAKEFULNESS_ASLEEP);
+ }
+
+
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testInattentiveSleep_goesToSleepFromDream() {
+ setAttentiveTimeout(20000);
+ createService();
+ startSystem();
+ setPluggedIn(true);
+ forceAwake();
+ forceDream();
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+
+ advanceTime(20500);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ }
+
+ @Test
+ public void testWakeLock_affectsProperDisplayGroup() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+ when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);
+
+ final String pkg = mContextSpy.getOpPackageName();
+ final Binder token = new Binder();
+ final String tag = "testWakeLock_affectsProperDisplayGroup";
+
+ setMinimumScreenOffTimeoutConfig(5);
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ mService.getBinderServiceInstance().acquireWakeLock(token,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg,
+ null /* workSource */, null /* historyTag */, Display.DEFAULT_DISPLAY, null);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+
+ advanceTime(15000);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_DOZING);
+ }
+
+ @Test
+ public void testInvalidDisplayGroupWakeLock_affectsAllDisplayGroups() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+ when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);
+
+ final String pkg = mContextSpy.getOpPackageName();
+ final Binder token = new Binder();
+ final String tag = "testInvalidDisplayGroupWakeLock_affectsAllDisplayGroups";
+
+ setMinimumScreenOffTimeoutConfig(5);
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ mService.getBinderServiceInstance().acquireWakeLock(token,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, null);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+
+ advanceTime(15000);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ }
+
+ @Test
+ public void testRemovedDisplayGroupWakeLock_affectsNoDisplayGroups() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = nonDefaultDisplayGroupId;
+ when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
+
+ doAnswer(inv -> {
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+ return null;
+ }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
+
+ final String pkg = mContextSpy.getOpPackageName();
+ final Binder token = new Binder();
+ final String tag = "testRemovedDisplayGroupWakeLock_affectsNoDisplayGroups";
+
+ setMinimumScreenOffTimeoutConfig(5);
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ mService.getBinderServiceInstance().acquireWakeLock(token,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg,
+ null /* workSource */, null /* historyTag */, nonDefaultDisplay, null);
+
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ listener.get().onDisplayGroupRemoved(nonDefaultDisplayGroupId);
+
+ advanceTime(15000);
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_DOZING);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ }
+
+ @Test
+ public void testBoot_ShouldBeAwake() {
+ createService();
+ startSystem();
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ verify(mNotifierMock, never()).onGlobalWakefulnessChangeStarted(anyInt(), anyInt(),
+ anyLong());
+ }
+
+ @Test
+ public void testBoot_DesiredScreenPolicyShouldBeBright() {
+ createService();
+ startSystem();
+
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
+ DisplayPowerRequest.POLICY_BRIGHT);
+ }
+
+ @Test
+ public void testQuiescentBoot_ShouldBeAsleep() {
+ when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), any())).thenReturn("1");
+ createService();
+ startSystem();
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ verify(mNotifierMock).onGlobalWakefulnessChangeStarted(eq(WAKEFULNESS_ASLEEP), anyInt(),
+ anyLong());
+ }
+
+ @Test
+ public void testQuiescentBoot_DesiredScreenPolicyShouldBeOff() {
+ when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), any())).thenReturn("1");
+ createService();
+ startSystem();
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
+ DisplayPowerRequest.POLICY_OFF);
+ }
+
+ @Test
+ public void testQuiescentBoot_WakeUp_DesiredScreenPolicyShouldBeBright() {
+ when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), any())).thenReturn("1");
+ createService();
+ startSystem();
+ forceAwake();
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
+ DisplayPowerRequest.POLICY_BRIGHT);
+ }
+
+ @Test
+ public void testQuiescentBoot_WakeKeyBeforeBootCompleted_AwakeAfterBootCompleted() {
+ when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), any())).thenReturn("1");
+ createService();
+ startSystem();
+
+ mService.getBinderServiceInstance().wakeUp(mClock.now(),
+ PowerManager.WAKE_REASON_UNKNOWN, "testing IPowerManager.wakeUp()", "pkg.name");
+
+ mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ DisplayPowerRequest.POLICY_BRIGHT);
+ }
+
+ @Test
+ public void testIsAmbientDisplayAvailable_available() {
+ createService();
+ when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(true);
+
+ assertThat(mService.getBinderServiceInstance().isAmbientDisplayAvailable()).isTrue();
+ }
+
+ @Test
+ public void testIsAmbientDisplayAvailable_unavailable() {
+ createService();
+ when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(false);
+
+ assertThat(mService.getBinderServiceInstance().isAmbientDisplayAvailable()).isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressed_default_notSuppressed() {
+ createService();
+
+ assertThat(mService.getBinderServiceInstance().isAmbientDisplaySuppressed()).isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressed_suppressed() {
+ createService();
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test", true);
+
+ assertThat(mService.getBinderServiceInstance().isAmbientDisplaySuppressed()).isTrue();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressed_notSuppressed() {
+ createService();
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test", false);
+
+ assertThat(mService.getBinderServiceInstance().isAmbientDisplaySuppressed()).isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressed_multipleTokens_suppressed() {
+ createService();
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test1", false);
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test2", true);
+
+ assertThat(mService.getBinderServiceInstance().isAmbientDisplaySuppressed()).isTrue();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressed_multipleTokens_notSuppressed() {
+ createService();
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test1", false);
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test2", false);
+
+ assertThat(mService.getBinderServiceInstance().isAmbientDisplaySuppressed()).isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressedForToken_default_notSuppressed() {
+ createService();
+
+ assertThat(mService.getBinderServiceInstance().isAmbientDisplaySuppressedForToken("test"))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressedForToken_suppressed() {
+ createService();
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test", true);
+
+ assertThat(mService.getBinderServiceInstance().isAmbientDisplaySuppressedForToken("test"))
+ .isTrue();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressedForToken_notSuppressed() {
+ createService();
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test", false);
+
+ assertThat(mService.getBinderServiceInstance().isAmbientDisplaySuppressedForToken("test"))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressedForToken_multipleTokens_suppressed() {
+ createService();
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test1", true);
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test2", true);
+
+ assertThat(mService.getBinderServiceInstance().isAmbientDisplaySuppressedForToken("test1"))
+ .isTrue();
+ assertThat(mService.getBinderServiceInstance().isAmbientDisplaySuppressedForToken("test2"))
+ .isTrue();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressedForToken_multipleTokens_notSuppressed() {
+ createService();
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test1", true);
+ mService.getBinderServiceInstance().suppressAmbientDisplay("test2", false);
+
+ assertThat(mService.getBinderServiceInstance().isAmbientDisplaySuppressedForToken("test1"))
+ .isTrue();
+ assertThat(mService.getBinderServiceInstance().isAmbientDisplaySuppressedForToken("test2"))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressedForTokenByApp_ambientDisplayUnavailable() {
+ createService();
+ when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(false);
+
+ BinderService service = mService.getBinderServiceInstance();
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressedForTokenByApp_default() {
+ createService();
+
+ BinderService service = mService.getBinderServiceInstance();
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressedForTokenByApp_suppressedByCallingApp() {
+ createService();
+ BinderService service = mService.getBinderServiceInstance();
+ service.suppressAmbientDisplay("test", true);
+
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+ .isTrue();
+ // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app.
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", /* appUid= */ 123))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressedForTokenByApp_notSuppressedByCallingApp() {
+ createService();
+ BinderService service = mService.getBinderServiceInstance();
+ service.suppressAmbientDisplay("test", false);
+
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+ .isFalse();
+ // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app.
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", /* appUid= */ 123))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressedForTokenByApp_multipleTokensSuppressedByCallingApp() {
+ createService();
+ BinderService service = mService.getBinderServiceInstance();
+ service.suppressAmbientDisplay("test1", true);
+ service.suppressAmbientDisplay("test2", true);
+
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test1", Binder.getCallingUid()))
+ .isTrue();
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test2", Binder.getCallingUid()))
+ .isTrue();
+ // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app.
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test1", /* appUid= */ 123))
+ .isFalse();
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test2", /* appUid= */ 123))
+ .isFalse();
+ }
+
+ @Test
+ public void testGetAmbientDisplaySuppressionTokens_default() {
+ createService();
+ BinderService service = mService.getBinderServiceInstance();
+
+ assertThat(service.getAmbientDisplaySuppressionTokens()).isEmpty();
+ }
+
+ @Test
+ public void testGetAmbientDisplaySuppressionTokens_singleToken() {
+ createService();
+ BinderService service = mService.getBinderServiceInstance();
+ service.suppressAmbientDisplay("test1", true);
+ service.suppressAmbientDisplay("test2", false);
+
+ assertThat(service.getAmbientDisplaySuppressionTokens()).containsExactly("test1");
+ }
+
+ @Test
+ public void testGetAmbientDisplaySuppressionTokens_multipleTokens() {
+ createService();
+ BinderService service = mService.getBinderServiceInstance();
+ service.suppressAmbientDisplay("test1", true);
+ service.suppressAmbientDisplay("test2", true);
+
+ assertThat(service.getAmbientDisplaySuppressionTokens())
+ .containsExactly("test1", "test2");
+ }
+
+ @Test
+ public void testSetPowerBoost_redirectsCallToNativeWrapper() {
+ createService();
+ startSystem();
+
+ mService.getBinderServiceInstance().setPowerBoost(Boost.INTERACTION, 1234);
+
+ verify(mNativeWrapperMock).nativeSetPowerBoost(eq(Boost.INTERACTION), eq(1234));
+ }
+
+ @Test
+ public void testSetPowerMode_redirectsCallToNativeWrapper() {
+ createService();
+ startSystem();
+
+ // Enabled launch boost in BatterySaverController to allow setting launch mode.
+ when(mBatterySaverControllerMock.isLaunchBoostDisabled()).thenReturn(false);
+ when(mNativeWrapperMock.nativeSetPowerMode(anyInt(), anyBoolean())).thenReturn(true);
+
+ mService.getBinderServiceInstance().setPowerMode(Mode.LAUNCH, true);
+
+ verify(mNativeWrapperMock).nativeSetPowerMode(eq(Mode.LAUNCH), eq(true));
+ }
+
+ @Test
+ public void testSetPowerMode_withLaunchBoostDisabledAndModeLaunch_ignoresCallToEnable() {
+ createService();
+ startSystem();
+
+ // Disables launch boost in BatterySaverController.
+ when(mBatterySaverControllerMock.isLaunchBoostDisabled()).thenReturn(true);
+ when(mNativeWrapperMock.nativeSetPowerMode(anyInt(), anyBoolean())).thenReturn(true);
+
+ mService.getBinderServiceInstance().setPowerMode(Mode.LAUNCH, true);
+ mService.getBinderServiceInstance().setPowerMode(Mode.LAUNCH, false);
+
+ verify(mNativeWrapperMock, never()).nativeSetPowerMode(eq(Mode.LAUNCH), eq(true));
+ verify(mNativeWrapperMock).nativeSetPowerMode(eq(Mode.LAUNCH), eq(false));
+ }
+
+ @Test
+ public void testSetPowerModeChecked_returnsNativeCallResult() {
+ createService();
+ startSystem();
+
+ // Disables launch boost in BatterySaverController.
+ when(mBatterySaverControllerMock.isLaunchBoostDisabled()).thenReturn(true);
+ when(mNativeWrapperMock.nativeSetPowerMode(anyInt(), anyBoolean())).thenReturn(true);
+ when(mNativeWrapperMock.nativeSetPowerMode(eq(Mode.INTERACTIVE), anyBoolean()))
+ .thenReturn(false);
+
+ // Ignored because isLaunchBoostDisabled is true. Should return false.
+ assertFalse(mService.getBinderServiceInstance().setPowerModeChecked(Mode.LAUNCH, true));
+ // Native calls return true.
+ assertTrue(mService.getBinderServiceInstance().setPowerModeChecked(Mode.LAUNCH, false));
+ assertTrue(mService.getBinderServiceInstance().setPowerModeChecked(Mode.LOW_POWER, true));
+ // Native call for interactive returns false.
+ assertFalse(
+ mService.getBinderServiceInstance().setPowerModeChecked(Mode.INTERACTIVE, false));
+ }
+
+ @Test
+ public void testMultiDisplay_wakefulnessUpdates() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_AWAKE, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @Test
+ public void testMultiDisplay_addDisplayGroup_wakesDeviceUp() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+ createService();
+ startSystem();
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @Test
+ public void testMultiDisplay_removeDisplayGroup_updatesWakefulness() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ listener.get().onDisplayGroupRemoved(nonDefaultDisplayGroupId);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_AWAKE, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @Test
+ public void testMultiDisplay_updatesLastGlobalWakeTime() {
+ final int nonDefaultPowerGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ long eventTime1 = 10;
+ long eventTime2 = eventTime1 + 1;
+ long eventTime3 = eventTime2 + 1;
+ long eventTime4 = eventTime3 + 1;
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultPowerGroupId);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_DOZING, eventTime1,
+ 0, PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE, 0, null, null);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(nonDefaultPowerGroupId, WAKEFULNESS_DOZING, eventTime2,
+ 0, PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
+ long eventElapsedRealtime1 = mLastElapsedRealtime;
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ assertThat(mService.getBinderServiceInstance().getLastSleepReason()).isEqualTo(
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION);
+
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_AWAKE,
+ eventTime3, /* uid= */ 0, PowerManager.WAKE_REASON_PLUGGED_IN, /* opUid= */
+ 0, /* opPackageName= */ null, /* details= */ null);
+ long eventElapsedRealtime2 = mLastElapsedRealtime;
+ PowerManager.WakeData wakeData = mService.getLocalServiceInstance().getLastWakeup();
+ assertThat(wakeData.wakeTime).isEqualTo(eventTime3);
+ assertThat(wakeData.wakeReason).isEqualTo(PowerManager.WAKE_REASON_PLUGGED_IN);
+ assertThat(wakeData.sleepDurationRealtime)
+ .isEqualTo(eventElapsedRealtime2 - eventElapsedRealtime1);
+
+ // The global wake time and reason as well as sleep duration shouldn't change when another
+ // PowerGroup wakes up.
+ mService.setWakefulnessLocked(nonDefaultPowerGroupId, WAKEFULNESS_AWAKE,
+ eventTime4, /* uid= */ 0, PowerManager.WAKE_REASON_CAMERA_LAUNCH, /* opUid= */
+ 0, /* opPackageName= */ null, /* details= */ null);
+ PowerManager.WakeData wakeData2 = mService.getLocalServiceInstance().getLastWakeup();
+ assertThat(wakeData2).isEqualTo(wakeData);
+ }
+
+ @Test
+ public void testMultiDisplay_defaultDisplayCanDoze() {
+ createService();
+ startSystem();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+
+ forceDozing();
+ // Allow handleSandman() to be called asynchronously
+ advanceTime(500);
+ verify(mDreamManagerInternalMock).startDream(eq(true), anyString());
+ }
+
+ @Test
+ public void testMultiDisplay_twoDisplays_defaultDisplayCanDoze() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = nonDefaultDisplayGroupId;
+ when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
+
+ createService();
+ startSystem();
+
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ forceDozing();
+
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_DOZING);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ // Allow handleSandman() to be called asynchronously
+ advanceTime(500);
+ verify(mDreamManagerInternalMock).startDream(eq(true), anyString());
+ }
+
+ @Test
+ public void testMultiDisplay_addNewDisplay_becomeGloballyAwakeButDefaultRemainsDozing() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = nonDefaultDisplayGroupId;
+ when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
+
+ doAnswer(inv -> {
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+ return null;
+ }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
+
+ createService();
+ startSystem();
+
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+
+ forceDozing();
+ advanceTime(500);
+
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_DOZING);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ verify(mDreamManagerInternalMock).stopDream(anyBoolean(), anyString());
+ verify(mDreamManagerInternalMock).startDream(eq(true), anyString());
+
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+ advanceTime(500);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_DOZING);
+
+ // Make sure there were no additional calls to stopDream or startDream
+ verify(mDreamManagerInternalMock, atMost(1)).stopDream(anyBoolean(), anyString());
+ verify(mDreamManagerInternalMock, atMost(1)).startDream(eq(true), anyString());
+ }
+
+ @Test
+ public void testLastSleepTime_notUpdatedWhenDreaming() {
+ createService();
+ startSystem();
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ PowerManager.WakeData initialWakeData = mService.getLocalServiceInstance().getLastWakeup();
+
+ forceDream();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+ assertThat(mService.getLocalServiceInstance().getLastWakeup()).isEqualTo(initialWakeData);
+ }
+
+ @Test
+ public void testMultiDisplay_onlyOneDisplaySleeps_onWakefulnessChangedEventsFire() {
+ createService();
+ startSystem();
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ forceSleep();
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_ASLEEP);
+
+ verify(mNotifierMock).onGroupWakefulnessChangeStarted(eq(Display.DEFAULT_DISPLAY_GROUP),
+ eq(WAKEFULNESS_ASLEEP), eq(PowerManager.GO_TO_SLEEP_REASON_APPLICATION), anyLong());
+ verify(mNotifierMock).onGlobalWakefulnessChangeStarted(eq(WAKEFULNESS_ASLEEP),
+ eq(PowerManager.GO_TO_SLEEP_REASON_APPLICATION), anyLong());
+ }
+
+ @Test
+ public void testMultiDisplay_bothDisplaysSleep_onWakefulnessChangedEventsFireCorrectly() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = nonDefaultDisplayGroupId;
+ when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
+
+ createService();
+ startSystem();
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, 0, 0,
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0,
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_ASLEEP);
+
+ verify(mNotifierMock).onGroupWakefulnessChangeStarted(eq(nonDefaultDisplayGroupId),
+ eq(WAKEFULNESS_ASLEEP), eq(PowerManager.GO_TO_SLEEP_REASON_APPLICATION), anyLong());
+ verify(mNotifierMock).onGroupWakefulnessChangeStarted(eq(Display.DEFAULT_DISPLAY_GROUP),
+ eq(WAKEFULNESS_ASLEEP), eq(PowerManager.GO_TO_SLEEP_REASON_APPLICATION), anyLong());
+ verify(mNotifierMock).onGlobalWakefulnessChangeStarted(eq(WAKEFULNESS_ASLEEP),
+ eq(PowerManager.GO_TO_SLEEP_REASON_APPLICATION), anyLong());
+ }
+
+ @Test
+ public void testMultiDisplay_separateWakeStates_onWakefulnessChangedEventsFireCorrectly() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = nonDefaultDisplayGroupId;
+ when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
+
+ createService();
+ startSystem();
+
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ final String pkg = mContextSpy.getOpPackageName();
+ final Binder token = new Binder();
+ final String tag =
+ "testMultiDisplay_separateWakeStates_onWakefulnessChangedEventFiresCorrectly";
+ mService.getBinderServiceInstance().acquireWakeLock(token,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg,
+ null /* workSource */, null /* historyTag */, nonDefaultDisplay, null);
+
+ forceSleep();
+
+ // The wakelock should have kept the second display awake, and we should notify that the
+ // default display went to sleep.
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ verify(mNotifierMock).onGroupWakefulnessChangeStarted(eq(nonDefaultDisplayGroupId),
+ eq(WAKEFULNESS_AWAKE), eq(PowerManager.WAKE_REASON_DISPLAY_GROUP_ADDED), anyLong());
+ verify(mNotifierMock).onGroupWakefulnessChangeStarted(eq(Display.DEFAULT_DISPLAY_GROUP),
+ eq(WAKEFULNESS_ASLEEP), eq(PowerManager.GO_TO_SLEEP_REASON_APPLICATION), anyLong());
+ verify(mNotifierMock, never()).onGlobalWakefulnessChangeStarted(eq(WAKEFULNESS_ASLEEP),
+ anyInt(), anyLong());
+ }
+
+ @Test
+ public void testMultiDisplay_oneDisplayGroupChanges_globalDoesNotChange() {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = nonDefaultDisplayGroupId;
+ when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
+
+ createService();
+ startSystem();
+
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ long eventTime = mClock.now();
+ mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, eventTime, 0,
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
+
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_ASLEEP);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ verify(mNotifierMock, never()).onGlobalWakefulnessChangeStarted(anyInt(), anyInt(),
+ anyLong());
+ verify(mNotifierMock, atMost(1)).onGroupWakefulnessChangeStarted(
+ eq(nonDefaultDisplayGroupId), eq(WAKEFULNESS_ASLEEP),
+ eq(PowerManager.GO_TO_SLEEP_REASON_APPLICATION), eq(eventTime));
+ }
+
+ @Test
+ public void testMultiDisplay_isInteractive_nonExistentGroup() {
+ createService();
+ startSystem();
+
+ int nonExistentDisplayGroup = 999;
+ BinderService binderService = mService.getBinderServiceInstance();
+ assertThat(binderService.isDisplayInteractive(nonExistentDisplayGroup)).isFalse();
+ }
+
+ private void testMultiDisplay_isInteractive_returnsCorrectValue(
+ boolean defaultDisplayAwake, boolean secondGroupDisplayAwake) {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ // We use a display id that does not match the group id, to make sure we aren't accidentally
+ // confusing display id's and display group id's in the implementation.
+ final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 17;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+ final DisplayInfo defaultDisplayInfo = new DisplayInfo();
+ defaultDisplayInfo.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
+ when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(
+ defaultDisplayInfo);
+
+ final DisplayInfo secondDisplayInfo = new DisplayInfo();
+ secondDisplayInfo.displayGroupId = nonDefaultDisplayGroupId;
+ when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(
+ secondDisplayInfo);
+
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ if (!defaultDisplayAwake) {
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP,
+ mClock.now(), 0, PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
+ }
+ if (!secondGroupDisplayAwake) {
+ mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP,
+ mClock.now(), 0,
+ PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
+ }
+ assertThat(PowerManagerInternal.isInteractive(
+ mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP))).isEqualTo(
+ defaultDisplayAwake);
+ assertThat(PowerManagerInternal.isInteractive(
+ mService.getWakefulnessLocked(nonDefaultDisplayGroupId))).isEqualTo(
+ secondGroupDisplayAwake);
+
+ BinderService binderService = mService.getBinderServiceInstance();
+ assertThat(binderService.isInteractive()).isEqualTo(
+ defaultDisplayAwake || secondGroupDisplayAwake);
+ assertThat(binderService.isDisplayInteractive(Display.DEFAULT_DISPLAY)).isEqualTo(
+ defaultDisplayAwake);
+ assertThat(binderService.isDisplayInteractive(nonDefaultDisplay)).isEqualTo(
+ secondGroupDisplayAwake);
+ }
+
+ @Test
+ public void testMultiDisplay_isInteractive_defaultGroupIsAwakeSecondGroupIsAwake() {
+ testMultiDisplay_isInteractive_returnsCorrectValue(true, true);
+ }
+
+ @Test
+ public void testMultiDisplay_isInteractive_defaultGroupIsAwakeSecondGroupIsAsleep() {
+ testMultiDisplay_isInteractive_returnsCorrectValue(true, false);
+ }
+
+ @Test
+ public void testMultiDisplay_isInteractive_defaultGroupIsAsleepSecondGroupIsAwake() {
+ testMultiDisplay_isInteractive_returnsCorrectValue(false, true);
+ }
+
+ @Test
+ public void testMultiDisplay_isInteractive_bothGroupsAreAsleep() {
+ testMultiDisplay_isInteractive_returnsCorrectValue(false, false);
+ }
+
+ @Test
+ public void testMultiDisplay_defaultGroupWakefulnessChange_causesIsInteractiveInvalidate()
+ throws Exception {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = nonDefaultDisplayGroupId;
+ when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ verify(mInvalidateInteractiveCachesMock).call();
+
+ mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP,
+ mClock.now(), 0, PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
+
+ verify(mInvalidateInteractiveCachesMock, times(2)).call();
+ }
+
+ @Test
+ public void testMultiDisplay_secondGroupWakefulness_causesIsInteractiveInvalidate()
+ throws Exception {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = nonDefaultDisplayGroupId;
+ when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ verify(mInvalidateInteractiveCachesMock).call();
+
+ mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, mClock.now(),
+ 0, PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
+
+ verify(mInvalidateInteractiveCachesMock, times(2)).call();
+ }
+
+ @Test
+ public void testGetFullPowerSavePolicy_returnsStateMachineResult() {
+ createService();
+ startSystem();
+ BatterySaverPolicyConfig mockReturnConfig = new BatterySaverPolicyConfig.Builder().build();
+ when(mBatterySaverStateMachineMock.getFullBatterySaverPolicy())
+ .thenReturn(mockReturnConfig);
+
+ mService.getBinderServiceInstance().setPowerSaveModeEnabled(true);
+ BatterySaverPolicyConfig policyConfig =
+ mService.getBinderServiceInstance().getFullPowerSavePolicy();
+ assertThat(mockReturnConfig).isEqualTo(policyConfig);
+ verify(mBatterySaverStateMachineMock).getFullBatterySaverPolicy();
+ }
+
+ @Test
+ public void testSetFullPowerSavePolicy_callsStateMachine() {
+ createService();
+ startSystem();
+ BatterySaverPolicyConfig mockSetPolicyConfig =
+ new BatterySaverPolicyConfig.Builder().build();
+ when(mBatterySaverStateMachineMock.setFullBatterySaverPolicy(any())).thenReturn(true);
+
+ mService.getBinderServiceInstance().setPowerSaveModeEnabled(true);
+ assertThat(mService.getBinderServiceInstance()
+ .setFullPowerSavePolicy(mockSetPolicyConfig)).isTrue();
+ verify(mBatterySaverStateMachineMock).setFullBatterySaverPolicy(eq(mockSetPolicyConfig));
+ }
+
+ @Test
+ public void testLowPowerStandby_whenInactive_FgsWakeLockEnabled() {
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("fgsWakeLock", PowerManager.PARTIAL_WAKE_LOCK);
+ mService.updateUidProcStateInternal(wakeLock.mOwnerUid, PROCESS_STATE_FOREGROUND_SERVICE);
+ mService.setDeviceIdleModeInternal(true);
+
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
+ public void testLowPowerStandby_whenActive_FgsWakeLockDisabled() {
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("fgsWakeLock", PowerManager.PARTIAL_WAKE_LOCK);
+ mService.updateUidProcStateInternal(wakeLock.mOwnerUid, PROCESS_STATE_FOREGROUND_SERVICE);
+ mService.setDeviceIdleModeInternal(true);
+ mService.setLowPowerStandbyActiveInternal(true);
+
+ assertThat(wakeLock.mDisabled).isTrue();
+ }
+
+ @Test
+ public void testLowPowerStandby_whenActive_FgsWakeLockEnabledIfAllowlisted() {
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("fgsWakeLock", PowerManager.PARTIAL_WAKE_LOCK);
+ mService.updateUidProcStateInternal(wakeLock.mOwnerUid, PROCESS_STATE_FOREGROUND_SERVICE);
+ mService.setDeviceIdleModeInternal(true);
+ mService.setLowPowerStandbyActiveInternal(true);
+ mService.setLowPowerStandbyAllowlistInternal(new int[]{wakeLock.mOwnerUid});
+
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
+ public void testLowPowerStandby_whenActive_BoundTopWakeLockDisabled() {
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("BoundTopWakeLock", PowerManager.PARTIAL_WAKE_LOCK);
+ mService.updateUidProcStateInternal(wakeLock.mOwnerUid, PROCESS_STATE_BOUND_TOP);
+ mService.setDeviceIdleModeInternal(true);
+ mService.setLowPowerStandbyActiveInternal(true);
+
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
+ public void testSetLowPowerStandbyActiveDuringMaintenance_redirectsCallToNativeWrapper() {
+ createService();
+ startSystem();
+
+ mService.getBinderServiceInstance().setLowPowerStandbyActiveDuringMaintenance(true);
+ verify(mLowPowerStandbyControllerMock).setActiveDuringMaintenance(true);
+
+ mService.getBinderServiceInstance().setLowPowerStandbyActiveDuringMaintenance(false);
+ verify(mLowPowerStandbyControllerMock).setActiveDuringMaintenance(false);
+ }
+
+ @Test
+ public void testPowerGroupInitialization_multipleDisplayGroups() {
+ IntArray displayGroupIds = IntArray.wrap(new int[]{1, 2, 3});
+ when(mDisplayManagerInternalMock.getDisplayGroupIds()).thenReturn(displayGroupIds);
+
+ createService();
+ startSystem();
+
+ // Power group for DEFAULT_DISPLAY_GROUP is added by default.
+ assertThat(mService.getPowerGroupSize()).isEqualTo(4);
+ }
+
+ @Test
+ public void testPowerGroupInitialization_multipleDisplayGroupsWithDefaultGroup() {
+ IntArray displayGroupIds = IntArray.wrap(new int[]{Display.DEFAULT_DISPLAY_GROUP, 1, 2, 3});
+ when(mDisplayManagerInternalMock.getDisplayGroupIds()).thenReturn(displayGroupIds);
+
+ createService();
+ startSystem();
+
+ // Power group for DEFAULT_DISPLAY_GROUP is added once even if getDisplayGroupIds() return
+ // an array including DEFAULT_DESIPLAY_GROUP.
+ assertThat(mService.getPowerGroupSize()).isEqualTo(4);
+ }
+
+ private WakeLock acquireWakeLock(String tag, int flags) {
+ IBinder token = new Binder();
+ String packageName = "pkg.name";
+ mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY,
+ null /* callback */);
+ return mService.findWakeLockLocked(token);
+ }
+
+ /**
+ * Test IPowerManager.acquireWakeLock() with a IWakeLockCallback.
+ */
+ @Test
+ public void testNotifyWakeLockCallback() {
+ createService();
+ startSystem();
+ final String tag = "wakelock1";
+ final String packageName = "pkg.name";
+ final IBinder token = new Binder();
+ final int flags = PowerManager.PARTIAL_WAKE_LOCK;
+ final IWakeLockCallback callback = Mockito.mock(IWakeLockCallback.class);
+ final IBinder callbackBinder = Mockito.mock(Binder.class);
+ when(callback.asBinder()).thenReturn(callbackBinder);
+ mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, callback);
+ verify(mNotifierMock).onWakeLockAcquired(anyInt(), eq(tag), eq(packageName), anyInt(),
+ anyInt(), any(), any(), same(callback));
+
+ mService.getBinderServiceInstance().releaseWakeLock(token, 0);
+ verify(mNotifierMock).onWakeLockReleased(anyInt(), eq(tag), eq(packageName), anyInt(),
+ anyInt(), any(), any(), same(callback));
+ }
+
+ /**
+ * Test IPowerManager.updateWakeLockCallback() with a new IWakeLockCallback.
+ */
+ @Test
+ public void testNotifyWakeLockCallbackChange() {
+ createService();
+ startSystem();
+ final String tag = "wakelock1";
+ final String packageName = "pkg.name";
+ final IBinder token = new Binder();
+ int flags = PowerManager.PARTIAL_WAKE_LOCK;
+ final IWakeLockCallback callback1 = Mockito.mock(IWakeLockCallback.class);
+ final IBinder callbackBinder1 = Mockito.mock(Binder.class);
+ when(callback1.asBinder()).thenReturn(callbackBinder1);
+ mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
+ null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY, callback1);
+ verify(mNotifierMock).onWakeLockAcquired(anyInt(), eq(tag), eq(packageName), anyInt(),
+ anyInt(), any(), any(), same(callback1));
+
+ final IWakeLockCallback callback2 = Mockito.mock(IWakeLockCallback.class);
+ final IBinder callbackBinder2 = Mockito.mock(Binder.class);
+ when(callback2.asBinder()).thenReturn(callbackBinder2);
+ mService.getBinderServiceInstance().updateWakeLockCallback(token, callback2);
+ verify(mNotifierMock).onWakeLockChanging(anyInt(), eq(tag), eq(packageName),
+ anyInt(), anyInt(), any(), any(), same(callback1),
+ anyInt(), eq(tag), eq(packageName), anyInt(), anyInt(), any(), any(),
+ same(callback2));
+
+ mService.getBinderServiceInstance().releaseWakeLock(token, 0);
+ verify(mNotifierMock).onWakeLockReleased(anyInt(), eq(tag), eq(packageName), anyInt(),
+ anyInt(), any(), any(), same(callback2));
+ }
+
+ @Test
+ public void testUserActivity_futureEventsAreIgnored() {
+ createService();
+ startSystem();
+ // Starting the system triggers a user activity event, so clear that before calling
+ // userActivity() directly.
+ clearInvocations(mNotifierMock);
+ final long eventTime = mClock.now() + Duration.ofHours(10).toMillis();
+ mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, eventTime,
+ USER_ACTIVITY_EVENT_BUTTON, /* flags= */ 0);
+ verify(mNotifierMock, never()).onUserActivity(anyInt(), anyInt(), anyInt());
+ }
+
+}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/ShutdownCheckPointsTest.java b/services/tests/powerservicetests/src/com/android/server/power/ShutdownCheckPointsTest.java
new file mode 100644
index 0000000..fe6cc28
--- /dev/null
+++ b/services/tests/powerservicetests/src/com/android/server/power/ShutdownCheckPointsTest.java
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2020 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.power;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * Run: atest FrameworksServicesTests:ShutdownCheckPointsTest
+ */
+@Presubmit
+public class ShutdownCheckPointsTest {
+
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ @Mock
+ private IActivityManager mActivityManager;
+
+ private TestInjector mTestInjector;
+ private ShutdownCheckPoints mInstance;
+
+ @Before
+ public void setUp() {
+ Locale.setDefault(Locale.UK);
+ TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+ mTestInjector = new TestInjector(mActivityManager);
+ mInstance = new ShutdownCheckPoints(mTestInjector);
+ }
+
+ @Test
+ public void testSystemServerEntry() {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal("reason1");
+
+ assertTrue(dumpToString().startsWith(
+ "Shutdown request from SYSTEM for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ + "com.android.server.power.ShutdownCheckPointsTest"
+ + ".testSystemServerEntry\n at "));
+ }
+
+ @Test
+ public void testSystemServerEntryWithoutReason() {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal(null);
+
+ assertTrue(dumpToString().startsWith(
+ "Shutdown request from SYSTEM at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"));
+ }
+
+ @Test
+ public void testSystemServiceBinderEntry() {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal(Process.myPid(), "reason1");
+
+ assertTrue(dumpToString().startsWith(
+ "Shutdown request from SYSTEM for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ + "com.android.server.power.ShutdownCheckPointsTest"
+ + ".testSystemServiceBinderEntry\n at "));
+ }
+
+ @Test
+ public void testCallerProcessBinderEntries() throws RemoteException {
+ List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfos = new ArrayList<>();
+ runningAppProcessInfos.add(
+ new ActivityManager.RunningAppProcessInfo("process_name", 1, new String[0]));
+ when(mActivityManager.getRunningAppProcesses()).thenReturn(runningAppProcessInfos);
+
+ mTestInjector.setCurrentTime(1000);
+ // Matching pid in getRunningAppProcesses
+ mInstance.recordCheckPointInternal(1, "reason1");
+ // Missing pid in getRunningAppProcesses
+ mInstance.recordCheckPointInternal(2, "reason2");
+
+ assertEquals(
+ "Shutdown request from BINDER for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ + "com.android.server.power.ShutdownCheckPointsTest"
+ + ".testCallerProcessBinderEntries\n"
+ + "From process process_name (pid=1)\n\n"
+ + "Shutdown request from BINDER for reason reason2 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ + "com.android.server.power.ShutdownCheckPointsTest"
+ + ".testCallerProcessBinderEntries\n"
+ + "From process ? (pid=2)\n\n",
+ dumpToString());
+ }
+
+ @Test
+ public void testNullCallerProcessBinderEntries() throws RemoteException {
+ when(mActivityManager.getRunningAppProcesses()).thenReturn(null);
+
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal(1, "reason1");
+
+ assertEquals(
+ "Shutdown request from BINDER for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ + "com.android.server.power.ShutdownCheckPointsTest"
+ + ".testNullCallerProcessBinderEntries\n"
+ + "From process ? (pid=1)\n\n",
+ dumpToString());
+ }
+
+ @Test
+ public void testRemoteExceptionOnBinderEntry() throws RemoteException {
+ when(mActivityManager.getRunningAppProcesses()).thenThrow(new RemoteException("Error"));
+
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal(1, "reason1");
+
+ assertEquals(
+ "Shutdown request from BINDER for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ + "com.android.server.power.ShutdownCheckPointsTest"
+ + ".testRemoteExceptionOnBinderEntry\n"
+ + "From process ? (pid=1)\n\n",
+ dumpToString());
+ }
+
+ @Test
+ public void testUnknownProcessBinderEntry() {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal(1, "reason1");
+
+ assertEquals(
+ "Shutdown request from BINDER for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ + "com.android.server.power.ShutdownCheckPointsTest"
+ + ".testUnknownProcessBinderEntry\n"
+ + "From process ? (pid=1)\n\n",
+ dumpToString());
+ }
+
+ @Test
+ public void testBinderEntryWithoutReason() throws RemoteException {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal(1, null);
+
+ assertTrue(dumpToString().startsWith(
+ "Shutdown request from BINDER at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"));
+ }
+
+ @Test
+ public void testSystemServiceIntentEntry() {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal("some.intent", "android", "reason1");
+
+ assertTrue(dumpToString().startsWith(
+ "Shutdown request from SYSTEM for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ + "com.android.server.power.ShutdownCheckPointsTest"
+ + ".testSystemServiceIntentEntry\n at "));
+ }
+
+ @Test
+ public void testIntentEntry() {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal("some.intent", "some.app", "reason1");
+
+ assertEquals(
+ "Shutdown request from INTENT for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ + "Intent: some.intent\n"
+ + "Package: some.app\n\n",
+ dumpToString());
+ }
+
+ @Test
+ public void testIntentEntryWithoutReason() {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal("some.intent", "some.app", null);
+
+ assertTrue(dumpToString().startsWith(
+ "Shutdown request from INTENT at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"));
+ }
+
+ @Test
+ public void testMultipleEntries() {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal(1, "reason1");
+ mTestInjector.setCurrentTime(2000);
+ mInstance.recordCheckPointInternal(2, "reason2");
+ mTestInjector.setCurrentTime(3000);
+ mInstance.recordCheckPointInternal("intent", "app", "reason3");
+
+ assertEquals(
+ "Shutdown request from BINDER for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ + "com.android.server.power.ShutdownCheckPointsTest.testMultipleEntries\n"
+ + "From process ? (pid=1)\n\n"
+ + "Shutdown request from BINDER for reason reason2 "
+ + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
+ + "com.android.server.power.ShutdownCheckPointsTest.testMultipleEntries\n"
+ + "From process ? (pid=2)\n\n"
+ + "Shutdown request from INTENT for reason reason3 "
+ + "at 1970-01-01 00:00:03.000 UTC (epoch=3000)\n"
+ + "Intent: intent\n"
+ + "Package: app\n\n",
+ dumpToString());
+ }
+
+ @Test
+ public void testTooManyEntriesDropsOlderOnes() {
+ mTestInjector.setCheckPointsLimit(2);
+ ShutdownCheckPoints limitedInstance = new ShutdownCheckPoints(mTestInjector);
+
+ mTestInjector.setCurrentTime(1000);
+ limitedInstance.recordCheckPointInternal("intent.1", "app.1", "reason1");
+ mTestInjector.setCurrentTime(2000);
+ limitedInstance.recordCheckPointInternal("intent.2", "app.2", "reason2");
+ mTestInjector.setCurrentTime(3000);
+ limitedInstance.recordCheckPointInternal("intent.3", "app.3", "reason3");
+
+ // Drops first intent.
+ assertEquals(
+ "Shutdown request from INTENT for reason reason2 "
+ + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
+ + "Intent: intent.2\n"
+ + "Package: app.2\n\n"
+ + "Shutdown request from INTENT for reason reason3 "
+ + "at 1970-01-01 00:00:03.000 UTC (epoch=3000)\n"
+ + "Intent: intent.3\n"
+ + "Package: app.3\n\n",
+ dumpToString(limitedInstance));
+ }
+
+ @Test
+ public void testDumpToFile() throws Exception {
+ File tempDir = createTempDir();
+ File baseFile = new File(tempDir, "checkpoints");
+
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal("first.intent", "first.app", "reason1");
+ dumpToFile(baseFile);
+
+ mTestInjector.setCurrentTime(2000);
+ mInstance.recordCheckPointInternal("second.intent", "second.app", "reason2");
+ dumpToFile(baseFile);
+
+ File[] dumpFiles = tempDir.listFiles();
+ Arrays.sort(dumpFiles);
+
+ assertEquals(2, dumpFiles.length);
+ assertEquals(
+ "Shutdown request from INTENT for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ + "Intent: first.intent\n"
+ + "Package: first.app\n\n",
+ readFileAsString(dumpFiles[0].getAbsolutePath()));
+ assertEquals(
+ "Shutdown request from INTENT for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ + "Intent: first.intent\n"
+ + "Package: first.app\n\n"
+ + "Shutdown request from INTENT for reason reason2 "
+ + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
+ + "Intent: second.intent\n"
+ + "Package: second.app\n\n",
+ readFileAsString(dumpFiles[1].getAbsolutePath()));
+ }
+
+ @Test
+ public void testTooManyFilesDropsOlderOnes() throws Exception {
+ mTestInjector.setDumpFilesLimit(1);
+ ShutdownCheckPoints instance = new ShutdownCheckPoints(mTestInjector);
+ File tempDir = createTempDir();
+ File baseFile = new File(tempDir, "checkpoints");
+
+ mTestInjector.setCurrentTime(1000);
+ instance.recordCheckPointInternal("first.intent", "first.app", "reason1");
+ dumpToFile(instance, baseFile);
+
+ mTestInjector.setCurrentTime(2000);
+ instance.recordCheckPointInternal("second.intent", "second.app", "reason2");
+ dumpToFile(instance, baseFile);
+
+ File[] dumpFiles = tempDir.listFiles();
+ assertEquals(1, dumpFiles.length);
+ assertEquals(
+ "Shutdown request from INTENT for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ + "Intent: first.intent\n"
+ + "Package: first.app\n\n"
+ + "Shutdown request from INTENT for reason reason2 "
+ + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
+ + "Intent: second.intent\n"
+ + "Package: second.app\n\n",
+ readFileAsString(dumpFiles[0].getAbsolutePath()));
+ }
+
+ private String dumpToString() {
+ return dumpToString(mInstance);
+ }
+
+ private String dumpToString(ShutdownCheckPoints instance) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ instance.dumpInternal(pw);
+ return sw.toString();
+ }
+
+ private void dumpToFile(File baseFile) throws InterruptedException {
+ dumpToFile(mInstance, baseFile);
+ }
+
+ private void dumpToFile(ShutdownCheckPoints instance, File baseFile)
+ throws InterruptedException {
+ Thread dumpThread = instance.newDumpThreadInternal(baseFile);
+ dumpThread.start();
+ dumpThread.join();
+ }
+
+ private String readFileAsString(String absolutePath) throws IOException {
+ return new String(Files.readAllBytes(Paths.get(absolutePath)), StandardCharsets.UTF_8);
+ }
+
+ private File createTempDir() throws IOException {
+ File tempDir = File.createTempFile("checkpoints", "out");
+ tempDir.delete();
+ tempDir.mkdir();
+ return tempDir;
+ }
+
+ /** Fake system dependencies for testing. */
+ private final class TestInjector implements ShutdownCheckPoints.Injector {
+ private long mNow;
+ private int mCheckPointsLimit;
+ private int mDumpFilesLimit;
+ private IActivityManager mActivityManager;
+
+ TestInjector(IActivityManager activityManager) {
+ mNow = 0;
+ mCheckPointsLimit = 100;
+ mDumpFilesLimit = 2;
+ mActivityManager = activityManager;
+ }
+
+ @Override
+ public long currentTimeMillis() {
+ return mNow;
+ }
+
+ @Override
+ public int maxCheckPoints() {
+ return mCheckPointsLimit;
+ }
+
+ @Override
+ public int maxDumpFiles() {
+ return mDumpFilesLimit;
+ }
+
+ @Override
+ public IActivityManager activityManager() {
+ return mActivityManager;
+ }
+
+ void setCurrentTime(long time) {
+ mNow = time;
+ }
+
+ void setCheckPointsLimit(int limit) {
+ mCheckPointsLimit = limit;
+ }
+
+ void setDumpFilesLimit(int dumpFilesLimit) {
+ mDumpFilesLimit = dumpFilesLimit;
+ }
+ }
+}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/ShutdownThreadTest.java b/services/tests/powerservicetests/src/com/android/server/power/ShutdownThreadTest.java
new file mode 100644
index 0000000..6041e91
--- /dev/null
+++ b/services/tests/powerservicetests/src/com/android/server/power/ShutdownThreadTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2020 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.power;
+
+import static com.android.server.power.ShutdownThread.DEFAULT_SHUTDOWN_VIBRATE_MS;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.util.AtomicFile;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Tests for {@link com.android.server.power.ShutdownThread}
+ */
+public class ShutdownThreadTest {
+
+ private static final String WAVEFORM_VIB_10MS_SERIALIZATION =
+ """
+ <vibration>
+ <waveform-effect>
+ <waveform-entry durationMs="10" amplitude="100"/>
+ </waveform-effect>
+ </vibration>
+ """;
+
+ private static final VibrationEffect WAVEFORM_VIB_10MS = VibrationEffect.createOneShot(10, 100);
+
+ private static final String REPEATING_VIB_SERIALIZATION =
+ """
+ <vibration>
+ <waveform-effect>
+ <repeating>
+ <waveform-entry durationMs="10" amplitude="100"/>
+ </repeating>
+ </waveform-effect>
+ </vibration>
+ """;
+
+ private static final String CLICK_VIB_SERIALIZATION =
+ """
+ <vibration>
+ <predefined-effect name="click"/>
+ </vibration>
+ """;
+
+ private static final VibrationEffect CLILCK_VIB =
+ VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK);
+
+ private static final String BAD_VIB_SERIALIZATION = "BAD SERIALIZATION";
+
+ @Mock private Context mContextMock;
+ @Mock private Vibrator mVibratorMock;
+
+ private String mDefaultShutdownVibrationFilePath;
+ private long mLastSleepDurationMs;
+
+ private ShutdownThread mShutdownThread;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mVibratorMock.hasVibrator()).thenReturn(true);
+
+ when(mVibratorMock.areVibrationFeaturesSupported(any())).thenReturn(true);
+
+ mShutdownThread = new ShutdownThread(new TestInjector());
+ }
+
+ @Test
+ public void testSuccessfulShutdownVibrationFromFile() throws Exception {
+ setShutdownVibrationFileContent(WAVEFORM_VIB_10MS_SERIALIZATION);
+
+ mShutdownThread.playShutdownVibration(mContextMock);
+
+ assertShutdownVibration(WAVEFORM_VIB_10MS, /* vibrationSleepDuration= */ 10);
+ }
+
+ @Test
+ public void testIOExceptionWhenParsingShutdownVibration() throws Exception {
+ mDefaultShutdownVibrationFilePath = "non/existent/file_path";
+
+ mShutdownThread.playShutdownVibration(mContextMock);
+
+ assertDefaultShutdownVibration();
+ }
+
+ @Test
+ public void testMalformedShutdownVibrationFileContent() throws Exception {
+ setShutdownVibrationFileContent(BAD_VIB_SERIALIZATION);
+
+ mShutdownThread.playShutdownVibration(mContextMock);
+
+ assertDefaultShutdownVibration();
+ }
+
+ @Test
+ public void testVibratorUnsupportedShutdownVibrationEffect() throws Exception {
+ setShutdownVibrationFileContent(WAVEFORM_VIB_10MS_SERIALIZATION);
+ when(mVibratorMock.areVibrationFeaturesSupported(any())).thenReturn(false);
+
+ mShutdownThread.playShutdownVibration(mContextMock);
+
+ assertDefaultShutdownVibration();
+ }
+
+ @Test
+ public void testRepeatinghutdownVibrationEffect() throws Exception {
+ setShutdownVibrationFileContent(REPEATING_VIB_SERIALIZATION);
+
+ mShutdownThread.playShutdownVibration(mContextMock);
+
+ assertDefaultShutdownVibration();
+ }
+
+ @Test
+ public void testVibrationEffectWithUnknownDuration() throws Exception {
+ setShutdownVibrationFileContent(CLICK_VIB_SERIALIZATION);
+
+ mShutdownThread.playShutdownVibration(mContextMock);
+
+ assertShutdownVibration(CLILCK_VIB, DEFAULT_SHUTDOWN_VIBRATE_MS);
+ }
+
+ @Test
+ public void testNoVibrator() {
+ when(mVibratorMock.hasVibrator()).thenReturn(false);
+
+ mShutdownThread.playShutdownVibration(mContextMock);
+
+ verify(mVibratorMock, never())
+ .vibrate(any(VibrationEffect.class), any(VibrationAttributes.class));
+ }
+
+ private void assertShutdownVibration(VibrationEffect effect, long vibrationSleepDuration)
+ throws Exception {
+ verify(mVibratorMock).vibrate(
+ eq(effect),
+ eq(VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH)));
+ assertEquals(vibrationSleepDuration, mLastSleepDurationMs);
+ }
+
+ private void assertDefaultShutdownVibration() throws Exception {
+ assertShutdownVibration(
+ VibrationEffect.createOneShot(
+ DEFAULT_SHUTDOWN_VIBRATE_MS, VibrationEffect.DEFAULT_AMPLITUDE),
+ DEFAULT_SHUTDOWN_VIBRATE_MS);
+ }
+
+ private void setShutdownVibrationFileContent(String content) throws Exception {
+ mDefaultShutdownVibrationFilePath = createFileForContent(content).getAbsolutePath();
+ }
+
+ private static File createFileForContent(String content) throws Exception {
+ File file = new File(InstrumentationRegistry.getContext().getCacheDir(), "test.xml");
+ file.createNewFile();
+
+ AtomicFile atomicFile = new AtomicFile(file);
+ FileOutputStream fos = atomicFile.startWrite();
+ fos.write(content.getBytes());
+ atomicFile.finishWrite(fos);
+
+ return file;
+ }
+
+ private class TestInjector extends ShutdownThread.Injector {
+ @Override
+ public Vibrator getVibrator(Context context) {
+ return mVibratorMock;
+ }
+
+ @Override
+ public String getDefaultShutdownVibrationEffectFilePath(Context context) {
+ return mDefaultShutdownVibrationFilePath;
+ }
+
+ @Override
+ public void sleep(long durationMs) {
+ mLastSleepDurationMs = durationMs;
+ }
+ }
+}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/WakeLockLogTest.java b/services/tests/powerservicetests/src/com/android/server/power/WakeLockLogTest.java
new file mode 100644
index 0000000..7af4b3d
--- /dev/null
+++ b/services/tests/powerservicetests/src/com/android/server/power/WakeLockLogTest.java
@@ -0,0 +1,453 @@
+/*
+ * 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.power;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.PowerManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.SimpleDateFormat;
+import java.util.TimeZone;
+
+/**
+ * Tests for {@link WakeLockLog}.
+ */
+public class WakeLockLogTest {
+
+ @Mock
+ private Context mContext;
+
+ @Mock
+ private PackageManager mPackageManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+
+ when(mPackageManager.getPackagesForUid(101)).thenReturn(new String[]{ "some.package1" });
+ when(mPackageManager.getPackagesForUid(102)).thenReturn(new String[]{ "some.package2" });
+ }
+
+ @Test
+ public void testAddTwoItems() {
+ final int tagDatabaseSize = 128;
+ final int logSize = 20;
+ TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+ WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+ log.onWakeLockAcquired("TagPartial", 101,
+ PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
+ log.onWakeLockAcquired("TagFull", 102,
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+
+ assertEquals("Wake Lock Log\n"
+ + " 01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial "
+ + "(partial,on-after-release)\n"
+ + " 01-01 00:00:01.150 - 102 (some.package2) - ACQ TagFull "
+ + "(full,acq-causes-wake)\n"
+ + " -\n"
+ + " Events: 2, Time-Resets: 0\n"
+ + " Buffer, Bytes used: 6\n",
+ dumpLog(log, false));
+ }
+
+ @Test
+ public void testAddTwoItemsWithTimeReset() {
+ final int tagDatabaseSize = 128;
+ final int logSize = 20;
+ TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+ WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+ log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1350L);
+ log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK);
+
+ assertEquals("Wake Lock Log\n"
+ + " 01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial (partial)\n"
+ + " 01-01 00:00:01.350 - 102 (some.package2) - ACQ TagFull (full)\n"
+ + " -\n"
+ + " Events: 2, Time-Resets: 1\n"
+ + " Buffer, Bytes used: 15\n",
+ dumpLog(log, false));
+ }
+
+ @Test
+ public void testAddTwoItemsWithTagOverwrite() {
+ final int tagDatabaseSize = 2;
+ final int logSize = 20;
+ TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+ WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+ log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
+ log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK);
+
+ assertEquals("Wake Lock Log\n"
+ + " 01-01 00:00:01.000 - --- - ACQ UNKNOWN (partial)\n"
+ + " 01-01 00:00:01.150 - 102 (some.package2) - ACQ TagFull (full)\n"
+ + " -\n"
+ + " Events: 2, Time-Resets: 0\n"
+ + " Buffer, Bytes used: 6\n",
+ dumpLog(log, false));
+ }
+
+ @Test
+ public void testAddFourItemsWithRingBufferOverflow() {
+ final int tagDatabaseSize = 6;
+ final int logSize = 10;
+ TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+ WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+
+ // Wake lock 1 acquired - log size = 3
+ when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+ log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK);
+
+ // Wake lock 2 acquired - log size = 3 + 3 = 6
+ when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
+ log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK);
+
+ // Wake lock 3 acquired - log size = 6 + 3 = 9
+ when(injectorSpy.currentTimeMillis()).thenReturn(1151L);
+ log.onWakeLockAcquired("TagThree", 101, PowerManager.PARTIAL_WAKE_LOCK);
+
+ // We need more space - wake lock 1 acquisition is removed from the log and saved in the
+ // list. Log size = 9 - 3 + 2 = 8
+ when(injectorSpy.currentTimeMillis()).thenReturn(1152L);
+ log.onWakeLockReleased("TagThree", 101);
+
+ // We need more space - wake lock 2 acquisition is removed from the log and saved in the
+ // list. Log size = 8 - 3 + 2 = 7
+ when(injectorSpy.currentTimeMillis()).thenReturn(1153L);
+ log.onWakeLockReleased("TagPartial", 101);
+
+ // We need more space - wake lock 3 acquisition is removed from the log and saved in the
+ // list. Log size = 7 - 3 + 3 = 7
+ when(injectorSpy.currentTimeMillis()).thenReturn(1154L);
+ log.onWakeLockAcquired("TagFour", 101, PowerManager.PARTIAL_WAKE_LOCK);
+
+ // We need more space - wake lock 3 release is removed from the log and wake lock 3
+ // acquisition is removed from the list. Log size = 7 - 2 + 3 = 8
+ when(injectorSpy.currentTimeMillis()).thenReturn(1155L);
+ log.onWakeLockAcquired("TagFive", 101, PowerManager.PARTIAL_WAKE_LOCK);
+
+ // We need more space - wake lock 1 release is removed from the log and wake lock 1
+ // acquisition is removed from the list. Log size = 8 - 2 + 2 = 8
+ when(injectorSpy.currentTimeMillis()).thenReturn(1156L);
+ log.onWakeLockReleased("TagFull", 102);
+
+ // Wake lock 2 acquisition is still printed because its release have not rolled off the log
+ // yet.
+ assertEquals("Wake Lock Log\n"
+ + " 01-01 00:00:01.150 - 102 (some.package2) - ACQ TagFull (full)\n"
+ + " 01-01 00:00:01.154 - 101 (some.package1) - ACQ TagFour (partial)\n"
+ + " 01-01 00:00:01.155 - 101 (some.package1) - ACQ TagFive (partial)\n"
+ + " 01-01 00:00:01.156 - 102 (some.package2) - REL TagFull\n"
+ + " -\n"
+ + " Events: 4, Time-Resets: 0\n"
+ + " Buffer, Bytes used: 8\n",
+ dumpLog(log, false));
+ }
+
+ @Test
+ public void testAddItemWithBadTag() {
+ final int tagDatabaseSize = 6;
+ final int logSize = 10;
+ TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+ WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+
+ // Bad tag means it wont get written
+ when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+ log.onWakeLockAcquired(null /* tag */, 0 /* ownerUid */, PowerManager.PARTIAL_WAKE_LOCK);
+
+ assertEquals("Wake Lock Log\n"
+ + " -\n"
+ + " Events: 0, Time-Resets: 0\n"
+ + " Buffer, Bytes used: 0\n",
+ dumpLog(log, false));
+ }
+
+ @Test
+ public void testAddItemWithReducedTagName() {
+ final int tagDatabaseSize = 6;
+ final int logSize = 10;
+ TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+ WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+ log.onWakeLockAcquired("*job*/com.one.two.3hree/.one..Last", 101,
+ PowerManager.PARTIAL_WAKE_LOCK);
+
+ assertEquals("Wake Lock Log\n"
+ + " 01-01 00:00:01.000 - 101 (some.package1) - ACQ "
+ + "*job*/c.o.t.3/.o..Last (partial)\n"
+ + " -\n"
+ + " Events: 1, Time-Resets: 0\n"
+ + " Buffer, Bytes used: 3\n",
+ dumpLog(log, false));
+ }
+
+ @Test
+ public void testAddAcquireAndReleaseWithRepeatTagName() {
+ final int tagDatabaseSize = 6;
+ final int logSize = 10;
+ TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+ WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+ log.onWakeLockAcquired("HowdyTag", 101, PowerManager.PARTIAL_WAKE_LOCK);
+ when(injectorSpy.currentTimeMillis()).thenReturn(1001L);
+ log.onWakeLockReleased("HowdyTag", 101);
+
+ assertEquals("Wake Lock Log\n"
+ + " 01-01 00:00:01.000 - 101 (some.package1) - ACQ HowdyTag (partial)\n"
+ + " 01-01 00:00:01.001 - 101 (some.package1) - REL HowdyTag\n"
+ + " -\n"
+ + " Events: 2, Time-Resets: 0\n"
+ + " Buffer, Bytes used: 5\n"
+ + " Tag Database: size(5), entries: 1, Bytes used: 80\n",
+ dumpLog(log, true));
+ }
+
+ @Test
+ public void testAddAcquireAndReleaseWithTimeTravel() {
+ final int tagDatabaseSize = 6;
+ final int logSize = 10;
+ TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+ WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1100L);
+ log.onWakeLockAcquired("HowdyTag", 101, PowerManager.PARTIAL_WAKE_LOCK);
+
+ // New element goes back in time...should not be written to log.
+ when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+ log.onWakeLockReleased("HowdyTag", 101);
+
+ assertEquals("Wake Lock Log\n"
+ + " 01-01 00:00:01.100 - 101 (some.package1) - ACQ HowdyTag (partial)\n"
+ + " -\n"
+ + " Events: 1, Time-Resets: 0\n"
+ + " Buffer, Bytes used: 3\n",
+ dumpLog(log, false));
+ }
+
+ @Test
+ public void testAddSystemWakelock() {
+ final int tagDatabaseSize = 6;
+ final int logSize = 10;
+ TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+ WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+ log.onWakeLockAcquired("TagPartial", 101,
+ PowerManager.PARTIAL_WAKE_LOCK | PowerManager.SYSTEM_WAKELOCK);
+
+ assertEquals("Wake Lock Log\n"
+ + " 01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial "
+ + "(partial,system-wakelock)\n"
+ + " -\n"
+ + " Events: 1, Time-Resets: 0\n"
+ + " Buffer, Bytes used: 3\n",
+ dumpLog(log, false));
+ }
+
+ @Test
+ public void testAddItemWithNoPackageName() {
+ final int tagDatabaseSize = 128;
+ final int logSize = 20;
+ TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+ WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+
+ when(mPackageManager.getPackagesForUid(101)).thenReturn(null);
+ when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+ log.onWakeLockAcquired("TagPartial", 101,
+ PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+
+ assertEquals("Wake Lock Log\n"
+ + " 01-01 00:00:01.000 - 101 - ACQ TagPartial "
+ + "(partial,on-after-release)\n"
+ + " -\n"
+ + " Events: 1, Time-Resets: 0\n"
+ + " Buffer, Bytes used: 3\n",
+ dumpLog(log, false));
+ }
+
+ @Test
+ public void testAddItemWithMultiplePackageNames() {
+ final int tagDatabaseSize = 128;
+ final int logSize = 20;
+ TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+ WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+
+ when(mPackageManager.getPackagesForUid(101)).thenReturn(
+ new String[]{ "some.package1", "some.package2", "some.package3" });
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+ log.onWakeLockAcquired("TagPartial", 101,
+ PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+
+ assertEquals("Wake Lock Log\n"
+ + " 01-01 00:00:01.000 - 101 (some.package1,...) - ACQ TagPartial "
+ + "(partial,on-after-release)\n"
+ + " -\n"
+ + " Events: 1, Time-Resets: 0\n"
+ + " Buffer, Bytes used: 3\n",
+ dumpLog(log, false));
+ }
+
+ @Test
+ public void testAddItemsWithRepeatOwnerUid_UsesCache() {
+ final int tagDatabaseSize = 128;
+ final int logSize = 20;
+ TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+ WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+ log.onWakeLockAcquired("TagPartial", 101,
+ PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
+ log.onWakeLockAcquired("TagFull", 101,
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1151L);
+ log.onWakeLockAcquired("TagFull2", 101,
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+
+ assertEquals("Wake Lock Log\n"
+ + " 01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial "
+ + "(partial,on-after-release)\n"
+ + " 01-01 00:00:01.150 - 101 (some.package1) - ACQ TagFull "
+ + "(full,acq-causes-wake)\n"
+ + " 01-01 00:00:01.151 - 101 (some.package1) - ACQ TagFull2 "
+ + "(full,acq-causes-wake)\n"
+ + " -\n"
+ + " Events: 3, Time-Resets: 0\n"
+ + " Buffer, Bytes used: 9\n",
+ dumpLog(log, false));
+
+ verify(mPackageManager, times(1)).getPackagesForUid(101);
+ }
+
+ @Test
+ public void testAddItemsWithRepeatOwnerUid_SavedAcquisitions_UsesCache() {
+ final int tagDatabaseSize = 128;
+ final int logSize = 10;
+ TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+ WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+ log.onWakeLockAcquired("TagPartial", 101,
+ PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
+ log.onWakeLockAcquired("TagFull", 101,
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1151L);
+ log.onWakeLockAcquired("TagFull2", 101,
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1152L);
+ log.onWakeLockAcquired("TagFull3", 101,
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1153L);
+ log.onWakeLockAcquired("TagFull4", 101,
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+
+ when(injectorSpy.currentTimeMillis()).thenReturn(1154L);
+ log.onWakeLockAcquired("TagFull5", 101,
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+
+ // The first 3 events have been removed from the log and they exist in the saved
+ // acquisitions list. They should also use the cache when fetching the package names.
+ assertEquals("Wake Lock Log\n"
+ + " 01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial "
+ + "(partial,on-after-release)\n"
+ + " 01-01 00:00:01.150 - 101 (some.package1) - ACQ TagFull "
+ + "(full,acq-causes-wake)\n"
+ + " 01-01 00:00:01.151 - 101 (some.package1) - ACQ TagFull2 "
+ + "(full,acq-causes-wake)\n"
+ + " 01-01 00:00:01.152 - 101 (some.package1) - ACQ TagFull3 "
+ + "(full,acq-causes-wake)\n"
+ + " 01-01 00:00:01.153 - 101 (some.package1) - ACQ TagFull4 "
+ + "(full,acq-causes-wake)\n"
+ + " 01-01 00:00:01.154 - 101 (some.package1) - ACQ TagFull5 "
+ + "(full,acq-causes-wake)\n"
+ + " -\n"
+ + " Events: 6, Time-Resets: 0\n"
+ + " Buffer, Bytes used: 9\n",
+ dumpLog(log, false));
+
+ verify(mPackageManager, times(1)).getPackagesForUid(101);
+ }
+
+ private String dumpLog(WakeLockLog log, boolean includeTagDb) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ log.dump(pw, includeTagDb);
+ return sw.toString();
+ }
+
+ public class TestInjector extends WakeLockLog.Injector {
+ private final int mTagDatabaseSize;
+ private final int mLogSize;
+
+ public TestInjector(int tagDatabaseSize, int logSize) {
+ mTagDatabaseSize = tagDatabaseSize;
+ mLogSize = logSize;
+ }
+
+ @Override
+ public int getTagDatabaseSize() {
+ return mTagDatabaseSize;
+ }
+
+ @Override
+ public int getLogSize() {
+ return mLogSize;
+ }
+
+ @Override
+ public SimpleDateFormat getDateFormat() {
+ SimpleDateFormat format = new SimpleDateFormat(super.getDateFormat().toPattern());
+ format.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return format;
+ }
+ }
+}