1 /*
2  * Copyright (C) 2022 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.appop;
18 
19 import static android.app.AppOpsManager.MODE_ALLOWED;
20 import static android.app.AppOpsManager.MODE_FOREGROUND;
21 import static android.app.AppOpsManager.MODE_IGNORED;
22 import static android.app.AppOpsManager.OP_CAMERA;
23 import static android.app.AppOpsManager.OP_COARSE_LOCATION;
24 import static android.app.AppOpsManager.OP_FINE_LOCATION;
25 import static android.app.AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO;
26 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
27 import static android.app.AppOpsManager.OP_WIFI_SCAN;
28 import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
29 import static android.app.AppOpsManager.UID_STATE_CACHED;
30 import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
31 import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
32 import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
33 import static android.app.AppOpsManager.UID_STATE_TOP;
34 
35 import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState;
36 
37 import static org.junit.Assert.assertEquals;
38 import static org.junit.Assert.assertFalse;
39 import static org.junit.Assert.assertTrue;
40 import static org.mockito.ArgumentMatchers.anyBoolean;
41 import static org.mockito.ArgumentMatchers.anyInt;
42 import static org.mockito.ArgumentMatchers.eq;
43 import static org.mockito.Mockito.atLeastOnce;
44 import static org.mockito.Mockito.doReturn;
45 import static org.mockito.Mockito.never;
46 import static org.mockito.Mockito.times;
47 import static org.mockito.Mockito.verify;
48 
49 import android.app.ActivityManager;
50 import android.app.ActivityManagerInternal;
51 import android.app.AppOpsManager;
52 import android.util.SparseArray;
53 
54 import com.android.dx.mockito.inline.extended.ExtendedMockito;
55 import com.android.dx.mockito.inline.extended.StaticMockitoSession;
56 import com.android.internal.os.Clock;
57 import com.android.server.appop.AppOpsUidStateTracker.UidStateChangedCallback;
58 import com.android.server.appop.AppOpsUidStateTrackerImpl.DelayableExecutor;
59 
60 import org.junit.After;
61 import org.junit.Before;
62 import org.junit.Test;
63 import org.mockito.Mock;
64 import org.mockito.Mockito;
65 import org.mockito.quality.Strictness;
66 
67 import java.util.PriorityQueue;
68 
69 public class AppOpsUidStateTrackerTest {
70 
71     private static final int UID = 10001;
72 
73     // An op code that's not location/cam/mic so that we can test the code for evaluating mode
74     // without a specific capability associated with it.
75     public static final int OP_NO_CAPABILITIES = OP_WIFI_SCAN;
76 
77     @Mock
78     ActivityManagerInternal mAmi;
79 
80     @Mock
81     AppOpsService.Constants mConstants;
82 
83     AppOpsUidStateTrackerTestExecutor mExecutor = new AppOpsUidStateTrackerTestExecutor();
84 
85     AppOpsUidStateTrackerTestClock mClock = new AppOpsUidStateTrackerTestClock(mExecutor);
86 
87     AppOpsUidStateTracker mIntf;
88 
89     StaticMockitoSession mSession;
90 
91     @Before
setUp()92     public void setUp() {
93         mSession = ExtendedMockito.mockitoSession()
94                 .initMocks(this)
95                 .strictness(Strictness.LENIENT)
96                 .startMocking();
97         mConstants.TOP_STATE_SETTLE_TIME = 10 * 1000L;
98         mConstants.FG_SERVICE_STATE_SETTLE_TIME = 5 * 1000L;
99         mConstants.BG_STATE_SETTLE_TIME = 1 * 1000L;
100         mIntf = new AppOpsUidStateTrackerImpl(mAmi, mExecutor, mClock, mConstants,
101                 Thread.currentThread());
102     }
103 
104     @After
tearDown()105     public void tearDown() {
106         mSession.finishMocking();
107     }
108 
109     /**
110      * This class makes the assumption that all ops are restricted at the same state, this is likely
111      * to be the case forever or become obsolete with the capability mechanism. If this fails
112      * something in {@link AppOpsUidStateTrackerImpl} might break when reporting if foreground mode
113      * might change.
114      */
115     @Test
testConstantFirstUnrestrictedUidState()116     public void testConstantFirstUnrestrictedUidState() {
117         for (int i = 0; i < AppOpsManager.getNumOps(); i++) {
118             assertEquals(UID_STATE_MAX_LAST_NON_RESTRICTED,
119                     AppOpsManager.resolveFirstUnrestrictedUidState(i));
120         }
121     }
122 
123     @Test
testNoCapability()124     public void testNoCapability() {
125         procStateBuilder(UID)
126                 .topState()
127                 .update();
128 
129         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
130         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
131         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
132         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
133         assertEquals(MODE_IGNORED,
134                 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
135     }
136 
137     @Test
testForegroundWithMicrophoneCapability()138     public void testForegroundWithMicrophoneCapability() {
139         procStateBuilder(UID)
140                 .topState()
141                 .microphoneCapability()
142                 .update();
143 
144         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
145         assertEquals(MODE_ALLOWED,
146                 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
147 
148         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
149         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
150         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
151     }
152 
153     @Test
testBackgroundWithMicrophoneCapability()154     public void testBackgroundWithMicrophoneCapability() {
155         procStateBuilder(UID)
156                 .backgroundState()
157                 .microphoneCapability()
158                 .update();
159 
160         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
161         assertEquals(MODE_ALLOWED,
162                 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
163 
164         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
165         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
166         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
167     }
168 
169     @Test
testForegroundWithCameraCapability()170     public void testForegroundWithCameraCapability() {
171         procStateBuilder(UID)
172                 .topState()
173                 .cameraCapability()
174                 .update();
175 
176         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
177 
178         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
179         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
180         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
181         assertEquals(MODE_IGNORED,
182                 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
183     }
184 
185     @Test
testBackgroundWithCameraCapability()186     public void testBackgroundWithCameraCapability() {
187         procStateBuilder(UID)
188                 .backgroundState()
189                 .cameraCapability()
190                 .update();
191 
192         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
193 
194         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
195         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
196         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
197         assertEquals(MODE_IGNORED,
198                 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
199     }
200 
201     @Test
testForegroundWithLocationCapability()202     public void testForegroundWithLocationCapability() {
203         procStateBuilder(UID)
204                 .topState()
205                 .locationCapability()
206                 .update();
207 
208         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
209         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
210 
211         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
212         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
213         assertEquals(MODE_IGNORED,
214                 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
215     }
216 
217     @Test
testBackgroundWithLocationCapability()218     public void testBackgroundWithLocationCapability() {
219         procStateBuilder(UID)
220                 .backgroundState()
221                 .locationCapability()
222                 .update();
223 
224         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
225         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
226 
227         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
228         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
229         assertEquals(MODE_IGNORED,
230                 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
231     }
232 
233     @Test
testForegroundNotCapabilitiesTracked()234     public void testForegroundNotCapabilitiesTracked() {
235         procStateBuilder(UID)
236                 .topState()
237                 .update();
238 
239         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_NO_CAPABILITIES, MODE_FOREGROUND));
240     }
241 
242     @Test
testBackgroundNotCapabilitiesTracked()243     public void testBackgroundNotCapabilitiesTracked() {
244         procStateBuilder(UID)
245                 .backgroundState()
246                 .update();
247 
248         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_NO_CAPABILITIES, MODE_FOREGROUND));
249     }
250 
251     @Test
testBackgroundToForegroundTransition()252     public void testBackgroundToForegroundTransition() {
253         procStateBuilder(UID)
254                 .backgroundState()
255                 .update();
256         assertBackground(UID);
257 
258         procStateBuilder(UID)
259                 .topState()
260                 .update();
261         assertForeground(UID);
262     }
263 
264     @Test
testForegroundToBackgroundTransition()265     public void testForegroundToBackgroundTransition() {
266         procStateBuilder(UID)
267                 .topState()
268                 .update();
269         assertForeground(UID);
270 
271         procStateBuilder(UID)
272                 .backgroundState()
273                 .update();
274         // Still in foreground due to settle time
275         assertForeground(UID);
276 
277         mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME - 1);
278         assertForeground(UID);
279 
280         mClock.advanceTime(1);
281         assertBackground(UID);
282     }
283 
284     @Test
testForegroundServiceToBackgroundTransition()285     public void testForegroundServiceToBackgroundTransition() {
286         procStateBuilder(UID)
287                 .foregroundServiceState()
288                 .update();
289         assertForeground(UID);
290 
291         procStateBuilder(UID)
292                 .backgroundState()
293                 .update();
294         // Still in foreground due to settle time
295         assertForeground(UID);
296 
297         mClock.advanceTime(mConstants.FG_SERVICE_STATE_SETTLE_TIME - 1);
298         assertForeground(UID);
299 
300         mClock.advanceTime(1);
301         assertBackground(UID);
302     }
303 
304     @Test
testEarlyUpdateDoesntCommit()305     public void testEarlyUpdateDoesntCommit() {
306         procStateBuilder(UID)
307                 .foregroundServiceState()
308                 .update();
309         assertForeground(UID);
310 
311         procStateBuilder(UID)
312                 .backgroundState()
313                 .update();
314         // Still in foreground due to settle time
315         assertForeground(UID);
316 
317         // 1 ms short of settle time
318         mClock.advanceTime(mConstants.FG_SERVICE_STATE_SETTLE_TIME - 1);
319         assertForeground(UID);
320     }
321 
322     @Test
testMicrophoneCapabilityAdded()323     public void testMicrophoneCapabilityAdded() {
324         procStateBuilder(UID)
325                 .backgroundState()
326                 .update();
327 
328         procStateBuilder(UID)
329                 .backgroundState()
330                 .microphoneCapability()
331                 .update();
332 
333         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
334         assertEquals(MODE_ALLOWED,
335                 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
336     }
337 
338     @Test
testMicrophoneCapabilityRemoved()339     public void testMicrophoneCapabilityRemoved() {
340         procStateBuilder(UID)
341                 .backgroundState()
342                 .microphoneCapability()
343                 .update();
344 
345         procStateBuilder(UID)
346                 .backgroundState()
347                 .update();
348 
349         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
350         assertEquals(MODE_IGNORED,
351                 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
352     }
353 
354     @Test
testCameraCapabilityAdded()355     public void testCameraCapabilityAdded() {
356         procStateBuilder(UID)
357                 .backgroundState()
358                 .update();
359 
360         procStateBuilder(UID)
361                 .backgroundState()
362                 .cameraCapability()
363                 .update();
364 
365         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
366     }
367 
368     @Test
testCameraCapabilityRemoved()369     public void testCameraCapabilityRemoved() {
370         procStateBuilder(UID)
371                 .backgroundState()
372                 .cameraCapability()
373                 .update();
374 
375         procStateBuilder(UID)
376                 .backgroundState()
377                 .update();
378 
379         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
380     }
381 
382     @Test
testLocationCapabilityAdded()383     public void testLocationCapabilityAdded() {
384         procStateBuilder(UID)
385                 .backgroundState()
386                 .update();
387 
388         procStateBuilder(UID)
389                 .backgroundState()
390                 .locationCapability()
391                 .update();
392 
393         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
394         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
395     }
396 
397     @Test
testLocationCapabilityRemoved()398     public void testLocationCapabilityRemoved() {
399         procStateBuilder(UID)
400                 .backgroundState()
401                 .locationCapability()
402                 .update();
403 
404         procStateBuilder(UID)
405                 .backgroundState()
406                 .update();
407 
408         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
409         assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
410     }
411 
412     @Test
testVisibleAppWidget()413     public void testVisibleAppWidget() {
414         procStateBuilder(UID)
415                 .backgroundState()
416                 .update();
417 
418         SparseArray<String> appPackageNames = new SparseArray<>();
419         appPackageNames.put(UID, "");
420         mIntf.updateAppWidgetVisibility(appPackageNames, true);
421 
422         assertForeground(UID);
423         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
424         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
425         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
426         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
427         assertEquals(MODE_ALLOWED,
428                 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
429     }
430 
431     @Test
testPendingTop()432     public void testPendingTop() {
433         procStateBuilder(UID)
434                 .backgroundState()
435                 .update();
436 
437         doReturn(true).when(mAmi).isPendingTopUid(eq(UID));
438 
439         assertForeground(UID);
440         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
441         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
442         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
443         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
444         assertEquals(MODE_ALLOWED,
445                 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
446     }
447 
448     @Test
testTempAllowlist()449     public void testTempAllowlist() {
450         procStateBuilder(UID)
451                 .backgroundState()
452                 .update();
453 
454         doReturn(true).when(mAmi).isTempAllowlistedForFgsWhileInUse(eq(UID));
455 
456         assertForeground(UID);
457         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
458         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
459         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
460         assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
461         assertEquals(MODE_ALLOWED,
462                 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND));
463     }
464 
465     @Test
testUidStateChangedCallbackNewProcessTop()466     public void testUidStateChangedCallbackNewProcessTop() {
467         UidStateChangedCallback cb = addUidStateChangeCallback();
468 
469         procStateBuilder(UID)
470                 .topState()
471                 .update();
472 
473         verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_TOP), eq(true));
474     }
475 
476     @Test
testUidStateChangedCallbackNewProcessForegroundService()477     public void testUidStateChangedCallbackNewProcessForegroundService() {
478         UidStateChangedCallback cb = addUidStateChangeCallback();
479 
480         procStateBuilder(UID)
481                 .foregroundServiceState()
482                 .update();
483 
484         verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_FOREGROUND_SERVICE), eq(true));
485     }
486 
487     @Test
testUidStateChangedCallbackNewProcessForeground()488     public void testUidStateChangedCallbackNewProcessForeground() {
489         UidStateChangedCallback cb = addUidStateChangeCallback();
490 
491         procStateBuilder(UID)
492                 .foregroundState()
493                 .update();
494 
495         verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_FOREGROUND), eq(true));
496     }
497 
498     @Test
testUidStateChangedCallbackNewProcessBackground()499     public void testUidStateChangedCallbackNewProcessBackground() {
500         UidStateChangedCallback cb = addUidStateChangeCallback();
501 
502         procStateBuilder(UID)
503                 .backgroundState()
504                 .update();
505 
506         verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_BACKGROUND), eq(false));
507     }
508 
509     @Test
testUidStateChangedCallbackNewProcessCached()510     public void testUidStateChangedCallbackNewProcessCached() {
511         UidStateChangedCallback cb = addUidStateChangeCallback();
512 
513         procStateBuilder(UID)
514                 .cachedState()
515                 .update();
516 
517         // Cached is the default, no change in uid state.
518         verify(cb, times(0)).onUidStateChanged(anyInt(), anyInt(), anyBoolean());
519     }
520 
521     @Test
testUidStateChangedCallbackCachedToBackground()522     public void testUidStateChangedCallbackCachedToBackground() {
523         testUidStateChangedCallback(
524                 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
525                 ActivityManager.PROCESS_STATE_RECEIVER);
526     }
527 
528     @Test
testUidStateChangedCallbackCachedToForeground()529     public void testUidStateChangedCallbackCachedToForeground() {
530         testUidStateChangedCallback(
531                 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
532                 ActivityManager.PROCESS_STATE_BOUND_TOP);
533     }
534 
535     @Test
testUidStateChangedCallbackCachedToForegroundService()536     public void testUidStateChangedCallbackCachedToForegroundService() {
537         testUidStateChangedCallback(
538                 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
539                 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
540     }
541 
542     @Test
testUidStateChangedCallbackCachedToTop()543     public void testUidStateChangedCallbackCachedToTop() {
544         testUidStateChangedCallback(
545                 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
546                 ActivityManager.PROCESS_STATE_TOP);
547     }
548 
549     @Test
testUidStateChangedCallbackBackgroundToCached()550     public void testUidStateChangedCallbackBackgroundToCached() {
551         testUidStateChangedCallback(
552                 ActivityManager.PROCESS_STATE_RECEIVER,
553                 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
554     }
555 
556     @Test
testUidStateChangedCallbackBackgroundToForeground()557     public void testUidStateChangedCallbackBackgroundToForeground() {
558         testUidStateChangedCallback(
559                 ActivityManager.PROCESS_STATE_RECEIVER,
560                 ActivityManager.PROCESS_STATE_BOUND_TOP);
561     }
562 
563     @Test
testUidStateChangedCallbackBackgroundToForegroundService()564     public void testUidStateChangedCallbackBackgroundToForegroundService() {
565         testUidStateChangedCallback(
566                 ActivityManager.PROCESS_STATE_RECEIVER,
567                 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
568     }
569 
570     @Test
testUidStateChangedCallbackBackgroundToTop()571     public void testUidStateChangedCallbackBackgroundToTop() {
572         testUidStateChangedCallback(
573                 ActivityManager.PROCESS_STATE_RECEIVER,
574                 ActivityManager.PROCESS_STATE_TOP);
575     }
576 
577     @Test
testUidStateChangedCallbackForegroundToCached()578     public void testUidStateChangedCallbackForegroundToCached() {
579         testUidStateChangedCallback(
580                 ActivityManager.PROCESS_STATE_BOUND_TOP,
581                 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
582     }
583 
584     @Test
testUidStateChangedCallbackForegroundToBackground()585     public void testUidStateChangedCallbackForegroundToBackground() {
586         testUidStateChangedCallback(
587                 ActivityManager.PROCESS_STATE_BOUND_TOP,
588                 ActivityManager.PROCESS_STATE_RECEIVER);
589     }
590 
591     @Test
testUidStateChangedCallbackForegroundToForegroundService()592     public void testUidStateChangedCallbackForegroundToForegroundService() {
593         testUidStateChangedCallback(
594                 ActivityManager.PROCESS_STATE_BOUND_TOP,
595                 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
596     }
597 
598     @Test
testUidStateChangedCallbackForegroundToTop()599     public void testUidStateChangedCallbackForegroundToTop() {
600         testUidStateChangedCallback(
601                 ActivityManager.PROCESS_STATE_BOUND_TOP,
602                 ActivityManager.PROCESS_STATE_TOP);
603     }
604 
605     @Test
testUidStateChangedCallbackForegroundServiceToCached()606     public void testUidStateChangedCallbackForegroundServiceToCached() {
607         testUidStateChangedCallback(
608                 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
609                 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
610     }
611 
612     @Test
testUidStateChangedCallbackForegroundServiceToBackground()613     public void testUidStateChangedCallbackForegroundServiceToBackground() {
614         testUidStateChangedCallback(
615                 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
616                 ActivityManager.PROCESS_STATE_RECEIVER);
617     }
618 
619     @Test
testUidStateChangedCallbackForegroundServiceToForeground()620     public void testUidStateChangedCallbackForegroundServiceToForeground() {
621         testUidStateChangedCallback(
622                 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
623                 ActivityManager.PROCESS_STATE_BOUND_TOP);
624     }
625 
626     @Test
testUidStateChangedCallbackForegroundServiceToTop()627     public void testUidStateChangedCallbackForegroundServiceToTop() {
628         testUidStateChangedCallback(
629                 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
630                 ActivityManager.PROCESS_STATE_TOP);
631     }
632 
633     @Test
testUidStateChangedCallbackTopToCached()634     public void testUidStateChangedCallbackTopToCached() {
635         testUidStateChangedCallback(
636                 ActivityManager.PROCESS_STATE_TOP,
637                 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
638     }
639 
640     @Test
testUidStateChangedCallbackTopToBackground()641     public void testUidStateChangedCallbackTopToBackground() {
642         testUidStateChangedCallback(
643                 ActivityManager.PROCESS_STATE_TOP,
644                 ActivityManager.PROCESS_STATE_RECEIVER);
645     }
646 
647     @Test
testUidStateChangedCallbackTopToForeground()648     public void testUidStateChangedCallbackTopToForeground() {
649         testUidStateChangedCallback(
650                 ActivityManager.PROCESS_STATE_TOP,
651                 ActivityManager.PROCESS_STATE_BOUND_TOP);
652     }
653 
654     @Test
testUidStateChangedCallbackTopToForegroundService()655     public void testUidStateChangedCallbackTopToForegroundService() {
656         testUidStateChangedCallback(
657                 ActivityManager.PROCESS_STATE_TOP,
658                 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
659     }
660 
661     @Test
testUidStateChangedCallbackCachedToNonexistent()662     public void testUidStateChangedCallbackCachedToNonexistent() {
663         UidStateChangedCallback cb = addUidStateChangeCallback();
664 
665         procStateBuilder(UID)
666                 .cachedState()
667                 .update();
668 
669         procStateBuilder(UID)
670                 .nonExistentState()
671                 .update();
672 
673         verify(cb, never()).onUidStateChanged(anyInt(), anyInt(), anyBoolean());
674     }
675 
676     @Test
testUidStateChangedCallbackBackgroundToNonexistent()677     public void testUidStateChangedCallbackBackgroundToNonexistent() {
678         UidStateChangedCallback cb = addUidStateChangeCallback();
679 
680         procStateBuilder(UID)
681                 .backgroundState()
682                 .update();
683 
684         procStateBuilder(UID)
685                 .nonExistentState()
686                 .update();
687 
688         verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(false));
689     }
690 
691     @Test
testUidStateChangedCallbackForegroundToNonexistent()692     public void testUidStateChangedCallbackForegroundToNonexistent() {
693         UidStateChangedCallback cb = addUidStateChangeCallback();
694 
695         procStateBuilder(UID)
696                 .foregroundState()
697                 .update();
698 
699         procStateBuilder(UID)
700                 .nonExistentState()
701                 .update();
702 
703         verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
704     }
705 
706     @Test
testUidStateChangedCallbackForegroundServiceToNonexistent()707     public void testUidStateChangedCallbackForegroundServiceToNonexistent() {
708         UidStateChangedCallback cb = addUidStateChangeCallback();
709 
710         procStateBuilder(UID)
711                 .foregroundServiceState()
712                 .update();
713 
714         procStateBuilder(UID)
715                 .nonExistentState()
716                 .update();
717 
718         verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
719     }
720 
721     @Test
testUidStateChangedCallbackTopToNonexistent()722     public void testUidStateChangedCallbackTopToNonexistent() {
723         UidStateChangedCallback cb = addUidStateChangeCallback();
724 
725         procStateBuilder(UID)
726                 .topState()
727                 .update();
728 
729         procStateBuilder(UID)
730                 .nonExistentState()
731                 .update();
732 
733         verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
734     }
735 
736     @Test
testUidStateChangedBackgroundThenForegroundImmediately()737     public void testUidStateChangedBackgroundThenForegroundImmediately() {
738         procStateBuilder(UID)
739             .topState()
740             .update();
741 
742         UidStateChangedCallback cb = addUidStateChangeCallback();
743 
744         procStateBuilder(UID)
745             .backgroundState()
746             .update();
747 
748         mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME - 1);
749 
750         procStateBuilder(UID)
751             .topState()
752             .update();
753 
754         mClock.advanceTime(1);
755 
756         verify(cb, never()).onUidStateChanged(anyInt(), anyInt(), anyBoolean());
757     }
758 
759     @Test
testIsUidInForegroundForBackgroundState()760     public void testIsUidInForegroundForBackgroundState() {
761         procStateBuilder(UID)
762                 .backgroundState()
763                 .update();
764         assertFalse(mIntf.isUidInForeground(UID));
765 
766         procStateBuilder(UID)
767                 .nonExistentState()
768                 .update();
769         assertFalse(mIntf.isUidInForeground(UID));
770     }
771 
772     @Test
testIsUidInForegroundForForegroundState()773     public void testIsUidInForegroundForForegroundState() {
774         procStateBuilder(UID)
775                 .topState()
776                 .update();
777         assertTrue(mIntf.isUidInForeground(UID));
778 
779         procStateBuilder(UID)
780                 .foregroundServiceState()
781                 .update();
782         assertTrue(mIntf.isUidInForeground(UID));
783     }
784 
785     @Test
testAppWidgetVisibleDoesntChangeUidState()786     public void testAppWidgetVisibleDoesntChangeUidState() {
787         procStateBuilder(UID)
788                 .topState()
789                 .update();
790 
791         SparseArray<String> updatedAppWidgetVisibilities = new SparseArray<>();
792         updatedAppWidgetVisibilities.put(UID, "");
793 
794         mIntf.updateAppWidgetVisibility(updatedAppWidgetVisibilities, true);
795 
796         assertEquals(UID_STATE_TOP, mIntf.getUidState(UID));
797     }
798 
799     @Test
testAppWidgetNotVisibleDoesntChangeUidState()800     public void testAppWidgetNotVisibleDoesntChangeUidState() {
801         SparseArray<String> updatedAppWidgetVisibilities = new SparseArray<>();
802         updatedAppWidgetVisibilities.put(UID, "");
803         mIntf.updateAppWidgetVisibility(updatedAppWidgetVisibilities, true);
804         procStateBuilder(UID)
805                 .topState()
806                 .update();
807 
808         mIntf.updateAppWidgetVisibility(updatedAppWidgetVisibilities, false);
809 
810         assertEquals(UID_STATE_TOP, mIntf.getUidState(UID));
811     }
812 
testUidStateChangedCallback(int initialState, int finalState)813     public void testUidStateChangedCallback(int initialState, int finalState) {
814         int initialUidState = processStateToUidState(initialState);
815         int finalUidState = processStateToUidState(finalState);
816         boolean foregroundChange = initialUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
817                         != finalUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED;
818         boolean finalUidStateIsBackgroundAndLessImportant =
819                 finalUidState > UID_STATE_MAX_LAST_NON_RESTRICTED
820                         && finalUidState > initialUidState;
821 
822         UidStateChangedCallback cb = addUidStateChangeCallback();
823 
824         procStateBuilder(UID)
825                 .setState(initialState)
826                 .update();
827 
828         procStateBuilder(UID)
829                 .setState(finalState)
830                 .update();
831 
832         if (finalUidStateIsBackgroundAndLessImportant) {
833             mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME + 1);
834         }
835 
836         verify(cb, atLeastOnce())
837                 .onUidStateChanged(eq(UID), eq(finalUidState), eq(foregroundChange));
838     }
839 
addUidStateChangeCallback()840     private UidStateChangedCallback addUidStateChangeCallback() {
841         UidStateChangedCallback cb =
842                 Mockito.mock(UidStateChangedCallback.class);
843         mIntf.addUidStateChangedCallback(r -> r.run(), cb);
844         return cb;
845     }
846 
847     /* If testForegroundNotCapabilitiesTracked fails, this assertion is probably incorrect */
assertForeground(int uid)848     private void assertForeground(int uid) {
849         assertEquals(MODE_ALLOWED, mIntf.evalMode(uid, OP_NO_CAPABILITIES, MODE_FOREGROUND));
850     }
851 
852     /* If testBackgroundNotCapabilitiesTracked fails, this assertion is probably incorrect */
assertBackground(int uid)853     private void assertBackground(int uid) {
854         assertEquals(MODE_IGNORED, mIntf.evalMode(uid, OP_NO_CAPABILITIES, MODE_FOREGROUND));
855     }
856 
procStateBuilder(int uid)857     private UidProcStateUpdateBuilder procStateBuilder(int uid) {
858         return new UidProcStateUpdateBuilder(mIntf, uid);
859     }
860 
861     private static class UidProcStateUpdateBuilder {
862         private AppOpsUidStateTracker mIntf;
863         private int mUid;
864         private int mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
865         private int mCapability = ActivityManager.PROCESS_CAPABILITY_NONE;
866 
UidProcStateUpdateBuilder(AppOpsUidStateTracker intf, int uid)867         private UidProcStateUpdateBuilder(AppOpsUidStateTracker intf, int uid) {
868             mUid = uid;
869             mIntf = intf;
870         }
871 
update()872         public void update() {
873             mIntf.updateUidProcState(mUid, mProcState, mCapability);
874         }
875 
persistentState()876         public UidProcStateUpdateBuilder persistentState() {
877             mProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
878             return this;
879         }
880 
setState(int procState)881         public UidProcStateUpdateBuilder setState(int procState) {
882             mProcState = procState;
883             return this;
884         }
885 
topState()886         public UidProcStateUpdateBuilder topState() {
887             mProcState = ActivityManager.PROCESS_STATE_TOP;
888             return this;
889         }
890 
foregroundServiceState()891         public UidProcStateUpdateBuilder foregroundServiceState() {
892             mProcState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
893             return this;
894         }
895 
foregroundState()896         public UidProcStateUpdateBuilder foregroundState() {
897             mProcState = ActivityManager.PROCESS_STATE_BOUND_TOP;
898             return this;
899         }
900 
backgroundState()901         public UidProcStateUpdateBuilder backgroundState() {
902             mProcState = ActivityManager.PROCESS_STATE_SERVICE;
903             return this;
904         }
905 
cachedState()906         public UidProcStateUpdateBuilder cachedState() {
907             mProcState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
908             return this;
909         }
910 
nonExistentState()911         public UidProcStateUpdateBuilder nonExistentState() {
912             mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
913             return this;
914         }
915 
locationCapability()916         public UidProcStateUpdateBuilder locationCapability() {
917             mCapability |= ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
918             return this;
919         }
920 
cameraCapability()921         public UidProcStateUpdateBuilder cameraCapability() {
922             mCapability |= ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
923             return this;
924         }
925 
microphoneCapability()926         public UidProcStateUpdateBuilder microphoneCapability() {
927             mCapability |= ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
928             return this;
929         }
930     }
931 
932     private static class AppOpsUidStateTrackerTestClock extends Clock {
933 
934         private AppOpsUidStateTrackerTestExecutor mExecutor;
935         long mElapsedRealTime = 0x5f3759df;
936 
AppOpsUidStateTrackerTestClock(AppOpsUidStateTrackerTestExecutor executor)937         AppOpsUidStateTrackerTestClock(AppOpsUidStateTrackerTestExecutor executor) {
938             mExecutor = executor;
939             executor.setUptime(mElapsedRealTime);
940         }
941 
942         @Override
elapsedRealtime()943         public long elapsedRealtime() {
944             return mElapsedRealTime;
945         }
946 
advanceTime(long time)947         void advanceTime(long time) {
948             mElapsedRealTime += time;
949             mExecutor.setUptime(mElapsedRealTime); // assume uptime == elapsedtime
950         }
951     }
952 
953     private static class AppOpsUidStateTrackerTestExecutor implements DelayableExecutor {
954 
955         private static class QueueElement implements Comparable<QueueElement> {
956 
957             private long mExecutionTime;
958             private Runnable mRunnable;
959 
QueueElement(long executionTime, Runnable runnable)960             private QueueElement(long executionTime, Runnable runnable) {
961                 mExecutionTime = executionTime;
962                 mRunnable = runnable;
963             }
964 
965             @Override
compareTo(QueueElement queueElement)966             public int compareTo(QueueElement queueElement) {
967                 return Long.compare(mExecutionTime, queueElement.mExecutionTime);
968             }
969         }
970 
971         private long mUptime = 0;
972 
973         private PriorityQueue<QueueElement> mDelayedMessages = new PriorityQueue();
974 
975         @Override
execute(Runnable runnable)976         public void execute(Runnable runnable) {
977             runnable.run();
978         }
979 
980         @Override
executeDelayed(Runnable runnable, long delay)981         public void executeDelayed(Runnable runnable, long delay) {
982             if (delay <= 0) {
983                 execute(runnable);
984             }
985 
986             mDelayedMessages.add(new QueueElement(mUptime + delay, runnable));
987         }
988 
setUptime(long uptime)989         private void setUptime(long uptime) {
990             while (!mDelayedMessages.isEmpty()
991                     && mDelayedMessages.peek().mExecutionTime <= uptime) {
992                 mDelayedMessages.poll().mRunnable.run();
993             }
994 
995             mUptime = uptime;
996         }
997     }
998 }
999