Loading core/java/android/content/pm/parsing/component/ParsedActivityUtils.java +8 −1 Original line number Original line Diff line number Diff line Loading @@ -302,7 +302,14 @@ public class ParsedActivityUtils { } } String permission = array.getNonConfigurationString(permissionAttr, 0); String permission = array.getNonConfigurationString(permissionAttr, 0); 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()); activity.setPermission(permission != null ? permission : pkg.getPermission()); } final boolean setExported = array.hasValue(exportedAttr); final boolean setExported = array.hasValue(exportedAttr); if (setExported) { if (setExported) { Loading core/java/android/content/pm/parsing/component/ParsedComponentUtils.java +20 −9 Original line number Original line Diff line number Diff line Loading @@ -20,7 +20,10 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.content.pm.parsing.ParsingPackage; import android.content.pm.parsing.ParsingPackage; import android.content.pm.parsing.ParsingPackageUtils; import android.content.pm.parsing.ParsingUtils; 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.Resources; import android.content.res.TypedArray; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.content.res.XmlResourceParser; Loading @@ -29,9 +32,6 @@ import android.text.TextUtils; import android.util.TypedValue; import android.util.TypedValue; import com.android.internal.annotations.VisibleForTesting; 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 */ /** @hide */ class ParsedComponentUtils { class ParsedComponentUtils { Loading Loading @@ -60,16 +60,27 @@ class ParsedComponentUtils { component.setName(className); component.setName(className); component.setPackageName(packageName); component.setPackageName(packageName); if (useRoundIcon) { int roundIconVal = useRoundIcon ? array.getResourceId(roundIconAttr, 0) : 0; component.icon = array.getResourceId(roundIconAttr, 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) { int logoVal = array.getResourceId(logoAttr, 0); component.icon = array.getResourceId(iconAttr, 0); if (logoVal != 0) { component.logo = logoVal; } } component.logo = array.getResourceId(logoAttr, 0); int bannerVal = array.getResourceId(bannerAttr, 0); component.banner = array.getResourceId(bannerAttr, 0); if (bannerVal != 0) { component.banner = bannerVal; } if (descriptionAttr != null) { if (descriptionAttr != null) { component.descriptionRes = array.getResourceId(descriptionAttr, 0); component.descriptionRes = array.getResourceId(descriptionAttr, 0); Loading services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt +78 −7 Original line number Original line Diff line number Diff line Loading @@ -18,8 +18,8 @@ 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 androidx.test.filters.LargeTest import com.google.common.truth.Expect import com.google.common.truth.Expect import com.google.common.truth.Truth.assertWithMessage import org.junit.Rule import org.junit.Rule import org.junit.Test import org.junit.Test Loading Loading @@ -52,6 +52,7 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() { } } } } @LargeTest @Test @Test fun packageInfoEquality() { fun packageInfoEquality() { val flags = PackageManager.GET_ACTIVITIES or val flags = PackageManager.GET_ACTIVITIES or Loading @@ -65,7 +66,9 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() { PackageManager.GET_SERVICES or PackageManager.GET_SERVICES or PackageManager.GET_SHARED_LIBRARY_FILES or PackageManager.GET_SHARED_LIBRARY_FILES or PackageManager.GET_SIGNATURES 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 oldPackageInfo = oldPackages.asSequence().map { oldPackageInfo(it, flags) } val newPackageInfo = newPackages.asSequence().map { newPackageInfo(it, flags) } val newPackageInfo = newPackages.asSequence().map { newPackageInfo(it, flags) } Loading @@ -77,11 +80,79 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() { } else { } else { "$firstName | $secondName" "$firstName | $secondName" } } expect.withMessage("${it.first?.applicationInfo?.sourceDir} $packageName") .that(it.first?.dumpToString()) // Main components are asserted independently to separate the failures. Otherwise the .isEqualTo(it.second?.dumpToString()) // 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()) } } } } } services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt +137 −37 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.pm.parsing import android.content.Context import android.content.Context import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo import android.content.pm.ComponentInfo import android.content.pm.ConfigurationInfo import android.content.pm.ConfigurationInfo import android.content.pm.FeatureInfo import android.content.pm.FeatureInfo import android.content.pm.InstrumentationInfo import android.content.pm.InstrumentationInfo Loading @@ -27,6 +28,8 @@ import android.content.pm.PackageParser import android.content.pm.PackageUserState import android.content.pm.PackageUserState import android.content.pm.PermissionInfo import android.content.pm.PermissionInfo import android.content.pm.ProviderInfo import android.content.pm.ProviderInfo import android.content.pm.ServiceInfo import android.os.Bundle import android.os.Debug import android.os.Debug import android.os.Environment import android.os.Environment import android.util.SparseArray import android.util.SparseArray Loading @@ -38,8 +41,10 @@ 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.BeforeClass 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.anyInt import org.mockito.Mockito.anyString import org.mockito.Mockito.mock import org.mockito.Mockito.mock import java.io.File import java.io.File Loading @@ -47,7 +52,7 @@ open class AndroidPackageParsingTestBase { companion object { companion object { private const val VERIFY_ALL_APKS = false private const val VERIFY_ALL_APKS = true /** For auditing memory usage differences */ /** For auditing memory usage differences */ private const val DUMP_HPROF_TO_EXTERNAL = false private const val DUMP_HPROF_TO_EXTERNAL = false Loading Loading @@ -81,10 +86,14 @@ open class AndroidPackageParsingTestBase { .filter { file -> file.name.endsWith(".apk") } .filter { file -> file.name.endsWith(".apk") } .toList() .toList() } } .distinct() private val dummyUserState = mock(PackageUserState::class.java).apply { private val dummyUserState = mock(PackageUserState::class.java).apply { installed = true 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> lateinit var oldPackages: List<PackageParser.Package> Loading Loading @@ -145,6 +154,7 @@ open class AndroidPackageParsingTestBase { private fun mockPkgSetting(aPkg: AndroidPackage) = mockThrowOnUnmocked<PackageSetting> { private fun mockPkgSetting(aPkg: AndroidPackage) = mockThrowOnUnmocked<PackageSetting> { this.pkg = aPkg this.pkg = aPkg whenever(pkgState) { PackageStateUnserialized() } whenever(pkgState) { PackageStateUnserialized() } whenever(readUserState(anyInt())) { dummyUserState } } } } } Loading @@ -156,19 +166,10 @@ open class AndroidPackageParsingTestBase { // The following methods prepend "this." because @hide APIs can cause an IDE to auto-import // 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. // the R.attr constant instead of referencing the field in an attempt to fix the error. /** // It's difficult to comment out a line in a triple quoted string, so this is used instead * Known exclusions: // to ignore specific fields. A comment is required to explain why a field was ignored. * - [ApplicationInfo.credentialProtectedDataDir] private fun Any?.ignored(comment: String): String = "IGNORED" * - [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]. */ protected fun ApplicationInfo.dumpToString() = """ protected fun ApplicationInfo.dumpToString() = """ appComponentFactory=${this.appComponentFactory} appComponentFactory=${this.appComponentFactory} backupAgentName=${this.backupAgentName} backupAgentName=${this.backupAgentName} Loading @@ -179,22 +180,31 @@ open class AndroidPackageParsingTestBase { compatibleWidthLimitDp=${this.compatibleWidthLimitDp} compatibleWidthLimitDp=${this.compatibleWidthLimitDp} compileSdkVersion=${this.compileSdkVersion} compileSdkVersion=${this.compileSdkVersion} compileSdkVersionCodename=${this.compileSdkVersionCodename} 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} descriptionRes=${this.descriptionRes} deviceProtectedDataDir=${this.deviceProtectedDataDir .ignored("Deferred pre-R, but assigned immediately in R")} enabled=${this.enabled} enabled=${this.enabled} enabledSetting=${this.enabledSetting} enabledSetting=${this.enabledSetting} flags=${Integer.toBinaryString(this.flags)} flags=${Integer.toBinaryString(this.flags)} fullBackupContent=${this.fullBackupContent} fullBackupContent=${this.fullBackupContent} gwpAsanMode=${this.gwpAsanMode.ignored("Added in R")} hiddenUntilInstalled=${this.hiddenUntilInstalled} hiddenUntilInstalled=${this.hiddenUntilInstalled} icon=${this.icon} icon=${this.icon} iconRes=${this.iconRes} iconRes=${this.iconRes} installLocation=${this.installLocation} installLocation=${this.installLocation} labelRes=${this.labelRes} largestWidthLimitDp=${this.largestWidthLimitDp} largestWidthLimitDp=${this.largestWidthLimitDp} logo=${this.logo} logo=${this.logo} longVersionCode=${this.longVersionCode} longVersionCode=${this.longVersionCode} ${"".ignored("mHiddenApiPolicy is a private field")} manageSpaceActivityName=${this.manageSpaceActivityName} manageSpaceActivityName=${this.manageSpaceActivityName} maxAspectRatio.compareTo(that.maxAspectRatio)=${this.maxAspectRatio} maxAspectRatio=${this.maxAspectRatio} metaData=${this.metaData} metaData=${this.metaData.dumpToString()} minAspectRatio.compareTo(that.minAspectRatio)=${this.minAspectRatio} minAspectRatio=${this.minAspectRatio} minSdkVersion=${this.minSdkVersion} minSdkVersion=${this.minSdkVersion} name=${this.name} name=${this.name} nativeLibraryDir=${this.nativeLibraryDir} nativeLibraryDir=${this.nativeLibraryDir} Loading @@ -206,18 +216,27 @@ open class AndroidPackageParsingTestBase { permission=${this.permission} permission=${this.permission} primaryCpuAbi=${this.primaryCpuAbi} primaryCpuAbi=${this.primaryCpuAbi} privateFlags=${Integer.toBinaryString(this.privateFlags)} 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} requiresSmallestWidthDp=${this.requiresSmallestWidthDp} resourceDirs=${this.resourceDirs?.contentToString()} resourceDirs=${this.resourceDirs?.contentToString()} roundIconRes=${this.roundIconRes} roundIconRes=${this.roundIconRes} secondaryCpuAbi=${this.secondaryCpuAbi} scanPublicSourceDir=${this.scanPublicSourceDir secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir} .ignored("Deferred pre-R, but assigned immediately in R")} scanSourceDir=${this.scanSourceDir .ignored("Deferred pre-R, but assigned immediately in R")} seInfo=${this.seInfo} seInfo=${this.seInfo} seInfoUser=${this.seInfoUser} seInfoUser=${this.seInfoUser} secondaryCpuAbi=${this.secondaryCpuAbi} secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir} sharedLibraryFiles=${this.sharedLibraryFiles?.contentToString()} sharedLibraryFiles=${this.sharedLibraryFiles?.contentToString()} sharedLibraryInfos=${this.sharedLibraryInfos} sharedLibraryInfos=${this.sharedLibraryInfos} showUserIcon=${this.showUserIcon} showUserIcon=${this.showUserIcon} sourceDir=${this.sourceDir .ignored("Deferred pre-R, but assigned immediately in R")} splitClassLoaderNames=${this.splitClassLoaderNames?.contentToString()} splitClassLoaderNames=${this.splitClassLoaderNames?.contentToString()} splitDependencies=${this.splitDependencies} splitDependencies=${this.splitDependencies.dumpToString()} splitNames=${this.splitNames?.contentToString()} splitNames=${this.splitNames?.contentToString()} splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()} splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()} splitSourceDirs=${this.splitSourceDirs?.contentToString()} splitSourceDirs=${this.splitSourceDirs?.contentToString()} Loading @@ -226,8 +245,8 @@ open class AndroidPackageParsingTestBase { targetSdkVersion=${this.targetSdkVersion} targetSdkVersion=${this.targetSdkVersion} taskAffinity=${this.taskAffinity} taskAffinity=${this.taskAffinity} theme=${this.theme} theme=${this.theme} uid=${this.uid} uiOptions=${this.uiOptions} uiOptions=${this.uiOptions} uid=${this.uid} versionCode=${this.versionCode} versionCode=${this.versionCode} volumeUuid=${this.volumeUuid} volumeUuid=${this.volumeUuid} zygotePreloadName=${this.zygotePreloadName} zygotePreloadName=${this.zygotePreloadName} Loading @@ -241,19 +260,27 @@ open class AndroidPackageParsingTestBase { """.trimIndent() """.trimIndent() protected fun InstrumentationInfo.dumpToString() = """ protected fun InstrumentationInfo.dumpToString() = """ banner=${this.banner} credentialProtectedDataDir=${this.credentialProtectedDataDir} credentialProtectedDataDir=${this.credentialProtectedDataDir} dataDir=${this.dataDir} dataDir=${this.dataDir} deviceProtectedDataDir=${this.deviceProtectedDataDir} deviceProtectedDataDir=${this.deviceProtectedDataDir} functionalTest=${this.functionalTest} functionalTest=${this.functionalTest} handleProfiling=${this.handleProfiling} handleProfiling=${this.handleProfiling} icon=${this.icon} labelRes=${this.labelRes} logo=${this.logo} metaData=${this.metaData} name=${this.name} nativeLibraryDir=${this.nativeLibraryDir} nativeLibraryDir=${this.nativeLibraryDir} nonLocalizedLabel=${this.nonLocalizedLabel} packageName=${this.packageName} primaryCpuAbi=${this.primaryCpuAbi} primaryCpuAbi=${this.primaryCpuAbi} publicSourceDir=${this.publicSourceDir} publicSourceDir=${this.publicSourceDir} secondaryCpuAbi=${this.secondaryCpuAbi} secondaryCpuAbi=${this.secondaryCpuAbi} secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir} secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir} showUserIcon=${this.showUserIcon} sourceDir=${this.sourceDir} sourceDir=${this.sourceDir} splitDependencies=${this.splitDependencies.sequence() splitDependencies=${this.splitDependencies.dumpToString()} .map { it.first to it.second?.contentToString() }.joinToString()} splitNames=${this.splitNames?.contentToString()} splitNames=${this.splitNames?.contentToString()} splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()} splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()} splitSourceDirs=${this.splitSourceDirs?.contentToString()} splitSourceDirs=${this.splitSourceDirs?.contentToString()} Loading @@ -262,25 +289,40 @@ open class AndroidPackageParsingTestBase { """.trimIndent() """.trimIndent() protected fun ActivityInfo.dumpToString() = """ protected fun ActivityInfo.dumpToString() = """ banner=${this.banner} colorMode=${this.colorMode} colorMode=${this.colorMode} configChanges=${this.configChanges} configChanges=${this.configChanges} descriptionRes=${this.descriptionRes} directBootAware=${this.directBootAware} documentLaunchMode=${this.documentLaunchMode} documentLaunchMode=${this.documentLaunchMode} enabled=${this.enabled} exported=${this.exported} flags=${Integer.toBinaryString(this.flags)} flags=${Integer.toBinaryString(this.flags)} icon=${this.icon} labelRes=${this.labelRes} launchMode=${this.launchMode} launchMode=${this.launchMode} launchToken=${this.launchToken} launchToken=${this.launchToken} lockTaskLaunchMode=${this.lockTaskLaunchMode} lockTaskLaunchMode=${this.lockTaskLaunchMode} logo=${this.logo} maxAspectRatio=${this.maxAspectRatio} maxAspectRatio=${this.maxAspectRatio} maxRecents=${this.maxRecents} maxRecents=${this.maxRecents} metaData=${this.metaData.dumpToString()} minAspectRatio=${this.minAspectRatio} minAspectRatio=${this.minAspectRatio} name=${this.name} nonLocalizedLabel=${this.nonLocalizedLabel} packageName=${this.packageName} parentActivityName=${this.parentActivityName} parentActivityName=${this.parentActivityName} permission=${this.permission} permission=${this.permission} persistableMode=${this.persistableMode} persistableMode=${this.persistableMode.ignored("Could be dropped pre-R, fixed in R")} privateFlags=${Integer.toBinaryString(this.privateFlags)} privateFlags=${this.privateFlags} processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")} requestedVrComponent=${this.requestedVrComponent} requestedVrComponent=${this.requestedVrComponent} resizeMode=${this.resizeMode} resizeMode=${this.resizeMode} rotationAnimation=${this.rotationAnimation} rotationAnimation=${this.rotationAnimation} screenOrientation=${this.screenOrientation} screenOrientation=${this.screenOrientation} showUserIcon=${this.showUserIcon} softInputMode=${this.softInputMode} softInputMode=${this.softInputMode} splitName=${this.splitName} targetActivity=${this.targetActivity} targetActivity=${this.targetActivity} taskAffinity=${this.taskAffinity} taskAffinity=${this.taskAffinity} theme=${this.theme} theme=${this.theme} Loading @@ -300,30 +342,77 @@ open class AndroidPackageParsingTestBase { protected fun PermissionInfo.dumpToString() = """ protected fun PermissionInfo.dumpToString() = """ backgroundPermission=${this.backgroundPermission} backgroundPermission=${this.backgroundPermission} banner=${this.banner} descriptionRes=${this.descriptionRes} descriptionRes=${this.descriptionRes} flags=${Integer.toBinaryString(this.flags)} flags=${Integer.toBinaryString(this.flags)} group=${this.group} group=${this.group} icon=${this.icon} labelRes=${this.labelRes} logo=${this.logo} metaData=${this.metaData.dumpToString()} name=${this.name} nonLocalizedDescription=${this.nonLocalizedDescription} nonLocalizedDescription=${this.nonLocalizedDescription} nonLocalizedLabel=${this.nonLocalizedLabel} packageName=${this.packageName} protectionLevel=${this.protectionLevel} protectionLevel=${this.protectionLevel} requestRes=${this.requestRes} requestRes=${this.requestRes} showUserIcon=${this.showUserIcon} """.trimIndent() """.trimIndent() protected fun ProviderInfo.dumpToString() = """ protected fun ProviderInfo.dumpToString() = """ applicationInfo=${this.applicationInfo.ignored("Already checked")} authority=${this.authority} authority=${this.authority} banner=${this.banner} descriptionRes=${this.descriptionRes} directBootAware=${this.directBootAware} enabled=${this.enabled} exported=${this.exported} flags=${Integer.toBinaryString(this.flags)} flags=${Integer.toBinaryString(this.flags)} forceUriPermissions=${this.forceUriPermissions} forceUriPermissions=${this.forceUriPermissions} grantUriPermissions=${this.grantUriPermissions} grantUriPermissions=${this.grantUriPermissions} icon=${this.icon} initOrder=${this.initOrder} initOrder=${this.initOrder} isSyncable=${this.isSyncable} isSyncable=${this.isSyncable} labelRes=${this.labelRes} logo=${this.logo} metaData=${this.metaData.dumpToString()} multiprocess=${this.multiprocess} multiprocess=${this.multiprocess} name=${this.name} nonLocalizedLabel=${this.nonLocalizedLabel} packageName=${this.packageName} pathPermissions=${this.pathPermissions?.joinToString { pathPermissions=${this.pathPermissions?.joinToString { "readPermission=${it.readPermission}\nwritePermission=${it.writePermission}" "readPermission=${it.readPermission}\nwritePermission=${it.writePermission}" }} }} processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")} readPermission=${this.readPermission} readPermission=${this.readPermission} showUserIcon=${this.showUserIcon} splitName=${this.splitName} uriPermissionPatterns=${this.uriPermissionPatterns?.contentToString()} uriPermissionPatterns=${this.uriPermissionPatterns?.contentToString()} writePermission=${this.writePermission} writePermission=${this.writePermission} """.trimIndent() """.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() = """ protected fun ConfigurationInfo.dumpToString() = """ reqGlEsVersion=${this.reqGlEsVersion} reqGlEsVersion=${this.reqGlEsVersion} reqInputFeatures=${this.reqInputFeatures} reqInputFeatures=${this.reqInputFeatures} Loading @@ -333,8 +422,10 @@ open class AndroidPackageParsingTestBase { """.trimIndent() """.trimIndent() protected fun PackageInfo.dumpToString() = """ protected fun PackageInfo.dumpToString() = """ activities=${this.activities?.joinToString { it.dumpToString() }} activities=${this.activities?.joinToString { it.dumpToString() } applicationInfo=${this.applicationInfo.dumpToString()} .ignored("Checked separately in test")} applicationInfo=${this.applicationInfo.dumpToString() .ignored("Checked separately in test")} baseRevisionCode=${this.baseRevisionCode} baseRevisionCode=${this.baseRevisionCode} compileSdkVersion=${this.compileSdkVersion} compileSdkVersion=${this.compileSdkVersion} compileSdkVersionCodename=${this.compileSdkVersionCodename} compileSdkVersionCodename=${this.compileSdkVersionCodename} Loading @@ -356,15 +447,18 @@ open class AndroidPackageParsingTestBase { overlayTarget=${this.overlayTarget} overlayTarget=${this.overlayTarget} packageName=${this.packageName} packageName=${this.packageName} permissions=${this.permissions?.joinToString { it.dumpToString() }} permissions=${this.permissions?.joinToString { it.dumpToString() }} providers=${this.providers?.joinToString { it.dumpToString() }} providers=${this.providers?.joinToString { it.dumpToString() } receivers=${this.receivers?.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() }} reqFeatures=${this.reqFeatures?.joinToString { it.dumpToString() }} requestedPermissions=${this.requestedPermissions?.contentToString()} requestedPermissions=${this.requestedPermissions?.contentToString()} requestedPermissionsFlags=${this.requestedPermissionsFlags?.contentToString()} requestedPermissionsFlags=${this.requestedPermissionsFlags?.contentToString()} requiredAccountType=${this.requiredAccountType} requiredAccountType=${this.requiredAccountType} requiredForAllUsers=${this.requiredForAllUsers} requiredForAllUsers=${this.requiredForAllUsers} restrictedAccountType=${this.restrictedAccountType} restrictedAccountType=${this.restrictedAccountType} services=${this.services?.contentToString()} services=${this.services?.joinToString { it.dumpToString() } .ignored("Checked separately in test")} sharedUserId=${this.sharedUserId} sharedUserId=${this.sharedUserId} sharedUserLabel=${this.sharedUserLabel} sharedUserLabel=${this.sharedUserLabel} signatures=${this.signatures?.joinToString { it.toCharsString() }} signatures=${this.signatures?.joinToString { it.toCharsString() }} Loading @@ -378,11 +472,17 @@ open class AndroidPackageParsingTestBase { versionName=${this.versionName} versionName=${this.versionName} """.trimIndent() """.trimIndent() @Suppress("unused") private fun Bundle?.dumpToString() = this?.keySet()?.associateWith { get(it) }?.toString() private fun <T> SparseArray<T>.sequence(): Sequence<Pair<Int, T>> { var index = 0 private fun <T> SparseArray<T>?.dumpToString(): String { return generateSequence { if (this == null) { index++.takeIf { it < size() }?.let { keyAt(it) to valueAt(index) } return "EMPTY" } val list = mutableListOf<Pair<Int, T>>() for (index in (0 until size())) { list += keyAt(index) to valueAt(index) } } return list.toString() } } } } Loading
core/java/android/content/pm/parsing/component/ParsedActivityUtils.java +8 −1 Original line number Original line Diff line number Diff line Loading @@ -302,7 +302,14 @@ public class ParsedActivityUtils { } } String permission = array.getNonConfigurationString(permissionAttr, 0); String permission = array.getNonConfigurationString(permissionAttr, 0); 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()); activity.setPermission(permission != null ? permission : pkg.getPermission()); } final boolean setExported = array.hasValue(exportedAttr); final boolean setExported = array.hasValue(exportedAttr); if (setExported) { if (setExported) { Loading
core/java/android/content/pm/parsing/component/ParsedComponentUtils.java +20 −9 Original line number Original line Diff line number Diff line Loading @@ -20,7 +20,10 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.content.pm.parsing.ParsingPackage; import android.content.pm.parsing.ParsingPackage; import android.content.pm.parsing.ParsingPackageUtils; import android.content.pm.parsing.ParsingUtils; 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.Resources; import android.content.res.TypedArray; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.content.res.XmlResourceParser; Loading @@ -29,9 +32,6 @@ import android.text.TextUtils; import android.util.TypedValue; import android.util.TypedValue; import com.android.internal.annotations.VisibleForTesting; 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 */ /** @hide */ class ParsedComponentUtils { class ParsedComponentUtils { Loading Loading @@ -60,16 +60,27 @@ class ParsedComponentUtils { component.setName(className); component.setName(className); component.setPackageName(packageName); component.setPackageName(packageName); if (useRoundIcon) { int roundIconVal = useRoundIcon ? array.getResourceId(roundIconAttr, 0) : 0; component.icon = array.getResourceId(roundIconAttr, 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) { int logoVal = array.getResourceId(logoAttr, 0); component.icon = array.getResourceId(iconAttr, 0); if (logoVal != 0) { component.logo = logoVal; } } component.logo = array.getResourceId(logoAttr, 0); int bannerVal = array.getResourceId(bannerAttr, 0); component.banner = array.getResourceId(bannerAttr, 0); if (bannerVal != 0) { component.banner = bannerVal; } if (descriptionAttr != null) { if (descriptionAttr != null) { component.descriptionRes = array.getResourceId(descriptionAttr, 0); component.descriptionRes = array.getResourceId(descriptionAttr, 0); Loading
services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt +78 −7 Original line number Original line Diff line number Diff line Loading @@ -18,8 +18,8 @@ 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 androidx.test.filters.LargeTest import com.google.common.truth.Expect import com.google.common.truth.Expect import com.google.common.truth.Truth.assertWithMessage import org.junit.Rule import org.junit.Rule import org.junit.Test import org.junit.Test Loading Loading @@ -52,6 +52,7 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() { } } } } @LargeTest @Test @Test fun packageInfoEquality() { fun packageInfoEquality() { val flags = PackageManager.GET_ACTIVITIES or val flags = PackageManager.GET_ACTIVITIES or Loading @@ -65,7 +66,9 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() { PackageManager.GET_SERVICES or PackageManager.GET_SERVICES or PackageManager.GET_SHARED_LIBRARY_FILES or PackageManager.GET_SHARED_LIBRARY_FILES or PackageManager.GET_SIGNATURES 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 oldPackageInfo = oldPackages.asSequence().map { oldPackageInfo(it, flags) } val newPackageInfo = newPackages.asSequence().map { newPackageInfo(it, flags) } val newPackageInfo = newPackages.asSequence().map { newPackageInfo(it, flags) } Loading @@ -77,11 +80,79 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() { } else { } else { "$firstName | $secondName" "$firstName | $secondName" } } expect.withMessage("${it.first?.applicationInfo?.sourceDir} $packageName") .that(it.first?.dumpToString()) // Main components are asserted independently to separate the failures. Otherwise the .isEqualTo(it.second?.dumpToString()) // 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()) } } } } }
services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt +137 −37 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.pm.parsing import android.content.Context import android.content.Context import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo import android.content.pm.ComponentInfo import android.content.pm.ConfigurationInfo import android.content.pm.ConfigurationInfo import android.content.pm.FeatureInfo import android.content.pm.FeatureInfo import android.content.pm.InstrumentationInfo import android.content.pm.InstrumentationInfo Loading @@ -27,6 +28,8 @@ import android.content.pm.PackageParser import android.content.pm.PackageUserState import android.content.pm.PackageUserState import android.content.pm.PermissionInfo import android.content.pm.PermissionInfo import android.content.pm.ProviderInfo import android.content.pm.ProviderInfo import android.content.pm.ServiceInfo import android.os.Bundle import android.os.Debug import android.os.Debug import android.os.Environment import android.os.Environment import android.util.SparseArray import android.util.SparseArray Loading @@ -38,8 +41,10 @@ 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.BeforeClass 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.anyInt import org.mockito.Mockito.anyString import org.mockito.Mockito.mock import org.mockito.Mockito.mock import java.io.File import java.io.File Loading @@ -47,7 +52,7 @@ open class AndroidPackageParsingTestBase { companion object { companion object { private const val VERIFY_ALL_APKS = false private const val VERIFY_ALL_APKS = true /** For auditing memory usage differences */ /** For auditing memory usage differences */ private const val DUMP_HPROF_TO_EXTERNAL = false private const val DUMP_HPROF_TO_EXTERNAL = false Loading Loading @@ -81,10 +86,14 @@ open class AndroidPackageParsingTestBase { .filter { file -> file.name.endsWith(".apk") } .filter { file -> file.name.endsWith(".apk") } .toList() .toList() } } .distinct() private val dummyUserState = mock(PackageUserState::class.java).apply { private val dummyUserState = mock(PackageUserState::class.java).apply { installed = true 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> lateinit var oldPackages: List<PackageParser.Package> Loading Loading @@ -145,6 +154,7 @@ open class AndroidPackageParsingTestBase { private fun mockPkgSetting(aPkg: AndroidPackage) = mockThrowOnUnmocked<PackageSetting> { private fun mockPkgSetting(aPkg: AndroidPackage) = mockThrowOnUnmocked<PackageSetting> { this.pkg = aPkg this.pkg = aPkg whenever(pkgState) { PackageStateUnserialized() } whenever(pkgState) { PackageStateUnserialized() } whenever(readUserState(anyInt())) { dummyUserState } } } } } Loading @@ -156,19 +166,10 @@ open class AndroidPackageParsingTestBase { // The following methods prepend "this." because @hide APIs can cause an IDE to auto-import // 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. // the R.attr constant instead of referencing the field in an attempt to fix the error. /** // It's difficult to comment out a line in a triple quoted string, so this is used instead * Known exclusions: // to ignore specific fields. A comment is required to explain why a field was ignored. * - [ApplicationInfo.credentialProtectedDataDir] private fun Any?.ignored(comment: String): String = "IGNORED" * - [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]. */ protected fun ApplicationInfo.dumpToString() = """ protected fun ApplicationInfo.dumpToString() = """ appComponentFactory=${this.appComponentFactory} appComponentFactory=${this.appComponentFactory} backupAgentName=${this.backupAgentName} backupAgentName=${this.backupAgentName} Loading @@ -179,22 +180,31 @@ open class AndroidPackageParsingTestBase { compatibleWidthLimitDp=${this.compatibleWidthLimitDp} compatibleWidthLimitDp=${this.compatibleWidthLimitDp} compileSdkVersion=${this.compileSdkVersion} compileSdkVersion=${this.compileSdkVersion} compileSdkVersionCodename=${this.compileSdkVersionCodename} 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} descriptionRes=${this.descriptionRes} deviceProtectedDataDir=${this.deviceProtectedDataDir .ignored("Deferred pre-R, but assigned immediately in R")} enabled=${this.enabled} enabled=${this.enabled} enabledSetting=${this.enabledSetting} enabledSetting=${this.enabledSetting} flags=${Integer.toBinaryString(this.flags)} flags=${Integer.toBinaryString(this.flags)} fullBackupContent=${this.fullBackupContent} fullBackupContent=${this.fullBackupContent} gwpAsanMode=${this.gwpAsanMode.ignored("Added in R")} hiddenUntilInstalled=${this.hiddenUntilInstalled} hiddenUntilInstalled=${this.hiddenUntilInstalled} icon=${this.icon} icon=${this.icon} iconRes=${this.iconRes} iconRes=${this.iconRes} installLocation=${this.installLocation} installLocation=${this.installLocation} labelRes=${this.labelRes} largestWidthLimitDp=${this.largestWidthLimitDp} largestWidthLimitDp=${this.largestWidthLimitDp} logo=${this.logo} logo=${this.logo} longVersionCode=${this.longVersionCode} longVersionCode=${this.longVersionCode} ${"".ignored("mHiddenApiPolicy is a private field")} manageSpaceActivityName=${this.manageSpaceActivityName} manageSpaceActivityName=${this.manageSpaceActivityName} maxAspectRatio.compareTo(that.maxAspectRatio)=${this.maxAspectRatio} maxAspectRatio=${this.maxAspectRatio} metaData=${this.metaData} metaData=${this.metaData.dumpToString()} minAspectRatio.compareTo(that.minAspectRatio)=${this.minAspectRatio} minAspectRatio=${this.minAspectRatio} minSdkVersion=${this.minSdkVersion} minSdkVersion=${this.minSdkVersion} name=${this.name} name=${this.name} nativeLibraryDir=${this.nativeLibraryDir} nativeLibraryDir=${this.nativeLibraryDir} Loading @@ -206,18 +216,27 @@ open class AndroidPackageParsingTestBase { permission=${this.permission} permission=${this.permission} primaryCpuAbi=${this.primaryCpuAbi} primaryCpuAbi=${this.primaryCpuAbi} privateFlags=${Integer.toBinaryString(this.privateFlags)} 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} requiresSmallestWidthDp=${this.requiresSmallestWidthDp} resourceDirs=${this.resourceDirs?.contentToString()} resourceDirs=${this.resourceDirs?.contentToString()} roundIconRes=${this.roundIconRes} roundIconRes=${this.roundIconRes} secondaryCpuAbi=${this.secondaryCpuAbi} scanPublicSourceDir=${this.scanPublicSourceDir secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir} .ignored("Deferred pre-R, but assigned immediately in R")} scanSourceDir=${this.scanSourceDir .ignored("Deferred pre-R, but assigned immediately in R")} seInfo=${this.seInfo} seInfo=${this.seInfo} seInfoUser=${this.seInfoUser} seInfoUser=${this.seInfoUser} secondaryCpuAbi=${this.secondaryCpuAbi} secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir} sharedLibraryFiles=${this.sharedLibraryFiles?.contentToString()} sharedLibraryFiles=${this.sharedLibraryFiles?.contentToString()} sharedLibraryInfos=${this.sharedLibraryInfos} sharedLibraryInfos=${this.sharedLibraryInfos} showUserIcon=${this.showUserIcon} showUserIcon=${this.showUserIcon} sourceDir=${this.sourceDir .ignored("Deferred pre-R, but assigned immediately in R")} splitClassLoaderNames=${this.splitClassLoaderNames?.contentToString()} splitClassLoaderNames=${this.splitClassLoaderNames?.contentToString()} splitDependencies=${this.splitDependencies} splitDependencies=${this.splitDependencies.dumpToString()} splitNames=${this.splitNames?.contentToString()} splitNames=${this.splitNames?.contentToString()} splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()} splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()} splitSourceDirs=${this.splitSourceDirs?.contentToString()} splitSourceDirs=${this.splitSourceDirs?.contentToString()} Loading @@ -226,8 +245,8 @@ open class AndroidPackageParsingTestBase { targetSdkVersion=${this.targetSdkVersion} targetSdkVersion=${this.targetSdkVersion} taskAffinity=${this.taskAffinity} taskAffinity=${this.taskAffinity} theme=${this.theme} theme=${this.theme} uid=${this.uid} uiOptions=${this.uiOptions} uiOptions=${this.uiOptions} uid=${this.uid} versionCode=${this.versionCode} versionCode=${this.versionCode} volumeUuid=${this.volumeUuid} volumeUuid=${this.volumeUuid} zygotePreloadName=${this.zygotePreloadName} zygotePreloadName=${this.zygotePreloadName} Loading @@ -241,19 +260,27 @@ open class AndroidPackageParsingTestBase { """.trimIndent() """.trimIndent() protected fun InstrumentationInfo.dumpToString() = """ protected fun InstrumentationInfo.dumpToString() = """ banner=${this.banner} credentialProtectedDataDir=${this.credentialProtectedDataDir} credentialProtectedDataDir=${this.credentialProtectedDataDir} dataDir=${this.dataDir} dataDir=${this.dataDir} deviceProtectedDataDir=${this.deviceProtectedDataDir} deviceProtectedDataDir=${this.deviceProtectedDataDir} functionalTest=${this.functionalTest} functionalTest=${this.functionalTest} handleProfiling=${this.handleProfiling} handleProfiling=${this.handleProfiling} icon=${this.icon} labelRes=${this.labelRes} logo=${this.logo} metaData=${this.metaData} name=${this.name} nativeLibraryDir=${this.nativeLibraryDir} nativeLibraryDir=${this.nativeLibraryDir} nonLocalizedLabel=${this.nonLocalizedLabel} packageName=${this.packageName} primaryCpuAbi=${this.primaryCpuAbi} primaryCpuAbi=${this.primaryCpuAbi} publicSourceDir=${this.publicSourceDir} publicSourceDir=${this.publicSourceDir} secondaryCpuAbi=${this.secondaryCpuAbi} secondaryCpuAbi=${this.secondaryCpuAbi} secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir} secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir} showUserIcon=${this.showUserIcon} sourceDir=${this.sourceDir} sourceDir=${this.sourceDir} splitDependencies=${this.splitDependencies.sequence() splitDependencies=${this.splitDependencies.dumpToString()} .map { it.first to it.second?.contentToString() }.joinToString()} splitNames=${this.splitNames?.contentToString()} splitNames=${this.splitNames?.contentToString()} splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()} splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()} splitSourceDirs=${this.splitSourceDirs?.contentToString()} splitSourceDirs=${this.splitSourceDirs?.contentToString()} Loading @@ -262,25 +289,40 @@ open class AndroidPackageParsingTestBase { """.trimIndent() """.trimIndent() protected fun ActivityInfo.dumpToString() = """ protected fun ActivityInfo.dumpToString() = """ banner=${this.banner} colorMode=${this.colorMode} colorMode=${this.colorMode} configChanges=${this.configChanges} configChanges=${this.configChanges} descriptionRes=${this.descriptionRes} directBootAware=${this.directBootAware} documentLaunchMode=${this.documentLaunchMode} documentLaunchMode=${this.documentLaunchMode} enabled=${this.enabled} exported=${this.exported} flags=${Integer.toBinaryString(this.flags)} flags=${Integer.toBinaryString(this.flags)} icon=${this.icon} labelRes=${this.labelRes} launchMode=${this.launchMode} launchMode=${this.launchMode} launchToken=${this.launchToken} launchToken=${this.launchToken} lockTaskLaunchMode=${this.lockTaskLaunchMode} lockTaskLaunchMode=${this.lockTaskLaunchMode} logo=${this.logo} maxAspectRatio=${this.maxAspectRatio} maxAspectRatio=${this.maxAspectRatio} maxRecents=${this.maxRecents} maxRecents=${this.maxRecents} metaData=${this.metaData.dumpToString()} minAspectRatio=${this.minAspectRatio} minAspectRatio=${this.minAspectRatio} name=${this.name} nonLocalizedLabel=${this.nonLocalizedLabel} packageName=${this.packageName} parentActivityName=${this.parentActivityName} parentActivityName=${this.parentActivityName} permission=${this.permission} permission=${this.permission} persistableMode=${this.persistableMode} persistableMode=${this.persistableMode.ignored("Could be dropped pre-R, fixed in R")} privateFlags=${Integer.toBinaryString(this.privateFlags)} privateFlags=${this.privateFlags} processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")} requestedVrComponent=${this.requestedVrComponent} requestedVrComponent=${this.requestedVrComponent} resizeMode=${this.resizeMode} resizeMode=${this.resizeMode} rotationAnimation=${this.rotationAnimation} rotationAnimation=${this.rotationAnimation} screenOrientation=${this.screenOrientation} screenOrientation=${this.screenOrientation} showUserIcon=${this.showUserIcon} softInputMode=${this.softInputMode} softInputMode=${this.softInputMode} splitName=${this.splitName} targetActivity=${this.targetActivity} targetActivity=${this.targetActivity} taskAffinity=${this.taskAffinity} taskAffinity=${this.taskAffinity} theme=${this.theme} theme=${this.theme} Loading @@ -300,30 +342,77 @@ open class AndroidPackageParsingTestBase { protected fun PermissionInfo.dumpToString() = """ protected fun PermissionInfo.dumpToString() = """ backgroundPermission=${this.backgroundPermission} backgroundPermission=${this.backgroundPermission} banner=${this.banner} descriptionRes=${this.descriptionRes} descriptionRes=${this.descriptionRes} flags=${Integer.toBinaryString(this.flags)} flags=${Integer.toBinaryString(this.flags)} group=${this.group} group=${this.group} icon=${this.icon} labelRes=${this.labelRes} logo=${this.logo} metaData=${this.metaData.dumpToString()} name=${this.name} nonLocalizedDescription=${this.nonLocalizedDescription} nonLocalizedDescription=${this.nonLocalizedDescription} nonLocalizedLabel=${this.nonLocalizedLabel} packageName=${this.packageName} protectionLevel=${this.protectionLevel} protectionLevel=${this.protectionLevel} requestRes=${this.requestRes} requestRes=${this.requestRes} showUserIcon=${this.showUserIcon} """.trimIndent() """.trimIndent() protected fun ProviderInfo.dumpToString() = """ protected fun ProviderInfo.dumpToString() = """ applicationInfo=${this.applicationInfo.ignored("Already checked")} authority=${this.authority} authority=${this.authority} banner=${this.banner} descriptionRes=${this.descriptionRes} directBootAware=${this.directBootAware} enabled=${this.enabled} exported=${this.exported} flags=${Integer.toBinaryString(this.flags)} flags=${Integer.toBinaryString(this.flags)} forceUriPermissions=${this.forceUriPermissions} forceUriPermissions=${this.forceUriPermissions} grantUriPermissions=${this.grantUriPermissions} grantUriPermissions=${this.grantUriPermissions} icon=${this.icon} initOrder=${this.initOrder} initOrder=${this.initOrder} isSyncable=${this.isSyncable} isSyncable=${this.isSyncable} labelRes=${this.labelRes} logo=${this.logo} metaData=${this.metaData.dumpToString()} multiprocess=${this.multiprocess} multiprocess=${this.multiprocess} name=${this.name} nonLocalizedLabel=${this.nonLocalizedLabel} packageName=${this.packageName} pathPermissions=${this.pathPermissions?.joinToString { pathPermissions=${this.pathPermissions?.joinToString { "readPermission=${it.readPermission}\nwritePermission=${it.writePermission}" "readPermission=${it.readPermission}\nwritePermission=${it.writePermission}" }} }} processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")} readPermission=${this.readPermission} readPermission=${this.readPermission} showUserIcon=${this.showUserIcon} splitName=${this.splitName} uriPermissionPatterns=${this.uriPermissionPatterns?.contentToString()} uriPermissionPatterns=${this.uriPermissionPatterns?.contentToString()} writePermission=${this.writePermission} writePermission=${this.writePermission} """.trimIndent() """.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() = """ protected fun ConfigurationInfo.dumpToString() = """ reqGlEsVersion=${this.reqGlEsVersion} reqGlEsVersion=${this.reqGlEsVersion} reqInputFeatures=${this.reqInputFeatures} reqInputFeatures=${this.reqInputFeatures} Loading @@ -333,8 +422,10 @@ open class AndroidPackageParsingTestBase { """.trimIndent() """.trimIndent() protected fun PackageInfo.dumpToString() = """ protected fun PackageInfo.dumpToString() = """ activities=${this.activities?.joinToString { it.dumpToString() }} activities=${this.activities?.joinToString { it.dumpToString() } applicationInfo=${this.applicationInfo.dumpToString()} .ignored("Checked separately in test")} applicationInfo=${this.applicationInfo.dumpToString() .ignored("Checked separately in test")} baseRevisionCode=${this.baseRevisionCode} baseRevisionCode=${this.baseRevisionCode} compileSdkVersion=${this.compileSdkVersion} compileSdkVersion=${this.compileSdkVersion} compileSdkVersionCodename=${this.compileSdkVersionCodename} compileSdkVersionCodename=${this.compileSdkVersionCodename} Loading @@ -356,15 +447,18 @@ open class AndroidPackageParsingTestBase { overlayTarget=${this.overlayTarget} overlayTarget=${this.overlayTarget} packageName=${this.packageName} packageName=${this.packageName} permissions=${this.permissions?.joinToString { it.dumpToString() }} permissions=${this.permissions?.joinToString { it.dumpToString() }} providers=${this.providers?.joinToString { it.dumpToString() }} providers=${this.providers?.joinToString { it.dumpToString() } receivers=${this.receivers?.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() }} reqFeatures=${this.reqFeatures?.joinToString { it.dumpToString() }} requestedPermissions=${this.requestedPermissions?.contentToString()} requestedPermissions=${this.requestedPermissions?.contentToString()} requestedPermissionsFlags=${this.requestedPermissionsFlags?.contentToString()} requestedPermissionsFlags=${this.requestedPermissionsFlags?.contentToString()} requiredAccountType=${this.requiredAccountType} requiredAccountType=${this.requiredAccountType} requiredForAllUsers=${this.requiredForAllUsers} requiredForAllUsers=${this.requiredForAllUsers} restrictedAccountType=${this.restrictedAccountType} restrictedAccountType=${this.restrictedAccountType} services=${this.services?.contentToString()} services=${this.services?.joinToString { it.dumpToString() } .ignored("Checked separately in test")} sharedUserId=${this.sharedUserId} sharedUserId=${this.sharedUserId} sharedUserLabel=${this.sharedUserLabel} sharedUserLabel=${this.sharedUserLabel} signatures=${this.signatures?.joinToString { it.toCharsString() }} signatures=${this.signatures?.joinToString { it.toCharsString() }} Loading @@ -378,11 +472,17 @@ open class AndroidPackageParsingTestBase { versionName=${this.versionName} versionName=${this.versionName} """.trimIndent() """.trimIndent() @Suppress("unused") private fun Bundle?.dumpToString() = this?.keySet()?.associateWith { get(it) }?.toString() private fun <T> SparseArray<T>.sequence(): Sequence<Pair<Int, T>> { var index = 0 private fun <T> SparseArray<T>?.dumpToString(): String { return generateSequence { if (this == null) { index++.takeIf { it < size() }?.let { keyAt(it) to valueAt(index) } return "EMPTY" } val list = mutableListOf<Pair<Int, T>>() for (index in (0 until size())) { list += keyAt(index) to valueAt(index) } } return list.toString() } } } }