1 /* 2 * Copyright (C) 2020 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 package com.android.server.pm 17 18 import android.app.PropertyInvalidatedCache 19 import android.content.Context 20 import android.content.Intent 21 import android.content.pm.ActivityInfo 22 import android.content.pm.ApplicationInfo 23 import android.content.pm.FallbackCategoryProvider 24 import android.content.pm.FeatureInfo 25 import android.content.pm.ResolveInfo 26 import android.content.pm.ServiceInfo 27 import android.content.pm.Signature 28 import android.content.pm.SigningDetails 29 import android.content.pm.UserInfo 30 import android.content.pm.parsing.result.ParseTypeImpl 31 import android.content.res.Resources 32 import android.hardware.display.DisplayManager 33 import android.os.Build 34 import android.os.Environment 35 import android.os.SystemProperties 36 import android.os.UserHandle 37 import android.os.UserManager 38 import android.os.incremental.IncrementalManager 39 import android.provider.DeviceConfig 40 import android.util.ArrayMap 41 import android.util.ArraySet 42 import android.util.DisplayMetrics 43 import android.util.EventLog 44 import android.view.Display 45 import com.android.dx.mockito.inline.extended.ExtendedMockito 46 import com.android.dx.mockito.inline.extended.ExtendedMockito.any 47 import com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean 48 import com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt 49 import com.android.dx.mockito.inline.extended.ExtendedMockito.anyLong 50 import com.android.dx.mockito.inline.extended.ExtendedMockito.anyString 51 import com.android.dx.mockito.inline.extended.ExtendedMockito.argThat 52 import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn 53 import com.android.dx.mockito.inline.extended.ExtendedMockito.eq 54 import com.android.dx.mockito.inline.extended.ExtendedMockito.spy 55 import com.android.dx.mockito.inline.extended.StaticMockitoSession 56 import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder 57 import com.android.internal.R 58 import com.android.server.LocalManagerRegistry 59 import com.android.server.LocalServices 60 import com.android.server.LockGuard 61 import com.android.server.SystemConfig 62 import com.android.server.SystemServerInitThreadPool 63 import com.android.server.compat.PlatformCompat 64 import com.android.server.extendedtestutils.wheneverStatic 65 import com.android.server.pm.dex.DexManager 66 import com.android.server.pm.dex.DynamicCodeLogger 67 import com.android.server.pm.parsing.PackageParser2 68 import com.android.server.pm.parsing.pkg.PackageImpl 69 import com.android.server.pm.parsing.pkg.ParsedPackage 70 import com.android.server.pm.permission.PermissionManagerServiceInternal 71 import com.android.server.pm.pkg.AndroidPackage 72 import com.android.server.pm.pkg.parsing.ParsingPackage 73 import com.android.server.pm.pkg.parsing.ParsingPackageUtils 74 import com.android.server.pm.resolution.ComponentResolver 75 import com.android.server.pm.snapshot.PackageDataSnapshot 76 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal 77 import com.android.server.sdksandbox.SdkSandboxManagerLocal 78 import com.android.server.testutils.TestHandler 79 import com.android.server.testutils.mock 80 import com.android.server.testutils.nullable 81 import com.android.server.testutils.whenever 82 import com.android.server.utils.WatchedArrayMap 83 import libcore.util.HexEncoding 84 import org.junit.Assert 85 import org.junit.rules.TestRule 86 import org.junit.runner.Description 87 import org.junit.runners.model.Statement 88 import org.mockito.AdditionalMatchers.or 89 import org.mockito.Mockito 90 import org.mockito.quality.Strictness 91 import java.io.File 92 import java.io.IOException 93 import java.nio.file.Files 94 import java.security.PublicKey 95 import java.security.cert.CertificateException 96 import java.util.Arrays 97 import java.util.Random 98 import java.util.concurrent.FutureTask 99 100 /** 101 * A utility for mocking behavior of the system and dependencies when testing PackageManagerService 102 * 103 * Create one of these and call [stageNominalSystemState] as a basis for additional behavior in most 104 * tests. 105 */ 106 class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { 107 private val random = Random() 108 val mocks = Mocks() 109 110 // TODO: getBackingApexFile does not handle paths that aren't /apex 111 val apexDirectory = File("/apex") 112 val packageCacheDirectory: File = 113 Files.createTempDirectory("packageCache").toFile() 114 val rootDirectory: File = 115 Files.createTempDirectory("root").toFile() 116 val dataAppDirectory: File = 117 File(Files.createTempDirectory("data").toFile(), "app") 118 val frameworkSignature: SigningDetails = SigningDetails(arrayOf(generateSpySignature()), 3) 119 val systemPartitions: List<ScanPartition> = 120 redirectScanPartitions(PackageManagerService.SYSTEM_PARTITIONS) 121 val session: StaticMockitoSession 122 123 /** Tracks temporary files created by this class during the running of a test. */ 124 private val createdFiles = ArrayList<File>() 125 126 /** Settings that are expected to be added as part of the test */ 127 private val mPendingPackageAdds: MutableList<Pair<String, PackageSetting>> = ArrayList() 128 129 /** Settings simulated to be stored on disk */ 130 private val mPreExistingSettings = ArrayMap<String, PackageSetting>() 131 132 /** The active map simulating the in memory storage of Settings */ 133 private val mSettingsMap = WatchedArrayMap<String, PackageSetting>() 134 135 /** The shared libraries on the device */ 136 private lateinit var mSharedLibraries: SharedLibrariesImpl 137 138 init { 139 PropertyInvalidatedCache.disableForTestMode() 140 val apply = ExtendedMockito.mockitoSession() 141 .strictness(Strictness.LENIENT) 142 .mockStatic(SystemProperties::class.java) 143 .mockStatic(SystemConfig::class.java) 144 .mockStatic(SELinuxMMAC::class.java, Mockito.CALLS_REAL_METHODS) 145 .mockStatic(FallbackCategoryProvider::class.java) 146 .mockStatic(PackageManagerServiceUtils::class.java) 147 .mockStatic(Environment::class.java) 148 .mockStatic(SystemServerInitThreadPool::class.java) 149 .mockStatic(ParsingPackageUtils::class.java, Mockito.CALLS_REAL_METHODS) 150 .mockStatic(LockGuard::class.java) 151 .mockStatic(EventLog::class.java) 152 .mockStatic(LocalServices::class.java) 153 .mockStatic(LocalManagerRegistry::class.java) 154 .mockStatic(DeviceConfig::class.java) 155 .mockStatic(HexEncoding::class.java) 156 .apply(withSession) 157 session = apply.startMocking() 158 whenever(mocks.settings.insertPackageSettingLPw( 159 any(PackageSetting::class.java), any(AndroidPackage::class.java))) { 160 val name: String = (getArgument<Any>(0) as PackageSetting).name 161 val pendingAdd = 162 mPendingPackageAdds.firstOrNull { it.first == name } ?: return@whenever null 163 mPendingPackageAdds.remove(pendingAdd) 164 mSettingsMap[name] = pendingAdd.second 165 null 166 } 167 whenever(mocks.settings.addPackageLPw(nullable(), nullable(), nullable(), nullable(), 168 nullable(), nullable(), nullable(), nullable(), nullable(), nullable(), nullable(), 169 nullable(), nullable(), nullable(), nullable(), nullable(), nullable())) { 170 val name: String = getArgument(0) 171 val pendingAdd = mPendingPackageAdds.firstOrNull { it.first == name } 172 ?: return@whenever null 173 mPendingPackageAdds.remove(pendingAdd) 174 mSettingsMap[name] = pendingAdd.second 175 pendingAdd.second 176 } 177 whenever(mocks.settings.packagesLocked).thenReturn(mSettingsMap) 178 whenever(mocks.settings.getPackageLPr(anyString())) { mSettingsMap[getArgument<Any>(0)] } 179 whenever(mocks.settings.readLPw(any(), nullable())) { 180 mSettingsMap.putAll(mPreExistingSettings) 181 !mPreExistingSettings.isEmpty() 182 } 183 } 184 185 /** Collection of mocks used for PackageManagerService tests. */ 186 187 class Mocks { 188 val lock = PackageManagerTracedLock() 189 val installLock = Any() 190 val injector: PackageManagerServiceInjector = mock() 191 val systemWrapper: PackageManagerServiceInjector.SystemWrapper = mock() 192 val context: Context = mock() 193 val userManagerService: UserManagerService = mock() 194 val componentResolver: ComponentResolver = mock() 195 val permissionManagerInternal: PermissionManagerServiceInternal = mock() 196 val incrementalManager: IncrementalManager = mock() 197 val platformCompat: PlatformCompat = mock() 198 val settings: Settings = mock() 199 val crossProfileIntentFilterHelper: CrossProfileIntentFilterHelper = mock() 200 val resources: Resources = mock() 201 val systemConfig: SystemConfig = mock() 202 val apexManager: ApexManager = mock() 203 val userManagerInternal: UserManagerInternal = mock() 204 val packageParser: PackageParser2 = mock() 205 val keySetManagerService: KeySetManagerService = mock() 206 val packageAbiHelper: PackageAbiHelper = mock() 207 val appsFilterSnapshot: AppsFilterSnapshotImpl = mock() 208 val appsFilter: AppsFilterImpl = mock { 209 whenever(snapshot()) { appsFilterSnapshot } 210 } 211 val dexManager: DexManager = mock() 212 val dynamicCodeLogger: DynamicCodeLogger = mock() 213 val installer: Installer = mock() 214 val displayMetrics: DisplayMetrics = mock() 215 val domainVerificationManagerInternal: DomainVerificationManagerInternal = mock() 216 val handler = TestHandler(null) 217 val defaultAppProvider: DefaultAppProvider = mock() 218 val backgroundHandler = TestHandler(null) 219 val updateOwnershipHelper: UpdateOwnershipHelper = mock() 220 } 221 222 companion object { 223 private const val DEVICE_PROVISIONING_PACKAGE_NAME = 224 "com.example.android.device.provisioning" 225 private val DEFAULT_AVAILABLE_FEATURES_MAP = ArrayMap<String, FeatureInfo>() 226 private val DEFAULT_ACTIVE_APEX_INFO_LIST = emptyList<ApexManager.ActiveApexInfo>() 227 private val DEFAULT_SHARED_LIBRARIES_LIST = 228 ArrayMap<String, SystemConfig.SharedLibraryEntry>() 229 private val DEFAULT_USERS = Arrays.asList( 230 UserInfo(UserHandle.USER_SYSTEM, "primary", "", 231 UserInfo.FLAG_PRIMARY or UserInfo.FLAG_SYSTEM or UserInfo.FLAG_FULL, 232 UserManager.USER_TYPE_FULL_SYSTEM)) 233 public val DEFAULT_VERSION_INFO = Settings.VersionInfo() 234 235 init { 236 DEFAULT_VERSION_INFO.fingerprint = "abcdef" 237 DEFAULT_VERSION_INFO.sdkVersion = Build.VERSION_CODES.R 238 DEFAULT_VERSION_INFO.databaseVersion = Settings.CURRENT_DATABASE_VERSION 239 } 240 241 fun addDefaultSharedLibrary(libName: String, libEntry: SystemConfig.SharedLibraryEntry) { 242 DEFAULT_SHARED_LIBRARIES_LIST[libName] = libEntry 243 } 244 } 245 246 /** 247 * Clean up any potentially dangling state. This should be run at the end of every test to 248 * account for changes to static memory, such as [LocalServices] 249 */ 250 fun cleanup() { 251 createdFiles.forEach(File::delete) 252 createdFiles.clear() 253 mSettingsMap.clear() 254 mPendingPackageAdds.clear() 255 mPreExistingSettings.clear() 256 session.finishMocking() 257 } 258 259 /** 260 * Run this method to ensure that all expected actions were executed, such as pending 261 * [Settings] adds. 262 */ 263 fun validateFinalState() { 264 if (mPendingPackageAdds.isNotEmpty()) { 265 Assert.fail( 266 "Not all expected settings were added: ${mPendingPackageAdds.map { it.first }}") 267 } 268 } 269 270 /** 271 * This method stages enough of system startup to execute the PackageManagerService constructor 272 * successfullly. 273 */ 274 @Throws(Exception::class) 275 fun stageNominalSystemState() { 276 whenever(mocks.injector.context).thenReturn(mocks.context) 277 whenever(mocks.injector.lock).thenReturn(mocks.lock) 278 whenever(mocks.injector.installLock).thenReturn(mocks.installLock) 279 whenever(mocks.injector.systemWrapper).thenReturn(mocks.systemWrapper) 280 whenever(mocks.injector.userManagerService).thenReturn(mocks.userManagerService) 281 whenever(mocks.injector.componentResolver).thenReturn(mocks.componentResolver) 282 whenever(mocks.injector.permissionManagerServiceInternal) { 283 mocks.permissionManagerInternal 284 } 285 whenever(mocks.injector.incrementalManager).thenReturn(mocks.incrementalManager) 286 whenever(mocks.injector.compatibility).thenReturn(mocks.platformCompat) 287 whenever(mocks.injector.settings).thenReturn(mocks.settings) 288 whenever(mocks.injector.crossProfileIntentFilterHelper) 289 .thenReturn(mocks.crossProfileIntentFilterHelper) 290 whenever(mocks.injector.dexManager).thenReturn(mocks.dexManager) 291 whenever(mocks.injector.dynamicCodeLogger).thenReturn(mocks.dynamicCodeLogger) 292 whenever(mocks.injector.systemConfig).thenReturn(mocks.systemConfig) 293 whenever(mocks.injector.apexManager).thenReturn(mocks.apexManager) 294 whenever(mocks.injector.scanningCachingPackageParser).thenReturn(mocks.packageParser) 295 whenever(mocks.injector.scanningPackageParser).thenReturn(mocks.packageParser) 296 whenever(mocks.injector.systemPartitions).thenReturn(systemPartitions) 297 whenever(mocks.injector.appsFilter).thenReturn(mocks.appsFilter) 298 whenever(mocks.injector.abiHelper).thenReturn(mocks.packageAbiHelper) 299 whenever(mocks.injector.userManagerInternal).thenReturn(mocks.userManagerInternal) 300 whenever(mocks.injector.installer).thenReturn(mocks.installer) 301 whenever(mocks.injector.displayMetrics).thenReturn(mocks.displayMetrics) 302 whenever(mocks.injector.domainVerificationManagerInternal) 303 .thenReturn(mocks.domainVerificationManagerInternal) 304 whenever(mocks.injector.handler) { mocks.handler } 305 whenever(mocks.injector.defaultAppProvider) { mocks.defaultAppProvider } 306 whenever(mocks.injector.backgroundHandler) { mocks.backgroundHandler } 307 whenever(mocks.injector.updateOwnershipHelper) { mocks.updateOwnershipHelper } 308 wheneverStatic { SystemConfig.getInstance() }.thenReturn(mocks.systemConfig) 309 whenever(mocks.systemConfig.availableFeatures).thenReturn(DEFAULT_AVAILABLE_FEATURES_MAP) 310 whenever(mocks.systemConfig.sharedLibraries).thenReturn(DEFAULT_SHARED_LIBRARIES_LIST) 311 whenever(mocks.systemConfig.defaultVrComponents).thenReturn(ArraySet()) 312 whenever(mocks.systemConfig.hiddenApiWhitelistedApps).thenReturn(ArraySet()) 313 whenever(mocks.systemConfig.appMetadataFilePaths).thenReturn(ArrayMap()) 314 wheneverStatic { SystemProperties.set(anyString(), anyString()) }.thenDoNothing() 315 wheneverStatic { SystemProperties.getBoolean("fw.free_cache_v2", true) }.thenReturn(true) 316 wheneverStatic { Environment.getApexDirectory() }.thenReturn(apexDirectory) 317 wheneverStatic { Environment.getPackageCacheDirectory() }.thenReturn(packageCacheDirectory) 318 wheneverStatic { SystemProperties.digestOf("ro.build.fingerprint") }.thenReturn("cacheName") 319 wheneverStatic { Environment.getRootDirectory() }.thenReturn(rootDirectory) 320 wheneverStatic { SystemServerInitThreadPool.submit(any(Runnable::class.java), anyString()) } 321 .thenAnswer { FutureTask<Any?>(it.getArgument(0), null) } 322 323 wheneverStatic { Environment.getDataDirectory() }.thenReturn(dataAppDirectory.parentFile) 324 wheneverStatic { Environment.getDataSystemDirectory() } 325 .thenReturn(File(dataAppDirectory.parentFile, "system")) 326 whenever(mocks.context.resources).thenReturn(mocks.resources) 327 whenever(mocks.resources.getString(R.string.config_deviceProvisioningPackage)) { 328 DEVICE_PROVISIONING_PACKAGE_NAME 329 } 330 whenever(mocks.apexManager.activeApexInfos).thenReturn(DEFAULT_ACTIVE_APEX_INFO_LIST) 331 whenever(mocks.settings.packagesLocked).thenReturn(mSettingsMap) 332 whenever(mocks.settings.internalVersion).thenReturn(DEFAULT_VERSION_INFO) 333 whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService) 334 whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService) 335 whenever(mocks.settings.snapshot()).thenReturn(mocks.settings) 336 whenever(mocks.packageAbiHelper.derivePackageAbi(any(AndroidPackage::class.java), 337 anyBoolean(), anyBoolean(), nullable(), any(File::class.java))) { 338 android.util.Pair(PackageAbiHelper.Abis("", ""), 339 PackageAbiHelper.NativeLibraryPaths("", false, "", "")) 340 } 341 whenever(mocks.userManagerInternal.getUsers(true, false, false)).thenReturn(DEFAULT_USERS) 342 whenever(mocks.userManagerService.userIds).thenReturn(intArrayOf(0)) 343 whenever(mocks.userManagerService.exists(0)).thenReturn(true) 344 whenever(mocks.packageAbiHelper.deriveNativeLibraryPaths(any(AndroidPackage::class.java), 345 anyBoolean(), anyBoolean(), any(File::class.java))) { 346 PackageAbiHelper.NativeLibraryPaths("", false, "", "") 347 } 348 whenever(mocks.injector.bootstrap(any(PackageManagerService::class.java))) { 349 mSharedLibraries = SharedLibrariesImpl( 350 getArgument<Any>(0) as PackageManagerService, mocks.injector) 351 } 352 whenever(mocks.injector.sharedLibrariesImpl) { mSharedLibraries } 353 // everything visible by default 354 whenever(mocks.appsFilter.shouldFilterApplication(any(PackageDataSnapshot::class.java), 355 anyInt(), nullable(), nullable(), anyInt())) { false } 356 whenever(mocks.appsFilterSnapshot.shouldFilterApplication( 357 any(PackageDataSnapshot::class.java), 358 anyInt(), nullable(), nullable(), anyInt())) { false } 359 360 val displayManager: DisplayManager = mock() 361 whenever(mocks.context.getSystemService(DisplayManager::class.java)) 362 .thenReturn(displayManager) 363 val display: Display = mock() 364 whenever(displayManager.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(display) 365 366 stageFrameworkScan() 367 stageInstallerScan() 368 stageServicesExtensionScan() 369 stageSystemSharedLibraryScan() 370 stagePermissionsControllerScan() 371 stageSupplementalProcessScan() 372 stageInstantAppResolverScan() 373 } 374 375 /** 376 * This method will stage the parsing and scanning of a package as well as add it to the 377 * [PackageSetting]s read from disk. 378 */ 379 @Throws(Exception::class) 380 fun stageScanExistingPackage( 381 packageName: String, 382 versionCode: Long, 383 parent: File?, 384 withPackage: (PackageImpl) -> PackageImpl = { it }, 385 withSetting: 386 (PackageSettingBuilder) -> PackageSettingBuilder = { it }, 387 withExistingSetting: 388 (PackageSettingBuilder) -> PackageSettingBuilder = { it } 389 ) { 390 val existingSettingBuilderRef = arrayOfNulls<PackageSettingBuilder>(1) 391 stageScanNewPackage(packageName, versionCode, parent, withPackage, 392 withSetting = { settingBuilder -> 393 withSetting(settingBuilder) 394 existingSettingBuilderRef[0] = settingBuilder 395 settingBuilder 396 }) 397 existingSettingBuilderRef[0]?.setPackage(null) 398 val packageSetting = existingSettingBuilderRef[0]?.let { withExistingSetting(it) }!!.build() 399 addPreExistingSetting(packageSetting.name, packageSetting) 400 } 401 402 /** 403 * This method will stage a [PackageSetting] read from disk, but does not stage any scanning 404 * or parsing of the package. 405 */ 406 fun addPreExistingSetting(packageName: String, packageSetting: PackageSetting) { 407 mPreExistingSettings[packageName] = packageSetting 408 } 409 410 /** 411 * This method will stage the parsing and scanning of a package but will not add it to the set 412 * of [PackageSetting]s read from disk. 413 */ 414 @Throws(Exception::class) 415 fun stageScanNewPackage( 416 packageName: String, 417 versionCode: Long, 418 parent: File?, 419 withPackage: (PackageImpl) -> PackageImpl = { it }, 420 withSetting: (PackageSettingBuilder) -> PackageSettingBuilder = { it } 421 ) { 422 val pair = createBasicAndroidPackage(parent, packageName, versionCode) 423 val apkPath = pair.first 424 val pkg = withPackage(pair.second) 425 stageParse(apkPath, pkg) 426 val parentFile = apkPath.parentFile 427 val settingBuilder = withSetting(createBasicSettingBuilder(parentFile, pkg)) 428 val packageSetting = settingBuilder.build() 429 stageSettingInsert(packageSetting.name, packageSetting) 430 } 431 432 /** 433 * Creates a simple package that should reasonably parse for scan operations. This can be used 434 * as a basis for more complicated packages. 435 */ 436 fun createBasicAndroidPackage( 437 parent: File?, 438 packageName: String, 439 versionCode: Long, 440 signingDetails: SigningDetails = 441 createRandomSigningDetails() 442 ): Pair<File, PackageImpl> { 443 val apkPath = File(File(parent, packageName), "base.apk") 444 val pkg = PackageImpl.forTesting(packageName, apkPath.parentFile.path) as PackageImpl 445 pkg.signingDetails = signingDetails 446 val result = ParseTypeImpl.forDefaultParsing().success(signingDetails) 447 wheneverStatic { ParsingPackageUtils.getSigningDetails( 448 any(ParseTypeImpl::class.java), eq(pkg), anyBoolean()) } 449 .thenReturn(result) 450 pkg.versionCode = versionCode.toInt() 451 pkg.versionCodeMajor = (versionCode shr 32).toInt() 452 pkg.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT 453 return Pair(apkPath, pkg) 454 } 455 456 /** 457 * This method will create a spy of a [SigningDetails] object to be used when simulating the 458 * collection of signatures. 459 */ 460 fun createRandomSigningDetails(): SigningDetails { 461 val signingDetails = spy(SigningDetails(arrayOf(generateSpySignature()), 462 SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3)) 463 doReturn(true).whenever(signingDetails).checkCapability( 464 anyString(), anyInt()) 465 doReturn(true).whenever(signingDetails).checkCapability( 466 any(SigningDetails::class.java), anyInt()) 467 return signingDetails 468 } 469 470 /** 471 * This method will create a basic [PackageSettingBuilder] from an [AndroidPackage] with all of 472 * the necessary parameters to be returned by a simple scan. This can be used as a basis for 473 * more complicated settings. 474 */ 475 fun createBasicSettingBuilder(parentFile: File, pkg: AndroidPackage): PackageSettingBuilder { 476 return createBasicSettingBuilder(parentFile, pkg.packageName, pkg.longVersionCode, 477 pkg.signingDetails) 478 .setPackage(pkg) 479 } 480 481 /** 482 * This method will create a basic [PackageSettingBuilder] with all of the necessary parameters 483 * to be returned by a simple scan. This can be used as a basis for more complicated settings. 484 */ 485 fun createBasicSettingBuilder( 486 parentFile: File, 487 packageName: String, 488 versionCode: Long, 489 signingDetails: SigningDetails 490 ): PackageSettingBuilder { 491 return PackageSettingBuilder() 492 .setCodePath(parentFile.path) 493 .setName(packageName) 494 .setPVersionCode(versionCode) 495 .setSigningDetails(signingDetails) 496 } 497 498 fun createBasicApplicationInfo(pkg: ParsingPackage): ApplicationInfo { 499 val applicationInfo: ApplicationInfo = mock() 500 applicationInfo.packageName = pkg.packageName 501 return applicationInfo 502 } 503 504 fun createBasicActivityInfo( 505 pkg: ParsingPackage, 506 applicationInfo: ApplicationInfo?, 507 className: String? 508 ): 509 ActivityInfo { 510 val activityInfo = ActivityInfo() 511 activityInfo.applicationInfo = applicationInfo 512 activityInfo.packageName = pkg.packageName 513 activityInfo.name = className 514 return activityInfo 515 } 516 517 fun createBasicServiceInfo( 518 pkg: ParsingPackage, 519 applicationInfo: ApplicationInfo?, 520 className: String? 521 ): 522 ServiceInfo { 523 val serviceInfo = ServiceInfo() 524 serviceInfo.applicationInfo = applicationInfo 525 serviceInfo.packageName = pkg.packageName 526 serviceInfo.name = className 527 return serviceInfo 528 } 529 530 /** Finds the appropriate partition, if available, based on a scan flag unique to it. */ 531 fun getPartitionFromFlag(scanFlagMask: Int): ScanPartition = 532 systemPartitions.first { (it.scanFlag and scanFlagMask) != 0 } 533 534 @Throws(Exception::class) 535 private fun stageParse(path: File, parseResult: ParsingPackage): ParsedPackage { 536 val basePath = path.parentFile 537 basePath.mkdirs() 538 path.createNewFile() 539 createdFiles.add(path) 540 val parsedPackage = parseResult.hideAsParsed() as ParsedPackage 541 whenever(mocks.packageParser.parsePackage( 542 or(eq(path), eq(basePath)), anyInt(), anyBoolean())) { parsedPackage } 543 whenever(mocks.packageParser.parsePackage( 544 or(eq(path), eq(basePath)), anyInt(), anyBoolean())) { parsedPackage } 545 return parsedPackage 546 } 547 548 private fun stageSettingInsert(name: String, setting: PackageSetting): PackageSetting { 549 mPendingPackageAdds.add(Pair(name, setting)) 550 return setting 551 } 552 553 @Throws(Exception::class) 554 private fun stageFrameworkScan() { 555 val apk = File(File(rootDirectory, "framework"), "framework-res.apk") 556 val frameworkPkg = PackageImpl.forTesting("android", 557 apk.parentFile.path) as PackageImpl 558 val result = ParseTypeImpl.forDefaultParsing().success(frameworkSignature) 559 wheneverStatic { ParsingPackageUtils.getSigningDetails( 560 any(ParseTypeImpl::class.java), eq(frameworkPkg), eq(true)) } 561 .thenReturn(result) 562 stageParse(apk, frameworkPkg) 563 stageSettingInsert("android", 564 PackageSettingBuilder().setCodePath(apk.path).setName( 565 "android").setPackage(frameworkPkg).build()) 566 } 567 568 @Throws(Exception::class) 569 private fun stageInstantAppResolverScan() { 570 whenever(mocks.resources.getStringArray(R.array.config_ephemeralResolverPackage)) { 571 arrayOf("com.android.test.ephemeral.resolver") 572 } 573 stageScanNewPackage("com.android.test.ephemeral.resolver", 574 1L, getPartitionFromFlag(PackageManagerService.SCAN_AS_PRODUCT).privAppFolder, 575 withPackage = { pkg: PackageImpl -> 576 val applicationInfo: ApplicationInfo = createBasicApplicationInfo(pkg) 577 whenever(applicationInfo.isPrivilegedApp).thenReturn(true) 578 mockQueryServices(Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE, 579 createBasicServiceInfo(pkg, applicationInfo, "test.EphemeralService")) 580 mockQueryActivities(Intent.ACTION_INSTANT_APP_RESOLVER_SETTINGS, 581 createBasicActivityInfo(pkg, applicationInfo, "test.SettingsActivity")) 582 pkg 583 }, 584 withSetting = { setting: PackageSettingBuilder -> 585 setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM) 586 }) 587 } 588 589 @Throws(Exception::class) 590 private fun stagePermissionsControllerScan() { 591 stageScanNewPackage("com.android.permissions.controller", 592 1L, systemPartitions[0].privAppFolder, 593 withPackage = { pkg: PackageImpl -> 594 val applicationInfo: ApplicationInfo = createBasicApplicationInfo(pkg) 595 whenever(applicationInfo.isPrivilegedApp).thenReturn(true) 596 mockQueryActivities(Intent.ACTION_MANAGE_PERMISSIONS, 597 createBasicActivityInfo( 598 pkg, applicationInfo, "test.PermissionActivity")) 599 pkg 600 }, 601 withSetting = { setting: PackageSettingBuilder -> 602 setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM) 603 }) 604 } 605 606 @Throws(Exception::class) 607 private fun stageSupplementalProcessScan() { 608 stageScanNewPackage("com.android.supplemental.process", 609 1L, systemPartitions[0].privAppFolder, 610 withPackage = { pkg: PackageImpl -> 611 val applicationInfo: ApplicationInfo = createBasicApplicationInfo(pkg) 612 mockQueryServices(SdkSandboxManagerLocal.SERVICE_INTERFACE, 613 createBasicServiceInfo( 614 pkg, applicationInfo, "SupplementalProcessService")) 615 pkg 616 }, 617 withSetting = { setting: PackageSettingBuilder -> 618 setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM) 619 }) 620 } 621 622 @Throws(Exception::class) 623 private fun stageSystemSharedLibraryScan() { 624 stageScanNewPackage("android.ext.shared", 625 1L, systemPartitions[0].appFolder, 626 withPackage = { it.addLibraryName("android.ext.shared") as PackageImpl }, 627 withSetting = { setting: PackageSettingBuilder -> 628 setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM) 629 } 630 ) 631 } 632 633 @Throws(Exception::class) 634 private fun stageServicesExtensionScan() { 635 whenever(mocks.context.getString(R.string.config_servicesExtensionPackage)) { 636 "com.android.test.services.extension" 637 } 638 stageScanNewPackage("com.android.test.services.extension", 639 1L, getPartitionFromFlag(PackageManagerService.SCAN_AS_SYSTEM_EXT).privAppFolder, 640 withSetting = { setting: PackageSettingBuilder -> 641 setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM) 642 }) 643 } 644 645 @Throws(Exception::class) 646 private fun stageInstallerScan() { 647 stageScanNewPackage( 648 "com.android.test.installer", 649 1L, getPartitionFromFlag(PackageManagerService.SCAN_AS_PRODUCT).privAppFolder, 650 withPackage = { pkg: PackageImpl -> 651 val applicationInfo: ApplicationInfo = createBasicApplicationInfo(pkg) 652 whenever(applicationInfo.isPrivilegedApp).thenReturn(true) 653 val installerActivity: ActivityInfo = createBasicActivityInfo( 654 pkg, applicationInfo, "test.InstallerActivity") 655 mockQueryActivities(Intent.ACTION_INSTALL_PACKAGE, installerActivity) 656 mockQueryActivities(Intent.ACTION_UNINSTALL_PACKAGE, installerActivity) 657 mockQueryActivities(Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE, 658 installerActivity) 659 pkg 660 }, 661 withSetting = { setting: PackageSettingBuilder -> 662 setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM) 663 } 664 ) 665 } 666 667 private fun mockQueryActivities(action: String, vararg activities: ActivityInfo) { 668 whenever(mocks.componentResolver.queryActivities(any(), 669 argThat { intent: Intent? -> intent != null && (action == intent.action) }, 670 nullable(), anyLong(), anyInt())) { 671 ArrayList(activities.asList().map { info: ActivityInfo? -> 672 ResolveInfo().apply { activityInfo = info } 673 }) 674 } 675 } 676 677 private fun mockQueryServices(action: String, vararg services: ServiceInfo) { 678 whenever(mocks.componentResolver.queryServices(any(), 679 argThat { intent: Intent? -> intent != null && (action == intent.action) }, 680 nullable(), anyLong(), anyInt())) { 681 ArrayList(services.asList().map { info -> 682 ResolveInfo().apply { serviceInfo = info } 683 }) 684 } 685 } 686 687 fun generateSpySignature(): Signature { 688 val bytes = ByteArray(32) 689 random.nextBytes(bytes) 690 val signature = spy(Signature(bytes)) 691 try { 692 val mockPublicKey: PublicKey = mock() 693 doReturn(mockPublicKey).whenever(signature).getPublicKey() 694 } catch (e: CertificateException) { 695 throw RuntimeException(e) 696 } 697 return signature 698 } 699 700 /** Override get*Folder methods to point to temporary local directories */ 701 702 @Throws(IOException::class) 703 private fun redirectScanPartitions(partitions: List<ScanPartition>): 704 List<ScanPartition> { 705 val spiedPartitions: MutableList<ScanPartition> = 706 ArrayList(partitions.size) 707 for (partition: ScanPartition in partitions) { 708 val spy = spy(partition) 709 val newRoot = Files.createTempDirectory(partition.folder.name).toFile() 710 whenever(spy.overlayFolder).thenReturn(File(newRoot, "overlay")) 711 whenever(spy.appFolder).thenReturn(File(newRoot, "app")) 712 whenever(spy.privAppFolder).thenReturn(File(newRoot, "priv-app")) 713 whenever(spy.folder).thenReturn(newRoot) 714 spiedPartitions.add(spy) 715 } 716 return spiedPartitions 717 } 718 } 719 720 /** 721 * Sets up a basic [MockSystem] for use in a test method. This will create a MockSystem before the 722 * test method and any [org.junit.Before] annotated methods. It can then be used to access the 723 * MockSystem via the [system] method or the mocks directly via [mocks]. 724 */ 725 class MockSystemRule : TestRule { 726 var mockSystem: MockSystem? = null 727 override fun apply(base: Statement?, description: Description?) = object : Statement() { 728 @Throws(Throwable::class) 729 override fun evaluate() { 730 mockSystem = MockSystem() 731 try { 732 base!!.evaluate() 733 } finally { 734 mockSystem?.cleanup() 735 mockSystem = null 736 } 737 } 738 } 739 740 /** Fetch the [MockSystem] instance prepared for this test */ 741 fun system(): MockSystem = mockSystem!! 742 /** Fetch the [MockSystem.Mocks] prepared for this test */ 743 fun mocks(): MockSystem.Mocks = mockSystem!!.mocks 744 } 745