From 593df2ce1ed128a61c6146bd3e98a049986d67d5 Mon Sep 17 00:00:00 2001 From: Winson Date: Fri, 18 Jun 2021 12:35:40 -0700 Subject: [PATCH] Add parsing class parcelling tests Uses reflection to read all of the getters for each of the data classes and finds their setters to input test data, serialize it, deserialize it, and compare the before and after values. Also records all of the methods available in the class, to ensure that any new fields/methods are caught by the test. Bug: 178852754 Test: atest com.android.server.pm.test.parsing.parcelling Change-Id: I642fd43a3ff2e5675129f0f4ad3646c97e3f0e22 --- .../android/content/pm/PackageParser.java | 66 +- .../parsing/PackageInfoWithoutStateUtils.java | 2 +- .../content/pm/parsing/ParsingPackage.java | 2 +- .../pm/parsing/ParsingPackageImpl.java | 6 +- .../pm/parsing/component/ParsedActivity.java | 6 +- .../pm/parsing/component/ParsedComponent.java | 4 +- .../component/ParsedInstrumentation.java | 2 + .../parsing/component/ParsedIntentInfo.java | 2 + .../parsing/component/ParsedPermission.java | 2 + .../pm/parsing/component/ParsedProcess.java | 1 - .../pm/parsing/component/ParsedProvider.java | 1 + .../pm/parsing/component/ParsedService.java | 2 + .../server/pm/parsing/pkg/PackageImpl.java | 5 + .../unit/Android.bp | 1 + .../unit/TEST_MAPPING | 7 + .../parsing/parcelling/AndroidPackageTest.kt | 572 ++++++++++++++++++ .../parcelling/ParcelableComponentTest.kt | 413 +++++++++++++ .../ParcelableCreatorInvalidTest.kt | 59 ++ .../parcelling/ParcelableCreatorValidTest.kt | 47 ++ .../parsing/parcelling/ParsedActivityTest.kt | 73 +++ .../parcelling/ParsedAttributionTest.kt | 36 ++ .../parsing/parcelling/ParsedComponentTest.kt | 95 +++ .../parcelling/ParsedInstrumentationTest.kt | 34 ++ .../parcelling/ParsedIntentInfoTest.kt | 152 +++++ .../parcelling/ParsedMainComponentTest.kt | 53 ++ .../parcelling/ParsedPermissionGroupTest.kt | 35 ++ .../parcelling/ParsedPermissionTest.kt | 55 ++ .../parsing/parcelling/ParsedProcessTest.kt | 43 ++ .../parsing/parcelling/ParsedProviderTest.kt | 78 +++ .../parsing/parcelling/ParsedServiceTest.kt | 32 + .../parcelling/ParsedUsesPermissionTest.kt | 35 ++ .../parcelling/java/TestSubWithCreator.java | 56 ++ .../java/TestSubWithoutCreator.java | 41 ++ .../parcelling/java/TestSuperClass.java | 118 ++++ .../server/pm/test/util/IgnoreableExpect.kt | 53 ++ .../android/server/pm/PackageParserTest.java | 2 +- 36 files changed, 2116 insertions(+), 75 deletions(-) create mode 100644 services/tests/PackageManagerServiceTests/unit/TEST_MAPPING create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableComponentTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableCreatorInvalidTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableCreatorValidTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSubWithCreator.java create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSubWithoutCreator.java create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSuperClass.java create mode 100644 services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/util/IgnoreableExpect.kt diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index bed03835707ff..29ce3971e83a3 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -55,6 +55,8 @@ import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.overlay.OverlayPaths; +import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.split.SplitAssetLoader; import android.content.pm.parsing.result.ParseResult; import android.content.pm.parsing.result.ParseTypeImpl; import android.content.res.ApkAssets; @@ -7425,7 +7427,7 @@ public class PackageParser { mCompileSdkVersionCodename = dest.readString(); mUpgradeKeySets = (ArraySet) dest.readArraySet(boot); - mKeySetMapping = readKeySetMapping(dest); + mKeySetMapping = ParsingPackageUtils.readKeySetMapping(dest); cpuAbiOverride = dest.readString(); use32bitAbi = (dest.readInt() == 1); @@ -7551,73 +7553,13 @@ public class PackageParser { dest.writeInt(mCompileSdkVersion); dest.writeString(mCompileSdkVersionCodename); dest.writeArraySet(mUpgradeKeySets); - writeKeySetMapping(dest, mKeySetMapping); + ParsingPackageUtils.writeKeySetMapping(dest, mKeySetMapping); dest.writeString(cpuAbiOverride); dest.writeInt(use32bitAbi ? 1 : 0); dest.writeByteArray(restrictUpdateHash); dest.writeInt(visibleToInstantApps ? 1 : 0); } - /** - * Writes the keyset mapping to the provided package. {@code null} mappings are permitted. - */ - private static void writeKeySetMapping( - Parcel dest, ArrayMap> keySetMapping) { - if (keySetMapping == null) { - dest.writeInt(-1); - return; - } - - final int N = keySetMapping.size(); - dest.writeInt(N); - - for (int i = 0; i < N; i++) { - dest.writeString(keySetMapping.keyAt(i)); - ArraySet keys = keySetMapping.valueAt(i); - if (keys == null) { - dest.writeInt(-1); - continue; - } - - final int M = keys.size(); - dest.writeInt(M); - for (int j = 0; j < M; j++) { - dest.writeSerializable(keys.valueAt(j)); - } - } - } - - /** - * Reads a keyset mapping from the given parcel at the given data position. May return - * {@code null} if the serialized mapping was {@code null}. - */ - private static ArrayMap> readKeySetMapping(Parcel in) { - final int N = in.readInt(); - if (N == -1) { - return null; - } - - ArrayMap> keySetMapping = new ArrayMap<>(); - for (int i = 0; i < N; ++i) { - String key = in.readString(); - final int M = in.readInt(); - if (M == -1) { - keySetMapping.put(key, null); - continue; - } - - ArraySet keys = new ArraySet<>(M); - for (int j = 0; j < M; ++j) { - PublicKey pk = (PublicKey) in.readSerializable(); - keys.add(pk); - } - - keySetMapping.put(key, keys); - } - - return keySetMapping; - } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public Package createFromParcel(Parcel in) { return new Package(in); diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java index 9fee7bb924900..f2a6a5c9382f1 100644 --- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java +++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java @@ -535,7 +535,7 @@ public class PackageInfoWithoutStateUtils { ai.setMaxAspectRatio(maxAspectRatio != null ? maxAspectRatio : 0f); Float minAspectRatio = a.getMinAspectRatio(); ai.setMinAspectRatio(minAspectRatio != null ? minAspectRatio : 0f); - ai.supportsSizeChanges = a.getSupportsSizeChanges(); + ai.supportsSizeChanges = a.isSupportsSizeChanges(); ai.requestedVrComponent = a.getRequestedVrComponent(); ai.rotationAnimation = a.getRotationAnimation(); ai.colorMode = a.getColorMode(); diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java index 72cc9299376a4..d6e1ac903c42f 100644 --- a/core/java/android/content/pm/parsing/ParsingPackage.java +++ b/core/java/android/content/pm/parsing/ParsingPackage.java @@ -360,7 +360,7 @@ public interface ParsingPackage extends ParsingPackageRead { ParsingPackage setCompileSdkVersion(int compileSdkVersion); - ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename); + ParsingPackage setCompileSdkVersionCodeName(String compileSdkVersionCodeName); ParsingPackage setAttributionsAreUserVisible(boolean attributionsAreUserVisible); diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java index 0db65467c6865..f0d95d97263a9 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java +++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java @@ -553,7 +553,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { setCompileSdkVersion(manifestArray.getInteger( R.styleable.AndroidManifest_compileSdkVersion, 0)); - setCompileSdkVersionCodename(manifestArray.getNonConfigurationString( + setCompileSdkVersionCodeName(manifestArray.getNonConfigurationString( R.styleable.AndroidManifest_compileSdkVersionCodename, 0)); setIsolatedSplitLoading(manifestArray.getBoolean( @@ -2686,8 +2686,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { } @Override - public ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename) { - this.compileSdkVersionCodeName = compileSdkVersionCodename; + public ParsingPackage setCompileSdkVersionCodeName(String compileSdkVersionCodeName) { + this.compileSdkVersionCodeName = compileSdkVersionCodeName; return this; } diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java index 73ee13212e90d..adb6b76473eb0 100644 --- a/core/java/android/content/pm/parsing/component/ParsedActivity.java +++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java @@ -23,6 +23,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityTaskManager; import android.content.ComponentName; @@ -423,6 +424,7 @@ public class ParsedActivity extends ParsedMainComponent { } } + @NonNull public static final Parcelable.Creator CREATOR = new Creator() { @Override public ParsedActivity createFromParcel(Parcel source) { @@ -513,10 +515,6 @@ public class ParsedActivity extends ParsedMainComponent { return minAspectRatio; } - public boolean getSupportsSizeChanges() { - return supportsSizeChanges; - } - @Nullable public String getRequestedVrComponent() { return requestedVrComponent; diff --git a/core/java/android/content/pm/parsing/component/ParsedComponent.java b/core/java/android/content/pm/parsing/component/ParsedComponent.java index 3c0f097285ca3..838adfd3215e0 100644 --- a/core/java/android/content/pm/parsing/component/ParsedComponent.java +++ b/core/java/android/content/pm/parsing/component/ParsedComponent.java @@ -43,8 +43,8 @@ import java.util.Map; /** @hide */ public abstract class ParsedComponent implements Parcelable { - private static ParsedIntentInfo.ListParceler sForIntentInfos = Parcelling.Cache.getOrCreate( - ParsedIntentInfo.ListParceler.class); + private static final ParsedIntentInfo.ListParceler sForIntentInfos = + Parcelling.Cache.getOrCreate(ParsedIntentInfo.ListParceler.class); @NonNull @DataClass.ParcelWith(ForInternedString.class) diff --git a/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java b/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java index 65ff4720063b6..41789204a76d4 100644 --- a/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java +++ b/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java @@ -18,6 +18,7 @@ package android.content.pm.parsing.component; import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.os.Parcel; @@ -94,6 +95,7 @@ public class ParsedInstrumentation extends ParsedComponent { this.functionalTest = in.readByte() != 0; } + @NonNull public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java index 01ee0f4828f97..59d4a95edb0aa 100644 --- a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java +++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java @@ -16,6 +16,7 @@ package android.content.pm.parsing.component; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.IntentFilter; import android.os.Parcel; @@ -58,6 +59,7 @@ public final class ParsedIntentInfo extends IntentFilter { item.writeIntentInfoToParcel(dest, parcelFlags); } + @NonNull @Override public ParsedIntentInfo unparcel(Parcel source) { return new ParsedIntentInfo(source); diff --git a/core/java/android/content/pm/parsing/component/ParsedPermission.java b/core/java/android/content/pm/parsing/component/ParsedPermission.java index 50bc3d98fb2a0..0f82941f92b12 100644 --- a/core/java/android/content/pm/parsing/component/ParsedPermission.java +++ b/core/java/android/content/pm/parsing/component/ParsedPermission.java @@ -16,6 +16,7 @@ package android.content.pm.parsing.component; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.PermissionInfo; import android.os.Parcel; @@ -167,6 +168,7 @@ public class ParsedPermission extends ParsedComponent { this.knownCerts = sForStringSet.unparcel(in); } + @NonNull public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override diff --git a/core/java/android/content/pm/parsing/component/ParsedProcess.java b/core/java/android/content/pm/parsing/component/ParsedProcess.java index c39d6b1d32505..fe102252931e5 100644 --- a/core/java/android/content/pm/parsing/component/ParsedProcess.java +++ b/core/java/android/content/pm/parsing/component/ParsedProcess.java @@ -19,7 +19,6 @@ package android.content.pm.parsing.component; import static java.util.Collections.emptySet; import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.pm.ApplicationInfo; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/content/pm/parsing/component/ParsedProvider.java b/core/java/android/content/pm/parsing/component/ParsedProvider.java index ebf85f71d2821..9a12b48cffb06 100644 --- a/core/java/android/content/pm/parsing/component/ParsedProvider.java +++ b/core/java/android/content/pm/parsing/component/ParsedProvider.java @@ -169,6 +169,7 @@ public class ParsedProvider extends ParsedMainComponent { this.pathPermissions = in.createTypedArray(PathPermission.CREATOR); } + @NonNull public static final Parcelable.Creator CREATOR = new Creator() { @Override public ParsedProvider createFromParcel(Parcel source) { diff --git a/core/java/android/content/pm/parsing/component/ParsedService.java b/core/java/android/content/pm/parsing/component/ParsedService.java index 471d3468a084a..5499a130a4ad1 100644 --- a/core/java/android/content/pm/parsing/component/ParsedService.java +++ b/core/java/android/content/pm/parsing/component/ParsedService.java @@ -18,6 +18,7 @@ package android.content.pm.parsing.component; import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.os.Parcel; @@ -83,6 +84,7 @@ public class ParsedService extends ParsedMainComponent { this.permission = sForInternedString.unparcel(in); } + @NonNull public static final Parcelable.Creator CREATOR = new Creator() { @Override public ParsedService createFromParcel(Parcel source) { diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java index 3eb4bde6c67d0..2fcc4b2fae59e 100644 --- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java +++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java @@ -55,6 +55,7 @@ import java.util.UUID; */ public final class PackageImpl extends ParsingPackageImpl implements ParsedPackage, AndroidPackage { + @NonNull public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath, @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp) { return new PackageImpl(packageName, baseCodePath, codePath, manifestArray, isCoreApp); @@ -70,6 +71,7 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka * this case only cares about * volumeUuid, just fake it rather than having separate method paths. */ + @NonNull public static AndroidPackage buildFakeForDeletion(String packageName, String volumeUuid) { return ((ParsedPackage) PackageImpl.forTesting(packageName) .setVolumeUuid(volumeUuid) @@ -77,11 +79,13 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka .hideAsFinal(); } + @NonNull @VisibleForTesting public static ParsingPackage forTesting(String packageName) { return forTesting(packageName, ""); } + @NonNull @VisibleForTesting public static ParsingPackage forTesting(String packageName, String baseCodePath) { return new PackageImpl(packageName, baseCodePath, baseCodePath, null, false); @@ -568,6 +572,7 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka assignDerivedFields(); } + @NonNull public static final Creator CREATOR = new Creator() { @Override public PackageImpl createFromParcel(Parcel source) { diff --git a/services/tests/PackageManagerServiceTests/unit/Android.bp b/services/tests/PackageManagerServiceTests/unit/Android.bp index 988c02bfb3db5..1bcc3d1f70ad8 100644 --- a/services/tests/PackageManagerServiceTests/unit/Android.bp +++ b/services/tests/PackageManagerServiceTests/unit/Android.bp @@ -32,6 +32,7 @@ android_test { "androidx.test.runner", "junit", "kotlin-test", + "kotlin-reflect", "services.core", "servicestests-utils", "truth-prebuilt", diff --git a/services/tests/PackageManagerServiceTests/unit/TEST_MAPPING b/services/tests/PackageManagerServiceTests/unit/TEST_MAPPING new file mode 100644 index 0000000000000..cacfcf0dbebce --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "PackageManagerServiceUnitTests" + } + ] +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt new file mode 100644 index 0000000000000..a7644ec439da5 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt @@ -0,0 +1,572 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.content.Intent +import android.content.pm.ApplicationInfo +import android.content.pm.ConfigurationInfo +import android.content.pm.FeatureGroupInfo +import android.content.pm.FeatureInfo +import android.content.pm.PackageManager +import android.content.pm.SigningDetails +import android.content.pm.parsing.ParsingPackage +import android.content.pm.parsing.component.ParsedActivity +import android.content.pm.parsing.component.ParsedAttribution +import android.content.pm.parsing.component.ParsedComponent +import android.content.pm.parsing.component.ParsedInstrumentation +import android.content.pm.parsing.component.ParsedIntentInfo +import android.content.pm.parsing.component.ParsedPermission +import android.content.pm.parsing.component.ParsedPermissionGroup +import android.content.pm.parsing.component.ParsedProcess +import android.content.pm.parsing.component.ParsedProvider +import android.content.pm.parsing.component.ParsedService +import android.content.pm.parsing.component.ParsedUsesPermission +import android.net.Uri +import android.os.Bundle +import android.os.Parcelable +import android.util.ArraySet +import android.util.SparseArray +import android.util.SparseIntArray +import com.android.internal.R +import com.android.server.pm.parsing.pkg.AndroidPackage +import com.android.server.pm.parsing.pkg.PackageImpl +import com.android.server.testutils.mockThrowOnUnmocked +import com.android.server.testutils.whenever +import java.security.KeyPairGenerator +import java.security.PublicKey +import kotlin.contracts.ExperimentalContracts + +@ExperimentalContracts +class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, PackageImpl::class) { + + override val defaultImpl = PackageImpl.forTesting("com.example.test") + override val creator = PackageImpl.CREATOR + + override val excludedMethods = listOf( + // Internal methods + "toAppInfoToString", + "toAppInfoWithoutState", + "toAppInfoWithoutStateWithoutFlags", + "assignDerivedFields", + "buildFakeForDeletion", + "capPermissionPriorities", + "forParsing", + "forTesting", + "getBaseAppDataCredentialProtectedDirForSystemUser", + "getBaseAppDataDeviceProtectedDirForSystemUser", + "getBoolean", + "setBoolean", + "hideAsFinal", + "hideAsParsed", + "markNotActivitiesAsNotExportedIfSingleUser", + "sortActivities", + "sortReceivers", + "sortServices", + "setAllComponentsDirectBootAware", + // Tested through setting minor/major manually + "setLongVersionCode", + "getLongVersionCode", + // Tested through constructor + "getManifestPackageName", + "setManifestPackageName", + // Utility methods + "getStorageUuid", + // Removal not tested, irrelevant for parcelling concerns + "removeUsesOptionalLibrary", + "clearAdoptPermissions", + "clearOriginalPackages", + "clearProtectedBroadcasts", + "removePermission", + "removeUsesLibrary", + "removeUsesOptionalNativeLibrary", + // Tested manually + "getMimeGroups", + "getRequestedPermissions", + // Tested through asSplit + "asSplit", + "getSplitNames", + "getSplitCodePaths", + "getSplitRevisionCodes", + "getSplitFlags", + "getSplitClassLoaderNames", + "getSplitDependencies", + "setSplitCodePaths", + "setSplitClassLoaderName", + "setSplitHasCode", + ) + + override val baseParams = listOf( + AndroidPackage::getAppComponentFactory, + AndroidPackage::getAutoRevokePermissions, + AndroidPackage::getBackupAgentName, + AndroidPackage::getBanner, + AndroidPackage::getBaseApkPath, + AndroidPackage::getBaseRevisionCode, + AndroidPackage::getCategory, + AndroidPackage::getClassLoaderName, + AndroidPackage::getClassName, + AndroidPackage::getCompatibleWidthLimitDp, + AndroidPackage::getCompileSdkVersion, + AndroidPackage::getCompileSdkVersionCodeName, + AndroidPackage::getDataExtractionRules, + AndroidPackage::getDescriptionRes, + AndroidPackage::getFullBackupContent, + AndroidPackage::getGwpAsanMode, + AndroidPackage::getIconRes, + AndroidPackage::getInstallLocation, + AndroidPackage::getLabelRes, + AndroidPackage::getLargestWidthLimitDp, + AndroidPackage::getLogo, + AndroidPackage::getManageSpaceActivityName, + AndroidPackage::getMemtagMode, + AndroidPackage::getMinSdkVersion, + AndroidPackage::getNativeHeapZeroInitialized, + AndroidPackage::getNativeLibraryDir, + AndroidPackage::getNativeLibraryRootDir, + AndroidPackage::getNetworkSecurityConfigRes, + AndroidPackage::getNonLocalizedLabel, + AndroidPackage::getOverlayCategory, + AndroidPackage::getOverlayPriority, + AndroidPackage::getOverlayTarget, + AndroidPackage::getOverlayTargetName, + AndroidPackage::getPackageName, + AndroidPackage::getPath, + AndroidPackage::getPermission, + AndroidPackage::getPrimaryCpuAbi, + AndroidPackage::getProcessName, + AndroidPackage::getRealPackage, + AndroidPackage::getRequiredAccountType, + AndroidPackage::getRequiresSmallestWidthDp, + AndroidPackage::getResizeableActivity, + AndroidPackage::getRestrictedAccountType, + AndroidPackage::getRoundIconRes, + AndroidPackage::getSeInfo, + AndroidPackage::getSeInfoUser, + AndroidPackage::getSecondaryCpuAbi, + AndroidPackage::getSecondaryNativeLibraryDir, + AndroidPackage::getSharedUserId, + AndroidPackage::getSharedUserLabel, + AndroidPackage::getStaticSharedLibName, + AndroidPackage::getStaticSharedLibVersion, + AndroidPackage::getTargetSandboxVersion, + AndroidPackage::getTargetSdkVersion, + AndroidPackage::getTaskAffinity, + AndroidPackage::getTheme, + AndroidPackage::getUiOptions, + AndroidPackage::getUid, + AndroidPackage::getVersionName, + AndroidPackage::getZygotePreloadName, + AndroidPackage::isAllowAudioPlaybackCapture, + AndroidPackage::isAllowBackup, + AndroidPackage::isAllowClearUserData, + AndroidPackage::isAllowClearUserDataOnFailedRestore, + AndroidPackage::isAllowNativeHeapPointerTagging, + AndroidPackage::isAllowTaskReparenting, + AndroidPackage::isBackupInForeground, + AndroidPackage::isBaseHardwareAccelerated, + AndroidPackage::isCantSaveState, + AndroidPackage::isCoreApp, + AndroidPackage::isCrossProfile, + AndroidPackage::isDebuggable, + AndroidPackage::isDefaultToDeviceProtectedStorage, + AndroidPackage::isDirectBootAware, + AndroidPackage::isEnabled, + AndroidPackage::isExternalStorage, + AndroidPackage::isExtractNativeLibs, + AndroidPackage::isFactoryTest, + AndroidPackage::isForceQueryable, + AndroidPackage::isFullBackupOnly, + AndroidPackage::isGame, + AndroidPackage::isHasCode, + AndroidPackage::isHasDomainUrls, + AndroidPackage::isHasFragileUserData, + AndroidPackage::isIsolatedSplitLoading, + AndroidPackage::isKillAfterRestore, + AndroidPackage::isLargeHeap, + AndroidPackage::isMultiArch, + AndroidPackage::isNativeLibraryRootRequiresIsa, + AndroidPackage::isOdm, + AndroidPackage::isOem, + AndroidPackage::isOverlay, + AndroidPackage::isOverlayIsStatic, + AndroidPackage::isPartiallyDirectBootAware, + AndroidPackage::isPersistent, + AndroidPackage::isPrivileged, + AndroidPackage::isProduct, + AndroidPackage::isProfileableByShell, + AndroidPackage::isRequestLegacyExternalStorage, + AndroidPackage::isRequiredForAllUsers, + AndroidPackage::isResizeableActivityViaSdkVersion, + AndroidPackage::isRestoreAnyVersion, + AndroidPackage::isSignedWithPlatformKey, + AndroidPackage::isStaticSharedLibrary, + AndroidPackage::isStub, + AndroidPackage::isSupportsRtl, + AndroidPackage::isSystem, + AndroidPackage::isSystemExt, + AndroidPackage::isTestOnly, + AndroidPackage::isUse32BitAbi, + AndroidPackage::isUseEmbeddedDex, + AndroidPackage::isUsesCleartextTraffic, + AndroidPackage::isUsesNonSdkApi, + AndroidPackage::isVendor, + AndroidPackage::isVisibleToInstantApps, + AndroidPackage::isVmSafeMode, + AndroidPackage::getMaxAspectRatio, + AndroidPackage::getMinAspectRatio, + AndroidPackage::hasPreserveLegacyExternalStorage, + AndroidPackage::hasRequestForegroundServiceExemption, + AndroidPackage::hasRequestRawExternalStorageAccess, + ) + + override fun extraParams() = listOf( + getter(AndroidPackage::getVolumeUuid, "57554103-df3e-4475-ae7a-8feba49353ac"), + getter(AndroidPackage::isProfileable, true), + getter(AndroidPackage::getVersionCode, 3), + getter(AndroidPackage::getVersionCodeMajor, 9), + getter(AndroidPackage::getUpgradeKeySets, setOf("testUpgradeKeySet")), + getter(AndroidPackage::isAnyDensity, false, 0), + getter(AndroidPackage::isResizeable, false, 0), + getter(AndroidPackage::isSupportsSmallScreens, false, 0), + getter(AndroidPackage::isSupportsNormalScreens, false, 0), + getter(AndroidPackage::isSupportsLargeScreens, false, 0), + getter(AndroidPackage::isSupportsExtraLargeScreens, false, 0), + adder(AndroidPackage::getAdoptPermissions, "test.adopt.PERMISSION"), + adder(AndroidPackage::getOriginalPackages, "com.test.original"), + adder(AndroidPackage::getImplicitPermissions, "test.implicit.PERMISSION"), + adder(AndroidPackage::getLibraryNames, "testLibraryName"), + adder(AndroidPackage::getProtectedBroadcasts, "test.protected.BROADCAST"), + adder(AndroidPackage::getQueriesPackages, "com.test.package.queries"), + adder(AndroidPackage::getQueriesProviders, "com.test.package.queries.provider"), + adder(AndroidPackage::getUsesLibraries, "testUsesLibrary"), + adder(AndroidPackage::getUsesNativeLibraries, "testUsesNativeLibrary"), + adder(AndroidPackage::getUsesOptionalLibraries, "testUsesOptionalLibrary"), + adder(AndroidPackage::getUsesOptionalNativeLibraries, "testUsesOptionalNativeLibrary"), + adder(AndroidPackage::getUsesStaticLibraries, "testUsesStaticLibrary"), + getSetByValue( + AndroidPackage::getUsesStaticLibrariesVersions, + PackageImpl::addUsesStaticLibraryVersion, + (testCounter++).toLong(), + transformGet = { it?.singleOrNull() } + ), + getSetByValue( + AndroidPackage::areAttributionsUserVisible, + ParsingPackage::setAttributionsAreUserVisible, + true + ), + getSetByValue2( + AndroidPackage::getOverlayables, + PackageImpl::addOverlayable, + "testOverlayableName" to "testActorName", + transformGet = { "testOverlayableName" to it["testOverlayableName"] } + ), + getSetByValue( + AndroidPackage::getMetaData, + PackageImpl::setMetaData, + "testBundleKey" to "testBundleValue", + transformGet = { "testBundleKey" to it?.getString("testBundleKey") }, + transformSet = { Bundle().apply { putString(it.first, it.second) } } + ), + getSetByValue( + AndroidPackage::getAttributions, + PackageImpl::addAttribution, + Triple("testTag", 13, listOf("testInherit")), + transformGet = { it.singleOrNull()?.let { Triple(it.tag, it.label, it.inheritFrom) } }, + transformSet = { it?.let { ParsedAttribution(it.first, it.second, it.third) } } + ), + getSetByValue2( + AndroidPackage::getKeySetMapping, + PackageImpl::addKeySet, + "testKeySetName" to testKey(), + transformGet = { "testKeySetName" to it["testKeySetName"]?.singleOrNull() }, + ), + getSetByValue( + AndroidPackage::getPermissionGroups, + PackageImpl::addPermissionGroup, + "test.permission.GROUP", + transformGet = { it.singleOrNull()?.name }, + transformSet = { ParsedPermissionGroup().apply { setName(it) } } + ), + getSetByValue2( + AndroidPackage::getPreferredActivityFilters, + PackageImpl::addPreferredActivityFilter, + "TestClassName" to ParsedIntentInfo().apply { + addDataScheme("http") + addDataAuthority("test.pm.server.android.com", null) + }, + transformGet = { it.singleOrNull()?.let { it.first to it.second } }, + compare = { first, second -> + equalBy( + first, second, + { it.first }, + { it.second.schemesIterator().asSequence().singleOrNull() }, + { it.second.authoritiesIterator().asSequence().singleOrNull()?.host }, + ) + } + ), + getSetByValue( + AndroidPackage::getQueriesIntents, + PackageImpl::addQueriesIntent, + Intent(Intent.ACTION_VIEW, Uri.parse("https://test.pm.server.android.com")), + transformGet = { it.singleOrNull() }, + compare = { first, second -> first?.filterEquals(second) }, + ), + getSetByValue( + AndroidPackage::getRestrictUpdateHash, + PackageImpl::setRestrictUpdateHash, + byteArrayOf(0, 1, 2, 3, 4), + compare = ByteArray::contentEquals + ), + getSetByValue( + AndroidPackage::getSigningDetails, + PackageImpl::setSigningDetails, + testKey(), + transformGet = { it.publicKeys?.takeIf { it.size > 0 }?.valueAt(0) }, + transformSet = { + SigningDetails( + null, + SigningDetails.SignatureSchemeVersion.UNKNOWN, + ArraySet().apply { add(it) }, + null + ) + } + ), + getSetByValue( + AndroidPackage::getUsesStaticLibrariesCertDigests, + PackageImpl::addUsesStaticLibraryCertDigests, + arrayOf("testCertDigest"), + transformGet = { it?.singleOrNull() }, + compare = Array?::contentEquals + ), + getSetByValue( + AndroidPackage::getActivities, + PackageImpl::addActivity, + "TestActivityName", + transformGet = { it.singleOrNull()?.name.orEmpty() }, + transformSet = { ParsedActivity().apply { name = it }.withMimeGroups() } + ), + getSetByValue( + AndroidPackage::getReceivers, + PackageImpl::addReceiver, + "TestReceiverName", + transformGet = { it.singleOrNull()?.name.orEmpty() }, + transformSet = { ParsedActivity().apply { name = it }.withMimeGroups() } + ), + getSetByValue( + AndroidPackage::getServices, + PackageImpl::addService, + "TestServiceName", + transformGet = { it.singleOrNull()?.name.orEmpty() }, + transformSet = { ParsedService().apply { name = it }.withMimeGroups() } + ), + getSetByValue( + AndroidPackage::getProviders, + PackageImpl::addProvider, + "TestProviderName", + transformGet = { it.singleOrNull()?.name.orEmpty() }, + transformSet = { ParsedProvider().apply { name = it }.withMimeGroups() } + ), + getSetByValue( + AndroidPackage::getInstrumentations, + PackageImpl::addInstrumentation, + "TestInstrumentationName", + transformGet = { it.singleOrNull()?.name.orEmpty() }, + transformSet = { ParsedInstrumentation().apply { name = it } } + ), + getSetByValue( + AndroidPackage::getConfigPreferences, + PackageImpl::addConfigPreference, + testCounter++, + transformGet = { it.singleOrNull()?.reqGlEsVersion ?: -1 }, + transformSet = { ConfigurationInfo().apply { reqGlEsVersion = it } } + ), + getSetByValue( + AndroidPackage::getFeatureGroups, + PackageImpl::addFeatureGroup, + "test.feature.GROUP", + transformGet = { it.singleOrNull()?.features?.singleOrNull()?.name.orEmpty() }, + transformSet = { + FeatureGroupInfo().apply { + features = arrayOf(FeatureInfo().apply { name = it }) + } + } + ), + getSetByValue( + AndroidPackage::getPermissions, + PackageImpl::addPermission, + "test.PERMISSION", + transformGet = { it.singleOrNull()?.name.orEmpty() }, + transformSet = { ParsedPermission().apply { name = it } } + ), + getSetByValue( + AndroidPackage::getUsesPermissions, + PackageImpl::addUsesPermission, + "test.USES_PERMISSION", + transformGet = { + // Need to strip implicit permission, which calls addUsesPermission when added + it.filterNot { it.name == "test.implicit.PERMISSION" } + .singleOrNull()?.name.orEmpty() + }, + transformSet = { ParsedUsesPermission(it, 0) } + ), + getSetByValue( + AndroidPackage::getReqFeatures, + PackageImpl::addReqFeature, + "test.feature.INFO", + transformGet = { it.singleOrNull()?.name.orEmpty() }, + transformSet = { FeatureInfo().apply { name = it } } + ), + getSetByValue( + AndroidPackage::getMinExtensionVersions, + PackageImpl::setMinExtensionVersions, + SparseIntArray().apply { put(testCounter++, testCounter++) }, + compare = { first, second -> + equalBy( + first, second, + { it.size() }, + { it.keyAt(0) }, + { it.valueAt(0) }, + ) + } + ), + getSetByValue( + AndroidPackage::getProcesses, + PackageImpl::setProcesses, + mapOf("testProcess" to ParsedProcess().apply { name = "testProcessName" }), + compare = { first, second -> + equalBy( + first, second, + { it["testProcess"]?.name }, + ) + } + ), + getSetByValue( + AndroidPackage::getProperties, + PackageImpl::addProperty, + PackageManager.Property( + "testPropertyName", + "testPropertyValue", + "testPropertyClassName", + "testPropertyPackageName" + ), + transformGet = { it["testPropertyName"] }, + compare = { first, second -> + equalBy( + first, second, + PackageManager.Property::getName, + PackageManager.Property::getClassName, + PackageManager.Property::getPackageName, + PackageManager.Property::getString, + ) + } + ), + ) + + override fun initialObject() = PackageImpl.forParsing( + "com.example.test", + "/test/test/base.apk", + "/test/test", + mockThrowOnUnmocked { + whenever(getInteger(R.styleable.AndroidManifest_revisionCode, 0)) { 4 } + whenever(getBoolean(R.styleable.AndroidManifest_isolatedSplits, false)) { true } + + // Return invalid values here so that the getter/setter is tested properly + whenever(getInteger(R.styleable.AndroidManifest_versionCode, 0)) { -1 } + whenever(getInteger(R.styleable.AndroidManifest_versionCodeMajor, 0)) { -1 } + whenever( + getNonConfigurationString( + R.styleable.AndroidManifest_versionName, + 0 + ) + ) { "" } + whenever(getInteger(R.styleable.AndroidManifest_compileSdkVersion, 0)) { 31 } + whenever( + getNonConfigurationString( + R.styleable.AndroidManifest_compileSdkVersionCodename, + 0 + ) + ) { "" } + }, + true + ) + .asSplit( + arrayOf("testSplitNameZero", "testSplitNameOne"), + arrayOf("/test/testSplitZero.apk", "/test/testSplitOne.apk"), + intArrayOf(10, 11), + SparseArray().apply { + put(0, intArrayOf(-1)) + put(1, intArrayOf(0)) + } + ) + .setSplitHasCode(0, true) + .setSplitHasCode(1, false) + .setSplitClassLoaderName(0, "testSplitClassLoaderNameZero") + .setSplitClassLoaderName(1, "testSplitClassLoaderNameOne") + + override fun extraAssertions(before: Parcelable, after: Parcelable) { + super.extraAssertions(before, after) + after as PackageImpl + expect.that(after.manifestPackageName).isEqualTo("com.example.test") + expect.that(after.isCoreApp).isTrue() + expect.that(after.isIsolatedSplitLoading).isEqualTo(true) + expect.that(after.longVersionCode).isEqualTo(38654705667) + expect.that(after.requestedPermissions) + .containsExactlyElementsIn(after.usesPermissions.map { it.name }) + .inOrder() + + expect.that(after.mimeGroups).containsExactly( + "TestActivityName/mimeGroup", + "TestReceiverName/mimeGroup", + "TestServiceName/mimeGroup", + "TestProviderName/mimeGroup" + ) + + expect.that(after.splitNames).asList() + .containsExactly("testSplitNameZero", "testSplitNameOne") + .inOrder() + expect.that(after.splitCodePaths).asList() + .containsExactly("/test/testSplitZero.apk", "/test/testSplitOne.apk") + .inOrder() + expect.that(after.splitRevisionCodes).asList() + .containsExactly(10, 11) + .inOrder() + expect.that(after.splitFlags).asList() + .containsExactly(ApplicationInfo.FLAG_HAS_CODE, 0) + .inOrder() + expect.that(after.splitClassLoaderNames).asList() + .containsExactly("testSplitClassLoaderNameZero", "testSplitClassLoaderNameOne") + .inOrder() + + expect.that(after.splitDependencies).isNotNull() + after.splitDependencies?.let { + expect.that(it.size()).isEqualTo(2) + expect.that(it.get(0)).asList().containsExactly(-1) + expect.that(it.get(1)).asList().containsExactly(0) + } + } + + private fun testKey() = KeyPairGenerator.getInstance("RSA") + .generateKeyPair() + .public + + private fun T.withMimeGroups() = apply { + val componentName = name + addIntent(ParsedIntentInfo().apply { + addMimeGroup("$componentName/mimeGroup") + }) + } +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableComponentTest.kt new file mode 100644 index 0000000000000..e16a1871f8b8b --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableComponentTest.kt @@ -0,0 +1,413 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.os.Parcel +import android.os.Parcelable +import com.android.server.pm.test.util.IgnoreableExpect +import com.google.common.truth.Expect +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TestRule +import java.util.Objects +import kotlin.contracts.ExperimentalContracts +import kotlin.reflect.KClass +import kotlin.reflect.KFunction +import kotlin.reflect.KFunction1 +import kotlin.reflect.KFunction2 +import kotlin.reflect.KFunction3 +import kotlin.reflect.KVisibility +import kotlin.reflect.full.allSuperclasses +import kotlin.reflect.full.createInstance +import kotlin.reflect.full.isSubclassOf +import kotlin.reflect.full.memberFunctions +import kotlin.reflect.full.memberProperties +import kotlin.reflect.full.staticProperties +import kotlin.reflect.jvm.jvmErasure + + +@ExperimentalContracts +abstract class ParcelableComponentTest( + private val getterType: KClass<*>, + private val setterType: KClass +) { + + companion object { + private val DEFAULT_EXCLUDED = listOf( + // Java + "toString", + "equals", + "hashCode", + // Parcelable + "getStability", + "describeContents", + "writeToParcel", + // @DataClass + "__metadata" + ) + } + + internal val ignoreableExpect = IgnoreableExpect() + + // Hides internal type + @get:Rule + val ignoreableAsTestRule: TestRule = ignoreableExpect + + val expect: Expect + get() = ignoreableExpect.expect + + protected var testCounter = 1 + + protected abstract val defaultImpl: Any + protected abstract val creator: Parcelable.Creator + + protected open val excludedMethods: Collection = emptyList() + + protected abstract val baseParams: Collection> + + private val getters = getterType.memberFunctions + .filterNot { DEFAULT_EXCLUDED.contains(it.name) } + + private val setters = setterType.memberFunctions + .filterNot { DEFAULT_EXCLUDED.contains(it.name) } + + constructor(kClass: KClass) : this(kClass, kClass) + + @Before + fun checkNoPublicFields() { + // Fields are not currently testable, and the idea is to enforce interface access for + // immutability purposes, so disallow any public fields from existing. + expect.that(getterType.memberProperties.filter { it.visibility == KVisibility.PUBLIC } + .filterNot { DEFAULT_EXCLUDED.contains(it.name) }) + .isEmpty() + } + + @Suppress("UNCHECKED_CAST") + private fun buildParams( + getFunction: KFunction1, + ): Param? { + return buildParams( + getFunction, + autoValue(getFunction) as ReturnType ?: return null + ) + } + + @Suppress("UNCHECKED_CAST") + private fun buildParams( + getFunction: KFunction1, + value: SetType, + ): Param? { + return getSetByValue( + getFunction, + findSetFunction(getFunction) ?: return null, + value + ) + } + + @Suppress("UNCHECKED_CAST") + private fun findSetFunction( + getFunction: KFunction1 + ): KFunction2? { + val getFunctionName = getFunction.name + val prefix = when { + getFunctionName.startsWith("get") -> "get" + getFunctionName.startsWith("is") -> "is" + getFunctionName.startsWith("has") -> "has" + else -> throw IllegalArgumentException("Unsupported method name $getFunctionName") + } + val setFunctionName = "set" + getFunctionName.removePrefix(prefix) + val setFunction = setters.filter { it.name == setFunctionName } + .minByOrNull { it.parameters.size } + + if (setFunction == null) { + expect.withMessage("$getFunctionName does not have corresponding $setFunctionName") + .fail() + return null + } + + return setFunction as KFunction2 + } + + @Suppress("UNCHECKED_CAST") + private fun findAddFunction( + getFunction: KFunction1 + ): KFunction2? { + val getFunctionName = getFunction.name + if (!getFunctionName.startsWith("get")) { + throw IllegalArgumentException("Unsupported method name $getFunctionName") + } + + val setFunctionName = "add" + getFunctionName.removePrefix("get").run { + // Remove plurality + when { + endsWith("ies") -> "${removeSuffix("ies")}y" + endsWith("s") -> removeSuffix("s") + else -> this + } + } + + val setFunction = setters.filter { it.name == setFunctionName } + .minByOrNull { it.parameters.size } + + if (setFunction == null) { + expect.withMessage("$getFunctionName does not have corresponding $setFunctionName") + .fail() + return null + } + + return setFunction as KFunction2 + } + + protected fun getter( + getFunction: KFunction1, + valueToSet: ReturnType + ) = buildParams(getFunction, valueToSet) + + protected fun getter( + getFunction: KFunction1, + expectedValue: CompareType, + valueToSet: SetType + ): Param? { + return getSetByValue( + getFunction, + findSetFunction(getFunction) ?: return null, + value = expectedValue, + transformSet = { valueToSet } + ) + } + + @Suppress("UNCHECKED_CAST") + protected fun adder( + getFunction: KFunction1, + value: ReturnType, + ): Param? { + return getSetByValue( + getFunction, + findAddFunction(getFunction) ?: return null, + value, + transformGet = { + // Primitive arrays don't implement Iterable, so cast manually + when (it) { + is BooleanArray -> it.singleOrNull() + is IntArray -> it.singleOrNull() + is LongArray -> it.singleOrNull() + is Iterable<*> -> it.singleOrNull() + else -> null + } + }, + ) + } + + /** + * Method to provide custom getter and setter logic for values which are not simple primitives + * or cannot be directly compared using [Objects.equals]. + * + * @param getFunction the getter function which will be called and marked as tested + * @param setFunction the setter function which will be called and marked as tested + * @param value the value for comparison through the parcel-unparcel cycle, which can be + * anything, like the [String] ID of an inner object + * @param transformGet the function to transform the result of [getFunction] into [value] + * @param transformSet the function to transform [value] into an input for [setFunction] + * @param compare the function that compares the pre/post-parcel [value] objects + */ + @Suppress("UNCHECKED_CAST") + protected fun getSetByValue( + getFunction: KFunction1, + setFunction: KFunction2, + value: CompareType, + transformGet: (ReturnType) -> CompareType = { it as CompareType }, + transformSet: (CompareType) -> SetType = { it as SetType }, + compare: (CompareType, CompareType) -> Boolean? = Objects::equals + ) = Param( + getFunction.name, + { transformGet(getFunction.call(it as ObjectType)) }, + setFunction.name, + { setFunction.call(it.first() as ObjectType, transformSet(it[1] as CompareType)) }, + { value }, + { first, second -> compare(first as CompareType, second as CompareType) == true } + ) + + /** + * Variant of [getSetByValue] that allows specifying a [setFunction] with 2 inputs. + */ + @Suppress("UNCHECKED_CAST") + protected fun + getSetByValue2( + getFunction: KFunction1, + setFunction: KFunction3, + value: CompareType, + transformGet: (ReturnType) -> CompareType = { it as CompareType }, + transformSet: (CompareType) -> Pair = + { it as Pair }, + compare: (CompareType, CompareType) -> Boolean = Objects::equals + ) = Param( + getFunction.name, + { transformGet(getFunction.call(it as ObjectType)) }, + setFunction.name, + { + val pair = transformSet(it[1] as CompareType) + setFunction.call(it.first() as ObjectType, pair.first, pair.second) + }, + { value }, + { first, second -> compare(first as CompareType, second as CompareType) } + ) + + protected fun autoValue(getFunction: KFunction<*>) = when (getFunction.returnType.jvmErasure) { + Boolean::class -> (getFunction.call(defaultImpl) as Boolean?)?.not() ?: true + CharSequence::class, + String::class -> getFunction.name + "TEST" + Int::class -> testCounter++ + Long::class -> (testCounter++).toLong() + Float::class -> (testCounter++).toFloat() + else -> { + expect.withMessage("${getFunction.name} needs to provide value").fail() + null + } + } + + /** + * Verifies two instances are equivalent via a series of properties. For use when a public API + * class has not implemented equals. + */ + @Suppress("UNCHECKED_CAST") + protected fun equalBy( + first: T?, + second: T?, + vararg properties: (T) -> Any? + ) = properties.all { property -> + first?.let { property(it) } == second?.let { property(it) } + } + + @Test + fun valueComparison() { + val params = baseParams.mapNotNull(::buildParams) + extraParams().filterNotNull() + val before = initialObject() + + params.forEach { it.setFunction(arrayOf(before, it.value())) } + + val parcel = Parcel.obtain() + writeToParcel(parcel, before) + + val dataSize = parcel.dataSize() + + parcel.setDataPosition(0) + + val after = creator.createFromParcel(parcel) + + expect.withMessage("Mismatched write and read data sizes") + .that(parcel.dataPosition()) + .isEqualTo(dataSize) + + parcel.recycle() + + runAssertions(params, before, after) + } + + @Test + open fun parcellingSize() { + val parcelOne = Parcel.obtain() + writeToParcel(parcelOne, initialObject()) + + val parcelTwo = Parcel.obtain() + initialObject().writeToParcel(parcelTwo, 0) + + val superDataSizes = setterType.allSuperclasses + .filter { it.isSubclassOf(Parcelable::class) } + .mapNotNull { it.memberFunctions.find { it.name == "writeToParcel" } } + .filter { it.isFinal } + .map { + val parcel = Parcel.obtain() + initialObject().writeToParcel(parcel, 0) + parcel.dataSize().also { parcel.recycle() } + } + + if ((superDataSizes + parcelOne.dataSize() + parcelTwo.dataSize()).distinct().size != 1) { + listOf(getterType, setterType).distinct().forEach { + val creatorProperties = it.staticProperties.filter { it.name == "CREATOR" } + if (creatorProperties.size > 1) { + expect.withMessage( + "Multiple matching CREATOR fields found for" + + it.qualifiedName + ) + .that(creatorProperties) + .hasSize(1) + } else { + val creator = creatorProperties.single().get() + if (creator !is Parcelable.Creator<*>) { + expect.that(creator).isInstanceOf(Parcelable.Creator::class.java) + return + } + + parcelTwo.setDataPosition(0) + val parcelable = creator.createFromParcel(parcelTwo) + if (parcelable::class.isSubclassOf(setterType)) { + expect.withMessage( + "${it.qualifiedName} which does not safely override writeToParcel " + + "cannot contain a subclass CREATOR field" + ) + .fail() + } + } + } + } + + parcelOne.recycle() + parcelTwo.recycle() + } + + private fun runAssertions(params: List, before: Parcelable, after: Parcelable) { + params.forEach { + val actual = it.getFunction(after) + val expected = it.value() + val equal = it.compare(actual, expected) + expect.withMessage("${it.getFunctionName} was $actual, expected $expected") + .that(equal) + .isTrue() + } + + extraAssertions(before, after) + + // TODO: Handle method overloads? + val expectedFunctions = (getters.map { it.name } + + setters.map { it.name } + - excludedMethods) + .distinct() + + val allTestedFunctions = params.flatMap { + listOfNotNull(it.getFunctionName, it.setFunctionName) + } + expect.that(allTestedFunctions).containsExactlyElementsIn(expectedFunctions) + } + + open fun extraParams(): Collection = emptyList() + + open fun initialObject(): Parcelable = setterType.createInstance() + + open fun extraAssertions(before: Parcelable, after: Parcelable) {} + + open fun writeToParcel(parcel: Parcel, value: Parcelable) = value.writeToParcel(parcel, 0) + + data class Param( + val getFunctionName: String, + val getFunction: (Any?) -> Any?, + val setFunctionName: String?, + val setFunction: (Array) -> Unit, + val value: () -> Any?, + val compare: (Any?, Any?) -> Boolean = Objects::equals + ) +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableCreatorInvalidTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableCreatorInvalidTest.kt new file mode 100644 index 0000000000000..d506190b8b094 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableCreatorInvalidTest.kt @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.os.Parcel +import android.os.Parcelable +import com.android.server.pm.test.parsing.parcelling.java.TestSubWithCreator +import com.android.server.pm.test.parsing.parcelling.java.TestSuperClass +import org.junit.Test +import kotlin.contracts.ExperimentalContracts + +/** + * Verifies the failing side of [ParcelableCreatorValidTest]. The sole difference is the addition + * of [TestSubWithCreator.CREATOR]. + */ +@ExperimentalContracts +class ParcelableCreatorInvalidTest : + ParcelableComponentTest(TestSuperClass::class, TestSubWithCreator::class) { + + override val defaultImpl = TestSubWithCreator() + + override val creator = object : Parcelable.Creator { + override fun createFromParcel(source: Parcel) = TestSubWithCreator(source) + override fun newArray(size: Int) = Array(size) { null } + } + + override val excludedMethods = listOf("writeSubToParcel") + + override val baseParams = listOf(TestSuperClass::getSuperString) + + override fun writeToParcel(parcel: Parcel, value: Parcelable) { + (value as TestSubWithCreator).writeSubToParcel(parcel, 0) + } + + @Test + override fun parcellingSize() { + super.parcellingSize() + if (expect.hasFailures()) { + // This is a hack to ignore an expected failure result. Doing it this way, rather than + // adding a switch in the test itself, prevents it from accidentally passing through a + // programming error. + ignoreableExpect.ignore() + } + } +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableCreatorValidTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableCreatorValidTest.kt new file mode 100644 index 0000000000000..f1bc7b5a07f4e --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableCreatorValidTest.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.os.Parcel +import android.os.Parcelable +import com.android.server.pm.test.parsing.parcelling.java.TestSubWithoutCreator +import com.android.server.pm.test.parsing.parcelling.java.TestSuperClass +import kotlin.contracts.ExperimentalContracts + +/** + * Tests the [Parcelable] CREATOR verification by using a mock object with known differences to + * ensure that the method succeeds/fails. + */ +@ExperimentalContracts +class ParcelableCreatorValidTest : + ParcelableComponentTest(TestSuperClass::class, TestSubWithoutCreator::class) { + + override val defaultImpl = TestSubWithoutCreator() + + override val creator = object : Parcelable.Creator { + override fun createFromParcel(source: Parcel) = TestSubWithoutCreator(source) + override fun newArray(size: Int) = Array(size) { null } + } + + override val excludedMethods = listOf("writeSubToParcel") + + override val baseParams = listOf(TestSuperClass::getSuperString) + + override fun writeToParcel(parcel: Parcel, value: Parcelable) { + (value as TestSubWithoutCreator).writeSubToParcel(parcel, 0) + } +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt new file mode 100644 index 0000000000000..ece600bc446e5 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.content.pm.ActivityInfo +import android.content.pm.parsing.component.ParsedActivity +import kotlin.contracts.ExperimentalContracts + +@ExperimentalContracts +class ParsedActivityTest : ParsedMainComponentTest(ParsedActivity::class) { + + override val defaultImpl = ParsedActivity() + override val creator = ParsedActivity.CREATOR + + override val mainComponentSubclassBaseParams = listOf( + ParsedActivity::getPermission, + ParsedActivity::getColorMode, + ParsedActivity::getConfigChanges, + ParsedActivity::getDocumentLaunchMode, + ParsedActivity::getLaunchMode, + ParsedActivity::getLockTaskLaunchMode, + ParsedActivity::getMaxAspectRatio, + ParsedActivity::getMaxRecents, + ParsedActivity::getMinAspectRatio, + ParsedActivity::getParentActivityName, + ParsedActivity::getPersistableMode, + ParsedActivity::getPrivateFlags, + ParsedActivity::getRequestedVrComponent, + ParsedActivity::getResizeMode, + ParsedActivity::getRotationAnimation, + ParsedActivity::getScreenOrientation, + ParsedActivity::getSoftInputMode, + ParsedActivity::getTargetActivity, + ParsedActivity::getTaskAffinity, + ParsedActivity::getTheme, + ParsedActivity::getUiOptions, + ParsedActivity::isSupportsSizeChanges, + ) + + override fun mainComponentSubclassExtraParams() = listOf( + getSetByValue( + ParsedActivity::getWindowLayout, + ParsedActivity::setWindowLayout, + ActivityInfo.WindowLayout(1, 1f, 2, 1f, 3, 4, 5), + compare = { first, second -> + equalBy( + first, second, + ActivityInfo.WindowLayout::width, + ActivityInfo.WindowLayout::widthFraction, + ActivityInfo.WindowLayout::height, + ActivityInfo.WindowLayout::heightFraction, + ActivityInfo.WindowLayout::gravity, + ActivityInfo.WindowLayout::minWidth, + ActivityInfo.WindowLayout::minHeight + ) + } + ) + ) +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt new file mode 100644 index 0000000000000..e739dc70cdbb3 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.content.pm.parsing.component.ParsedAttribution +import kotlin.contracts.ExperimentalContracts + +@ExperimentalContracts +class ParsedAttributionTest : ParcelableComponentTest(ParsedAttribution::class) { + + override val defaultImpl = ParsedAttribution("", 0, emptyList()) + override val creator = ParsedAttribution.CREATOR + + override val baseParams = listOf( + ParsedAttribution::getTag, + ParsedAttribution::getLabel, + ) + + override fun extraParams() = listOf( + getter(ParsedAttribution::getInheritFrom, listOf("testInheritFrom")) + ) +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt new file mode 100644 index 0000000000000..0a22f6d301a9d --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.content.pm.PackageManager +import android.content.pm.parsing.component.ParsedComponent +import android.content.pm.parsing.component.ParsedIntentInfo +import android.os.Bundle +import android.os.Parcelable +import kotlin.contracts.ExperimentalContracts +import kotlin.reflect.KClass +import kotlin.reflect.KFunction1 + +@ExperimentalContracts +abstract class ParsedComponentTest(kClass: KClass) : + ParcelableComponentTest(kClass) { + + final override val excludedMethods + get() = subclassExcludedMethods + listOf( + // Method aliases/utilities + "getClassName", + "getComponentName", + "setProperties" // Tested though addProperty + ) + + open val subclassExcludedMethods: Collection = emptyList() + + final override val baseParams + get() = subclassBaseParams + listOf( + ParsedComponent::getBanner, + ParsedComponent::getDescriptionRes, + ParsedComponent::getFlags, + ParsedComponent::getIcon, + ParsedComponent::getLabelRes, + ParsedComponent::getLogo, + ParsedComponent::getName, + ParsedComponent::getNonLocalizedLabel, + ParsedComponent::getPackageName, + ) + + abstract val subclassBaseParams: Collection> + + final override fun extraParams() = subclassExtraParams() + listOf( + getSetByValue( + ParsedComponent::getIntents, + ParsedComponent::addIntent, + "TestLabel", + transformGet = { it.singleOrNull()?.nonLocalizedLabel }, + transformSet = { ParsedIntentInfo().setNonLocalizedLabel(it) }, + ), + getSetByValue( + ParsedComponent::getProperties, + ParsedComponent::addProperty, + PackageManager.Property( + "testPropertyName", + "testPropertyValue", + "testPropertyClassName", + "testPropertyPackageName" + ), + transformGet = { it["testPropertyName"] }, + compare = { first, second -> + equalBy( + first, second, + PackageManager.Property::getName, + PackageManager.Property::getClassName, + PackageManager.Property::getPackageName, + PackageManager.Property::getString, + ) + } + ), + getSetByValue( + ParsedComponent::getMetaData, + ParsedComponent::setMetaData, + "testBundleKey" to "testBundleValue", + transformGet = { "testBundleKey" to it?.getString("testBundleKey") }, + transformSet = { Bundle().apply { putString(it.first, it.second) } } + ), + ) + + open fun subclassExtraParams(): Collection = emptyList() +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt new file mode 100644 index 0000000000000..b7a85cc3d186f --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.content.pm.parsing.component.ParsedInstrumentation +import kotlin.contracts.ExperimentalContracts + +@ExperimentalContracts +class ParsedInstrumentationTest : ParsedComponentTest(ParsedInstrumentation::class) { + + override val defaultImpl = ParsedInstrumentation() + override val creator = ParsedInstrumentation.CREATOR + + override val subclassBaseParams = listOf( + ParsedInstrumentation::getTargetPackage, + ParsedInstrumentation::getTargetProcesses, + ParsedInstrumentation::isFunctionalTest, + ParsedInstrumentation::isHandleProfiling, + ) +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt new file mode 100644 index 0000000000000..e27bdf23cfc66 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.content.pm.parsing.component.ParsedIntentInfo +import android.os.Parcel +import android.os.Parcelable +import android.os.PatternMatcher +import kotlin.contracts.ExperimentalContracts + +@ExperimentalContracts +class ParsedIntentInfoTest : ParcelableComponentTest(ParsedIntentInfo::class) { + + override val defaultImpl = ParsedIntentInfo() + + override val creator = object : Parcelable.Creator { + override fun createFromParcel(source: Parcel) = ParsedIntentInfo(source) + override fun newArray(size: Int) = Array(size) { null } + } + + override val excludedMethods = listOf( + // Used to parcel + "writeIntentInfoToParcel", + // All remaining IntentFilter methods, which are out of scope + "hasDataPath", + "hasDataSchemeSpecificPart", + "matchAction", + "matchData", + "actionsIterator", + "addAction", + "addCategory", + "addDataAuthority", + "addDataPath", + "addDataScheme", + "addDataSchemeSpecificPart", + "addDataType", + "addDynamicDataType", + "addMimeGroup", + "asPredicate", + "asPredicateWithTypeResolution", + "authoritiesIterator", + "categoriesIterator", + "clearDynamicDataTypes", + "countActions", + "countCategories", + "countDataAuthorities", + "countDataPaths", + "countDataSchemeSpecificParts", + "countDataSchemes", + "countDataTypes", + "countMimeGroups", + "countStaticDataTypes", + "dataTypes", + "debugCheck", + "dump", + "dumpDebug", + "getAction", + "getAutoVerify", + "getCategory", + "getDataAuthority", + "getDataPath", + "getDataScheme", + "getDataSchemeSpecificPart", + "getDataType", + "getHosts", + "getHostsList", + "getMimeGroup", + "getOrder", + "getPriority", + "getVisibilityToInstantApp", + "handleAllWebDataURI", + "handlesWebUris", + "hasAction", + "hasCategory", + "hasDataAuthority", + "hasDataScheme", + "hasDataType", + "hasExactDataType", + "hasExactDynamicDataType", + "hasExactStaticDataType", + "hasMimeGroup", + "isExplicitlyVisibleToInstantApp", + "isImplicitlyVisibleToInstantApp", + "isVerified", + "isVisibleToInstantApp", + "match", + "matchCategories", + "matchDataAuthority", + "mimeGroupsIterator", + "needsVerification", + "pathsIterator", + "readFromXml", + "schemeSpecificPartsIterator", + "schemesIterator", + "setAutoVerify", + "setOrder", + "setPriority", + "setVerified", + "setVisibilityToInstantApp", + "typesIterator", + "writeToXml", + ) + + override val baseParams = listOf( + ParsedIntentInfo::getIcon, + ParsedIntentInfo::getLabelRes, + ParsedIntentInfo::isHasDefault, + ParsedIntentInfo::getNonLocalizedLabel, + ) + + override fun initialObject() = ParsedIntentInfo().apply { + addAction("test.ACTION") + addDataAuthority("testAuthority", "404") + addCategory("test.CATEGORY") + addMimeGroup("testMime") + addDataPath("testPath", PatternMatcher.PATTERN_LITERAL) + } + + override fun extraAssertions(before: Parcelable, after: Parcelable) { + super.extraAssertions(before, after) + after as ParsedIntentInfo + expect.that(after.actionsIterator().asSequence().singleOrNull()) + .isEqualTo("test.ACTION") + + val authority = after.authoritiesIterator().asSequence().singleOrNull() + expect.that(authority?.host).isEqualTo("testAuthority") + expect.that(authority?.port).isEqualTo(404) + + expect.that(after.categoriesIterator().asSequence().singleOrNull()) + .isEqualTo("test.CATEGORY") + expect.that(after.mimeGroupsIterator().asSequence().singleOrNull()) + .isEqualTo("testMime") + expect.that(after.hasDataPath("testPath")).isTrue() + } + + override fun writeToParcel(parcel: Parcel, value: Parcelable) = + ParsedIntentInfo.PARCELER.parcel(value as ParsedIntentInfo, parcel, 0) +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt new file mode 100644 index 0000000000000..411cb0950d180 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.content.pm.parsing.component.ParsedMainComponent +import android.content.pm.parsing.component.ParsedService +import android.os.Parcelable +import java.util.Arrays +import kotlin.contracts.ExperimentalContracts +import kotlin.reflect.KClass +import kotlin.reflect.KFunction1 + +@ExperimentalContracts +abstract class ParsedMainComponentTest(kClass: KClass) : + ParsedComponentTest(kClass) { + + final override val subclassBaseParams + get() = mainComponentSubclassBaseParams + listOf( + ParsedMainComponent::getOrder, + ParsedMainComponent::getProcessName, + ParsedMainComponent::getSplitName, + ParsedMainComponent::isDirectBootAware, + ParsedMainComponent::isEnabled, + ParsedMainComponent::isExported, + ) + + abstract val mainComponentSubclassBaseParams: Collection> + + final override fun subclassExtraParams() = mainComponentSubclassExtraParams() + listOf( + getSetByValue( + ParsedService::getAttributionTags, + ParsedService::setAttributionTags, + arrayOf("testAttributionTag"), + compare = Arrays::equals + ), + ) + + open fun mainComponentSubclassExtraParams(): Collection = emptyList() +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt new file mode 100644 index 0000000000000..53c862a519b15 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.content.pm.parsing.component.ParsedPermissionGroup +import kotlin.contracts.ExperimentalContracts + +@ExperimentalContracts +class ParsedPermissionGroupTest : ParsedComponentTest(ParsedPermissionGroup::class) { + + override val defaultImpl = ParsedPermissionGroup() + override val creator = ParsedPermissionGroup.CREATOR + + override val subclassBaseParams = listOf( + ParsedPermissionGroup::getRequestDetailResourceId, + ParsedPermissionGroup::getBackgroundRequestDetailResourceId, + ParsedPermissionGroup::getBackgroundRequestResourceId, + ParsedPermissionGroup::getRequestRes, + ParsedPermissionGroup::getPriority, + ) +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt new file mode 100644 index 0000000000000..bb63e2e2a61de --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.content.pm.parsing.component.ParsedPermission +import android.content.pm.parsing.component.ParsedPermissionGroup +import kotlin.contracts.ExperimentalContracts + +@ExperimentalContracts +class ParsedPermissionTest : ParsedComponentTest(ParsedPermission::class) { + + override val defaultImpl = ParsedPermission() + override val creator = ParsedPermission.CREATOR + + override val subclassExcludedMethods = listOf( + // Utility methods + "isAppOp", + "isRuntime", + "getProtection", + "getProtectionFlags", + "calculateFootprint", + "setKnownCert", // Tested through setKnownCerts + ) + override val subclassBaseParams = listOf( + ParsedPermission::getBackgroundPermission, + ParsedPermission::getGroup, + ParsedPermission::getRequestRes, + ParsedPermission::getProtectionLevel, + ParsedPermission::isTree, + ) + + override fun subclassExtraParams() = listOf( + getter(ParsedPermission::getKnownCerts, setOf("testCert")), + getSetByValue( + ParsedPermission::getParsedPermissionGroup, + ParsedPermission::setParsedPermissionGroup, + ParsedPermissionGroup().apply { name = "test.permission.group" }, + compare = { first, second -> equalBy(first, second, ParsedPermissionGroup::getName) } + ), + ) +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt new file mode 100644 index 0000000000000..34f46f2c0adba --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.content.pm.parsing.component.ParsedProcess +import kotlin.contracts.ExperimentalContracts + +@ExperimentalContracts +class ParsedProcessTest : ParcelableComponentTest(ParsedProcess::class) { + + override val defaultImpl = ParsedProcess() + override val creator = ParsedProcess.CREATOR + + override val excludedMethods = listOf( + // Copying method + "addStateFrom", + ) + + override val baseParams = listOf( + ParsedProcess::getName, + ParsedProcess::getGwpAsanMode, + ParsedProcess::getMemtagMode, + ParsedProcess::getNativeHeapZeroInitialized, + ) + + override fun extraParams() = listOf( + getter(ParsedProcess::getDeniedPermissions, setOf("testDeniedPermission")) + ) +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt new file mode 100644 index 0000000000000..e6d5c0fd258f5 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.content.pm.PathPermission +import android.content.pm.parsing.component.ParsedProvider +import android.os.PatternMatcher +import kotlin.contracts.ExperimentalContracts + +@ExperimentalContracts +class ParsedProviderTest : ParsedMainComponentTest(ParsedProvider::class) { + + override val defaultImpl = ParsedProvider() + override val creator = ParsedProvider.CREATOR + + override val mainComponentSubclassBaseParams = listOf( + ParsedProvider::getAuthority, + ParsedProvider::isSyncable, + ParsedProvider::getReadPermission, + ParsedProvider::getWritePermission, + ParsedProvider::isGrantUriPermissions, + ParsedProvider::isForceUriPermissions, + ParsedProvider::isMultiProcess, + ParsedProvider::getInitOrder, + ) + + override fun mainComponentSubclassExtraParams() = listOf( + getSetByValue( + ParsedProvider::getUriPermissionPatterns, + ParsedProvider::setUriPermissionPatterns, + PatternMatcher("testPattern", PatternMatcher.PATTERN_LITERAL), + transformGet = { it?.singleOrNull() }, + transformSet = { arrayOf(it) }, + compare = { first, second -> + equalBy( + first, second, + PatternMatcher::getPath, + PatternMatcher::getType + ) + } + ), + getSetByValue( + ParsedProvider::getPathPermissions, + ParsedProvider::setPathPermissions, + PathPermission( + "testPermissionPattern", + PatternMatcher.PATTERN_LITERAL, + "test.READ_PERMISSION", + "test.WRITE_PERMISSION" + ), + transformGet = { it?.singleOrNull() }, + transformSet = { arrayOf(it) }, + compare = { first, second -> + equalBy( + first, second, + PatternMatcher::getPath, + PatternMatcher::getType, + PathPermission::getReadPermission, + PathPermission::getWritePermission, + ) + } + ) + ) +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt new file mode 100644 index 0000000000000..553018493f8bd --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.content.pm.parsing.component.ParsedService +import kotlin.contracts.ExperimentalContracts + +@ExperimentalContracts +class ParsedServiceTest : ParsedMainComponentTest(ParsedService::class) { + + override val defaultImpl = ParsedService() + override val creator = ParsedService.CREATOR + + override val mainComponentSubclassBaseParams = listOf( + ParsedService::getForegroundServiceType, + ParsedService::getPermission, + ) +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt new file mode 100644 index 0000000000000..1131c72152adb --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling + +import android.content.pm.parsing.component.ParsedUsesPermission +import android.os.Parcelable +import kotlin.contracts.ExperimentalContracts + +@ExperimentalContracts +class ParsedUsesPermissionTest : ParcelableComponentTest(ParsedUsesPermission::class) { + + override val defaultImpl = ParsedUsesPermission("", 0) + override val creator = ParsedUsesPermission.CREATOR + + override val baseParams = listOf( + ParsedUsesPermission::getName, + ParsedUsesPermission::getUsesPermissionFlags + ) + + override fun initialObject() = ParsedUsesPermission("", 0) +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSubWithCreator.java b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSubWithCreator.java new file mode 100644 index 0000000000000..581d2b2d72b80 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSubWithCreator.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling.java; + +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; + +public class TestSubWithCreator extends TestSuperClass { + + @NonNull + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public TestSubWithCreator createFromParcel(Parcel source) { + return new TestSubWithCreator(source); + } + + @Override + public TestSubWithCreator[] newArray(int size) { + return new TestSubWithCreator[size]; + } + }; + + @Nullable + private String subString; + + public TestSubWithCreator() { + } + + public TestSubWithCreator(@NonNull Parcel in) { + super(in); + subString = in.readString(); + } + + public void writeSubToParcel(@NonNull Parcel parcel, int flags) { + super.writeToParcel(parcel, flags); + parcel.writeString(subString); + } +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSubWithoutCreator.java b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSubWithoutCreator.java new file mode 100644 index 0000000000000..4264a11c03e37 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSubWithoutCreator.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling.java; + +import android.annotation.Nullable; +import android.os.Parcel; + +import androidx.annotation.NonNull; + +public class TestSubWithoutCreator extends TestSuperClass { + + @Nullable + private String subString; + + public TestSubWithoutCreator() { + } + + public TestSubWithoutCreator(@NonNull Parcel in) { + super(in); + subString = in.readString(); + } + + public void writeSubToParcel(@NonNull Parcel parcel, int flags) { + super.writeToParcel(parcel, flags); + parcel.writeString(subString); + } +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSuperClass.java b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSuperClass.java new file mode 100644 index 0000000000000..a009786de3528 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSuperClass.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.parsing.parcelling.java; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +@DataClass(genGetters = true, genSetters = true, genBuilder = false, genAidl = false, + genParcelable = true, genConstructor = false) +public class TestSuperClass implements Parcelable { + + @Nullable + private String superString; + + public TestSuperClass() { + } + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSuperClass.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public @Nullable String getSuperString() { + return superString; + } + + @DataClass.Generated.Member + public @NonNull TestSuperClass setSuperString(@NonNull String value) { + superString = value; + return this; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + byte flg = 0; + if (superString != null) flg |= 0x1; + dest.writeByte(flg); + if (superString != null) dest.writeString(superString); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected TestSuperClass(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + String _superString = (flg & 0x1) == 0 ? null : in.readString(); + + this.superString = _superString; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public TestSuperClass[] newArray(int size) { + return new TestSuperClass[size]; + } + + @Override + public TestSuperClass createFromParcel(@NonNull android.os.Parcel in) { + return new TestSuperClass(in); + } + }; + + @DataClass.Generated( + time = 1624381019144L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSuperClass.java", + inputSignatures = "private @android.annotation.Nullable java.lang.String superString\nclass TestSuperClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genAidl=false, genParcelable=true, genConstructor=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/util/IgnoreableExpect.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/util/IgnoreableExpect.kt new file mode 100644 index 0000000000000..afb18f5be669f --- /dev/null +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/util/IgnoreableExpect.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.test.util + +import com.google.common.truth.Expect +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement + +/** + * Wrapper for [Expect] which supports ignoring any failures. This should be used with caution, but + * it allows a base test to be written which doesn't switch success/failure in the test itself, + * preventing any logic errors from causing the test to accidentally succeed. + */ +internal class IgnoreableExpect : TestRule { + + val expect = Expect.create() + + private var ignore = false + + override fun apply(base: Statement?, description: Description?): Statement { + return object : Statement() { + override fun evaluate() { + ignore = false + try { + expect.apply(base, description).evaluate() + } catch (t: Throwable) { + if (!ignore) { + throw t + } + } + } + } + } + + fun ignore() { + ignore = true + } +} diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java index e8c5fb3ecf5c5..38b98ca7a9c58 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java @@ -949,7 +949,7 @@ public class PackageParserTest { .addConfigPreference(new ConfigurationInfo()) .addReqFeature(new FeatureInfo()) .addFeatureGroup(new FeatureGroupInfo()) - .setCompileSdkVersionCodename("foo23") + .setCompileSdkVersionCodeName("foo23") .setCompileSdkVersion(100) .setOverlayCategory("foo24") .setOverlayIsStatic(true)