• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.os.cts;
18 
19 import static android.os.Flags.batterySaverSupportedCheckApi;
20 
21 import static com.android.compatibility.common.util.TestUtils.waitUntil;
22 
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertNull;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
28 
29 import android.content.ContentResolver;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.os.PowerManager;
34 import android.os.PowerManager.WakeLock;
35 import android.platform.test.annotations.AppModeFull;
36 import android.provider.Settings.Global;
37 
38 import androidx.test.ext.junit.runners.AndroidJUnit4;
39 import androidx.test.filters.LargeTest;
40 import androidx.test.platform.app.InstrumentationRegistry;
41 
42 import com.android.compatibility.common.util.BatteryUtils;
43 import com.android.compatibility.common.util.CallbackAsserter;
44 import com.android.compatibility.common.util.SystemUtil;
45 
46 import org.junit.After;
47 import org.junit.Before;
48 import org.junit.Test;
49 import org.junit.runner.RunWith;
50 
51 import java.time.Duration;
52 
53 @AppModeFull(reason = "Instant Apps don't have the WRITE_SECURE_SETTINGS permission "
54         + "required in tearDown for Global#putInt")
55 @RunWith(AndroidJUnit4.class)
56 public class PowerManagerTest {
57     private static final String TAG = "PowerManagerTest";
58     public static final long TIME = 3000;
59     public static final int MORE_TIME = 300;
60     private static final int BROADCAST_TIMEOUT_SECONDS = 70;
61     private static final Duration LONG_DISCHARGE_DURATION = Duration.ofMillis(2000);
62     private static final Duration SHORT_DISCHARGE_DURATION = Duration.ofMillis(1000);
63 
64     private int mInitialPowerSaverMode;
65     private int mInitialDynamicPowerSavingsEnabled;
66     private int mInitialThreshold;
67 
68     /**
69      * test points:
70      * 1 Get a wake lock at the level of the flags parameter
71      * 2 Force the device to go to sleep
72      * 3 User activity happened
73      */
74     @Test
testPowerManager()75     public void testPowerManager() throws InterruptedException {
76         PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
77 
78         WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, TAG);
79         wl.acquire(TIME);
80         assertTrue(wl.isHeld());
81         Thread.sleep(TIME + MORE_TIME);
82         assertFalse(wl.isHeld());
83 
84         try {
85             pm.reboot("Testing");
86             fail("reboot should throw SecurityException");
87         } catch (SecurityException e) {
88             // expected
89         }
90     }
91 
getContext()92     private Context getContext() {
93         return InstrumentationRegistry.getInstrumentation().getContext();
94     }
95 
96     @Before
setUp()97     public void setUp() {
98         // store the current value so we can restore it
99         ContentResolver resolver = getContext().getContentResolver();
100         mInitialPowerSaverMode = Global.getInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE, 0);
101         mInitialDynamicPowerSavingsEnabled =
102                 Global.getInt(resolver, Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
103         mInitialThreshold =
104                 Global.getInt(resolver, Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 0);
105 
106     }
107 
108     @After
tearDown()109     public void tearDown() {
110         SystemUtil.runWithShellPermissionIdentity(() -> {
111             ContentResolver resolver = getContext().getContentResolver();
112 
113             // Verify we can change it to dynamic.
114             Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE, mInitialPowerSaverMode);
115             Global.putInt(resolver,
116                     Global.DYNAMIC_POWER_SAVINGS_ENABLED, mInitialDynamicPowerSavingsEnabled);
117             Global.putInt(resolver,
118                     Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, mInitialThreshold);
119         });
120     }
121 
122     @Test
testPowerManager_getPowerSaveMode()123     public void testPowerManager_getPowerSaveMode() {
124         PowerManager manager = BatteryUtils.getPowerManager();
125         if (batterySaverSupportedCheckApi() && !manager.isBatterySaverSupported()) {
126             return;
127         }
128 
129         SystemUtil.runWithShellPermissionIdentity(() -> {
130             ContentResolver resolver = getContext().getContentResolver();
131 
132             // Verify we can change it to percentage.
133             Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE, 0);
134             assertEquals(
135                     PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE,
136                     manager.getPowerSaveModeTrigger());
137 
138             // Verify we can change it to dynamic.
139             Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE, 1);
140             assertEquals(
141                     PowerManager.POWER_SAVE_MODE_TRIGGER_DYNAMIC,
142                     manager.getPowerSaveModeTrigger());
143         });
144     }
145 
146     @Test
testPowerManager_setDynamicPowerSavings()147     public void testPowerManager_setDynamicPowerSavings() {
148         PowerManager manager = BatteryUtils.getPowerManager();
149         if (batterySaverSupportedCheckApi() && !manager.isBatterySaverSupported()) {
150             return;
151         }
152 
153         SystemUtil.runWithShellPermissionIdentity(() -> {
154             ContentResolver resolver = getContext().getContentResolver();
155 
156             // Verify settings are actually updated.
157             manager.setDynamicPowerSaveHint(true, 80);
158             assertEquals(1, Global.getInt(resolver, Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0));
159             assertEquals(80, Global.getInt(resolver,
160                     Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 0));
161 
162             manager.setDynamicPowerSaveHint(false, 20);
163             assertEquals(0, Global.getInt(resolver, Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1));
164             assertEquals(20, Global.getInt(resolver,
165                     Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 0));
166         });
167     }
168 
169     @LargeTest
170     @Test
testPowerManager_batteryDischargePrediction()171     public void testPowerManager_batteryDischargePrediction() throws Exception {
172         final PowerManager manager = BatteryUtils.getPowerManager();
173         if (batterySaverSupportedCheckApi() && !manager.isBatterySaverSupported()) {
174             return;
175         }
176 
177         if (!BatteryUtils.hasBattery()) {
178             assertNull(manager.getBatteryDischargePrediction());
179             return;
180         }
181 
182         // Unplug to ensure the plugged in broadcast is sent.
183         BatteryUtils.runDumpsysBatteryUnplug();
184 
185         // Plugged in. No prediction should be given.
186         final CallbackAsserter pluggedBroadcastAsserter = CallbackAsserter.forBroadcast(
187                 new IntentFilter(Intent.ACTION_POWER_CONNECTED));
188         BatteryUtils.runDumpsysBatterySetPluggedIn(true);
189         pluggedBroadcastAsserter.assertCalled("Didn't get power connected broadcast",
190                 BROADCAST_TIMEOUT_SECONDS);
191         // PowerManagerService may get the BATTERY_CHANGED broadcast after we get our broadcast,
192         // so we have to have a little wait.
193         waitUntil("PowerManager doesn't think the device has connected power",
194                 () -> manager.getBatteryDischargePrediction() == null);
195 
196         // Not plugged in. At the very least, the basic discharge estimation should be returned.
197         final CallbackAsserter unpluggedBroadcastAsserter = CallbackAsserter.forBroadcast(
198                 new IntentFilter(Intent.ACTION_POWER_DISCONNECTED));
199         BatteryUtils.runDumpsysBatteryUnplug();
200         unpluggedBroadcastAsserter.assertCalled("Didn't get power disconnected broadcast",
201                 BROADCAST_TIMEOUT_SECONDS);
202         // PowerManagerService may get the BATTERY_CHANGED broadcast after we get our broadcast,
203         // so we have to have a little wait.
204         waitUntil("PowerManager still thinks the device has connected power",
205                 () -> manager.getBatteryDischargePrediction() != null);
206 
207         CallbackAsserter predictionChangedBroadcastAsserter = CallbackAsserter.forBroadcast(
208                 new IntentFilter(PowerManager.ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED));
209         setDischargePrediction(LONG_DISCHARGE_DURATION, true);
210         assertDischargePrediction(LONG_DISCHARGE_DURATION, true);
211         predictionChangedBroadcastAsserter.assertCalled("Prediction changed broadcast not received",
212                 BROADCAST_TIMEOUT_SECONDS);
213 
214 
215         predictionChangedBroadcastAsserter = CallbackAsserter.forBroadcast(
216                 new IntentFilter(PowerManager.ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED));
217         setDischargePrediction(SHORT_DISCHARGE_DURATION, false);
218         assertDischargePrediction(SHORT_DISCHARGE_DURATION, false);
219         predictionChangedBroadcastAsserter.assertCalled("Prediction changed broadcast not received",
220                 BROADCAST_TIMEOUT_SECONDS);
221     }
222 
setDischargePrediction(Duration d, boolean isPersonalized)223     private void setDischargePrediction(Duration d, boolean isPersonalized) {
224         final PowerManager manager = BatteryUtils.getPowerManager();
225         SystemUtil.runWithShellPermissionIdentity(
226                 () -> manager.setBatteryDischargePrediction(d, isPersonalized),
227                 android.Manifest.permission.BATTERY_PREDICTION);
228     }
229 
assertDischargePrediction(Duration d, boolean isPersonalized)230     private void assertDischargePrediction(Duration d, boolean isPersonalized) {
231         final PowerManager manager = BatteryUtils.getPowerManager();
232         // We can't pause time so must use >= because the time remaining should decrease as
233         // time goes on.
234         Duration prediction = manager.getBatteryDischargePrediction();
235         assertTrue("Prediction is greater than " + d.toMillis() + "ms: "
236                 + prediction, d.toMillis() >= prediction.toMillis());
237         assertEquals(isPersonalized, manager.isBatteryDischargePredictionPersonalized());
238     }
239 }
240