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.pm;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.ArgumentMatchers.anyInt;
27 import static org.mockito.ArgumentMatchers.anyString;
28 import static org.mockito.ArgumentMatchers.eq;
29 import static org.mockito.Mockito.doReturn;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
33 
34 import android.app.usage.UsageEvents;
35 import android.app.usage.UsageEvents.Event;
36 import android.app.usage.UsageStatsManagerInternal;
37 import android.app.usage.UsageStatsManagerInternal.UsageEventListener;
38 import android.content.Context;
39 import android.content.pm.ApplicationInfo;
40 import android.content.pm.InstallSourceInfo;
41 import android.content.pm.PackageInfo;
42 import android.content.pm.PackageManager;
43 import android.content.pm.PackageManagerInternal;
44 import android.os.FileUtils;
45 import android.os.Looper;
46 import android.os.RemoteException;
47 import android.os.SystemClock;
48 import android.os.UserHandle;
49 import android.os.test.TestLooper;
50 import android.platform.test.annotations.Presubmit;
51 import android.util.AtomicFile;
52 import android.util.SparseSetArray;
53 import android.util.proto.ProtoInputStream;
54 import android.util.proto.ProtoOutputStream;
55 
56 import androidx.test.platform.app.InstrumentationRegistry;
57 
58 import com.android.server.pm.permission.PermissionManagerServiceInternal;
59 
60 import org.junit.After;
61 import org.junit.Before;
62 import org.junit.Test;
63 import org.mockito.ArgumentCaptor;
64 import org.mockito.Captor;
65 import org.mockito.Mock;
66 import org.mockito.MockitoAnnotations;
67 import org.mockito.internal.util.reflection.FieldSetter;
68 
69 import java.io.File;
70 import java.io.FileInputStream;
71 import java.io.FileOutputStream;
72 import java.io.IOException;
73 import java.util.ArrayList;
74 import java.util.List;
75 
76 /**
77  * Tests for {@link com.android.server.pm.BackgroundInstallControlService}
78  */
79 @Presubmit
80 public final class BackgroundInstallControlServiceTest {
81     private static final String INSTALLER_NAME_1 = "installer1";
82     private static final String INSTALLER_NAME_2 = "installer2";
83     private static final String PACKAGE_NAME_1 = "package1";
84     private static final String PACKAGE_NAME_2 = "package2";
85     private static final String PACKAGE_NAME_3 = "package3";
86     private static final int USER_ID_1 = 1;
87     private static final int USER_ID_2 = 2;
88     private static final long USAGE_EVENT_TIMESTAMP_1 = 1000;
89     private static final long USAGE_EVENT_TIMESTAMP_2 = 2000;
90     private static final long USAGE_EVENT_TIMESTAMP_3 = 3000;
91     private static final long PACKAGE_ADD_TIMESTAMP_1 = 1500;
92 
93     private BackgroundInstallControlService mBackgroundInstallControlService;
94     private PackageManagerInternal.PackageListObserver mPackageListObserver;
95     private UsageEventListener mUsageEventListener;
96     private TestLooper mTestLooper;
97     private Looper mLooper;
98     private File mFile;
99 
100 
101     @Mock
102     private Context mContext;
103     @Mock
104     private PackageManager mPackageManager;
105     @Mock
106     private PackageManagerInternal mPackageManagerInternal;
107     @Mock
108     private UsageStatsManagerInternal mUsageStatsManagerInternal;
109     @Mock
110     private PermissionManagerServiceInternal mPermissionManager;
111     @Captor
112     private ArgumentCaptor<PackageManagerInternal.PackageListObserver> mPackageListObserverCaptor;
113     @Captor
114     private ArgumentCaptor<UsageEventListener> mUsageEventListenerCaptor;
115 
116     @Before
setUp()117     public void setUp() {
118         MockitoAnnotations.initMocks(this);
119 
120         mTestLooper = new TestLooper();
121         mLooper = mTestLooper.getLooper();
122         mFile = new File(
123                 InstrumentationRegistry.getInstrumentation().getContext().getCacheDir(),
124                 "test");
125         mBackgroundInstallControlService = new BackgroundInstallControlService(
126                 new MockInjector(mContext));
127 
128         verify(mUsageStatsManagerInternal).registerListener(mUsageEventListenerCaptor.capture());
129         mUsageEventListener = mUsageEventListenerCaptor.getValue();
130 
131         mBackgroundInstallControlService.onStart(true);
132         verify(mPackageManagerInternal).getPackageList(mPackageListObserverCaptor.capture());
133         mPackageListObserver = mPackageListObserverCaptor.getValue();
134     }
135 
136     @After
tearDown()137     public void tearDown() {
138         FileUtils.deleteContentsAndDir(mFile);
139     }
140 
141     @Test
testInitBackgroundInstalledPackages_empty()142     public void testInitBackgroundInstalledPackages_empty() {
143         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
144         mBackgroundInstallControlService.initBackgroundInstalledPackages();
145         assertNotNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
146         assertEquals(0,
147                 mBackgroundInstallControlService.getBackgroundInstalledPackages().size());
148     }
149 
150     @Test
testInitBackgroundInstalledPackages_one()151     public void testInitBackgroundInstalledPackages_one() {
152         AtomicFile atomicFile = new AtomicFile(mFile);
153         FileOutputStream fileOutputStream;
154         try {
155             fileOutputStream = atomicFile.startWrite();
156         } catch (IOException e) {
157             fail("Failed to start write to states protobuf." + e);
158             return;
159         }
160 
161         // Write test data to the file on the disk.
162         try {
163             ProtoOutputStream protoOutputStream = new ProtoOutputStream(fileOutputStream);
164             long token = protoOutputStream.start(
165                     BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
166             protoOutputStream.write(
167                     BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_1);
168             protoOutputStream.write(
169                     BackgroundInstalledPackageProto.USER_ID, USER_ID_1 + 1);
170             protoOutputStream.end(token);
171             protoOutputStream.flush();
172             atomicFile.finishWrite(fileOutputStream);
173         } catch (Exception e) {
174             fail("Failed to finish write to states protobuf. " + e);
175             atomicFile.failWrite(fileOutputStream);
176         }
177 
178         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
179         mBackgroundInstallControlService.initBackgroundInstalledPackages();
180         var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
181         assertNotNull(packages);
182         assertEquals(1, packages.size());
183         assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1));
184     }
185 
186     @Test
testInitBackgroundInstalledPackages_two()187     public void testInitBackgroundInstalledPackages_two() {
188         AtomicFile atomicFile = new AtomicFile(mFile);
189         FileOutputStream fileOutputStream;
190         try {
191             fileOutputStream = atomicFile.startWrite();
192         } catch (IOException e) {
193             fail("Failed to start write to states protobuf." + e);
194             return;
195         }
196 
197         // Write test data to the file on the disk.
198         try {
199             ProtoOutputStream protoOutputStream = new ProtoOutputStream(fileOutputStream);
200 
201             long token = protoOutputStream.start(
202                     BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
203             protoOutputStream.write(
204                     BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_1);
205             protoOutputStream.write(
206                     BackgroundInstalledPackageProto.USER_ID, USER_ID_1 + 1);
207             protoOutputStream.end(token);
208 
209             token = protoOutputStream.start(
210                     BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
211             protoOutputStream.write(
212                     BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_2);
213             protoOutputStream.write(
214                     BackgroundInstalledPackageProto.USER_ID, USER_ID_2 + 1);
215             protoOutputStream.end(token);
216 
217             protoOutputStream.flush();
218             atomicFile.finishWrite(fileOutputStream);
219         } catch (Exception e) {
220             fail("Failed to finish write to states protobuf. " + e);
221             atomicFile.failWrite(fileOutputStream);
222         }
223 
224         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
225         mBackgroundInstallControlService.initBackgroundInstalledPackages();
226         var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
227         assertNotNull(packages);
228         assertEquals(2, packages.size());
229         assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1));
230         assertTrue(packages.contains(USER_ID_2, PACKAGE_NAME_2));
231     }
232 
233     @Test
testWriteBackgroundInstalledPackagesToDisk_empty()234     public void testWriteBackgroundInstalledPackagesToDisk_empty() {
235         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
236         mBackgroundInstallControlService.initBackgroundInstalledPackages();
237         var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
238         assertNotNull(packages);
239         mBackgroundInstallControlService.writeBackgroundInstalledPackagesToDisk();
240 
241         // Read the file on the disk to verify
242         var packagesInDisk = new SparseSetArray<>();
243         AtomicFile atomicFile = new AtomicFile(mFile);
244         try (FileInputStream fileInputStream  = atomicFile.openRead()) {
245             ProtoInputStream protoInputStream = new ProtoInputStream(fileInputStream);
246 
247             while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
248                 if (protoInputStream.getFieldNumber()
249                         != (int) BackgroundInstalledPackagesProto.BG_INSTALLED_PKG) {
250                     continue;
251                 }
252                 long token = protoInputStream.start(
253                         BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
254                 String packageName = null;
255                 int userId = UserHandle.USER_NULL;
256                 while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
257                     switch (protoInputStream.getFieldNumber()) {
258                         case (int) BackgroundInstalledPackageProto.PACKAGE_NAME:
259                             packageName = protoInputStream.readString(
260                                     BackgroundInstalledPackageProto.PACKAGE_NAME);
261                             break;
262                         case (int) BackgroundInstalledPackageProto.USER_ID:
263                             userId = protoInputStream.readInt(
264                                     BackgroundInstalledPackageProto.USER_ID) - 1;
265                             break;
266                         default:
267                             fail("Undefined field in proto: "
268                                     + protoInputStream.getFieldNumber());
269                     }
270                 }
271                 protoInputStream.end(token);
272                 if (packageName != null && userId != UserHandle.USER_NULL) {
273                     packagesInDisk.add(userId, packageName);
274                 } else {
275                     fail("Fails to get packageName or UserId from proto file");
276                 }
277             }
278         } catch (IOException e) {
279             fail("Error reading state from the disk. " + e);
280         }
281 
282         assertEquals(0, packagesInDisk.size());
283         assertEquals(packages.size(), packagesInDisk.size());
284     }
285 
286     @Test
testWriteBackgroundInstalledPackagesToDisk_one()287     public void testWriteBackgroundInstalledPackagesToDisk_one() {
288         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
289         mBackgroundInstallControlService.initBackgroundInstalledPackages();
290         var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
291         assertNotNull(packages);
292 
293         packages.add(USER_ID_1, PACKAGE_NAME_1);
294         mBackgroundInstallControlService.writeBackgroundInstalledPackagesToDisk();
295 
296         // Read the file on the disk to verify
297         var packagesInDisk = new SparseSetArray<>();
298         AtomicFile atomicFile = new AtomicFile(mFile);
299         try (FileInputStream fileInputStream  = atomicFile.openRead()) {
300             ProtoInputStream protoInputStream = new ProtoInputStream(fileInputStream);
301 
302             while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
303                 if (protoInputStream.getFieldNumber()
304                         != (int) BackgroundInstalledPackagesProto.BG_INSTALLED_PKG) {
305                     continue;
306                 }
307                 long token = protoInputStream.start(
308                         BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
309                 String packageName = null;
310                 int userId = UserHandle.USER_NULL;
311                 while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
312                     switch (protoInputStream.getFieldNumber()) {
313                         case (int) BackgroundInstalledPackageProto.PACKAGE_NAME:
314                             packageName = protoInputStream.readString(
315                                     BackgroundInstalledPackageProto.PACKAGE_NAME);
316                             break;
317                         case (int) BackgroundInstalledPackageProto.USER_ID:
318                             userId = protoInputStream.readInt(
319                                     BackgroundInstalledPackageProto.USER_ID) - 1;
320                             break;
321                         default:
322                             fail("Undefined field in proto: "
323                                     + protoInputStream.getFieldNumber());
324                     }
325                 }
326                 protoInputStream.end(token);
327                 if (packageName != null && userId != UserHandle.USER_NULL) {
328                     packagesInDisk.add(userId, packageName);
329                 } else {
330                     fail("Fails to get packageName or UserId from proto file");
331                 }
332             }
333         } catch (IOException e) {
334             fail("Error reading state from the disk. " + e);
335         }
336 
337         assertEquals(1, packagesInDisk.size());
338         assertEquals(packages.size(), packagesInDisk.size());
339         assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1));
340     }
341 
342     @Test
testWriteBackgroundInstalledPackagesToDisk_two()343     public void testWriteBackgroundInstalledPackagesToDisk_two() {
344         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
345         mBackgroundInstallControlService.initBackgroundInstalledPackages();
346         var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
347         assertNotNull(packages);
348 
349         packages.add(USER_ID_1, PACKAGE_NAME_1);
350         packages.add(USER_ID_2, PACKAGE_NAME_2);
351         mBackgroundInstallControlService.writeBackgroundInstalledPackagesToDisk();
352 
353         // Read the file on the disk to verify
354         var packagesInDisk = new SparseSetArray<>();
355         AtomicFile atomicFile = new AtomicFile(mFile);
356         try (FileInputStream fileInputStream  = atomicFile.openRead()) {
357             ProtoInputStream protoInputStream = new ProtoInputStream(fileInputStream);
358 
359             while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
360                 if (protoInputStream.getFieldNumber()
361                         != (int) BackgroundInstalledPackagesProto.BG_INSTALLED_PKG) {
362                     continue;
363                 }
364                 long token = protoInputStream.start(
365                         BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
366                 String packageName = null;
367                 int userId = UserHandle.USER_NULL;
368                 while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
369                     switch (protoInputStream.getFieldNumber()) {
370                         case (int) BackgroundInstalledPackageProto.PACKAGE_NAME:
371                             packageName = protoInputStream.readString(
372                                     BackgroundInstalledPackageProto.PACKAGE_NAME);
373                             break;
374                         case (int) BackgroundInstalledPackageProto.USER_ID:
375                             userId = protoInputStream.readInt(
376                                     BackgroundInstalledPackageProto.USER_ID) - 1;
377                             break;
378                         default:
379                             fail("Undefined field in proto: "
380                                     + protoInputStream.getFieldNumber());
381                     }
382                 }
383                 protoInputStream.end(token);
384                 if (packageName != null && userId != UserHandle.USER_NULL) {
385                     packagesInDisk.add(userId, packageName);
386                 } else {
387                     fail("Fails to get packageName or UserId from proto file");
388                 }
389             }
390         } catch (IOException e) {
391             fail("Error reading state from the disk. " + e);
392         }
393 
394         assertEquals(2, packagesInDisk.size());
395         assertEquals(packages.size(), packagesInDisk.size());
396         assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1));
397         assertTrue(packages.contains(USER_ID_2, PACKAGE_NAME_2));
398     }
399 
400     @Test
testHandleUsageEvent_permissionDenied()401     public void testHandleUsageEvent_permissionDenied() {
402         assertEquals(0,
403                 mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
404         doReturn(PackageManager.PERMISSION_DENIED).when(mPermissionManager).checkPermission(
405                 anyString(), anyString(), anyInt());
406         generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
407                 USER_ID_1, INSTALLER_NAME_1, 0);
408         mTestLooper.dispatchAll();
409         assertEquals(0,
410                 mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
411     }
412 
413     @Test
testHandleUsageEvent_permissionGranted()414     public void testHandleUsageEvent_permissionGranted() {
415         assertEquals(0,
416                 mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
417         doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
418                 anyString(), anyString(), anyInt());
419         generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
420                 USER_ID_1, INSTALLER_NAME_1, 0);
421         mTestLooper.dispatchAll();
422         assertEquals(1,
423                 mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
424     }
425 
426     @Test
testHandleUsageEvent_ignoredEvent()427     public void testHandleUsageEvent_ignoredEvent() {
428         assertEquals(0,
429                 mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
430         doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
431                 anyString(), anyString(), anyInt());
432         generateUsageEvent(UsageEvents.Event.USER_INTERACTION,
433                 USER_ID_1, INSTALLER_NAME_1, 0);
434         mTestLooper.dispatchAll();
435         assertEquals(0,
436                 mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
437     }
438 
439     @Test
testHandleUsageEvent_firstActivityResumedHalfTimeFrame()440     public void testHandleUsageEvent_firstActivityResumedHalfTimeFrame() {
441         assertEquals(0,
442                 mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
443         doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
444                 anyString(), anyString(), anyInt());
445         generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
446                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
447         mTestLooper.dispatchAll();
448 
449         var installerForegroundTimeFrames =
450                 mBackgroundInstallControlService.getInstallerForegroundTimeFrames();
451         assertEquals(1, installerForegroundTimeFrames.numMaps());
452         assertEquals(1, installerForegroundTimeFrames.numElementsForKey(USER_ID_1));
453 
454         var foregroundTimeFrames = installerForegroundTimeFrames.get(USER_ID_1, INSTALLER_NAME_1);
455         assertEquals(1, foregroundTimeFrames.size());
456 
457         var foregroundTimeFrame = foregroundTimeFrames.first();
458         assertEquals(USAGE_EVENT_TIMESTAMP_1, foregroundTimeFrame.startTimeStampMillis);
459         assertFalse(foregroundTimeFrame.isDone());
460     }
461 
462     @Test
testHandleUsageEvent_firstActivityResumedOneTimeFrame()463     public void testHandleUsageEvent_firstActivityResumedOneTimeFrame() {
464         assertEquals(0,
465                 mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
466         doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
467                 anyString(), anyString(), anyInt());
468         generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
469                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
470         generateUsageEvent(Event.ACTIVITY_STOPPED,
471                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
472         mTestLooper.dispatchAll();
473 
474         var installerForegroundTimeFrames =
475                 mBackgroundInstallControlService.getInstallerForegroundTimeFrames();
476         assertEquals(1, installerForegroundTimeFrames.numMaps());
477         assertEquals(1, installerForegroundTimeFrames.numElementsForKey(USER_ID_1));
478 
479         var foregroundTimeFrames = installerForegroundTimeFrames.get(USER_ID_1, INSTALLER_NAME_1);
480         assertEquals(1, foregroundTimeFrames.size());
481 
482         var foregroundTimeFrame = foregroundTimeFrames.first();
483         assertEquals(USAGE_EVENT_TIMESTAMP_1, foregroundTimeFrame.startTimeStampMillis);
484         assertTrue(foregroundTimeFrame.isDone());
485     }
486 
487     @Test
testHandleUsageEvent_firstActivityResumedOneAndHalfTimeFrame()488     public void testHandleUsageEvent_firstActivityResumedOneAndHalfTimeFrame() {
489         assertEquals(0,
490                 mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
491         doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
492                 anyString(), anyString(), anyInt());
493         generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
494                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
495         generateUsageEvent(Event.ACTIVITY_STOPPED,
496                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
497         generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
498                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
499         mTestLooper.dispatchAll();
500 
501         var installerForegroundTimeFrames =
502                 mBackgroundInstallControlService.getInstallerForegroundTimeFrames();
503         assertEquals(1, installerForegroundTimeFrames.numMaps());
504         assertEquals(1, installerForegroundTimeFrames.numElementsForKey(USER_ID_1));
505 
506         var foregroundTimeFrames = installerForegroundTimeFrames.get(USER_ID_1, INSTALLER_NAME_1);
507         assertEquals(2, foregroundTimeFrames.size());
508 
509         var foregroundTimeFrame1 = foregroundTimeFrames.first();
510         assertEquals(USAGE_EVENT_TIMESTAMP_1, foregroundTimeFrame1.startTimeStampMillis);
511         assertTrue(foregroundTimeFrame1.isDone());
512 
513         var foregroundTimeFrame2 = foregroundTimeFrames.last();
514         assertEquals(USAGE_EVENT_TIMESTAMP_3, foregroundTimeFrame2.startTimeStampMillis);
515         assertFalse(foregroundTimeFrame2.isDone());
516     }
517 
518     @Test
testHandleUsageEvent_firstNoneActivityResumed()519     public void testHandleUsageEvent_firstNoneActivityResumed() {
520         assertEquals(0,
521                 mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
522         doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
523                 anyString(), anyString(), anyInt());
524         generateUsageEvent(Event.ACTIVITY_STOPPED,
525                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
526         mTestLooper.dispatchAll();
527 
528         var installerForegroundTimeFrames =
529                 mBackgroundInstallControlService.getInstallerForegroundTimeFrames();
530         assertEquals(1, installerForegroundTimeFrames.numMaps());
531         assertEquals(1, installerForegroundTimeFrames.numElementsForKey(USER_ID_1));
532 
533         var foregroundTimeFrames = installerForegroundTimeFrames.get(USER_ID_1, INSTALLER_NAME_1);
534         assertEquals(0, foregroundTimeFrames.size());
535     }
536 
537     @Test
testHandleUsageEvent_packageAddedNoUsageEvent()538     public void testHandleUsageEvent_packageAddedNoUsageEvent() throws
539             NoSuchFieldException, PackageManager.NameNotFoundException {
540         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
541         InstallSourceInfo installSourceInfo = new InstallSourceInfo(
542                 /* initiatingPackageName = */ INSTALLER_NAME_1,
543                 /* initiatingPackageSigningInfo = */ null,
544                 /* originatingPackageName = */ null,
545                 /* installingPackageName = */ INSTALLER_NAME_1);
546         assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
547         when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
548         ApplicationInfo appInfo = mock(ApplicationInfo.class);
549 
550         when(mPackageManager.getApplicationInfoAsUser(
551                 eq(PACKAGE_NAME_1),
552                 any(),
553                 anyInt())
554         ).thenReturn(appInfo);
555 
556         long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
557                 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
558         FieldSetter.setField(appInfo,
559                 ApplicationInfo.class.getDeclaredField("createTimestamp"),
560                 createTimestamp);
561 
562         int uid = USER_ID_1 * UserHandle.PER_USER_RANGE;
563         assertEquals(USER_ID_1, UserHandle.getUserId(uid));
564 
565         mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
566         mTestLooper.dispatchAll();
567 
568         var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
569         assertNotNull(packages);
570         assertEquals(1, packages.size());
571         assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1));
572     }
573 
574     @Test
testHandleUsageEvent_packageAddedInsideTimeFrame()575     public void testHandleUsageEvent_packageAddedInsideTimeFrame() throws
576             NoSuchFieldException, PackageManager.NameNotFoundException {
577         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
578         InstallSourceInfo installSourceInfo = new InstallSourceInfo(
579                 /* initiatingPackageName = */ INSTALLER_NAME_1,
580                 /* initiatingPackageSigningInfo = */ null,
581                 /* originatingPackageName = */ null,
582                 /* installingPackageName = */ INSTALLER_NAME_1);
583         assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
584         when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
585         ApplicationInfo appInfo = mock(ApplicationInfo.class);
586 
587         when(mPackageManager.getApplicationInfoAsUser(
588                 eq(PACKAGE_NAME_1),
589                 any(),
590                 anyInt())
591         ).thenReturn(appInfo);
592 
593         long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
594                 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
595         FieldSetter.setField(appInfo,
596                 ApplicationInfo.class.getDeclaredField("createTimestamp"),
597                 createTimestamp);
598 
599         int uid = USER_ID_1 * UserHandle.PER_USER_RANGE;
600         assertEquals(USER_ID_1, UserHandle.getUserId(uid));
601 
602         // The following 2 usage events generation is the only difference from the
603         // testHandleUsageEvent_packageAddedNoUsageEvent test.
604         // The 2 usage events make the package adding inside a time frame.
605         // So it's not a background install. Thus, it's null for the return of
606         // mBackgroundInstallControlService.getBackgroundInstalledPackages()
607         doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
608                 anyString(), anyString(), anyInt());
609         generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
610                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
611         generateUsageEvent(Event.ACTIVITY_STOPPED,
612                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
613 
614         mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
615         mTestLooper.dispatchAll();
616         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
617     }
618 
619     @Test
testHandleUsageEvent_packageAddedOutsideTimeFrame1()620     public void testHandleUsageEvent_packageAddedOutsideTimeFrame1() throws
621             NoSuchFieldException, PackageManager.NameNotFoundException {
622         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
623         InstallSourceInfo installSourceInfo = new InstallSourceInfo(
624                 /* initiatingPackageName = */ INSTALLER_NAME_1,
625                 /* initiatingPackageSigningInfo = */ null,
626                 /* originatingPackageName = */ null,
627                 /* installingPackageName = */ INSTALLER_NAME_1);
628         assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
629         when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
630         ApplicationInfo appInfo = mock(ApplicationInfo.class);
631 
632         when(mPackageManager.getApplicationInfoAsUser(
633                 eq(PACKAGE_NAME_1),
634                 any(),
635                 anyInt())
636         ).thenReturn(appInfo);
637 
638         long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
639                 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
640         FieldSetter.setField(appInfo,
641                 ApplicationInfo.class.getDeclaredField("createTimestamp"),
642                 createTimestamp);
643 
644         int uid = USER_ID_1 * UserHandle.PER_USER_RANGE;
645         assertEquals(USER_ID_1, UserHandle.getUserId(uid));
646 
647         // The following 2 usage events generation is the only difference from the
648         // testHandleUsageEvent_packageAddedNoUsageEvent test.
649         // The 2 usage events make the package adding outside a time frame.
650         // Compared to testHandleUsageEvent_packageAddedInsideTimeFrame,
651         // it's a background install. Thus, it's not null for the return of
652         // mBackgroundInstallControlService.getBackgroundInstalledPackages()
653         doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
654                 anyString(), anyString(), anyInt());
655         generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
656                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
657         generateUsageEvent(Event.ACTIVITY_STOPPED,
658                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
659 
660         mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
661         mTestLooper.dispatchAll();
662 
663         var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
664         assertNotNull(packages);
665         assertEquals(1, packages.size());
666         assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1));
667     }
668     @Test
testHandleUsageEvent_packageAddedOutsideTimeFrame2()669     public void testHandleUsageEvent_packageAddedOutsideTimeFrame2() throws
670             NoSuchFieldException, PackageManager.NameNotFoundException {
671         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
672         InstallSourceInfo installSourceInfo = new InstallSourceInfo(
673                 /* initiatingPackageName = */ INSTALLER_NAME_1,
674                 /* initiatingPackageSigningInfo = */ null,
675                 /* originatingPackageName = */ null,
676                 /* installingPackageName = */ INSTALLER_NAME_1);
677         assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
678         when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
679         ApplicationInfo appInfo = mock(ApplicationInfo.class);
680 
681         when(mPackageManager.getApplicationInfoAsUser(
682                 eq(PACKAGE_NAME_1),
683                 any(),
684                 anyInt())
685         ).thenReturn(appInfo);
686 
687         long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
688                 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
689         FieldSetter.setField(appInfo,
690                 ApplicationInfo.class.getDeclaredField("createTimestamp"),
691                 createTimestamp);
692 
693         int uid = USER_ID_1 * UserHandle.PER_USER_RANGE;
694         assertEquals(USER_ID_1, UserHandle.getUserId(uid));
695 
696         // The following 2 usage events generation is the only difference from the
697         // testHandleUsageEvent_packageAddedNoUsageEvent test.
698         // These 2 usage events are triggered by INSTALLER_NAME_2.
699         // The 2 usage events make the package adding outside a time frame.
700         // Compared to testHandleUsageEvent_packageAddedInsideTimeFrame,
701         // it's a background install. Thus, it's not null for the return of
702         // mBackgroundInstallControlService.getBackgroundInstalledPackages()
703         doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
704                 anyString(), anyString(), anyInt());
705         generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
706                 USER_ID_2, INSTALLER_NAME_2, USAGE_EVENT_TIMESTAMP_2);
707         generateUsageEvent(Event.ACTIVITY_STOPPED,
708                 USER_ID_2, INSTALLER_NAME_2, USAGE_EVENT_TIMESTAMP_3);
709 
710         mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
711         mTestLooper.dispatchAll();
712 
713         var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
714         assertNotNull(packages);
715         assertEquals(1, packages.size());
716         assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1));
717     }
718     @Test
testHandleUsageEvent_packageAddedThroughAdb()719     public void testHandleUsageEvent_packageAddedThroughAdb() throws
720             NoSuchFieldException, PackageManager.NameNotFoundException {
721         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
722         // This test is a duplicate of testHandleUsageEvent_packageAddedThroughAdb except the
723         // initiatingPackageName used to be null but is now "com.android.shell". This test ensures
724         // that the behavior is still the same for when the initiatingPackageName is null.
725         InstallSourceInfo installSourceInfo = new InstallSourceInfo(
726                 /* initiatingPackageName = */ null,
727                 /* initiatingPackageSigningInfo = */ null,
728                 /* originatingPackageName = */ null,
729                 /* installingPackageName = */ INSTALLER_NAME_1);
730         // b/265203007
731         when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
732         ApplicationInfo appInfo = mock(ApplicationInfo.class);
733 
734         when(mPackageManager.getApplicationInfoAsUser(
735                 eq(PACKAGE_NAME_1),
736                 any(),
737                 anyInt())
738         ).thenReturn(appInfo);
739 
740         long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
741                 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
742         FieldSetter.setField(appInfo,
743                 ApplicationInfo.class.getDeclaredField("createTimestamp"),
744                 createTimestamp);
745 
746         int uid = USER_ID_1 * UserHandle.PER_USER_RANGE;
747         assertEquals(USER_ID_1, UserHandle.getUserId(uid));
748 
749         // The following usage events generation is the same as
750         // testHandleUsageEvent_packageAddedOutsideTimeFrame2 test. The only difference is that
751         // for ADB installs the initiatingPackageName used to be null, despite being detected
752         // as a background install. Since we do not want to treat side-loaded apps as background
753         // install getBackgroundInstalledPackages() is expected to return null
754         doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
755                 anyString(), anyString(), anyInt());
756         generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
757                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
758         generateUsageEvent(Event.ACTIVITY_STOPPED,
759                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
760 
761         mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
762         mTestLooper.dispatchAll();
763 
764         var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
765         assertNull(packages);
766     }
767     @Test
testHandleUsageEvent_packageAddedThroughAdb2()768     public void testHandleUsageEvent_packageAddedThroughAdb2() throws
769             NoSuchFieldException, PackageManager.NameNotFoundException {
770         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
771         // This test is a duplicate of testHandleUsageEvent_packageAddedThroughAdb except the
772         // initiatingPackageName used to be null but is now "com.android.shell". This test ensures
773         // that the behavior is still the same after this change.
774         InstallSourceInfo installSourceInfo = new InstallSourceInfo(
775                 /* initiatingPackageName = */ "com.android.shell",
776                 /* initiatingPackageSigningInfo = */ null,
777                 /* originatingPackageName = */ null,
778                 /* installingPackageName = */ INSTALLER_NAME_1);
779         // b/265203007
780         when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
781         ApplicationInfo appInfo = mock(ApplicationInfo.class);
782 
783         when(mPackageManager.getApplicationInfoAsUser(
784                 eq(PACKAGE_NAME_1),
785                 any(),
786                 anyInt())
787         ).thenReturn(appInfo);
788 
789         long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
790                 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
791         FieldSetter.setField(appInfo,
792                 ApplicationInfo.class.getDeclaredField("createTimestamp"),
793                 createTimestamp);
794 
795         int uid = USER_ID_1 * UserHandle.PER_USER_RANGE;
796         assertEquals(USER_ID_1, UserHandle.getUserId(uid));
797 
798         // The following  usage events generation is the same as
799         // testHandleUsageEvent_packageAddedOutsideTimeFrame2 test. The only difference is that
800         // for ADB installs the initiatingPackageName is com.android.shell, despite being detected
801         // as a background install. Since we do not want to treat side-loaded apps as background
802         // install getBackgroundInstalledPackages() is expected to return null
803         doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
804                 anyString(), anyString(), anyInt());
805         generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
806                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
807         generateUsageEvent(Event.ACTIVITY_STOPPED,
808                 USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
809 
810         mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
811         mTestLooper.dispatchAll();
812 
813         var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
814         assertNull(packages);
815     }
816     @Test
testPackageRemoved()817     public void testPackageRemoved() {
818         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
819         mBackgroundInstallControlService.initBackgroundInstalledPackages();
820         var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
821         assertNotNull(packages);
822 
823         packages.add(USER_ID_1, PACKAGE_NAME_1);
824         packages.add(USER_ID_2, PACKAGE_NAME_2);
825 
826         assertEquals(2, packages.size());
827         assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1));
828         assertTrue(packages.contains(USER_ID_2, PACKAGE_NAME_2));
829 
830         int uid = USER_ID_1 * UserHandle.PER_USER_RANGE;
831         assertEquals(USER_ID_1, UserHandle.getUserId(uid));
832 
833         mPackageListObserver.onPackageRemoved(PACKAGE_NAME_1, uid);
834         mTestLooper.dispatchAll();
835 
836         assertEquals(1, packages.size());
837         assertFalse(packages.contains(USER_ID_1, PACKAGE_NAME_1));
838         assertTrue(packages.contains(USER_ID_2, PACKAGE_NAME_2));
839     }
840 
841     @Test
testGetBackgroundInstalledPackages()842     public void testGetBackgroundInstalledPackages() throws RemoteException {
843         assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
844         mBackgroundInstallControlService.initBackgroundInstalledPackages();
845         var bgPackages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
846         assertNotNull(bgPackages);
847 
848         bgPackages.add(USER_ID_1, PACKAGE_NAME_1);
849         bgPackages.add(USER_ID_2, PACKAGE_NAME_2);
850 
851         assertEquals(2, bgPackages.size());
852         assertTrue(bgPackages.contains(USER_ID_1, PACKAGE_NAME_1));
853         assertTrue(bgPackages.contains(USER_ID_2, PACKAGE_NAME_2));
854 
855         List<PackageInfo> packages = new ArrayList<>();
856         var packageInfo1 = makePackageInfo(PACKAGE_NAME_1);
857         packages.add(packageInfo1);
858         var packageInfo2 = makePackageInfo(PACKAGE_NAME_2);
859         packages.add(packageInfo2);
860         var packageInfo3 = makePackageInfo(PACKAGE_NAME_3);
861         packages.add(packageInfo3);
862         doReturn(packages).when(mPackageManager).getInstalledPackagesAsUser(
863                 any(), anyInt());
864 
865         var resultPackages =
866                 mBackgroundInstallControlService.getBackgroundInstalledPackages(0L, USER_ID_1);
867         assertEquals(1, resultPackages.getList().size());
868         assertTrue(resultPackages.getList().contains(packageInfo1));
869         assertFalse(resultPackages.getList().contains(packageInfo2));
870         assertFalse(resultPackages.getList().contains(packageInfo3));
871     }
872 
873     /**
874      * Mock a usage event occurring.
875      *
876      * @param usageEventId id of a usage event
877      * @param userId user id of a usage event
878      * @param pkgName package name of a usage event
879      * @param timestamp timestamp of a usage event
880      */
generateUsageEvent(int usageEventId, int userId, String pkgName, long timestamp)881     private void generateUsageEvent(int usageEventId,
882             int userId,
883             String pkgName,
884             long timestamp) {
885         Event event = new Event(usageEventId, timestamp);
886         event.mPackage = pkgName;
887         mUsageEventListener.onUsageEvent(userId, event);
888     }
889 
makePackageInfo(String packageName)890     private PackageInfo makePackageInfo(String packageName) {
891         PackageInfo pkg = new PackageInfo();
892         pkg.packageName = packageName;
893         pkg.applicationInfo = new ApplicationInfo();
894         return pkg;
895     }
896 
897     private class MockInjector implements BackgroundInstallControlService.Injector {
898         private final Context mContext;
899 
MockInjector(Context context)900         MockInjector(Context context) {
901             mContext = context;
902         }
903 
904         @Override
getContext()905         public Context getContext() {
906             return mContext;
907         }
908 
909         @Override
getPackageManager()910         public PackageManager getPackageManager() {
911             return mPackageManager;
912         }
913 
914         @Override
getPackageManagerInternal()915         public PackageManagerInternal getPackageManagerInternal() {
916             return mPackageManagerInternal;
917         }
918 
919         @Override
getUsageStatsManagerInternal()920         public UsageStatsManagerInternal getUsageStatsManagerInternal() {
921             return mUsageStatsManagerInternal;
922         }
923 
924         @Override
getPermissionManager()925         public PermissionManagerServiceInternal getPermissionManager() {
926             return mPermissionManager;
927         }
928 
929         @Override
getLooper()930         public Looper getLooper() {
931             return mLooper;
932         }
933 
934         @Override
getDiskFile()935         public File getDiskFile() {
936             return mFile;
937         }
938     }
939 }
940