Merge "Query PlatformCompat for targetSdk check in AndroidPackageParsingTestBase" into rvc-dev am: b6eaf6ed79
Change-Id: I7fac2656e35ec1f71bc1ddc1052af6cb8525846d
This commit is contained in:
@@ -322,7 +322,12 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
|
|||||||
private String className;
|
private String className;
|
||||||
private int compatibleWidthLimitDp;
|
private int compatibleWidthLimitDp;
|
||||||
private int descriptionRes;
|
private int descriptionRes;
|
||||||
private boolean enabled;
|
|
||||||
|
// Usually there's code to set this to true during parsing, but it's possible to install an APK
|
||||||
|
// targeting <R that doesn't contain an <application> tag. That code would be skipped and never
|
||||||
|
// assign this, so initialize this to true for those cases.
|
||||||
|
private boolean enabled = true;
|
||||||
|
|
||||||
private boolean crossProfile;
|
private boolean crossProfile;
|
||||||
private int fullBackupContent;
|
private int fullBackupContent;
|
||||||
private int iconRes;
|
private int iconRes;
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ package com.android.server.pm.parsing
|
|||||||
|
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.platform.test.annotations.Presubmit
|
import android.platform.test.annotations.Presubmit
|
||||||
|
import com.google.common.truth.Expect
|
||||||
import com.google.common.truth.Truth.assertWithMessage
|
import com.google.common.truth.Truth.assertWithMessage
|
||||||
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,6 +30,9 @@ import org.junit.Test
|
|||||||
@Presubmit
|
@Presubmit
|
||||||
class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
|
class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val expect = Expect.create()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun applicationInfoEquality() {
|
fun applicationInfoEquality() {
|
||||||
val flags = PackageManager.GET_META_DATA or PackageManager.GET_SHARED_LIBRARY_FILES
|
val flags = PackageManager.GET_META_DATA or PackageManager.GET_SHARED_LIBRARY_FILES
|
||||||
@@ -41,7 +46,8 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
|
|||||||
} else {
|
} else {
|
||||||
"$firstName | $secondName"
|
"$firstName | $secondName"
|
||||||
}
|
}
|
||||||
assertWithMessage(packageName).that(it.first?.dumpToString())
|
expect.withMessage("${it.first?.sourceDir} $packageName")
|
||||||
|
.that(it.first?.dumpToString())
|
||||||
.isEqualTo(it.second?.dumpToString())
|
.isEqualTo(it.second?.dumpToString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,7 +77,8 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
|
|||||||
} else {
|
} else {
|
||||||
"$firstName | $secondName"
|
"$firstName | $secondName"
|
||||||
}
|
}
|
||||||
assertWithMessage(packageName).that(it.first?.dumpToString())
|
expect.withMessage("${it.first?.applicationInfo?.sourceDir} $packageName")
|
||||||
|
.that(it.first?.dumpToString())
|
||||||
.isEqualTo(it.second?.dumpToString())
|
.isEqualTo(it.second?.dumpToString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,14 +29,17 @@ import android.content.pm.PermissionInfo
|
|||||||
import android.content.pm.ProviderInfo
|
import android.content.pm.ProviderInfo
|
||||||
import android.os.Debug
|
import android.os.Debug
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
|
import android.os.ServiceManager
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import com.android.internal.compat.IPlatformCompat
|
||||||
import com.android.server.pm.PackageManagerService
|
import com.android.server.pm.PackageManagerService
|
||||||
import com.android.server.pm.PackageSetting
|
import com.android.server.pm.PackageSetting
|
||||||
import com.android.server.pm.parsing.pkg.AndroidPackage
|
import com.android.server.pm.parsing.pkg.AndroidPackage
|
||||||
import com.android.server.pm.pkg.PackageStateUnserialized
|
import com.android.server.pm.pkg.PackageStateUnserialized
|
||||||
import com.android.server.testutils.mockThrowOnUnmocked
|
import com.android.server.testutils.mockThrowOnUnmocked
|
||||||
import com.android.server.testutils.whenever
|
import com.android.server.testutils.whenever
|
||||||
|
import org.junit.After
|
||||||
import org.junit.BeforeClass
|
import org.junit.BeforeClass
|
||||||
import org.mockito.Mockito
|
import org.mockito.Mockito
|
||||||
import org.mockito.Mockito.anyInt
|
import org.mockito.Mockito.anyInt
|
||||||
@@ -59,7 +62,27 @@ open class AndroidPackageParsingTestBase {
|
|||||||
setCallback { false /* hasFeature */ }
|
setCallback { false /* hasFeature */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected val packageParser2 = TestPackageParser2()
|
private val platformCompat = IPlatformCompat.Stub
|
||||||
|
.asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE))
|
||||||
|
|
||||||
|
protected val packageParser2 = PackageParser2(null /* separateProcesses */,
|
||||||
|
false /* onlyCoreApps */, context.resources.displayMetrics, null /* cacheDir */,
|
||||||
|
object : PackageParser2.Callback() {
|
||||||
|
override fun isChangeEnabled(
|
||||||
|
changeId: Long,
|
||||||
|
appInfo: ApplicationInfo
|
||||||
|
): Boolean {
|
||||||
|
// This test queries PlatformCompat because prebuilts in the tree
|
||||||
|
// may not be updated to be compliant with the latest enforcement checks.
|
||||||
|
return platformCompat.isChangeEnabled(changeId, appInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume the device doesn't support anything. This will affect permission
|
||||||
|
// parsing and will force <uses-permission/> declarations to include all
|
||||||
|
// requiredNotFeature permissions and exclude all requiredFeature permissions.
|
||||||
|
// This mirrors the old behavior.
|
||||||
|
override fun hasFeature(feature: String) = false
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It would be difficult to mock all possibilities, so just use the APKs on device.
|
* It would be difficult to mock all possibilities, so just use the APKs on device.
|
||||||
@@ -91,35 +114,31 @@ open class AndroidPackageParsingTestBase {
|
|||||||
|
|
||||||
lateinit var newPackages: List<AndroidPackage>
|
lateinit var newPackages: List<AndroidPackage>
|
||||||
|
|
||||||
var failureInBeforeClass: Throwable? = null
|
private val thrownInSetUp = mutableListOf<Throwable>()
|
||||||
|
|
||||||
@Suppress("ConstantConditionIf")
|
@Suppress("ConstantConditionIf")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
fun setUpPackages() {
|
fun setUpPackages() {
|
||||||
failureInBeforeClass = null
|
this.oldPackages = apks.mapNotNull {
|
||||||
try {
|
tryOrNull {
|
||||||
this.oldPackages = apks.map {
|
|
||||||
packageParser.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
|
packageParser.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.newPackages = apks.map {
|
this.newPackages = apks.mapNotNull {
|
||||||
|
tryOrNull {
|
||||||
packageParser2.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
|
packageParser2.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (DUMP_HPROF_TO_EXTERNAL) {
|
if (DUMP_HPROF_TO_EXTERNAL) {
|
||||||
System.gc()
|
System.gc()
|
||||||
Environment.getExternalStorageDirectory()
|
Environment.getExternalStorageDirectory()
|
||||||
.resolve(
|
.resolve(
|
||||||
"${AndroidPackageParsingTestBase::class.java.simpleName}.hprof")
|
"${AndroidPackageParsingTestBase::class.java.simpleName}.hprof")
|
||||||
.absolutePath
|
.absolutePath
|
||||||
.run(Debug::dumpHprofData)
|
.run(Debug::dumpHprofData)
|
||||||
}
|
|
||||||
} catch (t: Throwable) {
|
|
||||||
// If we crash here we cause a tool failure (because we don't run any of the tests
|
|
||||||
// in the subclasses, leading to a difference between expected and actual test
|
|
||||||
// result counts).
|
|
||||||
failureInBeforeClass = t
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,13 +165,36 @@ open class AndroidPackageParsingTestBase {
|
|||||||
this.pkg = aPkg
|
this.pkg = aPkg
|
||||||
whenever(pkgState) { PackageStateUnserialized() }
|
whenever(pkgState) { PackageStateUnserialized() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun <T> tryOrNull(block: () -> T) = try {
|
||||||
|
block()
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
thrownInSetUp.add(t)
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@org.junit.Before
|
@After
|
||||||
fun verifySetUpPackages() {
|
fun verifySetUpPackages() {
|
||||||
failureInBeforeClass?.let {
|
if (thrownInSetUp.isEmpty()) return
|
||||||
throw AssertionError("setUpPackages failed:", it)
|
val exception = AssertionError("setUpPackages failed with ${thrownInSetUp.size} errors:\n" +
|
||||||
}
|
thrownInSetUp.joinToString(separator = "\n") { it.message.orEmpty() })
|
||||||
|
|
||||||
|
/*
|
||||||
|
Testing infrastructure doesn't currently support errors thrown in @AfterClass,
|
||||||
|
so instead it's thrown here. But to avoid throwing a massive repeated stack for every
|
||||||
|
test method, only throw on the first method run in the class, clearing the list so that
|
||||||
|
subsequent methods can run without failing. Doing this in @After lets true method
|
||||||
|
failures propagate, as those should throw before this does.
|
||||||
|
|
||||||
|
This will cause the failure to be attached to a different method depending on run order,
|
||||||
|
which could make comparisons difficult. So if a failure points here, it's worth
|
||||||
|
checking failures for all methods in all subclasses.
|
||||||
|
|
||||||
|
TODO: When infrastructure supports @AfterClass errors, move this
|
||||||
|
*/
|
||||||
|
thrownInSetUp.clear()
|
||||||
|
throw exception
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following methods dump an exact set of fields from the object to compare, because
|
// The following methods dump an exact set of fields from the object to compare, because
|
||||||
|
|||||||
Reference in New Issue
Block a user