Fix up discrepancies between v1 and v2 package parsing
For Activity aliases, it's possible some values are already set, which means they cannot be assumed to be 0, and can't be overwritten if a attribute in the alias is undefined. For the parsing v2 refactor, this was cleaned up to avoid redundant != 0 checks, but those checks are indeed necessary. This copies over the old logic and uses it exactly. In some future cleanup, there should be a more structured way of doing this, since it's not immediately obvious which values are overridden or not. For example, description is always overwritten even if no new value is provided in the alias. This also fixes up the comparison tests and other bugs that popped up because of them. The core issue was that when auto-generating the dumpToString methods, the Alt+Insert macro default selects all the fields in the current class, but not all the parent classes, so some shared fields like name/icon were not considered. A notable case that was found when running the comparison tests is that persistableMode is now "fixed" with v2. Previously, a bug in PackageParser caused this value to be dropped if the ActivityInfo object ever had to be copied. This is a change from Q behavior, but there's no good way to reconcile this, and it's better to be correct and consistent than broken, so this fix was left in and excluded from the comparison tests. Bug: 150106908 Test: manual run through steps in bug Test: atest com.android.server.pm.parsing Merged-In: I1301e28540314d0e643b73af7146c1a366eca6b5 Change-Id: I1301e28540314d0e643b73af7146c1a366eca6b5
This commit is contained in:
@@ -302,7 +302,14 @@ public class ParsedActivityUtils {
|
||||
}
|
||||
|
||||
String permission = array.getNonConfigurationString(permissionAttr, 0);
|
||||
activity.setPermission(permission != null ? permission : pkg.getPermission());
|
||||
if (isAlias) {
|
||||
// An alias will override permissions to allow referencing an Activity through its alias
|
||||
// without needing the original permission. If an alias needs the same permission,
|
||||
// it must be re-declared.
|
||||
activity.setPermission(permission);
|
||||
} else {
|
||||
activity.setPermission(permission != null ? permission : pkg.getPermission());
|
||||
}
|
||||
|
||||
final boolean setExported = array.hasValue(exportedAttr);
|
||||
if (setExported) {
|
||||
|
||||
@@ -20,7 +20,10 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.parsing.ParsingPackage;
|
||||
import android.content.pm.parsing.ParsingPackageUtils;
|
||||
import android.content.pm.parsing.ParsingUtils;
|
||||
import android.content.pm.parsing.result.ParseInput;
|
||||
import android.content.pm.parsing.result.ParseResult;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
@@ -29,9 +32,6 @@ import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import android.content.pm.parsing.ParsingPackageUtils;
|
||||
import android.content.pm.parsing.result.ParseInput;
|
||||
import android.content.pm.parsing.result.ParseResult;
|
||||
|
||||
/** @hide */
|
||||
class ParsedComponentUtils {
|
||||
@@ -60,16 +60,27 @@ class ParsedComponentUtils {
|
||||
component.setName(className);
|
||||
component.setPackageName(packageName);
|
||||
|
||||
if (useRoundIcon) {
|
||||
component.icon = array.getResourceId(roundIconAttr, 0);
|
||||
int roundIconVal = useRoundIcon ? array.getResourceId(roundIconAttr, 0) : 0;
|
||||
if (roundIconVal != 0) {
|
||||
component.icon = roundIconVal;
|
||||
component.nonLocalizedLabel = null;
|
||||
} else {
|
||||
int iconVal = array.getResourceId(iconAttr, 0);
|
||||
if (iconVal != 0) {
|
||||
component.icon = iconVal;
|
||||
component.nonLocalizedLabel = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (component.icon == 0) {
|
||||
component.icon = array.getResourceId(iconAttr, 0);
|
||||
int logoVal = array.getResourceId(logoAttr, 0);
|
||||
if (logoVal != 0) {
|
||||
component.logo = logoVal;
|
||||
}
|
||||
|
||||
component.logo = array.getResourceId(logoAttr, 0);
|
||||
component.banner = array.getResourceId(bannerAttr, 0);
|
||||
int bannerVal = array.getResourceId(bannerAttr, 0);
|
||||
if (bannerVal != 0) {
|
||||
component.banner = bannerVal;
|
||||
}
|
||||
|
||||
if (descriptionAttr != null) {
|
||||
component.descriptionRes = array.getResourceId(descriptionAttr, 0);
|
||||
|
||||
@@ -18,8 +18,8 @@ package com.android.server.pm.parsing
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import android.platform.test.annotations.Presubmit
|
||||
import androidx.test.filters.LargeTest
|
||||
import com.google.common.truth.Expect
|
||||
import com.google.common.truth.Truth.assertWithMessage
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
@@ -52,6 +52,7 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
|
||||
}
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
@Test
|
||||
fun packageInfoEquality() {
|
||||
val flags = PackageManager.GET_ACTIVITIES or
|
||||
@@ -65,7 +66,9 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
|
||||
PackageManager.GET_SERVICES or
|
||||
PackageManager.GET_SHARED_LIBRARY_FILES or
|
||||
PackageManager.GET_SIGNATURES or
|
||||
PackageManager.GET_SIGNING_CERTIFICATES
|
||||
PackageManager.GET_SIGNING_CERTIFICATES or
|
||||
PackageManager.MATCH_DIRECT_BOOT_UNAWARE or
|
||||
PackageManager.MATCH_DIRECT_BOOT_AWARE
|
||||
val oldPackageInfo = oldPackages.asSequence().map { oldPackageInfo(it, flags) }
|
||||
val newPackageInfo = newPackages.asSequence().map { newPackageInfo(it, flags) }
|
||||
|
||||
@@ -77,11 +80,79 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
|
||||
} else {
|
||||
"$firstName | $secondName"
|
||||
}
|
||||
expect.withMessage("${it.first?.applicationInfo?.sourceDir} $packageName")
|
||||
.that(it.first?.dumpToString())
|
||||
.isEqualTo(it.second?.dumpToString())
|
||||
|
||||
// Main components are asserted independently to separate the failures. Otherwise the
|
||||
// comparison would include every component in one massive string.
|
||||
|
||||
val prefix = "${it.first?.applicationInfo?.sourceDir} $packageName"
|
||||
|
||||
expect.withMessage("$prefix PackageInfo")
|
||||
.that(it.second?.dumpToString())
|
||||
.isEqualTo(it.first?.dumpToString())
|
||||
|
||||
expect.withMessage("$prefix ApplicationInfo")
|
||||
.that(it.second?.applicationInfo?.dumpToString())
|
||||
.isEqualTo(it.first?.applicationInfo?.dumpToString())
|
||||
|
||||
val firstActivityNames = it.first?.activities?.map { it.name } ?: emptyList()
|
||||
val secondActivityNames = it.second?.activities?.map { it.name } ?: emptyList()
|
||||
expect.withMessage("$prefix activities")
|
||||
.that(secondActivityNames)
|
||||
.containsExactlyElementsIn(firstActivityNames)
|
||||
.inOrder()
|
||||
|
||||
if (!it.first?.activities.isNullOrEmpty() && !it.second?.activities.isNullOrEmpty()) {
|
||||
it.first?.activities?.zip(it.second?.activities!!)?.forEach {
|
||||
expect.withMessage("$prefix ${it.first.name}")
|
||||
.that(it.second.dumpToString())
|
||||
.isEqualTo(it.first.dumpToString())
|
||||
}
|
||||
}
|
||||
|
||||
val firstReceiverNames = it.first?.receivers?.map { it.name } ?: emptyList()
|
||||
val secondReceiverNames = it.second?.receivers?.map { it.name } ?: emptyList()
|
||||
expect.withMessage("$prefix receivers")
|
||||
.that(secondReceiverNames)
|
||||
.containsExactlyElementsIn(firstReceiverNames)
|
||||
.inOrder()
|
||||
|
||||
if (!it.first?.receivers.isNullOrEmpty() && !it.second?.receivers.isNullOrEmpty()) {
|
||||
it.first?.receivers?.zip(it.second?.receivers!!)?.forEach {
|
||||
expect.withMessage("$prefix ${it.first.name}")
|
||||
.that(it.second.dumpToString())
|
||||
.isEqualTo(it.first.dumpToString())
|
||||
}
|
||||
}
|
||||
|
||||
val firstProviderNames = it.first?.providers?.map { it.name } ?: emptyList()
|
||||
val secondProviderNames = it.second?.providers?.map { it.name } ?: emptyList()
|
||||
expect.withMessage("$prefix providers")
|
||||
.that(secondProviderNames)
|
||||
.containsExactlyElementsIn(firstProviderNames)
|
||||
.inOrder()
|
||||
|
||||
if (!it.first?.providers.isNullOrEmpty() && !it.second?.providers.isNullOrEmpty()) {
|
||||
it.first?.providers?.zip(it.second?.providers!!)?.forEach {
|
||||
expect.withMessage("$prefix ${it.first.name}")
|
||||
.that(it.second.dumpToString())
|
||||
.isEqualTo(it.first.dumpToString())
|
||||
}
|
||||
}
|
||||
|
||||
val firstServiceNames = it.first?.services?.map { it.name } ?: emptyList()
|
||||
val secondServiceNames = it.second?.services?.map { it.name } ?: emptyList()
|
||||
expect.withMessage("$prefix services")
|
||||
.that(secondServiceNames)
|
||||
.containsExactlyElementsIn(firstServiceNames)
|
||||
.inOrder()
|
||||
|
||||
if (!it.first?.services.isNullOrEmpty() && !it.second?.services.isNullOrEmpty()) {
|
||||
it.first?.services?.zip(it.second?.services!!)?.forEach {
|
||||
expect.withMessage("$prefix ${it.first.name}")
|
||||
.that(it.second.dumpToString())
|
||||
.isEqualTo(it.first.dumpToString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.server.pm.parsing
|
||||
import android.content.Context
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.ComponentInfo
|
||||
import android.content.pm.ConfigurationInfo
|
||||
import android.content.pm.FeatureInfo
|
||||
import android.content.pm.InstrumentationInfo
|
||||
@@ -27,6 +28,8 @@ import android.content.pm.PackageParser
|
||||
import android.content.pm.PackageUserState
|
||||
import android.content.pm.PermissionInfo
|
||||
import android.content.pm.ProviderInfo
|
||||
import android.content.pm.ServiceInfo
|
||||
import android.os.Bundle
|
||||
import android.os.Debug
|
||||
import android.os.Environment
|
||||
import android.util.SparseArray
|
||||
@@ -38,8 +41,10 @@ import com.android.server.pm.pkg.PackageStateUnserialized
|
||||
import com.android.server.testutils.mockThrowOnUnmocked
|
||||
import com.android.server.testutils.whenever
|
||||
import org.junit.BeforeClass
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.anyBoolean
|
||||
import org.mockito.Mockito.anyInt
|
||||
import org.mockito.Mockito.anyString
|
||||
import org.mockito.Mockito.mock
|
||||
import java.io.File
|
||||
|
||||
@@ -47,7 +52,7 @@ open class AndroidPackageParsingTestBase {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val VERIFY_ALL_APKS = false
|
||||
private const val VERIFY_ALL_APKS = true
|
||||
|
||||
/** For auditing memory usage differences */
|
||||
private const val DUMP_HPROF_TO_EXTERNAL = false
|
||||
@@ -81,10 +86,14 @@ open class AndroidPackageParsingTestBase {
|
||||
.filter { file -> file.name.endsWith(".apk") }
|
||||
.toList()
|
||||
}
|
||||
.distinct()
|
||||
|
||||
private val dummyUserState = mock(PackageUserState::class.java).apply {
|
||||
installed = true
|
||||
Mockito.`when`(isAvailable(anyInt())).thenReturn(true)
|
||||
whenever(isAvailable(anyInt())) { true }
|
||||
whenever(isMatch(any<ComponentInfo>(), anyInt())) { true }
|
||||
whenever(isMatch(anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(),
|
||||
anyString(), anyInt())) { true }
|
||||
}
|
||||
|
||||
lateinit var oldPackages: List<PackageParser.Package>
|
||||
@@ -145,6 +154,7 @@ open class AndroidPackageParsingTestBase {
|
||||
private fun mockPkgSetting(aPkg: AndroidPackage) = mockThrowOnUnmocked<PackageSetting> {
|
||||
this.pkg = aPkg
|
||||
whenever(pkgState) { PackageStateUnserialized() }
|
||||
whenever(readUserState(anyInt())) { dummyUserState }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,19 +166,10 @@ open class AndroidPackageParsingTestBase {
|
||||
// The following methods prepend "this." because @hide APIs can cause an IDE to auto-import
|
||||
// the R.attr constant instead of referencing the field in an attempt to fix the error.
|
||||
|
||||
/**
|
||||
* Known exclusions:
|
||||
* - [ApplicationInfo.credentialProtectedDataDir]
|
||||
* - [ApplicationInfo.dataDir]
|
||||
* - [ApplicationInfo.deviceProtectedDataDir]
|
||||
* - [ApplicationInfo.processName]
|
||||
* - [ApplicationInfo.publicSourceDir]
|
||||
* - [ApplicationInfo.scanPublicSourceDir]
|
||||
* - [ApplicationInfo.scanSourceDir]
|
||||
* - [ApplicationInfo.sourceDir]
|
||||
* These attributes used to be assigned post-package-parsing as part of another component,
|
||||
* but are now adjusted directly inside [PackageImpl].
|
||||
*/
|
||||
// It's difficult to comment out a line in a triple quoted string, so this is used instead
|
||||
// to ignore specific fields. A comment is required to explain why a field was ignored.
|
||||
private fun Any?.ignored(comment: String): String = "IGNORED"
|
||||
|
||||
protected fun ApplicationInfo.dumpToString() = """
|
||||
appComponentFactory=${this.appComponentFactory}
|
||||
backupAgentName=${this.backupAgentName}
|
||||
@@ -179,22 +180,31 @@ open class AndroidPackageParsingTestBase {
|
||||
compatibleWidthLimitDp=${this.compatibleWidthLimitDp}
|
||||
compileSdkVersion=${this.compileSdkVersion}
|
||||
compileSdkVersionCodename=${this.compileSdkVersionCodename}
|
||||
credentialProtectedDataDir=${this.credentialProtectedDataDir
|
||||
.ignored("Deferred pre-R, but assigned immediately in R")}
|
||||
crossProfile=${this.crossProfile.ignored("Added in R")}
|
||||
dataDir=${this.dataDir.ignored("Deferred pre-R, but assigned immediately in R")}
|
||||
descriptionRes=${this.descriptionRes}
|
||||
deviceProtectedDataDir=${this.deviceProtectedDataDir
|
||||
.ignored("Deferred pre-R, but assigned immediately in R")}
|
||||
enabled=${this.enabled}
|
||||
enabledSetting=${this.enabledSetting}
|
||||
flags=${Integer.toBinaryString(this.flags)}
|
||||
fullBackupContent=${this.fullBackupContent}
|
||||
gwpAsanMode=${this.gwpAsanMode.ignored("Added in R")}
|
||||
hiddenUntilInstalled=${this.hiddenUntilInstalled}
|
||||
icon=${this.icon}
|
||||
iconRes=${this.iconRes}
|
||||
installLocation=${this.installLocation}
|
||||
labelRes=${this.labelRes}
|
||||
largestWidthLimitDp=${this.largestWidthLimitDp}
|
||||
logo=${this.logo}
|
||||
longVersionCode=${this.longVersionCode}
|
||||
${"".ignored("mHiddenApiPolicy is a private field")}
|
||||
manageSpaceActivityName=${this.manageSpaceActivityName}
|
||||
maxAspectRatio.compareTo(that.maxAspectRatio)=${this.maxAspectRatio}
|
||||
metaData=${this.metaData}
|
||||
minAspectRatio.compareTo(that.minAspectRatio)=${this.minAspectRatio}
|
||||
maxAspectRatio=${this.maxAspectRatio}
|
||||
metaData=${this.metaData.dumpToString()}
|
||||
minAspectRatio=${this.minAspectRatio}
|
||||
minSdkVersion=${this.minSdkVersion}
|
||||
name=${this.name}
|
||||
nativeLibraryDir=${this.nativeLibraryDir}
|
||||
@@ -206,18 +216,27 @@ open class AndroidPackageParsingTestBase {
|
||||
permission=${this.permission}
|
||||
primaryCpuAbi=${this.primaryCpuAbi}
|
||||
privateFlags=${Integer.toBinaryString(this.privateFlags)}
|
||||
processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
|
||||
publicSourceDir=${this.publicSourceDir
|
||||
.ignored("Deferred pre-R, but assigned immediately in R")}
|
||||
requiresSmallestWidthDp=${this.requiresSmallestWidthDp}
|
||||
resourceDirs=${this.resourceDirs?.contentToString()}
|
||||
roundIconRes=${this.roundIconRes}
|
||||
secondaryCpuAbi=${this.secondaryCpuAbi}
|
||||
secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
|
||||
scanPublicSourceDir=${this.scanPublicSourceDir
|
||||
.ignored("Deferred pre-R, but assigned immediately in R")}
|
||||
scanSourceDir=${this.scanSourceDir
|
||||
.ignored("Deferred pre-R, but assigned immediately in R")}
|
||||
seInfo=${this.seInfo}
|
||||
seInfoUser=${this.seInfoUser}
|
||||
secondaryCpuAbi=${this.secondaryCpuAbi}
|
||||
secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
|
||||
sharedLibraryFiles=${this.sharedLibraryFiles?.contentToString()}
|
||||
sharedLibraryInfos=${this.sharedLibraryInfos}
|
||||
showUserIcon=${this.showUserIcon}
|
||||
sourceDir=${this.sourceDir
|
||||
.ignored("Deferred pre-R, but assigned immediately in R")}
|
||||
splitClassLoaderNames=${this.splitClassLoaderNames?.contentToString()}
|
||||
splitDependencies=${this.splitDependencies}
|
||||
splitDependencies=${this.splitDependencies.dumpToString()}
|
||||
splitNames=${this.splitNames?.contentToString()}
|
||||
splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
|
||||
splitSourceDirs=${this.splitSourceDirs?.contentToString()}
|
||||
@@ -226,8 +245,8 @@ open class AndroidPackageParsingTestBase {
|
||||
targetSdkVersion=${this.targetSdkVersion}
|
||||
taskAffinity=${this.taskAffinity}
|
||||
theme=${this.theme}
|
||||
uid=${this.uid}
|
||||
uiOptions=${this.uiOptions}
|
||||
uid=${this.uid}
|
||||
versionCode=${this.versionCode}
|
||||
volumeUuid=${this.volumeUuid}
|
||||
zygotePreloadName=${this.zygotePreloadName}
|
||||
@@ -241,19 +260,27 @@ open class AndroidPackageParsingTestBase {
|
||||
""".trimIndent()
|
||||
|
||||
protected fun InstrumentationInfo.dumpToString() = """
|
||||
banner=${this.banner}
|
||||
credentialProtectedDataDir=${this.credentialProtectedDataDir}
|
||||
dataDir=${this.dataDir}
|
||||
deviceProtectedDataDir=${this.deviceProtectedDataDir}
|
||||
functionalTest=${this.functionalTest}
|
||||
handleProfiling=${this.handleProfiling}
|
||||
icon=${this.icon}
|
||||
labelRes=${this.labelRes}
|
||||
logo=${this.logo}
|
||||
metaData=${this.metaData}
|
||||
name=${this.name}
|
||||
nativeLibraryDir=${this.nativeLibraryDir}
|
||||
nonLocalizedLabel=${this.nonLocalizedLabel}
|
||||
packageName=${this.packageName}
|
||||
primaryCpuAbi=${this.primaryCpuAbi}
|
||||
publicSourceDir=${this.publicSourceDir}
|
||||
secondaryCpuAbi=${this.secondaryCpuAbi}
|
||||
secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
|
||||
showUserIcon=${this.showUserIcon}
|
||||
sourceDir=${this.sourceDir}
|
||||
splitDependencies=${this.splitDependencies.sequence()
|
||||
.map { it.first to it.second?.contentToString() }.joinToString()}
|
||||
splitDependencies=${this.splitDependencies.dumpToString()}
|
||||
splitNames=${this.splitNames?.contentToString()}
|
||||
splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
|
||||
splitSourceDirs=${this.splitSourceDirs?.contentToString()}
|
||||
@@ -262,25 +289,40 @@ open class AndroidPackageParsingTestBase {
|
||||
""".trimIndent()
|
||||
|
||||
protected fun ActivityInfo.dumpToString() = """
|
||||
banner=${this.banner}
|
||||
colorMode=${this.colorMode}
|
||||
configChanges=${this.configChanges}
|
||||
descriptionRes=${this.descriptionRes}
|
||||
directBootAware=${this.directBootAware}
|
||||
documentLaunchMode=${this.documentLaunchMode}
|
||||
enabled=${this.enabled}
|
||||
exported=${this.exported}
|
||||
flags=${Integer.toBinaryString(this.flags)}
|
||||
icon=${this.icon}
|
||||
labelRes=${this.labelRes}
|
||||
launchMode=${this.launchMode}
|
||||
launchToken=${this.launchToken}
|
||||
lockTaskLaunchMode=${this.lockTaskLaunchMode}
|
||||
logo=${this.logo}
|
||||
maxAspectRatio=${this.maxAspectRatio}
|
||||
maxRecents=${this.maxRecents}
|
||||
metaData=${this.metaData.dumpToString()}
|
||||
minAspectRatio=${this.minAspectRatio}
|
||||
name=${this.name}
|
||||
nonLocalizedLabel=${this.nonLocalizedLabel}
|
||||
packageName=${this.packageName}
|
||||
parentActivityName=${this.parentActivityName}
|
||||
permission=${this.permission}
|
||||
persistableMode=${this.persistableMode}
|
||||
privateFlags=${Integer.toBinaryString(this.privateFlags)}
|
||||
persistableMode=${this.persistableMode.ignored("Could be dropped pre-R, fixed in R")}
|
||||
privateFlags=${this.privateFlags}
|
||||
processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
|
||||
requestedVrComponent=${this.requestedVrComponent}
|
||||
resizeMode=${this.resizeMode}
|
||||
rotationAnimation=${this.rotationAnimation}
|
||||
screenOrientation=${this.screenOrientation}
|
||||
showUserIcon=${this.showUserIcon}
|
||||
softInputMode=${this.softInputMode}
|
||||
splitName=${this.splitName}
|
||||
targetActivity=${this.targetActivity}
|
||||
taskAffinity=${this.taskAffinity}
|
||||
theme=${this.theme}
|
||||
@@ -300,30 +342,77 @@ open class AndroidPackageParsingTestBase {
|
||||
|
||||
protected fun PermissionInfo.dumpToString() = """
|
||||
backgroundPermission=${this.backgroundPermission}
|
||||
banner=${this.banner}
|
||||
descriptionRes=${this.descriptionRes}
|
||||
flags=${Integer.toBinaryString(this.flags)}
|
||||
group=${this.group}
|
||||
icon=${this.icon}
|
||||
labelRes=${this.labelRes}
|
||||
logo=${this.logo}
|
||||
metaData=${this.metaData.dumpToString()}
|
||||
name=${this.name}
|
||||
nonLocalizedDescription=${this.nonLocalizedDescription}
|
||||
nonLocalizedLabel=${this.nonLocalizedLabel}
|
||||
packageName=${this.packageName}
|
||||
protectionLevel=${this.protectionLevel}
|
||||
requestRes=${this.requestRes}
|
||||
showUserIcon=${this.showUserIcon}
|
||||
""".trimIndent()
|
||||
|
||||
protected fun ProviderInfo.dumpToString() = """
|
||||
applicationInfo=${this.applicationInfo.ignored("Already checked")}
|
||||
authority=${this.authority}
|
||||
banner=${this.banner}
|
||||
descriptionRes=${this.descriptionRes}
|
||||
directBootAware=${this.directBootAware}
|
||||
enabled=${this.enabled}
|
||||
exported=${this.exported}
|
||||
flags=${Integer.toBinaryString(this.flags)}
|
||||
forceUriPermissions=${this.forceUriPermissions}
|
||||
grantUriPermissions=${this.grantUriPermissions}
|
||||
icon=${this.icon}
|
||||
initOrder=${this.initOrder}
|
||||
isSyncable=${this.isSyncable}
|
||||
labelRes=${this.labelRes}
|
||||
logo=${this.logo}
|
||||
metaData=${this.metaData.dumpToString()}
|
||||
multiprocess=${this.multiprocess}
|
||||
name=${this.name}
|
||||
nonLocalizedLabel=${this.nonLocalizedLabel}
|
||||
packageName=${this.packageName}
|
||||
pathPermissions=${this.pathPermissions?.joinToString {
|
||||
"readPermission=${it.readPermission}\nwritePermission=${it.writePermission}"
|
||||
}}
|
||||
processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
|
||||
readPermission=${this.readPermission}
|
||||
showUserIcon=${this.showUserIcon}
|
||||
splitName=${this.splitName}
|
||||
uriPermissionPatterns=${this.uriPermissionPatterns?.contentToString()}
|
||||
writePermission=${this.writePermission}
|
||||
""".trimIndent()
|
||||
|
||||
protected fun ServiceInfo.dumpToString() = """
|
||||
applicationInfo=${this.applicationInfo.ignored("Already checked")}
|
||||
banner=${this.banner}
|
||||
descriptionRes=${this.descriptionRes}
|
||||
directBootAware=${this.directBootAware}
|
||||
enabled=${this.enabled}
|
||||
exported=${this.exported}
|
||||
flags=${Integer.toBinaryString(this.flags)}
|
||||
icon=${this.icon}
|
||||
labelRes=${this.labelRes}
|
||||
logo=${this.logo}
|
||||
mForegroundServiceType"${this.mForegroundServiceType}
|
||||
metaData=${this.metaData.dumpToString()}
|
||||
name=${this.name}
|
||||
nonLocalizedLabel=${this.nonLocalizedLabel}
|
||||
packageName=${this.packageName}
|
||||
permission=${this.permission}
|
||||
processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
|
||||
showUserIcon=${this.showUserIcon}
|
||||
splitName=${this.splitName}
|
||||
""".trimIndent()
|
||||
|
||||
protected fun ConfigurationInfo.dumpToString() = """
|
||||
reqGlEsVersion=${this.reqGlEsVersion}
|
||||
reqInputFeatures=${this.reqInputFeatures}
|
||||
@@ -333,8 +422,10 @@ open class AndroidPackageParsingTestBase {
|
||||
""".trimIndent()
|
||||
|
||||
protected fun PackageInfo.dumpToString() = """
|
||||
activities=${this.activities?.joinToString { it.dumpToString() }}
|
||||
applicationInfo=${this.applicationInfo.dumpToString()}
|
||||
activities=${this.activities?.joinToString { it.dumpToString() }
|
||||
.ignored("Checked separately in test")}
|
||||
applicationInfo=${this.applicationInfo.dumpToString()
|
||||
.ignored("Checked separately in test")}
|
||||
baseRevisionCode=${this.baseRevisionCode}
|
||||
compileSdkVersion=${this.compileSdkVersion}
|
||||
compileSdkVersionCodename=${this.compileSdkVersionCodename}
|
||||
@@ -356,15 +447,18 @@ open class AndroidPackageParsingTestBase {
|
||||
overlayTarget=${this.overlayTarget}
|
||||
packageName=${this.packageName}
|
||||
permissions=${this.permissions?.joinToString { it.dumpToString() }}
|
||||
providers=${this.providers?.joinToString { it.dumpToString() }}
|
||||
receivers=${this.receivers?.joinToString { it.dumpToString() }}
|
||||
providers=${this.providers?.joinToString { it.dumpToString() }
|
||||
.ignored("Checked separately in test")}
|
||||
receivers=${this.receivers?.joinToString { it.dumpToString() }
|
||||
.ignored("Checked separately in test")}
|
||||
reqFeatures=${this.reqFeatures?.joinToString { it.dumpToString() }}
|
||||
requestedPermissions=${this.requestedPermissions?.contentToString()}
|
||||
requestedPermissionsFlags=${this.requestedPermissionsFlags?.contentToString()}
|
||||
requiredAccountType=${this.requiredAccountType}
|
||||
requiredForAllUsers=${this.requiredForAllUsers}
|
||||
restrictedAccountType=${this.restrictedAccountType}
|
||||
services=${this.services?.contentToString()}
|
||||
services=${this.services?.joinToString { it.dumpToString() }
|
||||
.ignored("Checked separately in test")}
|
||||
sharedUserId=${this.sharedUserId}
|
||||
sharedUserLabel=${this.sharedUserLabel}
|
||||
signatures=${this.signatures?.joinToString { it.toCharsString() }}
|
||||
@@ -378,11 +472,17 @@ open class AndroidPackageParsingTestBase {
|
||||
versionName=${this.versionName}
|
||||
""".trimIndent()
|
||||
|
||||
@Suppress("unused")
|
||||
private fun <T> SparseArray<T>.sequence(): Sequence<Pair<Int, T>> {
|
||||
var index = 0
|
||||
return generateSequence {
|
||||
index++.takeIf { it < size() }?.let { keyAt(it) to valueAt(index) }
|
||||
private fun Bundle?.dumpToString() = this?.keySet()?.associateWith { get(it) }?.toString()
|
||||
|
||||
private fun <T> SparseArray<T>?.dumpToString(): String {
|
||||
if (this == null) {
|
||||
return "EMPTY"
|
||||
}
|
||||
|
||||
val list = mutableListOf<Pair<Int, T>>()
|
||||
for (index in (0 until size())) {
|
||||
list += keyAt(index) to valueAt(index)
|
||||
}
|
||||
return list.toString()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user