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