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