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