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 com.android.server.power;
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.PROTOCOL_TCP;
25 import static android.os.PowerManager.LowPowerStandbyPortDescription.PROTOCOL_UDP;
26 
27 import static com.google.common.truth.Truth.assertThat;
28 
29 import static junit.framework.Assert.assertFalse;
30 import static junit.framework.Assert.assertTrue;
31 
32 import static org.mockito.ArgumentMatchers.any;
33 import static org.mockito.ArgumentMatchers.anyBoolean;
34 import static org.mockito.ArgumentMatchers.anyInt;
35 import static org.mockito.ArgumentMatchers.anyLong;
36 import static org.mockito.ArgumentMatchers.anyString;
37 import static org.mockito.ArgumentMatchers.eq;
38 import static org.mockito.Mockito.atLeast;
39 import static org.mockito.Mockito.inOrder;
40 import static org.mockito.Mockito.never;
41 import static org.mockito.Mockito.reset;
42 import static org.mockito.Mockito.spy;
43 import static org.mockito.Mockito.times;
44 import static org.mockito.Mockito.verify;
45 import static org.mockito.Mockito.verifyNoMoreInteractions;
46 import static org.mockito.Mockito.when;
47 
48 import android.app.ActivityManagerInternal;
49 import android.app.AlarmManager;
50 import android.app.IActivityManager;
51 import android.app.IForegroundServiceObserver;
52 import android.content.Intent;
53 import android.content.IntentFilter;
54 import android.content.pm.PackageManager;
55 import android.content.pm.ServiceInfo;
56 import android.content.res.Resources;
57 import android.net.Uri;
58 import android.os.Binder;
59 import android.os.IPowerManager;
60 import android.os.PowerManager;
61 import android.os.PowerManager.LowPowerStandbyPolicy;
62 import android.os.PowerManager.LowPowerStandbyPortDescription;
63 import android.os.PowerManagerInternal;
64 import android.os.UserHandle;
65 import android.os.UserManager;
66 import android.os.test.TestLooper;
67 import android.provider.Settings;
68 import android.test.mock.MockContentResolver;
69 import android.util.ArraySet;
70 
71 import androidx.test.InstrumentationRegistry;
72 
73 import com.android.internal.util.test.BroadcastInterceptingContext;
74 import com.android.internal.util.test.FakeSettingsProvider;
75 import com.android.server.LocalServices;
76 import com.android.server.PowerAllowlistInternal;
77 import com.android.server.PowerAllowlistInternal.TempAllowlistChangeListener;
78 import com.android.server.net.NetworkPolicyManagerInternal;
79 import com.android.server.power.LowPowerStandbyController.DeviceConfigWrapper;
80 import com.android.server.testutils.OffsettableClock;
81 
82 import org.junit.After;
83 import org.junit.Before;
84 import org.junit.Test;
85 import org.mockito.ArgumentCaptor;
86 import org.mockito.InOrder;
87 import org.mockito.Mock;
88 import org.mockito.MockitoAnnotations;
89 
90 import java.io.File;
91 import java.util.Collections;
92 import java.util.List;
93 import java.util.concurrent.TimeUnit;
94 
95 /**
96  * Tests for {@link com.android.server.power.LowPowerStandbyController}.
97  *
98  * Build/Install/Run:
99  * atest LowPowerStandbyControllerTest
100  */
101 public class LowPowerStandbyControllerTest {
102     private static final int STANDBY_TIMEOUT = 5000;
103     private static final String TEST_PKG1 = "PKG1";
104     private static final String TEST_PKG2 = "PKG2";
105     private static final int TEST_PKG1_APP_ID = 123;
106     private static final int TEST_PKG2_APP_ID = 456;
107     private static final int USER_ID_1 = 0;
108     private static final int USER_ID_2 = 10;
109     private static final LowPowerStandbyPolicy EMPTY_POLICY = new LowPowerStandbyPolicy(
110             "Test policy", Collections.emptySet(), 0, Collections.emptySet());
111     private static final LowPowerStandbyPortDescription PORT_DESC_1 =
112             new LowPowerStandbyPortDescription(PROTOCOL_UDP, MATCH_PORT_LOCAL, 5353);
113     private static final LowPowerStandbyPortDescription PORT_DESC_2 =
114             new LowPowerStandbyPortDescription(PROTOCOL_TCP, MATCH_PORT_LOCAL, 8008);
115 
116     private LowPowerStandbyController mController;
117     private BroadcastInterceptingContext mContextSpy;
118     private Resources mResourcesSpy;
119     private OffsettableClock mClock;
120     private TestLooper mTestLooper;
121     private File mTestPolicyFile;
122 
123     @Mock
124     private DeviceConfigWrapper mDeviceConfigWrapperMock;
125     @Mock
126     private IActivityManager mIActivityManagerMock;
127     @Mock
128     private AlarmManager mAlarmManagerMock;
129     @Mock
130     private PackageManager mPackageManagerMock;
131     @Mock
132     private UserManager mUserManagerMock;
133     @Mock
134     private IPowerManager mIPowerManagerMock;
135     @Mock
136     private PowerManagerInternal mPowerManagerInternalMock;
137     @Mock
138     private NetworkPolicyManagerInternal mNetworkPolicyManagerInternalMock;
139     @Mock
140     private PowerAllowlistInternal mPowerAllowlistInternalMock;
141     @Mock
142     private ActivityManagerInternal mActivityManagerInternalMock;
143 
144     @Before
setUp()145     public void setUp() throws Exception {
146         MockitoAnnotations.initMocks(this);
147 
148         mContextSpy = spy(new BroadcastInterceptingContext(InstrumentationRegistry.getContext()));
149         when(mContextSpy.getPackageManager()).thenReturn(mPackageManagerMock);
150         when(mContextSpy.getSystemService(AlarmManager.class)).thenReturn(mAlarmManagerMock);
151         when(mContextSpy.getSystemService(UserManager.class)).thenReturn(mUserManagerMock);
152         PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock, null, null);
153         when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
154         addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock);
155         addLocalServiceMock(NetworkPolicyManagerInternal.class, mNetworkPolicyManagerInternalMock);
156         addLocalServiceMock(PowerAllowlistInternal.class, mPowerAllowlistInternalMock);
157         addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock);
158 
159         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
160 
161         when(mDeviceConfigWrapperMock.enableCustomPolicy()).thenReturn(true);
162         when(mDeviceConfigWrapperMock.enableStandbyPorts()).thenReturn(true);
163         mResourcesSpy = spy(mContextSpy.getResources());
164         when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
165         when(mResourcesSpy.getBoolean(
166                 com.android.internal.R.bool.config_lowPowerStandbySupported))
167                 .thenReturn(true);
168         when(mResourcesSpy.getInteger(
169                 com.android.internal.R.integer.config_lowPowerStandbyNonInteractiveTimeout))
170                 .thenReturn(STANDBY_TIMEOUT);
171         when(mResourcesSpy.getBoolean(
172                 com.android.internal.R.bool.config_lowPowerStandbyEnabledByDefault))
173                 .thenReturn(false);
174 
175         FakeSettingsProvider.clearSettingsProvider();
176         MockContentResolver cr = new MockContentResolver(mContextSpy);
177         cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
178         when(mContextSpy.getContentResolver()).thenReturn(cr);
179 
180         when(mUserManagerMock.getUserHandles(true)).thenReturn(List.of(
181                 UserHandle.of(USER_ID_1), UserHandle.of(USER_ID_2)));
182         when(mPackageManagerMock.getPackageUid(eq(TEST_PKG1), any())).thenReturn(TEST_PKG1_APP_ID);
183         when(mPackageManagerMock.getPackageUid(eq(TEST_PKG2), any())).thenReturn(TEST_PKG2_APP_ID);
184         when(mPackageManagerMock.getPackageUidAsUser(eq(TEST_PKG1), eq(USER_ID_1)))
185                 .thenReturn(TEST_PKG1_APP_ID);
186         when(mPackageManagerMock.getPackageUidAsUser(eq(TEST_PKG2), eq(USER_ID_1)))
187                 .thenReturn(TEST_PKG2_APP_ID);
188 
189         mClock = new OffsettableClock.Stopped();
190         mTestLooper = new TestLooper(mClock::now);
191 
192         mTestPolicyFile = new File(mContextSpy.getCacheDir(), "lps_policy.xml");
193         mController = new LowPowerStandbyController(mContextSpy, mTestLooper.getLooper(),
194                 () -> mClock.now(), mDeviceConfigWrapperMock, () -> mIActivityManagerMock,
195                 mTestPolicyFile);
196     }
197 
198     @After
tearDown()199     public void tearDown() throws Exception {
200         LocalServices.removeServiceForTest(PowerManagerInternal.class);
201         LocalServices.removeServiceForTest(LowPowerStandbyControllerInternal.class);
202         LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
203         LocalServices.removeServiceForTest(PowerAllowlistInternal.class);
204         LocalServices.removeServiceForTest(ActivityManagerInternal.class);
205 
206         mTestPolicyFile.delete();
207     }
208 
209     @Test
testOnSystemReady_isInactivate()210     public void testOnSystemReady_isInactivate() {
211         setLowPowerStandbySupportedConfig(true);
212         mController.systemReady();
213 
214         assertThat(mController.isActive()).isFalse();
215         verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
216         verify(mNetworkPolicyManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
217     }
218 
219     @Test
testActivate()220     public void testActivate() throws Exception {
221         setLowPowerStandbySupportedConfig(true);
222         mController.systemReady();
223         mController.setEnabled(true);
224         setNonInteractive();
225         setDeviceIdleMode(true);
226         awaitStandbyTimeoutAlarm();
227         assertThat(mController.isActive()).isTrue();
228         verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(true);
229         verify(mNetworkPolicyManagerInternalMock, times(1)).setLowPowerStandbyActive(true);
230     }
231 
awaitStandbyTimeoutAlarm()232     private void awaitStandbyTimeoutAlarm() {
233         ArgumentCaptor<Long> timeArg = ArgumentCaptor.forClass(Long.class);
234         ArgumentCaptor<AlarmManager.OnAlarmListener> listenerArg =
235                 ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
236         verify(mAlarmManagerMock).setExact(
237                 eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
238                 timeArg.capture(), anyString(),
239                 listenerArg.capture(), any());
240         mClock.reset();
241         mClock.fastForward(timeArg.getValue());
242         listenerArg.getValue().onAlarm();
243         mTestLooper.dispatchAll();
244     }
245 
246     @Test
testOnNonInteractive_notImmediatelyActive()247     public void testOnNonInteractive_notImmediatelyActive() throws Exception {
248         setLowPowerStandbySupportedConfig(true);
249         mController.systemReady();
250         mController.setEnabled(true);
251 
252         setNonInteractive();
253         mTestLooper.dispatchAll();
254 
255         assertThat(mController.isActive()).isFalse();
256         verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
257         verify(mNetworkPolicyManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
258     }
259 
260     @Test
testOnNonInteractive_activateAfterStandbyTimeout()261     public void testOnNonInteractive_activateAfterStandbyTimeout() throws Exception {
262         setLowPowerStandbySupportedConfig(true);
263         mController.systemReady();
264         mController.setEnabled(true);
265 
266         setNonInteractive();
267         awaitStandbyTimeoutAlarm();
268 
269         assertThat(mController.isActive()).isTrue();
270         verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(true);
271         verify(mNetworkPolicyManagerInternalMock, times(1)).setLowPowerStandbyActive(true);
272     }
273 
274     @Test
testOnNonInteractive_doesNotActivateWhenBecomingInteractive()275     public void testOnNonInteractive_doesNotActivateWhenBecomingInteractive() throws Exception {
276         setLowPowerStandbySupportedConfig(true);
277         mController.systemReady();
278         mController.setEnabled(true);
279 
280         setNonInteractive();
281         advanceTime(STANDBY_TIMEOUT / 2);
282         setInteractive();
283         verifyStandbyAlarmCancelled();
284 
285         assertThat(mController.isActive()).isFalse();
286         verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
287         verify(mNetworkPolicyManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
288     }
289 
verifyStandbyAlarmCancelled()290     private void verifyStandbyAlarmCancelled() {
291         InOrder inOrder = inOrder(mAlarmManagerMock);
292         inOrder.verify(mAlarmManagerMock, atLeast(0)).setExact(anyInt(), anyLong(), anyString(),
293                 any(), any());
294         inOrder.verify(mAlarmManagerMock).cancel((AlarmManager.OnAlarmListener) any());
295         inOrder.verifyNoMoreInteractions();
296     }
297 
298     @Test
testOnInteractive_deactivate()299     public void testOnInteractive_deactivate() throws Exception {
300         setLowPowerStandbySupportedConfig(true);
301         mController.systemReady();
302         mController.setEnabled(true);
303         setNonInteractive();
304         setDeviceIdleMode(true);
305         awaitStandbyTimeoutAlarm();
306 
307         setInteractive();
308         mTestLooper.dispatchAll();
309 
310         assertThat(mController.isActive()).isFalse();
311         verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(false);
312         verify(mNetworkPolicyManagerInternalMock, times(1)).setLowPowerStandbyActive(false);
313     }
314 
315     @Test
testOnDozeMaintenance_deactivate()316     public void testOnDozeMaintenance_deactivate() throws Exception {
317         setLowPowerStandbySupportedConfig(true);
318         mController.systemReady();
319         mController.setEnabled(true);
320         mController.setActiveDuringMaintenance(false);
321         setNonInteractive();
322         setDeviceIdleMode(true);
323         awaitStandbyTimeoutAlarm();
324 
325         setDeviceIdleMode(false);
326         mTestLooper.dispatchAll();
327 
328         assertThat(mController.isActive()).isFalse();
329         verify(mPowerManagerInternalMock, times(1)).setLowPowerStandbyActive(false);
330         verify(mNetworkPolicyManagerInternalMock, times(1)).setLowPowerStandbyActive(false);
331     }
332 
333     @Test
testOnDozeMaintenance_activeDuringMaintenance_staysActive()334     public void testOnDozeMaintenance_activeDuringMaintenance_staysActive() throws Exception {
335         setLowPowerStandbySupportedConfig(true);
336         mController.systemReady();
337         mController.setEnabled(true);
338         mController.setActiveDuringMaintenance(true);
339         setNonInteractive();
340         setDeviceIdleMode(true);
341         awaitStandbyTimeoutAlarm();
342 
343         setDeviceIdleMode(false);
344         mTestLooper.dispatchAll();
345 
346         assertThat(mController.isActive()).isTrue();
347         verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(false);
348         verify(mNetworkPolicyManagerInternalMock, never()).setLowPowerStandbyActive(false);
349     }
350 
351     @Test
testOnDozeMaintenanceEnds_activate()352     public void testOnDozeMaintenanceEnds_activate() throws Exception {
353         setLowPowerStandbySupportedConfig(true);
354         mController.systemReady();
355         mController.setEnabled(true);
356         setNonInteractive();
357         setDeviceIdleMode(true);
358         awaitStandbyTimeoutAlarm();
359 
360         setDeviceIdleMode(false);
361         advanceTime(1000);
362         setDeviceIdleMode(true);
363         mTestLooper.dispatchAll();
364 
365         assertThat(mController.isActive()).isTrue();
366         verify(mPowerManagerInternalMock, times(2)).setLowPowerStandbyActive(true);
367         verify(mNetworkPolicyManagerInternalMock, times(2)).setLowPowerStandbyActive(true);
368     }
369 
370     @Test
testLowPowerStandbyDisabled_doesNotActivate()371     public void testLowPowerStandbyDisabled_doesNotActivate() throws Exception {
372         setLowPowerStandbySupportedConfig(true);
373         mController.systemReady();
374         mController.setEnabled(false);
375         setNonInteractive();
376 
377         assertThat(mController.isActive()).isFalse();
378         verify(mAlarmManagerMock, never()).setExact(anyInt(), anyLong(), anyString(), any(), any());
379         verify(mPowerManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
380         verify(mNetworkPolicyManagerInternalMock, never()).setLowPowerStandbyActive(anyBoolean());
381     }
382 
383     @Test
testLowPowerStandbyEnabled_EnabledChangedBroadcastsAreSent()384     public void testLowPowerStandbyEnabled_EnabledChangedBroadcastsAreSent() throws Exception {
385         setLowPowerStandbySupportedConfig(true);
386         mController.systemReady();
387 
388         BroadcastInterceptingContext.FutureIntent futureIntent = mContextSpy.nextBroadcastIntent(
389                 PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED);
390         mController.setEnabled(false);
391         futureIntent.assertNotReceived();
392 
393         futureIntent = mContextSpy.nextBroadcastIntent(
394                 PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED);
395         mController.setEnabled(true);
396         assertThat(futureIntent.get(1, TimeUnit.SECONDS)).isNotNull();
397 
398         futureIntent = mContextSpy.nextBroadcastIntent(
399                 PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED);
400         mController.setEnabled(true);
401         futureIntent.assertNotReceived();
402 
403         futureIntent = mContextSpy.nextBroadcastIntent(
404                 PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED);
405 
406         mController.setEnabled(false);
407         assertThat(futureIntent.get(1, TimeUnit.SECONDS)).isNotNull();
408     }
409 
410     @Test
testSetEnabled_WhenNotSupported_DoesNotEnable()411     public void testSetEnabled_WhenNotSupported_DoesNotEnable() throws Exception {
412         setLowPowerStandbySupportedConfig(false);
413         mController.systemReady();
414 
415         mController.setEnabled(true);
416 
417         assertThat(mController.isEnabled()).isFalse();
418     }
419 
420     @Test
testIsSupported_WhenSupported()421     public void testIsSupported_WhenSupported() throws Exception {
422         setLowPowerStandbySupportedConfig(true);
423         mController.systemReady();
424 
425         assertThat(mController.isSupported()).isTrue();
426     }
427 
428     @Test
testIsSupported_WhenNotSupported()429     public void testIsSupported_WhenNotSupported() throws Exception {
430         setLowPowerStandbySupportedConfig(false);
431         mController.systemReady();
432 
433         assertThat(mController.isSupported()).isFalse();
434     }
435 
436     @Test
testForceActive()437     public void testForceActive() throws Exception {
438         setLowPowerStandbySupportedConfig(false);
439         mController.systemReady();
440 
441         mController.forceActive(true);
442         mTestLooper.dispatchAll();
443 
444         assertThat(mController.isActive()).isTrue();
445         verify(mPowerManagerInternalMock).setLowPowerStandbyActive(true);
446         verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyActive(true);
447 
448         mController.forceActive(false);
449         mTestLooper.dispatchAll();
450 
451         assertThat(mController.isActive()).isFalse();
452         verify(mPowerManagerInternalMock).setLowPowerStandbyActive(false);
453         verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyActive(false);
454     }
455 
setLowPowerStandbySupportedConfig(boolean supported)456     private void setLowPowerStandbySupportedConfig(boolean supported) {
457         when(mResourcesSpy.getBoolean(
458                 com.android.internal.R.bool.config_lowPowerStandbySupported))
459                 .thenReturn(supported);
460     }
461 
462     @Test
testSetPolicy()463     public void testSetPolicy() throws Exception {
464         mController.systemReady();
465         mController.setPolicy(EMPTY_POLICY);
466         assertThat(mController.getPolicy()).isEqualTo(EMPTY_POLICY);
467     }
468 
469     @Test
testSetDefaultPolicy()470     public void testSetDefaultPolicy() throws Exception {
471         mController.systemReady();
472         mController.setPolicy(EMPTY_POLICY);
473         mController.setPolicy(null);
474         assertThat(mController.getPolicy()).isNotNull();
475         assertThat(mController.getPolicy()).isEqualTo(LowPowerStandbyController.DEFAULT_POLICY);
476     }
477 
478     @Test
testAddToAllowlist_ReasonIsAllowed_servicesAreNotified()479     public void testAddToAllowlist_ReasonIsAllowed_servicesAreNotified() throws Exception {
480         mController.systemReady();
481         mController.setPolicy(
482                 policyWithAllowedReasons(LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION));
483 
484         LowPowerStandbyControllerInternal service = LocalServices.getService(
485                 LowPowerStandbyControllerInternal.class);
486         service.addToAllowlist(10, LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION);
487         mTestLooper.dispatchAll();
488         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{10});
489         verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{10});
490 
491         service.removeFromAllowlist(10, LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION);
492         mTestLooper.dispatchAll();
493         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{});
494         verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{});
495     }
496 
497     @Test
testRemoveFromAllowlist_ReasonIsAllowed_servicesAreNotified()498     public void testRemoveFromAllowlist_ReasonIsAllowed_servicesAreNotified() throws Exception {
499         mController.systemReady();
500         mController.setPolicy(
501                 policyWithAllowedReasons(LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION));
502 
503         LowPowerStandbyControllerInternal service = LocalServices.getService(
504                 LowPowerStandbyControllerInternal.class);
505         service.addToAllowlist(10, LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION);
506         mTestLooper.dispatchAll();
507 
508         service.removeFromAllowlist(10, LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION);
509         mTestLooper.dispatchAll();
510         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{});
511         verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{});
512     }
513 
514     @Test
testSetAllowReasons_ActiveExemptionsNoLongerAllowed_servicesAreNotified()515     public void testSetAllowReasons_ActiveExemptionsNoLongerAllowed_servicesAreNotified() {
516         mController.systemReady();
517         mController.setEnabled(true);
518         mController.setPolicy(
519                 policyWithAllowedReasons(LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION));
520 
521         LowPowerStandbyControllerInternal service = LocalServices.getService(
522                 LowPowerStandbyControllerInternal.class);
523         service.addToAllowlist(10, LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION);
524         mTestLooper.dispatchAll();
525 
526         mController.setPolicy(EMPTY_POLICY);
527         mTestLooper.dispatchAll();
528 
529         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{});
530         verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{});
531     }
532 
533     @Test
testSetAllowReasons_ReasonBecomesAllowed_servicesAreNotified()534     public void testSetAllowReasons_ReasonBecomesAllowed_servicesAreNotified() throws Exception {
535         mController.systemReady();
536         mController.setEnabled(true);
537         mController.setPolicy(EMPTY_POLICY);
538 
539         LowPowerStandbyControllerInternal service = LocalServices.getService(
540                 LowPowerStandbyControllerInternal.class);
541         service.addToAllowlist(10, LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION);
542         mTestLooper.dispatchAll();
543 
544         verify(mPowerManagerInternalMock, never()).setLowPowerStandbyAllowlist(any());
545         verify(mNetworkPolicyManagerInternalMock, never()).setLowPowerStandbyAllowlist(any());
546 
547         mController.setPolicy(
548                 policyWithAllowedReasons(LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION));
549         mTestLooper.dispatchAll();
550 
551         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{10});
552         verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{10});
553     }
554 
555     @Test
testSetAllowReasons_NoActiveExemptions_servicesAreNotNotified()556     public void testSetAllowReasons_NoActiveExemptions_servicesAreNotNotified() throws Exception {
557         mController.systemReady();
558         mController.setEnabled(true);
559         mController.setPolicy(
560                 policyWithAllowedReasons(LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION));
561         mController.setPolicy(EMPTY_POLICY);
562         mTestLooper.dispatchAll();
563 
564         verify(mPowerManagerInternalMock, never()).setLowPowerStandbyAllowlist(any());
565         verify(mNetworkPolicyManagerInternalMock, never()).setLowPowerStandbyAllowlist(any());
566     }
567 
568     @Test
testSetAllowedFeatures_isAllowedIfDisabled()569     public void testSetAllowedFeatures_isAllowedIfDisabled() throws Exception {
570         mController.systemReady();
571         mController.setEnabled(false);
572         mTestLooper.dispatchAll();
573 
574         assertTrue(mController.isAllowed(FEATURE_WAKE_ON_LAN_IN_LOW_POWER_STANDBY));
575     }
576 
577     @Test
testSetAllowedFeatures_isAllowedWhenEnabled()578     public void testSetAllowedFeatures_isAllowedWhenEnabled() throws Exception {
579         mController.systemReady();
580         mController.setEnabled(true);
581         mController.setPolicy(policyWithAllowedFeatures(FEATURE_WAKE_ON_LAN_IN_LOW_POWER_STANDBY));
582         mTestLooper.dispatchAll();
583 
584         assertTrue(mController.isAllowed(FEATURE_WAKE_ON_LAN_IN_LOW_POWER_STANDBY));
585     }
586 
587     @Test
testSetAllowedFeatures_isNotAllowed()588     public void testSetAllowedFeatures_isNotAllowed() throws Exception {
589         mController.systemReady();
590         mController.setEnabled(true);
591         mTestLooper.dispatchAll();
592 
593         assertFalse(mController.isAllowed(FEATURE_WAKE_ON_LAN_IN_LOW_POWER_STANDBY));
594     }
595 
596     @Test
testSetExemptPackages_uidPerUserIsExempt()597     public void testSetExemptPackages_uidPerUserIsExempt() throws Exception {
598         mController.systemReady();
599         mController.setEnabled(true);
600         mController.setPolicy(policyWithExemptPackages(TEST_PKG1, TEST_PKG2));
601         mTestLooper.dispatchAll();
602 
603         int[] expectedUidAllowlist = {
604                 UserHandle.getUid(USER_ID_1, TEST_PKG1_APP_ID),
605                 UserHandle.getUid(USER_ID_1, TEST_PKG2_APP_ID),
606                 UserHandle.getUid(USER_ID_2, TEST_PKG1_APP_ID),
607                 UserHandle.getUid(USER_ID_2, TEST_PKG2_APP_ID)
608         };
609         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(expectedUidAllowlist);
610         verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(expectedUidAllowlist);
611     }
612 
613     @Test
testExemptPackageIsRemoved_servicesAreNotified()614     public void testExemptPackageIsRemoved_servicesAreNotified() throws Exception {
615         mController.systemReady();
616         mController.setEnabled(true);
617         mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
618         mTestLooper.dispatchAll();
619 
620         int[] expectedUidAllowlist = {
621                 UserHandle.getUid(USER_ID_1, TEST_PKG1_APP_ID),
622                 UserHandle.getUid(USER_ID_2, TEST_PKG1_APP_ID),
623         };
624         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(expectedUidAllowlist);
625         verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(expectedUidAllowlist);
626         verifyNoMoreInteractions(mPowerManagerInternalMock, mNetworkPolicyManagerInternalMock);
627 
628         reset(mPackageManagerMock);
629         when(mPackageManagerMock.getPackageUid(eq(TEST_PKG1), any()))
630                 .thenThrow(PackageManager.NameNotFoundException.class);
631 
632         Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
633         intent.setData(Uri.fromParts(IntentFilter.SCHEME_PACKAGE, TEST_PKG1, null));
634         intent.putExtra(Intent.EXTRA_REPLACING, false);
635         mContextSpy.sendBroadcast(intent);
636         mTestLooper.dispatchAll();
637 
638         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]);
639         verify(mNetworkPolicyManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]);
640     }
641 
642     @Test
testUsersChanged_packagesExemptForNewUser()643     public void testUsersChanged_packagesExemptForNewUser() throws Exception {
644         mController.systemReady();
645         mController.setEnabled(true);
646         mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
647         mTestLooper.dispatchAll();
648 
649         InOrder inOrder = inOrder(mPowerManagerInternalMock);
650 
651         inOrder.verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{
652                 UserHandle.getUid(USER_ID_1, TEST_PKG1_APP_ID),
653                 UserHandle.getUid(USER_ID_2, TEST_PKG1_APP_ID),
654         });
655         inOrder.verifyNoMoreInteractions();
656 
657         when(mUserManagerMock.getUserHandles(true)).thenReturn(List.of(UserHandle.of(USER_ID_1)));
658         Intent intent = new Intent(Intent.ACTION_USER_REMOVED);
659         intent.putExtra(Intent.EXTRA_USER, UserHandle.of(USER_ID_2));
660         mContextSpy.sendBroadcast(intent);
661         mTestLooper.dispatchAll();
662 
663         inOrder.verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{
664                 UserHandle.getUid(USER_ID_1, TEST_PKG1_APP_ID)
665         });
666         inOrder.verifyNoMoreInteractions();
667 
668         when(mUserManagerMock.getUserHandles(true)).thenReturn(
669                 List.of(UserHandle.of(USER_ID_1), UserHandle.of(USER_ID_2)));
670         intent = new Intent(Intent.ACTION_USER_ADDED);
671         intent.putExtra(Intent.EXTRA_USER, UserHandle.of(USER_ID_2));
672         mContextSpy.sendBroadcast(intent);
673         mTestLooper.dispatchAll();
674 
675         inOrder.verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{
676                 UserHandle.getUid(USER_ID_1, TEST_PKG1_APP_ID),
677                 UserHandle.getUid(USER_ID_2, TEST_PKG1_APP_ID)
678         });
679         inOrder.verifyNoMoreInteractions();
680     }
681 
682     @Test
testIsExempt_exemptIfDisabled()683     public void testIsExempt_exemptIfDisabled() throws Exception {
684         mController.systemReady();
685         mController.setEnabled(false);
686         mTestLooper.dispatchAll();
687 
688         assertTrue(mController.isPackageExempt(TEST_PKG1_APP_ID));
689     }
690 
691     @Test
testIsExempt_notExemptIfEnabled()692     public void testIsExempt_notExemptIfEnabled() throws Exception {
693         mController.systemReady();
694         mController.setEnabled(true);
695         mTestLooper.dispatchAll();
696 
697         assertFalse(mController.isPackageExempt(TEST_PKG1_APP_ID));
698     }
699 
700     @Test
testAllowReason_tempPowerSaveAllowlist()701     public void testAllowReason_tempPowerSaveAllowlist() throws Exception {
702         mController.systemReady();
703         mController.setEnabled(true);
704         mController.setPolicy(policyWithAllowedReasons(
705                 LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST));
706         mTestLooper.dispatchAll();
707 
708         ArgumentCaptor<TempAllowlistChangeListener> tempAllowlistChangeListenerArgumentCaptor =
709                 ArgumentCaptor.forClass(TempAllowlistChangeListener.class);
710         verify(mPowerAllowlistInternalMock).registerTempAllowlistChangeListener(
711                 tempAllowlistChangeListenerArgumentCaptor.capture());
712         TempAllowlistChangeListener tempAllowlistChangeListener =
713                 tempAllowlistChangeListenerArgumentCaptor.getValue();
714 
715         tempAllowlistChangeListener.onAppAdded(TEST_PKG1_APP_ID);
716         mTestLooper.dispatchAll();
717         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG1_APP_ID});
718 
719         tempAllowlistChangeListener.onAppAdded(TEST_PKG2_APP_ID);
720         mTestLooper.dispatchAll();
721         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(
722                 new int[]{TEST_PKG1_APP_ID, TEST_PKG2_APP_ID});
723 
724         tempAllowlistChangeListener.onAppRemoved(TEST_PKG1_APP_ID);
725         mTestLooper.dispatchAll();
726         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG2_APP_ID});
727 
728         mController.setPolicy(EMPTY_POLICY);
729         mTestLooper.dispatchAll();
730         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]);
731     }
732 
733     @Test
testAllowReason_ongoingPhoneCallService()734     public void testAllowReason_ongoingPhoneCallService() throws Exception {
735         mController.systemReady();
736         mController.setEnabled(true);
737         mController.setPolicy(policyWithAllowedReasons(
738                 LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL));
739         mTestLooper.dispatchAll();
740 
741         ArgumentCaptor<IForegroundServiceObserver> fgsObserverCapt =
742                 ArgumentCaptor.forClass(IForegroundServiceObserver.class);
743         verify(mIActivityManagerMock).registerForegroundServiceObserver(fgsObserverCapt.capture());
744         IForegroundServiceObserver fgsObserver = fgsObserverCapt.getValue();
745 
746         when(mActivityManagerInternalMock.hasRunningForegroundService(eq(TEST_PKG1_APP_ID),
747                 eq(ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL))).thenReturn(true);
748         fgsObserver.onForegroundStateChanged(null, TEST_PKG1, USER_ID_1, true);
749         mTestLooper.dispatchAll();
750         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG1_APP_ID});
751 
752         when(mActivityManagerInternalMock.hasRunningForegroundService(eq(TEST_PKG2_APP_ID),
753                 eq(ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL))).thenReturn(true);
754         fgsObserver.onForegroundStateChanged(null, TEST_PKG2, USER_ID_1, true);
755         mTestLooper.dispatchAll();
756         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(
757                 new int[]{TEST_PKG1_APP_ID, TEST_PKG2_APP_ID});
758 
759         when(mActivityManagerInternalMock.hasRunningForegroundService(eq(TEST_PKG1_APP_ID),
760                 eq(ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL))).thenReturn(false);
761         fgsObserver.onForegroundStateChanged(null, TEST_PKG1, USER_ID_1, false);
762         mTestLooper.dispatchAll();
763         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG2_APP_ID});
764 
765         mController.setPolicy(EMPTY_POLICY);
766         mTestLooper.dispatchAll();
767         verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]);
768     }
769 
770     @Test
testStandbyPorts_broadcastChangedIfPackageIsExempt()771     public void testStandbyPorts_broadcastChangedIfPackageIsExempt() throws Exception {
772         mController.systemReady();
773         mController.setEnabled(true);
774         mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
775 
776         Binder token = new Binder();
777         BroadcastInterceptingContext.FutureIntent futureIntent = mContextSpy.nextBroadcastIntent(
778                 PowerManager.ACTION_LOW_POWER_STANDBY_PORTS_CHANGED);
779         mController.acquireStandbyPorts(token, TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
780         mTestLooper.dispatchAll();
781         assertThat(futureIntent.get(1, TimeUnit.SECONDS)).isNotNull();
782 
783         futureIntent = mContextSpy.nextBroadcastIntent(
784                 PowerManager.ACTION_LOW_POWER_STANDBY_PORTS_CHANGED);
785         mController.releaseStandbyPorts(token);
786         mTestLooper.dispatchAll();
787         assertThat(futureIntent.get(1, TimeUnit.SECONDS)).isNotNull();
788     }
789 
790     @Test
testStandbyPorts_noBroadcastChangedIfPackageIsNotExempt()791     public void testStandbyPorts_noBroadcastChangedIfPackageIsNotExempt() throws Exception {
792         mController.systemReady();
793         mController.setEnabled(true);
794         mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
795 
796         BroadcastInterceptingContext.FutureIntent futureIntent = mContextSpy.nextBroadcastIntent(
797                 PowerManager.ACTION_LOW_POWER_STANDBY_PORTS_CHANGED);
798         mController.acquireStandbyPorts(new Binder(), TEST_PKG2_APP_ID, List.of(PORT_DESC_1));
799         mTestLooper.dispatchAll();
800         futureIntent.assertNotReceived();
801     }
802 
803     @Test
testActiveStandbyPorts_emptyIfDisabled()804     public void testActiveStandbyPorts_emptyIfDisabled() throws Exception {
805         mController.systemReady();
806         mController.setEnabled(false);
807         mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
808 
809         mController.acquireStandbyPorts(new Binder(), TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
810         assertThat(mController.getActiveStandbyPorts()).isEmpty();
811     }
812 
813     @Test
testActiveStandbyPorts_emptyIfPackageNotExempt()814     public void testActiveStandbyPorts_emptyIfPackageNotExempt() throws Exception {
815         mController.systemReady();
816         mController.setEnabled(true);
817         mController.setPolicy(policyWithExemptPackages(TEST_PKG2));
818 
819         mController.acquireStandbyPorts(new Binder(), TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
820         assertThat(mController.getActiveStandbyPorts()).isEmpty();
821     }
822 
823     @Test
testActiveStandbyPorts_activeIfPackageExempt()824     public void testActiveStandbyPorts_activeIfPackageExempt() throws Exception {
825         mController.systemReady();
826         mController.setEnabled(true);
827         mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
828 
829         mController.acquireStandbyPorts(new Binder(), TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
830         mController.acquireStandbyPorts(new Binder(), TEST_PKG2_APP_ID, List.of(PORT_DESC_2));
831         assertThat(mController.getActiveStandbyPorts()).containsExactly(PORT_DESC_1);
832     }
833 
834     @Test
testActiveStandbyPorts_removedAfterRelease()835     public void testActiveStandbyPorts_removedAfterRelease() throws Exception {
836         mController.systemReady();
837         mController.setEnabled(true);
838         mController.setPolicy(policyWithExemptPackages(TEST_PKG1));
839         Binder token = new Binder();
840         mController.acquireStandbyPorts(token, TEST_PKG1_APP_ID, List.of(PORT_DESC_1));
841         mController.releaseStandbyPorts(token);
842         assertThat(mController.getActiveStandbyPorts()).isEmpty();
843     }
844 
setInteractive()845     private void setInteractive() throws Exception {
846         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
847         mContextSpy.sendBroadcast(new Intent(Intent.ACTION_SCREEN_ON));
848     }
849 
setNonInteractive()850     private void setNonInteractive() throws Exception {
851         when(mIPowerManagerMock.isInteractive()).thenReturn(false);
852         mContextSpy.sendBroadcast(new Intent(Intent.ACTION_SCREEN_OFF));
853     }
854 
setDeviceIdleMode(boolean idle)855     private void setDeviceIdleMode(boolean idle) throws Exception {
856         when(mIPowerManagerMock.isDeviceIdleMode()).thenReturn(idle);
857         mContextSpy.sendBroadcast(new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
858     }
859 
policyWithAllowedReasons(int allowedReasons)860     private LowPowerStandbyPolicy policyWithAllowedReasons(int allowedReasons) {
861         return new LowPowerStandbyPolicy(
862                 "Test policy",
863                 Collections.emptySet(),
864                 allowedReasons,
865                 Collections.emptySet()
866         );
867     }
868 
policyWithAllowedFeatures(String... allowedFeatures)869     private LowPowerStandbyPolicy policyWithAllowedFeatures(String... allowedFeatures) {
870         return new LowPowerStandbyPolicy(
871                 "Test policy",
872                 Collections.emptySet(),
873                 0,
874                 new ArraySet<>(allowedFeatures)
875         );
876     }
877 
policyWithExemptPackages(String... exemptPackages)878     private LowPowerStandbyPolicy policyWithExemptPackages(String... exemptPackages) {
879         return new LowPowerStandbyPolicy(
880                 "Test policy",
881                 new ArraySet<>(exemptPackages),
882                 0,
883                 Collections.emptySet()
884         );
885     }
886 
advanceTime(long timeMs)887     private void advanceTime(long timeMs) {
888         mClock.fastForward(timeMs);
889         mTestLooper.dispatchAll();
890     }
891 
892     /**
893      * Creates a mock and registers it to {@link LocalServices}.
894      */
addLocalServiceMock(Class<T> clazz, T mock)895     private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
896         LocalServices.removeServiceForTest(clazz);
897         LocalServices.addService(clazz, mock);
898     }
899 }
900