1 /*
2  * Copyright (C) 2021 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.PowerManager.FEATURE_WAKE_ON_LAN_IN_LOW_POWER_STANDBY;
20 import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL;
21 import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST;
22 import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION;
23 import static android.os.PowerManager.LowPowerStandbyPortDescription.MATCH_PORT_LOCAL;
24 import static android.os.PowerManager.LowPowerStandbyPortDescription.MATCH_PORT_REMOTE;
25 import static android.os.PowerManager.LowPowerStandbyPortDescription.PROTOCOL_TCP;
26 import static android.os.PowerManager.LowPowerStandbyPortDescription.PROTOCOL_UDP;
27 import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
28 import static android.os.PowerManager.SYSTEM_WAKELOCK;
29 
30 import static com.google.common.truth.Truth.assertThat;
31 
32 import static org.junit.Assert.assertEquals;
33 import static org.junit.Assert.assertFalse;
34 import static org.junit.Assert.assertNotEquals;
35 import static org.junit.Assert.assertTrue;
36 import static org.junit.Assert.fail;
37 import static org.junit.Assume.assumeTrue;
38 
39 import android.Manifest;
40 import android.content.Context;
41 import android.content.Intent;
42 import android.content.IntentFilter;
43 import android.content.pm.ServiceInfo;
44 import android.net.ConnectivityManager;
45 import android.net.Network;
46 import android.os.PowerExemptionManager;
47 import android.os.PowerManager;
48 import android.os.PowerManager.LowPowerStandbyPolicy;
49 import android.os.PowerManager.LowPowerStandbyPortDescription;
50 import android.os.PowerManager.WakeLock;
51 import android.platform.test.annotations.AppModeFull;
52 import android.platform.test.annotations.AppModeSdkSandbox;
53 import android.util.ArraySet;
54 
55 import androidx.annotation.NonNull;
56 import androidx.test.InstrumentationRegistry;
57 import androidx.test.uiautomator.UiDevice;
58 
59 import com.android.bedstead.harrier.BedsteadJUnit4;
60 import com.android.bedstead.harrier.DeviceState;
61 import com.android.bedstead.permissions.annotations.EnsureHasPermission;
62 import com.android.bedstead.nene.TestApis;
63 import com.android.bedstead.permissions.PermissionContext;
64 import com.android.compatibility.common.util.ApiTest;
65 import com.android.compatibility.common.util.BlockingBroadcastReceiver;
66 import com.android.compatibility.common.util.CallbackAsserter;
67 import com.android.compatibility.common.util.PollingCheck;
68 import com.android.compatibility.common.util.ProtoUtils;
69 import com.android.server.power.nano.PowerManagerServiceDumpProto;
70 import com.android.server.power.nano.WakeLockProto;
71 
72 import org.junit.After;
73 import org.junit.Before;
74 import org.junit.ClassRule;
75 import org.junit.Rule;
76 import org.junit.Test;
77 import org.junit.runner.RunWith;
78 
79 import java.io.IOException;
80 import java.net.InetAddress;
81 import java.util.Collections;
82 import java.util.List;
83 import java.util.concurrent.TimeUnit;
84 
85 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).")
86 @RunWith(BedsteadJUnit4.class)
87 public class LowPowerStandbyTest {
88     private static final int BROADCAST_TIMEOUT_SEC = 3;
89     private static final int WAKELOCK_STATE_TIMEOUT = 1000;
90     private static final long LOW_POWER_STANDBY_ACTIVATE_TIMEOUT = TimeUnit.MINUTES.toMillis(2);
91 
92     private static final String SYSTEM_WAKE_LOCK_TAG = "LowPowerStandbyTest:KeepSystemAwake";
93     public static final String TEST_WAKE_LOCK_TAG = "LowPowerStandbyTest:TestWakeLock";
94     private static final LowPowerStandbyPortDescription PORT_DESC_1 =
95             new LowPowerStandbyPortDescription(PROTOCOL_UDP, MATCH_PORT_REMOTE, 1234);
96 
97     @ClassRule
98     @Rule
99     public static final DeviceState sDeviceState = new DeviceState();
100 
101     private Context mContext;
102     private PowerManager mPowerManager;
103     private LowPowerStandbyPolicy mOriginalPolicy;
104     private boolean mOriginalEnabled;
105     private WakeLock mSystemWakeLock;
106 
107     @Before
setUp()108     public void setUp() throws Exception {
109         mContext = InstrumentationRegistry.getInstrumentation().getContext();
110         mPowerManager = mContext.getSystemService(PowerManager.class);
111         mOriginalEnabled = mPowerManager.isLowPowerStandbyEnabled();
112         mOriginalPolicy = null;
113 
114         try (PermissionContext p = TestApis.permissions().withPermission(
115                 Manifest.permission.MANAGE_LOW_POWER_STANDBY)) {
116             assumeTrue(mPowerManager.isLowPowerStandbySupported());
117             mOriginalPolicy = mPowerManager.getLowPowerStandbyPolicy();
118 
119             // Reset to the default policy
120             mPowerManager.setLowPowerStandbyPolicy(null);
121         }
122     }
123 
124     @After
tearDown()125     public void tearDown() throws Exception {
126         if (mPowerManager != null) {
127             try (PermissionContext p = TestApis.permissions().withPermission(
128                     Manifest.permission.MANAGE_LOW_POWER_STANDBY)) {
129                 wakeUp();
130                 mPowerManager.setLowPowerStandbyEnabled(mOriginalEnabled);
131                 mPowerManager.forceLowPowerStandbyActive(false);
132                 mPowerManager.setLowPowerStandbyPolicy(mOriginalPolicy);
133             }
134         }
135         unforceDoze();
136 
137         if (mSystemWakeLock != null) {
138             mSystemWakeLock.release();
139         }
140     }
141 
142     @Test
143     @ApiTest(apis = "android.os.PowerManager#setLowPowerStandbyEnabled")
testSetLowPowerStandbyEnabled_withoutPermission_throwsSecurityException()144     public void testSetLowPowerStandbyEnabled_withoutPermission_throwsSecurityException() {
145         try {
146             mPowerManager.setLowPowerStandbyEnabled(false);
147             fail("PowerManager.setLowPowerStandbyEnabled() didn't throw SecurityException as "
148                     + "expected");
149         } catch (SecurityException e) {
150             // expected
151         }
152     }
153 
154     @Test
155     @ApiTest(apis = "android.os.PowerManager#setLowPowerStandbyEnabled")
156     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
157     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testSetLowPowerStandbyEnabled_withPermission_doesNotThrowsSecurityException()158     public void testSetLowPowerStandbyEnabled_withPermission_doesNotThrowsSecurityException() {
159         mPowerManager.setLowPowerStandbyEnabled(false);
160     }
161 
162     @Test
163     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyEnabled",
164             "android.os.PowerManager#isLowPowerStandbyEnabled"})
165     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
166     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testSetLowPowerStandbyEnabled_reflectedByIsLowPowerStandbyEnabled()167     public void testSetLowPowerStandbyEnabled_reflectedByIsLowPowerStandbyEnabled() {
168         mPowerManager.setLowPowerStandbyEnabled(true);
169         assertTrue(mPowerManager.isLowPowerStandbyEnabled());
170 
171         mPowerManager.setLowPowerStandbyEnabled(false);
172         assertFalse(mPowerManager.isLowPowerStandbyEnabled());
173     }
174 
175     @Test
176     @ApiTest(apis = "android.os.PowerManager#setLowPowerStandbyEnabled")
177     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
178     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testSetLowPowerStandbyEnabled_sendsBroadcast()179     public void testSetLowPowerStandbyEnabled_sendsBroadcast() throws Exception {
180         mPowerManager.setLowPowerStandbyEnabled(false);
181 
182         CallbackAsserter broadcastAsserter = CallbackAsserter.forBroadcast(
183                 new IntentFilter(PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED));
184         mPowerManager.setLowPowerStandbyEnabled(true);
185         broadcastAsserter.assertCalled(
186                 "ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED broadcast not received",
187                 BROADCAST_TIMEOUT_SEC);
188 
189         broadcastAsserter = CallbackAsserter.forBroadcast(
190                 new IntentFilter(PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED));
191         mPowerManager.setLowPowerStandbyEnabled(false);
192         broadcastAsserter.assertCalled(
193                 "ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED broadcast not received",
194                 BROADCAST_TIMEOUT_SEC);
195     }
196 
197     @Test
198     @ApiTest(apis = "android.os.PowerManager#setLowPowerStandbyEnabled")
199     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
200     @EnsureHasPermission({Manifest.permission.MANAGE_LOW_POWER_STANDBY,
201             Manifest.permission.DEVICE_POWER})
testLowPowerStandby_wakelockIsDisabled()202     public void testLowPowerStandby_wakelockIsDisabled() throws Exception {
203         keepSystemAwake();
204 
205         // Acquire test wakelock, which should be disabled by LPS
206         WakeLock testWakeLock = mPowerManager.newWakeLock(PARTIAL_WAKE_LOCK, TEST_WAKE_LOCK_TAG);
207         testWakeLock.acquire();
208 
209         mPowerManager.setLowPowerStandbyEnabled(true);
210         goToSleep();
211         mPowerManager.forceLowPowerStandbyActive(true);
212 
213         PollingCheck.check("Test wakelock not disabled", WAKELOCK_STATE_TIMEOUT,
214                 () -> isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
215         PollingCheck.check("System wakelock is disabled", WAKELOCK_STATE_TIMEOUT,
216                 () -> !isWakeLockDisabled(SYSTEM_WAKE_LOCK_TAG));
217 
218         testWakeLock.release();
219     }
220 
221     @Test
222     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyEnabled",
223             "android.os.PowerManager#setLowPowerStandbyActiveDuringMaintenance"})
224     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
225     @EnsureHasPermission({Manifest.permission.MANAGE_LOW_POWER_STANDBY,
226             Manifest.permission.DEVICE_POWER})
testSetLowPowerStandbyActiveDuringMaintenance()227     public void testSetLowPowerStandbyActiveDuringMaintenance() throws Exception {
228         // Keep system awake with system wakelock
229         keepSystemAwake();
230 
231         // Acquire test wakelock, which should be disabled by LPS
232         WakeLock testWakeLock = mPowerManager.newWakeLock(PARTIAL_WAKE_LOCK,
233                 TEST_WAKE_LOCK_TAG);
234         testWakeLock.acquire();
235 
236         mPowerManager.setLowPowerStandbyEnabled(true);
237         mPowerManager.setLowPowerStandbyActiveDuringMaintenance(true);
238 
239         goToSleep();
240         forceDoze();
241 
242         PollingCheck.check(
243                 "Test wakelock still enabled, expected to be disabled by Low Power Standby",
244                 LOW_POWER_STANDBY_ACTIVATE_TIMEOUT, () -> isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
245 
246         enterDozeMaintenance();
247 
248         assertTrue(isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
249 
250         mPowerManager.setLowPowerStandbyActiveDuringMaintenance(false);
251         PollingCheck.check(
252                 "Test wakelock disabled during doze maintenance, even though Low Power Standby "
253                         + "should not be active during maintenance",
254                 WAKELOCK_STATE_TIMEOUT, () -> !isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
255 
256         mPowerManager.setLowPowerStandbyActiveDuringMaintenance(true);
257 
258         PollingCheck.check(
259                 "Test wakelock enabled during doze maintenance, even though Low Power Standby "
260                         + "should be active during maintenance",
261                 WAKELOCK_STATE_TIMEOUT, () -> isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
262 
263         testWakeLock.release();
264     }
265 
266     @Test
267     @ApiTest(apis = "android.os.PowerManager#setLowPowerStandbyEnabled")
268     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
269     @EnsureHasPermission({Manifest.permission.MANAGE_LOW_POWER_STANDBY,
270             Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.DEVICE_POWER})
testLowPowerStandby_networkIsBlocked()271     public void testLowPowerStandby_networkIsBlocked() throws Exception {
272         keepSystemAwake();
273 
274         NetworkBlockedStateAsserter asserter = new NetworkBlockedStateAsserter(mContext);
275         asserter.register();
276 
277         try {
278             mPowerManager.setLowPowerStandbyEnabled(true);
279             goToSleep();
280             mPowerManager.forceLowPowerStandbyActive(true);
281 
282             asserter.assertNetworkBlocked("Network is not blocked", true);
283 
284             wakeUp();
285             mPowerManager.forceLowPowerStandbyActive(false);
286 
287             asserter.assertNetworkBlocked("Network is blocked after waking up", false);
288         } finally {
289             asserter.unregister();
290         }
291     }
292 
293     @Test
294     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyEnabled",
295             "android.os.PowerManager#setLowPowerStandbyPolicy",
296             "android.os.PowerManager#isExemptFromLowPowerStandby"})
297     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
298     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testLowPowerStandby_isExempt_whenEnabled()299     public void testLowPowerStandby_isExempt_whenEnabled() throws Exception {
300         mPowerManager.setLowPowerStandbyEnabled(true);
301         mPowerManager.setLowPowerStandbyPolicy(emptyPolicy());
302         assertFalse(mPowerManager.isExemptFromLowPowerStandby());
303 
304         mPowerManager.setLowPowerStandbyPolicy(ownPackageExemptPolicy());
305         assertTrue(mPowerManager.isExemptFromLowPowerStandby());
306 
307         mPowerManager.setLowPowerStandbyPolicy(new LowPowerStandbyPolicy(
308                 "testLowPowerStandby_isExempt",
309                 new ArraySet<>(new String[]{"some.other.package"}),
310                 0,
311                 Collections.emptySet()
312         ));
313         assertFalse(mPowerManager.isExemptFromLowPowerStandby());
314     }
315 
316     @Test
317     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyEnabled",
318             "android.os.PowerManager#setLowPowerStandbyPolicy",
319             "android.os.PowerManager#isExemptFromLowPowerStandby"})
320     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
321     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testLowPowerStandby_isExempt_whenDisabled()322     public void testLowPowerStandby_isExempt_whenDisabled() throws Exception {
323         mPowerManager.setLowPowerStandbyEnabled(false);
324         mPowerManager.setLowPowerStandbyPolicy(emptyPolicy());
325         assertTrue(mPowerManager.isExemptFromLowPowerStandby());
326     }
327 
328     @Test
329     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyEnabled",
330             "android.os.PowerManager#setLowPowerStandbyPolicy",
331             "android.os.PowerManager#getLowPowerStandbyPolicy"})
332     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
333     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testLowPowerStandby_getPolicy()334     public void testLowPowerStandby_getPolicy() throws Exception {
335         LowPowerStandbyPolicy policy = new LowPowerStandbyPolicy(
336                 "testLowPowerStandby_getPolicy",
337                 new ArraySet<>(new String[]{"package1", "package2"}),
338                 123,
339                 new ArraySet<>(new String[]{"feature1", "feature2"})
340         );
341         mPowerManager.setLowPowerStandbyPolicy(policy);
342         assertEquals(policy, mPowerManager.getLowPowerStandbyPolicy());
343 
344         mPowerManager.setLowPowerStandbyPolicy(null);
345         assertNotEquals(policy, mPowerManager.getLowPowerStandbyPolicy());
346     }
347 
348     @Test
349     @ApiTest(apis = "android.os.PowerManager#setLowPowerStandbyPolicy")
350     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
351     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testLowPowerStandby_setPolicy_changeBroadcastIsSent()352     public void testLowPowerStandby_setPolicy_changeBroadcastIsSent() throws Exception {
353         CallbackAsserter broadcastAsserter = CallbackAsserter.forBroadcast(
354                 new IntentFilter(PowerManager.ACTION_LOW_POWER_STANDBY_POLICY_CHANGED));
355         mPowerManager.setLowPowerStandbyPolicy(ownPackageExemptPolicy());
356         broadcastAsserter.assertCalled(
357                 "ACTION_LOW_POWER_STANDBY_POLICY_CHANGED broadcast not received",
358                 BROADCAST_TIMEOUT_SEC);
359     }
360 
361     @Test
362     @ApiTest(apis = "android.os.PowerManager#setLowPowerStandbyPolicy")
363     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
364     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testLowPowerStandby_setPolicy_exemptPackageIsNotRestricted()365     public void testLowPowerStandby_setPolicy_exemptPackageIsNotRestricted() throws Exception {
366         WakeLock testWakeLock = mPowerManager.newWakeLock(PARTIAL_WAKE_LOCK, TEST_WAKE_LOCK_TAG);
367         testWakeLock.acquire();
368 
369         mPowerManager.forceLowPowerStandbyActive(true);
370         PollingCheck.check("Test wakelock not disabled",
371                 WAKELOCK_STATE_TIMEOUT, () -> isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
372 
373         mPowerManager.setLowPowerStandbyPolicy(ownPackageExemptPolicy());
374         PollingCheck.check("Test wakelock disabled, though package should be exempt",
375                 WAKELOCK_STATE_TIMEOUT, () -> !isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
376 
377         testWakeLock.release();
378     }
379 
380     @Test
381     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyPolicy",
382             "android.os.PowerManager#isAllowedInLowPowerStandby"})
383     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
384     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testLowPowerStandby_isAllowedReason_trueIfDisabled()385     public void testLowPowerStandby_isAllowedReason_trueIfDisabled() throws Exception {
386         mPowerManager.setLowPowerStandbyEnabled(false);
387         assertTrue(mPowerManager.isAllowedInLowPowerStandby(
388                 LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION));
389     }
390 
391     @Test
392     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyEnabled",
393             "android.os.PowerManager#setLowPowerStandbyPolicy",
394             "android.os.PowerManager#isAllowedInLowPowerStandby"})
395     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
396     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testLowPowerStandby_isAllowedReason_falseIfNotAllowed()397     public void testLowPowerStandby_isAllowedReason_falseIfNotAllowed() throws Exception {
398         mPowerManager.setLowPowerStandbyPolicy(emptyPolicy());
399         mPowerManager.setLowPowerStandbyEnabled(true);
400         assertFalse(mPowerManager.isAllowedInLowPowerStandby(
401                 LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION));
402     }
403 
404     @Test
405     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyEnabled",
406             "android.os.PowerManager#setLowPowerStandbyPolicy",
407             "android.os.PowerManager#isAllowedInLowPowerStandby"})
408     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
409     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testLowPowerStandby_isAllowedReason_trueIfAllowed()410     public void testLowPowerStandby_isAllowedReason_trueIfAllowed() throws Exception {
411         mPowerManager.setLowPowerStandbyPolicy(policyWithAllowedReasons(
412                 LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION));
413         mPowerManager.setLowPowerStandbyEnabled(true);
414         assertTrue(mPowerManager.isAllowedInLowPowerStandby(
415                 LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION));
416     }
417 
418     @Test
419     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyEnabled",
420             "android.os.PowerManager#isAllowedInLowPowerStandby"})
421     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
422     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testLowPowerStandby_isAllowedFeature_trueIfDisabled()423     public void testLowPowerStandby_isAllowedFeature_trueIfDisabled() throws Exception {
424         mPowerManager.setLowPowerStandbyEnabled(false);
425         assertTrue(
426                 mPowerManager.isAllowedInLowPowerStandby(FEATURE_WAKE_ON_LAN_IN_LOW_POWER_STANDBY));
427     }
428 
429     @Test
430     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyEnabled",
431             "android.os.PowerManager#setLowPowerStandbyPolicy",
432             "android.os.PowerManager#isAllowedInLowPowerStandby"})
433     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
434     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testLowPowerStandby_isAllowedFeature_falseIfNotAllowed()435     public void testLowPowerStandby_isAllowedFeature_falseIfNotAllowed() throws Exception {
436         mPowerManager.setLowPowerStandbyPolicy(emptyPolicy());
437         mPowerManager.setLowPowerStandbyEnabled(true);
438         assertFalse(mPowerManager.isAllowedInLowPowerStandby(
439                 FEATURE_WAKE_ON_LAN_IN_LOW_POWER_STANDBY));
440     }
441 
442     @Test
443     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyEnabled",
444             "android.os.PowerManager#setLowPowerStandbyPolicy",
445             "android.os.PowerManager#isAllowedInLowPowerStandby"})
446     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
447     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testLowPowerStandby_isAllowedFeature_trueIfAllowed()448     public void testLowPowerStandby_isAllowedFeature_trueIfAllowed() throws Exception {
449         mPowerManager.setLowPowerStandbyPolicy(policyWithAllowedFeatures(
450                 FEATURE_WAKE_ON_LAN_IN_LOW_POWER_STANDBY));
451         mPowerManager.setLowPowerStandbyEnabled(true);
452         assertTrue(
453                 mPowerManager.isAllowedInLowPowerStandby(FEATURE_WAKE_ON_LAN_IN_LOW_POWER_STANDBY));
454     }
455 
456     @Test
457     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyPolicy",
458             "android.os.PowerManager#LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST"})
459     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
460     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testLowPowerStandby_allowedReason_tempPowerSaveAllowlist()461     public void testLowPowerStandby_allowedReason_tempPowerSaveAllowlist() throws Exception {
462         WakeLock testWakeLock = mPowerManager.newWakeLock(PARTIAL_WAKE_LOCK, TEST_WAKE_LOCK_TAG);
463         testWakeLock.acquire();
464         PollingCheck.check("Test wakelock disabled", WAKELOCK_STATE_TIMEOUT,
465                 () -> !isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
466 
467         mPowerManager.forceLowPowerStandbyActive(true);
468         PollingCheck.check("Test wakelock not disabled", WAKELOCK_STATE_TIMEOUT,
469                 () -> isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
470 
471         mPowerManager.setLowPowerStandbyPolicy(policyWithAllowedReasons(
472                 LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST));
473         assertTrue("Test wakelock not disabled", isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
474 
475         PowerExemptionManager powerExemptionManager =
476                 mContext.getSystemService(PowerExemptionManager.class);
477         try (PermissionContext p = TestApis.permissions().withPermission(
478                 Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)) {
479             powerExemptionManager.addToTemporaryAllowList(mContext.getPackageName(),
480                     PowerExemptionManager.REASON_OTHER, "", 5000);
481         }
482         PollingCheck.check("Test wakelock disabled, though UID should be exempt",
483                 WAKELOCK_STATE_TIMEOUT, () -> !isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
484 
485         testWakeLock.release();
486     }
487 
488     @Test
489     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyPolicy",
490             "android.os.PowerManager#LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL"})
491     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
492     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testLowPowerStandby_allowedReason_ongoingCall_phoneCallServiceExempt()493     public void testLowPowerStandby_allowedReason_ongoingCall_phoneCallServiceExempt()
494             throws Exception {
495         Intent intent = LowPowerStandbyForegroundService.createIntentWithForegroundServiceType(
496                 mContext, ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL);
497         mContext.startForegroundService(intent);
498 
499         mPowerManager.forceLowPowerStandbyActive(true);
500         PollingCheck.check("Test wakelock not disabled", WAKELOCK_STATE_TIMEOUT,
501                 () -> isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
502 
503         mPowerManager.setLowPowerStandbyPolicy(
504                 policyWithAllowedReasons(LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL));
505         PollingCheck.check("Test wakelock disabled, though UID should be exempt",
506                 WAKELOCK_STATE_TIMEOUT, () -> !isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
507 
508         mContext.stopService(intent);
509     }
510 
511     @Test
512     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyPolicy",
513             "android.os.PowerManager#LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL"})
514     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
515     @EnsureHasPermission(Manifest.permission.MANAGE_LOW_POWER_STANDBY)
testLowPowerStandby_allowedReason_ongoingCall_otherFgsServiceNotExempt()516     public void testLowPowerStandby_allowedReason_ongoingCall_otherFgsServiceNotExempt()
517             throws Exception {
518         Intent intent = LowPowerStandbyForegroundService.createIntentWithForegroundServiceType(
519                 mContext, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK);
520         mContext.startForegroundService(intent);
521         mPowerManager.setLowPowerStandbyPolicy(
522                 policyWithAllowedReasons(LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL));
523         mPowerManager.forceLowPowerStandbyActive(true);
524 
525         PollingCheck.check("Test wakelock not disabled", WAKELOCK_STATE_TIMEOUT,
526                 () -> isWakeLockDisabled(TEST_WAKE_LOCK_TAG));
527 
528         mContext.stopService(intent);
529     }
530 
531     @Test
532     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyEnabled",
533             "android.os.PowerManager#setLowPowerStandbyPolicy",
534             "android.os.PowerManager#newLowPowerStandbyPortsLock",
535             "android.os.PowerManager#getActiveLowPowerStandbyPorts"})
536     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
537     @EnsureHasPermission({Manifest.permission.MANAGE_LOW_POWER_STANDBY,
538             Manifest.permission.SET_LOW_POWER_STANDBY_PORTS})
testActiveStandbyPorts_disabled()539     public void testActiveStandbyPorts_disabled() throws Exception {
540         mPowerManager.setLowPowerStandbyEnabled(false);
541         mPowerManager.setLowPowerStandbyPolicy(ownPackageExemptPolicy());
542         PowerManager.LowPowerStandbyPortsLock standbyPorts =
543                 mPowerManager.newLowPowerStandbyPortsLock(List.of(PORT_DESC_1));
544         standbyPorts.acquire();
545 
546         assertThat(mPowerManager.getActiveLowPowerStandbyPorts()).doesNotContain(PORT_DESC_1);
547         standbyPorts.release();
548     }
549 
550     @Test
551     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyEnabled",
552             "android.os.PowerManager#newLowPowerStandbyPortsLock",
553             "android.os.PowerManager#getActiveLowPowerStandbyPorts"})
554     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
555     @EnsureHasPermission({Manifest.permission.MANAGE_LOW_POWER_STANDBY,
556             Manifest.permission.SET_LOW_POWER_STANDBY_PORTS})
testActiveStandbyPorts_notExempt()557     public void testActiveStandbyPorts_notExempt() throws Exception {
558         mPowerManager.setLowPowerStandbyEnabled(true);
559 
560         PowerManager.LowPowerStandbyPortsLock standbyPorts =
561                 mPowerManager.newLowPowerStandbyPortsLock(List.of(PORT_DESC_1));
562         standbyPorts.acquire();
563 
564         assertThat(mPowerManager.getActiveLowPowerStandbyPorts()).doesNotContain(PORT_DESC_1);
565         standbyPorts.release();
566     }
567 
568     @Test
569     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyEnabled",
570             "android.os.PowerManager#setLowPowerStandbyPolicy",
571             "android.os.PowerManager#newLowPowerStandbyPortsLock",
572             "android.os.PowerManager#getActiveLowPowerStandbyPorts"})
573     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
574     @EnsureHasPermission({Manifest.permission.MANAGE_LOW_POWER_STANDBY,
575             Manifest.permission.SET_LOW_POWER_STANDBY_PORTS})
testActiveStandbyPorts_exempt()576     public void testActiveStandbyPorts_exempt() throws Exception {
577         mPowerManager.setLowPowerStandbyEnabled(true);
578         mPowerManager.setLowPowerStandbyPolicy(ownPackageExemptPolicy());
579         PowerManager.LowPowerStandbyPortsLock standbyPorts =
580                 mPowerManager.newLowPowerStandbyPortsLock(List.of(PORT_DESC_1));
581         standbyPorts.acquire();
582 
583         assertThat(mPowerManager.getActiveLowPowerStandbyPorts()).contains(PORT_DESC_1);
584         standbyPorts.release();
585     }
586 
587     @Test
588     @ApiTest(apis = {
589             "android.os.PowerManager.LowPowerStandbyPortDescription#getProtocol",
590             "android.os.PowerManager.LowPowerStandbyPortDescription#getPortMatcher",
591             "android.os.PowerManager.LowPowerStandbyPortDescription#getPortNumber",
592             "android.os.PowerManager.LowPowerStandbyPortDescription#getLocalAddress"
593     })
testPortDescriptionGetters()594     public void testPortDescriptionGetters() throws Exception {
595         int protocol = PROTOCOL_UDP;
596         int portMatcher = MATCH_PORT_LOCAL;
597         int portNumber = 5555;
598         LowPowerStandbyPortDescription portDesc =
599                 new LowPowerStandbyPortDescription(protocol, portMatcher, portNumber);
600 
601         assertThat(portDesc.getProtocol()).isEqualTo(protocol);
602         assertThat(portDesc.getPortMatcher()).isEqualTo(portMatcher);
603         assertThat(portDesc.getPortNumber()).isEqualTo(portNumber);
604         assertThat(portDesc.getLocalAddress()).isEqualTo(null);
605 
606         protocol = PROTOCOL_TCP;
607         portMatcher = MATCH_PORT_REMOTE;
608         portNumber = 433;
609         InetAddress localAddress = InetAddress.getByName("192.168.5.5");
610         portDesc =
611                 new LowPowerStandbyPortDescription(protocol, portMatcher, portNumber, localAddress);
612 
613         assertThat(portDesc.getProtocol()).isEqualTo(protocol);
614         assertThat(portDesc.getPortMatcher()).isEqualTo(portMatcher);
615         assertThat(portDesc.getPortNumber()).isEqualTo(portNumber);
616         assertThat(portDesc.getLocalAddress()).isEqualTo(localAddress);
617     }
618 
619     @Test
620     @ApiTest(apis = {"android.os.PowerManager#setLowPowerStandbyEnabled",
621             "android.os.PowerManager#setLowPowerStandbyPolicy",
622             "android.os.PowerManager#newLowPowerStandbyPortsLock",
623             "android.os.PowerManager#getActiveLowPowerStandbyPorts"})
624     @AppModeFull(reason = "Instant apps cannot hold MANAGE_LOW_POWER_STANDBY permission")
625     @EnsureHasPermission({Manifest.permission.MANAGE_LOW_POWER_STANDBY,
626             Manifest.permission.SET_LOW_POWER_STANDBY_PORTS})
testActiveStandbyPorts_becomesActiveOnceExempt()627     public void testActiveStandbyPorts_becomesActiveOnceExempt() throws Exception {
628         mPowerManager.setLowPowerStandbyEnabled(true);
629         PowerManager.LowPowerStandbyPortsLock standbyPorts =
630                 mPowerManager.newLowPowerStandbyPortsLock(List.of(PORT_DESC_1));
631         standbyPorts.acquire();
632 
633         mPowerManager.setLowPowerStandbyPolicy(ownPackageExemptPolicy());
634         assertThat(mPowerManager.getActiveLowPowerStandbyPorts()).contains(PORT_DESC_1);
635         standbyPorts.release();
636     }
637 
emptyPolicy()638     private LowPowerStandbyPolicy emptyPolicy() {
639         return new LowPowerStandbyPolicy(
640                 "CTS: LowPowerStandbyTest empty policy",
641                 Collections.emptySet(),
642                 0,
643                 Collections.emptySet()
644         );
645     }
646 
ownPackageExemptPolicy()647     private LowPowerStandbyPolicy ownPackageExemptPolicy() {
648         return new LowPowerStandbyPolicy(
649                 "CTS: LowPowerStandbyTest own package exempt policy",
650                 new ArraySet<>(new String[]{mContext.getPackageName()}),
651                 0,
652                 Collections.emptySet()
653         );
654     }
655 
policyWithAllowedReasons(int allowedReasons)656     private LowPowerStandbyPolicy policyWithAllowedReasons(int allowedReasons) {
657         return new LowPowerStandbyPolicy(
658                 "CTS: LowPowerStandbyTest policy",
659                 Collections.emptySet(),
660                 allowedReasons,
661                 Collections.emptySet()
662         );
663     }
664 
policyWithAllowedFeatures(String... allowedFeatures)665     private LowPowerStandbyPolicy policyWithAllowedFeatures(String... allowedFeatures) {
666         return new LowPowerStandbyPolicy(
667                 "CTS: LowPowerStandbyTest policy",
668                 Collections.emptySet(),
669                 0,
670                 new ArraySet<>(allowedFeatures)
671         );
672     }
673 
goToSleep()674     private void goToSleep() throws Exception {
675         if (!mPowerManager.isInteractive()) {
676             return;
677         }
678 
679         final BlockingBroadcastReceiver screenOffReceiver = new BlockingBroadcastReceiver(mContext,
680                 Intent.ACTION_SCREEN_OFF);
681         screenOffReceiver.register();
682 
683         executeShellCommand("input keyevent SLEEP");
684 
685         screenOffReceiver.awaitForBroadcast(1000);
686         screenOffReceiver.unregisterQuietly();
687     }
688 
wakeUp()689     private void wakeUp() throws Exception {
690         if (mPowerManager.isInteractive()) {
691             return;
692         }
693 
694         final BlockingBroadcastReceiver screenOnReceiver = new BlockingBroadcastReceiver(mContext,
695                 Intent.ACTION_SCREEN_ON);
696         screenOnReceiver.register();
697 
698         executeShellCommand("input keyevent WAKEUP");
699 
700         screenOnReceiver.awaitForBroadcast(1000);
701         screenOnReceiver.unregisterQuietly();
702     }
703 
forceDoze()704     private void forceDoze() throws Exception {
705         executeShellCommand("dumpsys deviceidle force-idle deep");
706     }
707 
unforceDoze()708     private void unforceDoze() throws Exception {
709         executeShellCommand("dumpsys deviceidle unforce");
710     }
711 
enterDozeMaintenance()712     private void enterDozeMaintenance() throws Exception {
713         executeShellCommand("dumpsys deviceidle force-idle deep");
714 
715         for (int i = 0; i < 4; i++) {
716             String stepResult = executeShellCommand("dumpsys deviceidle step deep");
717             if (stepResult != null && stepResult.contains("IDLE_MAINTENANCE")) {
718                 return;
719             }
720         }
721 
722         fail("Failed to enter doze maintenance mode");
723     }
724 
isWakeLockDisabled(@onNull String tag)725     private boolean isWakeLockDisabled(@NonNull String tag) throws Exception {
726         final PowerManagerServiceDumpProto powerManagerServiceDump = getPowerManagerDump();
727         for (WakeLockProto wakelock : powerManagerServiceDump.wakeLocks) {
728             if (tag.equals(wakelock.tag)) {
729                 return wakelock.isDisabled;
730             }
731         }
732         throw new IllegalStateException("WakeLock " + tag + " is not held");
733     }
734 
getPowerManagerDump()735     private static PowerManagerServiceDumpProto getPowerManagerDump() throws Exception {
736         return ProtoUtils.getProto(InstrumentationRegistry.getInstrumentation().getUiAutomation(),
737                 PowerManagerServiceDumpProto.class, "dumpsys power --proto");
738     }
739 
keepSystemAwake()740     private void keepSystemAwake() {
741         mSystemWakeLock = mPowerManager.newWakeLock(PARTIAL_WAKE_LOCK | SYSTEM_WAKELOCK,
742                 SYSTEM_WAKE_LOCK_TAG);
743         mSystemWakeLock.acquire();
744     }
745 
executeShellCommand(String command)746     private String executeShellCommand(String command) throws IOException {
747         UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
748         return uiDevice.executeShellCommand(command);
749     }
750 
751     private static class NetworkBlockedStateAsserter {
752         private final ConnectivityManager mConnectivityManager;
753         private final ConnectivityManager.NetworkCallback mNetworkCallback;
754 
755         private final Object mLock = new Object();
756         private boolean mIsBlocked = false;
757 
NetworkBlockedStateAsserter(Context context)758         NetworkBlockedStateAsserter(Context context) {
759             mConnectivityManager = context.getSystemService(ConnectivityManager.class);
760             mNetworkCallback =
761                     new ConnectivityManager.NetworkCallback() {
762                         @Override
763                         public void onBlockedStatusChanged(Network network, boolean blocked) {
764                             synchronized (mLock) {
765                                 if (mIsBlocked != blocked) {
766                                     mIsBlocked = blocked;
767                                     mLock.notify();
768                                 }
769                             }
770                         }
771                     };
772         }
773 
register()774         private void register() {
775             mConnectivityManager.registerDefaultNetworkCallback(mNetworkCallback);
776         }
777 
assertNetworkBlocked(String message, boolean expected)778         private void assertNetworkBlocked(String message, boolean expected) throws Exception {
779             synchronized (mLock) {
780                 if (mIsBlocked == expected) {
781                     return;
782                 }
783                 mLock.wait(5000);
784                 assertEquals(message, expected, mIsBlocked);
785             }
786         }
787 
unregister()788         private void unregister() {
789             mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
790         }
791     }
792 }
793