Move shared library info out of PackageManagerService (2/n)
- Adding tests for SharedLibrariesImpl
- Rename SharedLibraryHelper to SharedLibraryUtils
Bug: 200588896
Test: atest StaticSharedLibsHostTests
Test: atest SharedLibrariesImplTest
Change-Id: I7f03720f54ae14b68ba7531f4f407a99d361a680
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 2f4f271..df83d11 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -4788,7 +4788,7 @@
@Override
public List<PackageStateInternal> findSharedNonSystemLibraries(
@NonNull PackageStateInternal pkgSetting) {
- List<SharedLibraryInfo> deps = SharedLibraryHelper.findSharedLibraries(pkgSetting);
+ List<SharedLibraryInfo> deps = SharedLibraryUtils.findSharedLibraries(pkgSetting);
if (!deps.isEmpty()) {
List<PackageStateInternal> retValue = new ArrayList<>();
for (SharedLibraryInfo info : deps) {
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index eac38af..dcad3ec 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -379,7 +379,7 @@
// at boot, or background job), the passed 'targetCompilerFilter' stays the same,
// and the first package that uses the library will dexopt it. The
// others will see that the compiled code for the library is up to date.
- Collection<SharedLibraryInfo> deps = SharedLibraryHelper.findSharedLibraries(pkgSetting);
+ Collection<SharedLibraryInfo> deps = SharedLibraryUtils.findSharedLibraries(pkgSetting);
final String[] instructionSets = getAppDexInstructionSets(
AndroidPackageUtils.getPrimaryCpuAbi(p, pkgSetting),
AndroidPackageUtils.getSecondaryCpuAbi(p, pkgSetting));
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index 5a25004..7d2aa53 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -67,11 +67,11 @@
// in the first pass, we'll build up the set of incoming shared libraries
final List<SharedLibraryInfo> allowedSharedLibInfos =
- SharedLibraryHelper.getAllowedSharedLibInfos(scanResult,
+ SharedLibraryUtils.getAllowedSharedLibInfos(scanResult,
request.mSharedLibrarySource);
if (allowedSharedLibInfos != null) {
for (SharedLibraryInfo info : allowedSharedLibInfos) {
- if (!SharedLibraryHelper.addSharedLibraryToPackageVersionMap(
+ if (!SharedLibraryUtils.addSharedLibraryToPackageVersionMap(
incomingSharedLibraries, info)) {
throw new ReconcileFailure("Shared Library " + info.getName()
+ " is being installed twice in this set!");
@@ -264,7 +264,7 @@
}
try {
result.get(installPackageName).mCollectedSharedLibraryInfos =
- SharedLibraryHelper.collectSharedLibraryInfos(
+ SharedLibraryUtils.collectSharedLibraryInfos(
scanResult.mRequest.mParsedPackage,
combinedPackages, request.mSharedLibrarySource,
incomingSharedLibraries, injector.getCompatibility());
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index 0055f4e..2335cc1 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -494,7 +494,7 @@
@NonNull Map<String, AndroidPackage> availablePackages)
throws PackageManagerException {
final ArrayList<SharedLibraryInfo> sharedLibraryInfos =
- SharedLibraryHelper.collectSharedLibraryInfos(
+ SharedLibraryUtils.collectSharedLibraryInfos(
pkgSetting.getPkg(), availablePackages, mSharedLibraries,
null /* newLibraries */, mInjector.getCompatibility());
executeSharedLibrariesUpdateLPw(pkg, pkgSetting, changingLib, changingLibSetting,
diff --git a/services/core/java/com/android/server/pm/SharedLibraryHelper.java b/services/core/java/com/android/server/pm/SharedLibraryUtils.java
similarity index 99%
rename from services/core/java/com/android/server/pm/SharedLibraryHelper.java
rename to services/core/java/com/android/server/pm/SharedLibraryUtils.java
index dd8fad0..5259c58 100644
--- a/services/core/java/com/android/server/pm/SharedLibraryHelper.java
+++ b/services/core/java/com/android/server/pm/SharedLibraryUtils.java
@@ -47,7 +47,7 @@
import java.util.Map;
import java.util.Set;
-final class SharedLibraryHelper {
+final class SharedLibraryUtils {
private static final boolean DEBUG_SHARED_LIBRARIES = false;
/**
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 44a8b30..04a6eee 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -74,6 +74,7 @@
import com.android.server.testutils.nullable
import com.android.server.testutils.whenever
import com.android.server.utils.WatchedArrayMap
+import libcore.util.HexEncoding
import org.junit.Assert
import org.junit.rules.TestRule
import org.junit.runner.Description
@@ -140,6 +141,7 @@
.mockStatic(EventLog::class.java)
.mockStatic(LocalServices::class.java)
.mockStatic(DeviceConfig::class.java)
+ .mockStatic(HexEncoding::class.java)
.apply(withSession)
session = apply.startMocking()
whenever(mocks.settings.insertPackageSettingLPw(
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
new file mode 100644
index 0000000..f305321
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm
+
+import android.content.pm.PackageManager
+import android.content.pm.SharedLibraryInfo
+import android.content.pm.VersionedPackage
+import android.os.Build
+import android.os.storage.StorageManager
+import android.util.ArrayMap
+import android.util.PackageUtils
+import com.android.server.SystemConfig.SharedLibraryEntry
+import com.android.server.compat.PlatformCompat
+import com.android.server.extendedtestutils.wheneverStatic
+import com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME
+import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.PackageImpl
+import com.android.server.pm.parsing.pkg.ParsedPackage
+import com.android.server.testutils.any
+import com.android.server.testutils.eq
+import com.android.server.testutils.nullable
+import com.android.server.testutils.spy
+import com.android.server.testutils.whenever
+import com.android.server.utils.WatchedLongSparseArray
+import com.google.common.truth.Truth.assertThat
+import libcore.util.HexEncoding
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import java.io.File
+import kotlin.test.assertFailsWith
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+
+@RunWith(JUnit4::class)
+class SharedLibrariesImplTest {
+
+ companion object {
+ const val TEST_LIB_NAME = "test.lib"
+ const val TEST_LIB_PACKAGE_NAME = "com.android.lib.test"
+ const val BUILTIN_LIB_NAME = "builtin.lib"
+ const val STATIC_LIB_NAME = "static.lib"
+ const val STATIC_LIB_VERSION = 7L
+ const val STATIC_LIB_PACKAGE_NAME = "com.android.lib.static.provider"
+ const val DYNAMIC_LIB_NAME = "dynamic.lib"
+ const val DYNAMIC_LIB_PACKAGE_NAME = "com.android.lib.dynamic.provider"
+ const val CONSUMER_PACKAGE_NAME = "com.android.lib.consumer"
+ const val VERSION_UNDEFINED = SharedLibraryInfo.VERSION_UNDEFINED.toLong()
+ }
+
+ @Rule
+ @JvmField
+ val mRule = MockSystemRule()
+
+ private val mExistingPackages: ArrayMap<String, AndroidPackage> = ArrayMap()
+ private val mExistingSettings: MutableMap<String, PackageSetting> = mutableMapOf()
+
+ private lateinit var mSharedLibrariesImpl: SharedLibrariesImpl
+ private lateinit var mPms: PackageManagerService
+ private lateinit var mSettings: Settings
+
+ @Mock
+ private lateinit var mDeletePackageHelper: DeletePackageHelper
+ @Mock
+ private lateinit var mStorageManager: StorageManager
+ @Mock
+ private lateinit var mFile: File
+ @Mock
+ private lateinit var mPlatformCompat: PlatformCompat
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ mRule.system().stageNominalSystemState()
+ addExistingPackages()
+
+ val testParams = PackageManagerServiceTestParams().apply {
+ packages = mExistingPackages
+ }
+ mPms = spy(PackageManagerService(mRule.mocks().injector, testParams))
+ mSettings = mRule.mocks().injector.settings
+ mSharedLibrariesImpl = SharedLibrariesImpl(mPms, mRule.mocks().injector)
+ mSharedLibrariesImpl.setDeletePackageHelper(mDeletePackageHelper)
+ addExistingSharedLibraries()
+
+ whenever(mSettings.getPackageLPr(any())) { mExistingSettings[arguments[0]] }
+ whenever(mRule.mocks().injector.getSystemService(StorageManager::class.java))
+ .thenReturn(mStorageManager)
+ whenever(mStorageManager.findPathForUuid(nullable())).thenReturn(mFile)
+ doAnswer { it.arguments[0] }.`when`(mPms).resolveInternalPackageNameLPr(any(), any())
+ whenever(mDeletePackageHelper.deletePackageX(any(), any(), any(), any(), any()))
+ .thenReturn(PackageManager.DELETE_SUCCEEDED)
+ whenever(mRule.mocks().injector.compatibility).thenReturn(mPlatformCompat)
+ wheneverStatic { HexEncoding.decode(STATIC_LIB_NAME, false) }
+ .thenReturn(PackageUtils.computeSha256DigestBytes(
+ mExistingSettings[STATIC_LIB_PACKAGE_NAME]!!
+ .pkg.signingDetails.signatures!![0].toByteArray()))
+ }
+
+ @Test
+ fun snapshot_shouldSealed() {
+ val builtinLibs = mSharedLibrariesImpl.snapshot().all[BUILTIN_LIB_NAME]
+ assertThat(builtinLibs).isNotNull()
+
+ assertFailsWith(IllegalStateException::class) {
+ mSharedLibrariesImpl.snapshot().all[BUILTIN_LIB_NAME] = WatchedLongSparseArray()
+ }
+ assertFailsWith(IllegalStateException::class) {
+ builtinLibs!!.put(VERSION_UNDEFINED, libOfBuiltin(BUILTIN_LIB_NAME))
+ }
+ }
+
+ @Test
+ fun addBuiltInSharedLibrary() {
+ mSharedLibrariesImpl.addBuiltInSharedLibraryLPw(libEntry(TEST_LIB_NAME))
+
+ assertThat(mSharedLibrariesImpl.getSharedLibraryInfos(TEST_LIB_NAME)).isNotNull()
+ assertThat(mSharedLibrariesImpl.getSharedLibraryInfo(TEST_LIB_NAME, VERSION_UNDEFINED))
+ .isNotNull()
+ }
+
+ @Test
+ fun addBuiltInSharedLibrary_withDuplicateLibName() {
+ val duplicate = libEntry(BUILTIN_LIB_NAME, "duplicate.path")
+ mSharedLibrariesImpl.addBuiltInSharedLibraryLPw(duplicate)
+ val sharedLibInfo = mSharedLibrariesImpl
+ .getSharedLibraryInfo(BUILTIN_LIB_NAME, VERSION_UNDEFINED)
+
+ assertThat(sharedLibInfo).isNotNull()
+ assertThat(sharedLibInfo!!.path).isNotEqualTo(duplicate.filename)
+ }
+
+ @Test
+ fun commitSharedLibraryInfo_withStaticSharedLib() {
+ val testInfo = libOfStatic(TEST_LIB_PACKAGE_NAME, TEST_LIB_NAME, 1L)
+ mSharedLibrariesImpl.commitSharedLibraryInfoLPw(testInfo)
+ val sharedLibInfos = mSharedLibrariesImpl
+ .getStaticLibraryInfos(testInfo.declaringPackage.packageName)
+
+ assertThat(mSharedLibrariesImpl.getSharedLibraryInfos(TEST_LIB_NAME))
+ .isNotNull()
+ assertThat(mSharedLibrariesImpl.getSharedLibraryInfo(testInfo.name, testInfo.longVersion))
+ .isNotNull()
+ assertThat(sharedLibInfos).isNotNull()
+ assertThat(sharedLibInfos.get(testInfo.longVersion)).isNotNull()
+ }
+
+ @Test
+ fun removeSharedLibrary() {
+ doAnswer { mutableListOf(VersionedPackage(CONSUMER_PACKAGE_NAME, 1L)) }.`when`(mPms)
+ .getPackagesUsingSharedLibrary(any(), any(), any(), any())
+ val staticInfo = mSharedLibrariesImpl
+ .getSharedLibraryInfo(STATIC_LIB_NAME, STATIC_LIB_VERSION)!!
+
+ mSharedLibrariesImpl.removeSharedLibraryLPw(STATIC_LIB_NAME, STATIC_LIB_VERSION)
+
+ assertThat(mSharedLibrariesImpl.getSharedLibraryInfos(STATIC_LIB_NAME)).isNull()
+ assertThat(mSharedLibrariesImpl
+ .getStaticLibraryInfos(staticInfo.declaringPackage.packageName)).isNull()
+ verify(mExistingSettings[CONSUMER_PACKAGE_NAME]!!)
+ .setOverlayPathsForLibrary(any(), nullable(), any())
+ }
+
+ @Test
+ fun pruneUnusedStaticSharedLibraries() {
+ mSharedLibrariesImpl.pruneUnusedStaticSharedLibraries(Long.MAX_VALUE, 0)
+
+ verify(mDeletePackageHelper)
+ .deletePackageX(eq(STATIC_LIB_PACKAGE_NAME), any(), any(), any(), any())
+ }
+
+ @Test
+ fun getLatestSharedLibraVersion() {
+ val newLibSetting = addPackage(STATIC_LIB_PACKAGE_NAME + "_" + 10, 10L,
+ staticLibrary = STATIC_LIB_NAME, staticLibraryVersion = 10L)
+
+ val latestInfo = mSharedLibrariesImpl.getLatestSharedLibraVersionLPr(newLibSetting.pkg)!!
+
+ assertThat(latestInfo).isNotNull()
+ assertThat(latestInfo.name).isEqualTo(STATIC_LIB_NAME)
+ assertThat(latestInfo.longVersion).isEqualTo(STATIC_LIB_VERSION)
+ }
+
+ @Test
+ fun getStaticSharedLibLatestVersionSetting() {
+ val pair = createBasicAndroidPackage(STATIC_LIB_PACKAGE_NAME + "_" + 10, 10L,
+ staticLibrary = STATIC_LIB_NAME, staticLibraryVersion = 10L)
+ val parsedPackage = pair.second as ParsedPackage
+ val scanRequest = ScanRequest(parsedPackage, null, null, null,
+ null, null, null, 0, 0, false, null, null)
+ val scanResult = ScanResult(scanRequest, true, null, null, false, 0, null, null, null)
+
+ val latestInfoSetting =
+ mSharedLibrariesImpl.getStaticSharedLibLatestVersionSetting(scanResult)!!
+
+ assertThat(latestInfoSetting).isNotNull()
+ assertThat(latestInfoSetting.packageName).isEqualTo(STATIC_LIB_PACKAGE_NAME)
+ }
+
+ @Test
+ fun updateSharedLibraries_withDynamicLibPackage() {
+ val testPackageSetting = mExistingSettings[DYNAMIC_LIB_PACKAGE_NAME]!!
+ assertThat(testPackageSetting.usesLibraryFiles).isEmpty()
+
+ mSharedLibrariesImpl.updateSharedLibrariesLPw(testPackageSetting.pkg, testPackageSetting,
+ null /* changingLib */, null /* changingLibSetting */, mExistingPackages)
+
+ assertThat(testPackageSetting.usesLibraryFiles).hasSize(1)
+ assertThat(testPackageSetting.usesLibraryFiles).contains(builtinLibPath(BUILTIN_LIB_NAME))
+ }
+
+ @Test
+ fun updateSharedLibraries_withStaticLibPackage() {
+ val testPackageSetting = mExistingSettings[STATIC_LIB_PACKAGE_NAME]!!
+ assertThat(testPackageSetting.usesLibraryFiles).isEmpty()
+
+ mSharedLibrariesImpl.updateSharedLibrariesLPw(testPackageSetting.pkg, testPackageSetting,
+ null /* changingLib */, null /* changingLibSetting */, mExistingPackages)
+
+ assertThat(testPackageSetting.usesLibraryFiles).hasSize(1)
+ assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(DYNAMIC_LIB_PACKAGE_NAME))
+ }
+
+ @Test
+ fun updateSharedLibraries_withConsumerPackage() {
+ val testPackageSetting = mExistingSettings[CONSUMER_PACKAGE_NAME]!!
+ assertThat(testPackageSetting.usesLibraryFiles).isEmpty()
+
+ mSharedLibrariesImpl.updateSharedLibrariesLPw(testPackageSetting.pkg, testPackageSetting,
+ null /* changingLib */, null /* changingLibSetting */, mExistingPackages)
+
+ assertThat(testPackageSetting.usesLibraryFiles).hasSize(2)
+ assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(DYNAMIC_LIB_PACKAGE_NAME))
+ assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(STATIC_LIB_PACKAGE_NAME))
+ }
+
+ @Test
+ fun updateAllSharedLibraries() {
+ mExistingSettings.forEach {
+ assertThat(it.value.usesLibraryFiles).isEmpty()
+ }
+
+ mSharedLibrariesImpl.updateAllSharedLibrariesLPw(
+ null /* updatedPkg */, null /* updatedPkgSetting */, mExistingPackages)
+
+ var testPackageSetting = mExistingSettings[DYNAMIC_LIB_PACKAGE_NAME]!!
+ assertThat(testPackageSetting.usesLibraryFiles).hasSize(1)
+ assertThat(testPackageSetting.usesLibraryFiles).contains(builtinLibPath(BUILTIN_LIB_NAME))
+
+ testPackageSetting = mExistingSettings[STATIC_LIB_PACKAGE_NAME]!!
+ assertThat(testPackageSetting.usesLibraryFiles).hasSize(2)
+ assertThat(testPackageSetting.usesLibraryFiles).contains(builtinLibPath(BUILTIN_LIB_NAME))
+ assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(DYNAMIC_LIB_PACKAGE_NAME))
+
+ testPackageSetting = mExistingSettings[CONSUMER_PACKAGE_NAME]!!
+ assertThat(testPackageSetting.usesLibraryFiles).hasSize(3)
+ assertThat(testPackageSetting.usesLibraryFiles).contains(builtinLibPath(BUILTIN_LIB_NAME))
+ assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(DYNAMIC_LIB_PACKAGE_NAME))
+ assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(STATIC_LIB_PACKAGE_NAME))
+ }
+
+ private fun addExistingPackages() {
+ // add a dynamic shared library that is using the builtin library
+ addPackage(DYNAMIC_LIB_PACKAGE_NAME, 1L,
+ libraries = arrayOf(DYNAMIC_LIB_NAME),
+ usesLibraries = arrayOf(BUILTIN_LIB_NAME))
+
+ // add a static shared library v7 that is using the dynamic shared library
+ addPackage(STATIC_LIB_PACKAGE_NAME, STATIC_LIB_VERSION,
+ staticLibrary = STATIC_LIB_NAME, staticLibraryVersion = STATIC_LIB_VERSION,
+ usesLibraries = arrayOf(DYNAMIC_LIB_NAME))
+
+ // add a consumer package that is using the dynamic and static shared library
+ addPackage(CONSUMER_PACKAGE_NAME, 1L,
+ usesLibraries = arrayOf(DYNAMIC_LIB_NAME),
+ usesStaticLibraries = arrayOf(STATIC_LIB_NAME),
+ usesStaticLibraryVersions = arrayOf(STATIC_LIB_VERSION))
+ }
+
+ private fun addExistingSharedLibraries() {
+ mSharedLibrariesImpl.addBuiltInSharedLibraryLPw(libEntry(BUILTIN_LIB_NAME))
+ mSharedLibrariesImpl.commitSharedLibraryInfoLPw(
+ libOfDynamic(DYNAMIC_LIB_PACKAGE_NAME, DYNAMIC_LIB_NAME))
+ mSharedLibrariesImpl.commitSharedLibraryInfoLPw(
+ libOfStatic(STATIC_LIB_PACKAGE_NAME, STATIC_LIB_NAME, STATIC_LIB_VERSION))
+ }
+
+ private fun addPackage(
+ packageName: String,
+ version: Long,
+ libraries: Array<String>? = null,
+ staticLibrary: String? = null,
+ staticLibraryVersion: Long = 0L,
+ usesLibraries: Array<String>? = null,
+ usesStaticLibraries: Array<String>? = null,
+ usesStaticLibraryVersions: Array<Long>? = null
+ ): PackageSetting {
+ val pair = createBasicAndroidPackage(packageName, version, libraries, staticLibrary,
+ staticLibraryVersion, usesLibraries, usesStaticLibraries, usesStaticLibraryVersions)
+ val apkPath = pair.first
+ val parsingPackage = pair.second
+ val spyPkg = spy((parsingPackage as ParsedPackage).hideAsFinal())
+ mExistingPackages[packageName] = spyPkg
+
+ val spyPackageSetting = spy(mRule.system()
+ .createBasicSettingBuilder(apkPath.parentFile, spyPkg).build())
+ mExistingSettings[spyPackageSetting.packageName] = spyPackageSetting
+
+ return spyPackageSetting
+ }
+
+ private fun createBasicAndroidPackage(
+ packageName: String,
+ version: Long,
+ libraries: Array<String>? = null,
+ staticLibrary: String? = null,
+ staticLibraryVersion: Long = 0L,
+ usesLibraries: Array<String>? = null,
+ usesStaticLibraries: Array<String>? = null,
+ usesStaticLibraryVersions: Array<Long>? = null
+ ): Pair<File, PackageImpl> {
+ assertFalse { libraries != null && staticLibrary != null }
+ assertTrue { (usesStaticLibraries?.size ?: -1) == (usesStaticLibraryVersions?.size ?: -1) }
+
+ val pair = mRule.system()
+ .createBasicAndroidPackage(mRule.system().dataAppDirectory, packageName, version)
+ pair.second.apply {
+ setTargetSdkVersion(Build.VERSION_CODES.S)
+ libraries?.forEach { addLibraryName(it) }
+ staticLibrary?.let {
+ setStaticSharedLibName(it)
+ setStaticSharedLibVersion(staticLibraryVersion)
+ setStaticSharedLibrary(true)
+ }
+ usesLibraries?.forEach { addUsesLibrary(it) }
+ usesStaticLibraries?.forEachIndexed { index, s ->
+ addUsesStaticLibrary(s,
+ usesStaticLibraryVersions?.get(index) ?: 0L,
+ arrayOf(s))
+ }
+ }
+ return pair
+ }
+
+ private fun libEntry(libName: String, path: String? = null): SharedLibraryEntry =
+ SharedLibraryEntry(libName, path ?: builtinLibPath(libName),
+ arrayOfNulls(0), false /* isNative */)
+
+ private fun libOfBuiltin(libName: String): SharedLibraryInfo =
+ SharedLibraryInfo(builtinLibPath(libName),
+ null /* packageName */,
+ null /* codePaths */,
+ libName,
+ VERSION_UNDEFINED,
+ SharedLibraryInfo.TYPE_BUILTIN,
+ VersionedPackage(PLATFORM_PACKAGE_NAME, 0L /* versionCode */),
+ null /* dependentPackages */,
+ null /* dependencies */,
+ false /* isNative */)
+
+ private fun libOfStatic(
+ packageName: String,
+ libName: String,
+ version: Long
+ ): SharedLibraryInfo =
+ SharedLibraryInfo(null /* path */,
+ packageName,
+ listOf(apkPath(packageName)),
+ libName,
+ version,
+ SharedLibraryInfo.TYPE_STATIC,
+ VersionedPackage(packageName, version /* versionCode */),
+ null /* dependentPackages */,
+ null /* dependencies */,
+ false /* isNative */)
+
+ private fun libOfDynamic(packageName: String, libName: String): SharedLibraryInfo =
+ SharedLibraryInfo(null /* path */,
+ packageName,
+ listOf(apkPath(packageName)),
+ libName,
+ VERSION_UNDEFINED,
+ SharedLibraryInfo.TYPE_DYNAMIC,
+ VersionedPackage(packageName, 1L /* versionCode */),
+ null /* dependentPackages */,
+ null /* dependencies */,
+ false /* isNative */)
+
+ private fun builtinLibPath(libName: String): String = "/system/app/$libName/$libName.jar"
+
+ private fun apkPath(packageName: String): String =
+ File(mRule.system().dataAppDirectory, packageName).path
+}