Loading core/java/android/content/pm/PermissionInfo.java +7 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,9 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import com.android.internal.util.Parcelling; import com.android.internal.util.Parcelling.BuiltIn.ForStringSet; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Set; Loading Loading @@ -477,6 +480,8 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { */ public @Nullable CharSequence nonLocalizedDescription; private static ForStringSet sForStringSet = Parcelling.Cache.getOrCreate(ForStringSet.class); /** * A {@link Set} of trusted signing certificate digests. If this permission has the {@link * #PROTECTION_FLAG_KNOWN_SIGNER} flag set the permission will be granted to a requesting app Loading Loading @@ -688,6 +693,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { dest.writeInt(descriptionRes); dest.writeInt(requestRes); TextUtils.writeToParcel(nonLocalizedDescription, dest, parcelableFlags); sForStringSet.parcel(knownCerts, dest, parcelableFlags); } /** @hide */ Loading Loading @@ -753,5 +759,6 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { descriptionRes = source.readInt(); requestRes = source.readInt(); nonLocalizedDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); knownCerts = sForStringSet.unparcel(source); } } core/java/android/content/pm/parsing/component/ParsedPermission.java +21 −0 Original line number Diff line number Diff line Loading @@ -21,16 +21,22 @@ import android.content.pm.PermissionInfo; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DataClass; import com.android.internal.util.Parcelling; import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; import com.android.internal.util.Parcelling.BuiltIn.ForStringSet; import java.util.Locale; import java.util.Set; /** @hide */ public class ParsedPermission extends ParsedComponent { private static ForStringSet sForStringSet = Parcelling.Cache.getOrCreate(ForStringSet.class); @Nullable String backgroundPermission; @Nullable Loading Loading @@ -89,6 +95,19 @@ public class ParsedPermission extends ParsedComponent { return knownCerts; } protected void setKnownCert(String knownCert) { // Convert the provided digest to upper case for consistent Set membership // checks when verifying the signing certificate digests of requesting apps. this.knownCerts = Set.of(knownCert.toUpperCase(Locale.US)); } protected void setKnownCerts(String[] knownCerts) { this.knownCerts = new ArraySet<>(); for (String knownCert : knownCerts) { this.knownCerts.add(knownCert.toUpperCase(Locale.US)); } } public int calculateFootprint() { int size = getName().length(); if (getNonLocalizedLabel() != null) { Loading Loading @@ -117,6 +136,7 @@ public class ParsedPermission extends ParsedComponent { dest.writeInt(this.protectionLevel); dest.writeBoolean(this.tree); dest.writeParcelable(this.parsedPermissionGroup, flags); sForStringSet.parcel(knownCerts, dest, flags); } protected ParsedPermission(Parcel in) { Loading @@ -129,6 +149,7 @@ public class ParsedPermission extends ParsedComponent { this.protectionLevel = in.readInt(); this.tree = in.readBoolean(); this.parsedPermissionGroup = in.readParcelable(boot); this.knownCerts = sForStringSet.unparcel(in); } public static final Parcelable.Creator<ParsedPermission> CREATOR = Loading core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java +3 −11 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import android.content.pm.parsing.result.ParseResult; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.util.ArraySet; import android.util.Slog; import com.android.internal.R; Loading @@ -33,8 +32,6 @@ import com.android.internal.R; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.Locale; import java.util.Set; /** @hide */ public class ParsedPermissionUtils { Loading Loading @@ -103,17 +100,12 @@ public class ParsedPermissionUtils { if (resourceType.equals("array")) { final String[] knownCerts = res.getStringArray(knownCertsResource); if (knownCerts != null) { // Convert the provided digest to upper case for consistent Set membership // checks when verifying the signing certificate digests of requesting apps. permission.knownCerts = new ArraySet<>(); for (String knownCert : knownCerts) { permission.knownCerts.add(knownCert.toUpperCase(Locale.US)); } permission.setKnownCerts(knownCerts); } } else { final String knownCert = res.getString(knownCertsResource); if (knownCert != null) { permission.knownCerts = Set.of(knownCert.toUpperCase(Locale.US)); permission.setKnownCert(knownCert); } } if (permission.knownCerts == null) { Loading @@ -126,7 +118,7 @@ public class ParsedPermissionUtils { final String knownCert = sa.getString( R.styleable.AndroidManifestPermission_knownCerts); if (knownCert != null) { permission.knownCerts = Set.of(knownCert.toUpperCase(Locale.US)); permission.setKnownCert(knownCert); } } Loading core/tests/coretests/src/android/content/pm/PermissionInfoTest.java 0 → 100644 +61 −0 Original line number Diff line number Diff line /* * 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 android.content.pm; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.os.Parcel; import android.util.ArraySet; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public final class PermissionInfoTest { private static final String KNOWN_CERT_DIGEST_1 = "6a8b96e278e58f62cfe3584022cec1d0527fcb85a9e5d2e1694eb0405be5b599"; private static final String KNOWN_CERT_DIGEST_2 = "9369370ffcfdc1e92dae777252c05c483b8cbb55fa9d5fd9f6317f623ae6d8c6"; @Test public void createFromParcel_returnsKnownCerts() { // The platform supports a knownSigner permission protection flag that allows one or more // trusted signing certificates to be specified with the permission declaration; if a // requesting app is signed by any of these trusted certificates the permission is granted. // This test verifies the Set of knownCerts is properly parceled / unparceled. PermissionInfo permissionInfo = new PermissionInfo(); permissionInfo.protectionLevel = PermissionInfo.PROTECTION_SIGNATURE | PermissionInfo.PROTECTION_FLAG_KNOWN_SIGNER; permissionInfo.knownCerts = new ArraySet<>(2); permissionInfo.knownCerts.add(KNOWN_CERT_DIGEST_1); permissionInfo.knownCerts.add(KNOWN_CERT_DIGEST_2); Parcel parcel = Parcel.obtain(); permissionInfo.writeToParcel(parcel, 0); parcel.setDataPosition(0); PermissionInfo unparceledPermissionInfo = PermissionInfo.CREATOR.createFromParcel(parcel); assertNotNull(unparceledPermissionInfo.knownCerts); assertEquals(2, unparceledPermissionInfo.knownCerts.size()); assertTrue(unparceledPermissionInfo.knownCerts.contains(KNOWN_CERT_DIGEST_1)); assertTrue(unparceledPermissionInfo.knownCerts.contains(KNOWN_CERT_DIGEST_2)); } } Loading
core/java/android/content/pm/PermissionInfo.java +7 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,9 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import com.android.internal.util.Parcelling; import com.android.internal.util.Parcelling.BuiltIn.ForStringSet; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Set; Loading Loading @@ -477,6 +480,8 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { */ public @Nullable CharSequence nonLocalizedDescription; private static ForStringSet sForStringSet = Parcelling.Cache.getOrCreate(ForStringSet.class); /** * A {@link Set} of trusted signing certificate digests. If this permission has the {@link * #PROTECTION_FLAG_KNOWN_SIGNER} flag set the permission will be granted to a requesting app Loading Loading @@ -688,6 +693,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { dest.writeInt(descriptionRes); dest.writeInt(requestRes); TextUtils.writeToParcel(nonLocalizedDescription, dest, parcelableFlags); sForStringSet.parcel(knownCerts, dest, parcelableFlags); } /** @hide */ Loading Loading @@ -753,5 +759,6 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { descriptionRes = source.readInt(); requestRes = source.readInt(); nonLocalizedDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); knownCerts = sForStringSet.unparcel(source); } }
core/java/android/content/pm/parsing/component/ParsedPermission.java +21 −0 Original line number Diff line number Diff line Loading @@ -21,16 +21,22 @@ import android.content.pm.PermissionInfo; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DataClass; import com.android.internal.util.Parcelling; import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; import com.android.internal.util.Parcelling.BuiltIn.ForStringSet; import java.util.Locale; import java.util.Set; /** @hide */ public class ParsedPermission extends ParsedComponent { private static ForStringSet sForStringSet = Parcelling.Cache.getOrCreate(ForStringSet.class); @Nullable String backgroundPermission; @Nullable Loading Loading @@ -89,6 +95,19 @@ public class ParsedPermission extends ParsedComponent { return knownCerts; } protected void setKnownCert(String knownCert) { // Convert the provided digest to upper case for consistent Set membership // checks when verifying the signing certificate digests of requesting apps. this.knownCerts = Set.of(knownCert.toUpperCase(Locale.US)); } protected void setKnownCerts(String[] knownCerts) { this.knownCerts = new ArraySet<>(); for (String knownCert : knownCerts) { this.knownCerts.add(knownCert.toUpperCase(Locale.US)); } } public int calculateFootprint() { int size = getName().length(); if (getNonLocalizedLabel() != null) { Loading Loading @@ -117,6 +136,7 @@ public class ParsedPermission extends ParsedComponent { dest.writeInt(this.protectionLevel); dest.writeBoolean(this.tree); dest.writeParcelable(this.parsedPermissionGroup, flags); sForStringSet.parcel(knownCerts, dest, flags); } protected ParsedPermission(Parcel in) { Loading @@ -129,6 +149,7 @@ public class ParsedPermission extends ParsedComponent { this.protectionLevel = in.readInt(); this.tree = in.readBoolean(); this.parsedPermissionGroup = in.readParcelable(boot); this.knownCerts = sForStringSet.unparcel(in); } public static final Parcelable.Creator<ParsedPermission> CREATOR = Loading
core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java +3 −11 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import android.content.pm.parsing.result.ParseResult; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.util.ArraySet; import android.util.Slog; import com.android.internal.R; Loading @@ -33,8 +32,6 @@ import com.android.internal.R; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.Locale; import java.util.Set; /** @hide */ public class ParsedPermissionUtils { Loading Loading @@ -103,17 +100,12 @@ public class ParsedPermissionUtils { if (resourceType.equals("array")) { final String[] knownCerts = res.getStringArray(knownCertsResource); if (knownCerts != null) { // Convert the provided digest to upper case for consistent Set membership // checks when verifying the signing certificate digests of requesting apps. permission.knownCerts = new ArraySet<>(); for (String knownCert : knownCerts) { permission.knownCerts.add(knownCert.toUpperCase(Locale.US)); } permission.setKnownCerts(knownCerts); } } else { final String knownCert = res.getString(knownCertsResource); if (knownCert != null) { permission.knownCerts = Set.of(knownCert.toUpperCase(Locale.US)); permission.setKnownCert(knownCert); } } if (permission.knownCerts == null) { Loading @@ -126,7 +118,7 @@ public class ParsedPermissionUtils { final String knownCert = sa.getString( R.styleable.AndroidManifestPermission_knownCerts); if (knownCert != null) { permission.knownCerts = Set.of(knownCert.toUpperCase(Locale.US)); permission.setKnownCert(knownCert); } } Loading
core/tests/coretests/src/android/content/pm/PermissionInfoTest.java 0 → 100644 +61 −0 Original line number Diff line number Diff line /* * 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 android.content.pm; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.os.Parcel; import android.util.ArraySet; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public final class PermissionInfoTest { private static final String KNOWN_CERT_DIGEST_1 = "6a8b96e278e58f62cfe3584022cec1d0527fcb85a9e5d2e1694eb0405be5b599"; private static final String KNOWN_CERT_DIGEST_2 = "9369370ffcfdc1e92dae777252c05c483b8cbb55fa9d5fd9f6317f623ae6d8c6"; @Test public void createFromParcel_returnsKnownCerts() { // The platform supports a knownSigner permission protection flag that allows one or more // trusted signing certificates to be specified with the permission declaration; if a // requesting app is signed by any of these trusted certificates the permission is granted. // This test verifies the Set of knownCerts is properly parceled / unparceled. PermissionInfo permissionInfo = new PermissionInfo(); permissionInfo.protectionLevel = PermissionInfo.PROTECTION_SIGNATURE | PermissionInfo.PROTECTION_FLAG_KNOWN_SIGNER; permissionInfo.knownCerts = new ArraySet<>(2); permissionInfo.knownCerts.add(KNOWN_CERT_DIGEST_1); permissionInfo.knownCerts.add(KNOWN_CERT_DIGEST_2); Parcel parcel = Parcel.obtain(); permissionInfo.writeToParcel(parcel, 0); parcel.setDataPosition(0); PermissionInfo unparceledPermissionInfo = PermissionInfo.CREATOR.createFromParcel(parcel); assertNotNull(unparceledPermissionInfo.knownCerts); assertEquals(2, unparceledPermissionInfo.knownCerts.size()); assertTrue(unparceledPermissionInfo.knownCerts.contains(KNOWN_CERT_DIGEST_1)); assertTrue(unparceledPermissionInfo.knownCerts.contains(KNOWN_CERT_DIGEST_2)); } }