Loading core/java/android/content/pm/PackageInfo.java +11 −2 Original line number Diff line number Diff line Loading @@ -188,7 +188,16 @@ public class PackageInfo implements Parcelable { /** * Array of all signatures read from the package file. This is only filled * in if the flag {@link PackageManager#GET_SIGNATURES} was set. * in if the flag {@link PackageManager#GET_SIGNATURES} was set. A package * must be singed with at least one certificate which is at position zero. * The package can be signed with additional certificates which appear as * subsequent entries. * * <strong>Note:</strong> Signature ordering is not guaranteed to be * stable which means that a package signed with certificates A and B is * equivalent to being signed with certificates B and A. This means that * in case multiple signatures are reported you cannot assume the one at * the first position to be the same across updates. */ public Signature[] signatures; Loading core/java/android/content/pm/PackageParser.java +74 −12 Original line number Diff line number Diff line Loading @@ -97,6 +97,7 @@ import com.android.internal.util.XmlUtils; import libcore.io.IoUtils; import libcore.util.EmptyArray; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; Loading Loading @@ -2824,14 +2825,14 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); final int version = sa.getInt( com.android.internal.R.styleable.AndroidManifestUsesStaticLibrary_version, -1); String certSha256 = sa.getNonResourceString(com.android.internal.R.styleable String certSha256Digest = sa.getNonResourceString(com.android.internal.R.styleable .AndroidManifestUsesStaticLibrary_certDigest); sa.recycle(); // Since an APK providing a static shared lib can only provide the lib - fail if malformed if (lname == null || version < 0 || certSha256 == null) { if (lname == null || version < 0 || certSha256Digest == null) { outError[0] = "Bad uses-static-library declaration name: " + lname + " version: " + version + " certDigest" + certSha256; + version + " certDigest" + certSha256Digest; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; XmlUtils.skipCurrentTag(parser); return false; Loading @@ -2848,16 +2849,73 @@ public class PackageParser { lname = lname.intern(); // We allow ":" delimiters in the SHA declaration as this is the format // emitted by the certtool making it easy for developers to copy/paste. certSha256 = certSha256.replace(":", "").toLowerCase(); certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); // Fot apps targeting O-MR1 we require explicit enumeration of all certs. String[] additionalCertSha256Digests = EmptyArray.STRING; if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.O) { additionalCertSha256Digests = parseAdditionalCertificates(res, parser, outError); if (additionalCertSha256Digests == null) { return false; } } else { XmlUtils.skipCurrentTag(parser); } final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1]; certSha256Digests[0] = certSha256Digest; System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests, 1, additionalCertSha256Digests.length); pkg.usesStaticLibraries = ArrayUtils.add(pkg.usesStaticLibraries, lname); pkg.usesStaticLibrariesVersions = ArrayUtils.appendInt( pkg.usesStaticLibrariesVersions, version, true); pkg.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String.class, pkg.usesStaticLibrariesCertDigests, certSha256, true); pkg.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class, pkg.usesStaticLibrariesCertDigests, certSha256Digests, true); return true; } private String[] parseAdditionalCertificates(Resources resources, XmlResourceParser parser, String[] outError) throws XmlPullParserException, IOException { String[] certSha256Digests = EmptyArray.STRING; int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } final String nodeName = parser.getName(); if (nodeName.equals("additional-certificate")) { final TypedArray sa = resources.obtainAttributes(parser, com.android.internal. R.styleable.AndroidManifestAdditionalCertificate); String certSha256Digest = sa.getNonResourceString(com.android.internal. R.styleable.AndroidManifestAdditionalCertificate_certDigest); sa.recycle(); if (TextUtils.isEmpty(certSha256Digest)) { outError[0] = "Bad additional-certificate declaration with empty" + " certDigest:" + certSha256Digest; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; XmlUtils.skipCurrentTag(parser); sa.recycle(); return null; } return true; // We allow ":" delimiters in the SHA declaration as this is the format // emitted by the certtool making it easy for developers to copy/paste. certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); certSha256Digests = ArrayUtils.appendElement(String.class, certSha256Digests, certSha256Digest); } else { XmlUtils.skipCurrentTag(parser); } } return certSha256Digests; } private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser) Loading Loading @@ -5826,7 +5884,7 @@ public class PackageParser { public ArrayList<String> usesLibraries = null; public ArrayList<String> usesStaticLibraries = null; public int[] usesStaticLibrariesVersions = null; public String[] usesStaticLibrariesCertDigests = null; public String[][] usesStaticLibrariesCertDigests = null; public ArrayList<String> usesOptionalLibraries = null; public String[] usesLibraryFiles = null; Loading Loading @@ -6324,8 +6382,10 @@ public class PackageParser { internStringArrayList(usesStaticLibraries); usesStaticLibrariesVersions = new int[libCount]; dest.readIntArray(usesStaticLibrariesVersions); usesStaticLibrariesCertDigests = new String[libCount]; dest.readStringArray(usesStaticLibrariesCertDigests); usesStaticLibrariesCertDigests = new String[libCount][]; for (int i = 0; i < libCount; i++) { usesStaticLibrariesCertDigests[i] = dest.createStringArray(); } } preferredActivityFilters = new ArrayList<>(); Loading Loading @@ -6471,7 +6531,9 @@ public class PackageParser { dest.writeInt(usesStaticLibraries.size()); dest.writeStringList(usesStaticLibraries); dest.writeIntArray(usesStaticLibrariesVersions); dest.writeStringArray(usesStaticLibrariesCertDigests); for (String[] usesStaticLibrariesCertDigest : usesStaticLibrariesCertDigests) { dest.writeStringArray(usesStaticLibrariesCertDigest); } } dest.writeParcelableList(preferredActivityFilters, flags); Loading core/java/android/util/PackageUtils.java +58 −22 Original line number Diff line number Diff line Loading @@ -18,12 +18,13 @@ package android.util; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.Signature; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; /** * Helper functions applicable to packages. Loading @@ -36,32 +37,67 @@ public final class PackageUtils { } /** * Computes the SHA256 digest of the signing cert for a package. * @param packageManager The package manager. * @param packageName The package for which to generate the digest. * @param userId The user for which to generate the digest. * @return The digest or null if the package does not exist for this user. * Computes the SHA256 digests of a list of signatures. Items in the * resulting array of hashes correspond to the signatures in the * input array. * @param signatures The signatures. * @return The digest array. */ public static @Nullable String computePackageCertSha256Digest( @NonNull PackageManager packageManager, @NonNull String packageName, int userId) { final PackageInfo packageInfo; try { packageInfo = packageManager.getPackageInfoAsUser(packageName, PackageManager.GET_SIGNATURES, userId); } catch (PackageManager.NameNotFoundException e) { return null; public static @NonNull String[] computeSignaturesSha256Digests( @NonNull Signature[] signatures) { final int signatureCount = signatures.length; final String[] digests = new String[signatureCount]; for (int i = 0; i < signatureCount; i++) { digests[i] = computeSha256Digest(signatures[i].toByteArray()); } return computeCertSha256Digest(packageInfo.signatures[0]); return digests; } /** * Computes a SHA256 digest of the signatures' SHA256 digests. First, * individual hashes for each signature is derived in a hexademical * form, then these strings are sorted based the natural ordering, and * finally a hash is derived from these strings' bytes. * @param signatures The signatures. * @return The digest. */ public static @NonNull String computeSignaturesSha256Digest( @NonNull Signature[] signatures) { // Shortcut for optimization - most apps singed by a single cert if (signatures.length == 1) { return computeSha256Digest(signatures[0].toByteArray()); } // Make sure these are sorted to handle reversed certificates final String[] sha256Digests = computeSignaturesSha256Digests(signatures); return computeSignaturesSha256Digest(sha256Digests); } /** * Computes the SHA256 digest of a cert. * @param signature The signature. * @return The digest or null if an error occurs. * Computes a SHA256 digest in of the signatures SHA256 digests. First, * the strings are sorted based the natural ordering, and then a hash is * derived from these strings' bytes. * @param sha256Digests Signature SHA256 hashes in hexademical form. * @return The digest. */ public static @Nullable String computeCertSha256Digest(@NonNull Signature signature) { return computeSha256Digest(signature.toByteArray()); public static @NonNull String computeSignaturesSha256Digest( @NonNull String[] sha256Digests) { // Shortcut for optimization - most apps singed by a single cert if (sha256Digests.length == 1) { return sha256Digests[0]; } // Make sure these are sorted to handle reversed certificates Arrays.sort(sha256Digests); final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); for (String sha256Digest : sha256Digests) { try { bytes.write(sha256Digest.getBytes()); } catch (IOException e) { /* ignore - can't happen */ } } return computeSha256Digest(bytes.toByteArray()); } /** Loading core/res/res/values/attrs_manifest.xml +16 −0 Original line number Diff line number Diff line Loading @@ -1781,6 +1781,11 @@ the library at build time while it offers apps to share code defined in such libraries. Hence, static libraries are strictly required. <p>On devices running O MR1 or higher, if the library is singed with multiple signing certificates you must to specify the SHA-256 hashes of the additional certificates via adding {@link #AndroidManifestAdditionalCertificate additional-certificate} tags. <p>This appears as a child tag of the {@link #AndroidManifestApplication application} tag. --> <declare-styleable name="AndroidManifestUsesStaticLibrary" parent="AndroidManifestApplication"> Loading @@ -1792,6 +1797,17 @@ <attr name="certDigest" format="string" /> </declare-styleable> <!-- The <code>additional-certificate</code> specifies the SHA-256 digest of a static shared library's additional signing certificate. You need to use this tag if the library is singed with more than one certificate. <p>This appears as a child tag of the {@link #AndroidManifestUsesStaticLibrary uses-static-library} tag. --> <declare-styleable name="AndroidManifestAdditionalCertificate" parent="AndroidManifestUsesStaticLibrary"> <!-- The SHA-256 digest of the library signing certificate. --> <attr name="certDigest" /> </declare-styleable> <!-- The <code>supports-screens</code> specifies the screen dimensions an application supports. By default a modern application supports all screen sizes and must explicitly disable certain screen sizes here; Loading services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java +25 −5 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.Signature; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.UserHandle; Loading @@ -30,6 +31,7 @@ import android.text.TextUtils; import android.util.Log; import android.util.PackageUtils; import android.util.Pair; import android.util.Slog; import android.util.Xml; import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; Loading Loading @@ -126,9 +128,18 @@ public final class AccountManagerBackupHelper { } catch (PackageManager.NameNotFoundException e) { return false; } String currentCertDigest = PackageUtils.computeCertSha256Digest( packageInfo.signatures[0]); if (!certDigest.equals(currentCertDigest)) { // Before we used only the first signature to compute the SHA 256 but some // apps could be singed by multiple certs and the cert order is undefined. // We prefer the modern computation procedure where all certs are taken // into account but also allow the value from the old computation to allow // restoring backed up grants on an older platform version. final String[] signaturesSha256Digests = PackageUtils.computeSignaturesSha256Digests( packageInfo.signatures); final String signaturesSha256Digest = PackageUtils.computeSignaturesSha256Digest( signaturesSha256Digests); if (!certDigest.equals(signaturesSha256Digest) && (packageInfo.signatures.length <= 1 || !certDigest.equals(signaturesSha256Digests[0]))) { return false; } final int uid = packageInfo.applicationInfo.uid; Loading Loading @@ -169,8 +180,17 @@ public final class AccountManagerBackupHelper { } for (String packageName : packageNames) { String digest = PackageUtils.computePackageCertSha256Digest( packageManager, packageName, userId); final PackageInfo packageInfo; try { packageInfo = packageManager.getPackageInfoAsUser(packageName, PackageManager.GET_SIGNATURES, userId); } catch (PackageManager.NameNotFoundException e) { Slog.i(TAG, "Skipping backup of account access grant for" + " non-existing package: " + packageName); continue; } final String digest = PackageUtils.computeSignaturesSha256Digest( packageInfo.signatures); if (digest != null) { serializer.startTag(null, TAG_PERMISSION); serializer.attribute(null, ATTR_ACCOUNT_SHA_256, Loading Loading
core/java/android/content/pm/PackageInfo.java +11 −2 Original line number Diff line number Diff line Loading @@ -188,7 +188,16 @@ public class PackageInfo implements Parcelable { /** * Array of all signatures read from the package file. This is only filled * in if the flag {@link PackageManager#GET_SIGNATURES} was set. * in if the flag {@link PackageManager#GET_SIGNATURES} was set. A package * must be singed with at least one certificate which is at position zero. * The package can be signed with additional certificates which appear as * subsequent entries. * * <strong>Note:</strong> Signature ordering is not guaranteed to be * stable which means that a package signed with certificates A and B is * equivalent to being signed with certificates B and A. This means that * in case multiple signatures are reported you cannot assume the one at * the first position to be the same across updates. */ public Signature[] signatures; Loading
core/java/android/content/pm/PackageParser.java +74 −12 Original line number Diff line number Diff line Loading @@ -97,6 +97,7 @@ import com.android.internal.util.XmlUtils; import libcore.io.IoUtils; import libcore.util.EmptyArray; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; Loading Loading @@ -2824,14 +2825,14 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); final int version = sa.getInt( com.android.internal.R.styleable.AndroidManifestUsesStaticLibrary_version, -1); String certSha256 = sa.getNonResourceString(com.android.internal.R.styleable String certSha256Digest = sa.getNonResourceString(com.android.internal.R.styleable .AndroidManifestUsesStaticLibrary_certDigest); sa.recycle(); // Since an APK providing a static shared lib can only provide the lib - fail if malformed if (lname == null || version < 0 || certSha256 == null) { if (lname == null || version < 0 || certSha256Digest == null) { outError[0] = "Bad uses-static-library declaration name: " + lname + " version: " + version + " certDigest" + certSha256; + version + " certDigest" + certSha256Digest; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; XmlUtils.skipCurrentTag(parser); return false; Loading @@ -2848,16 +2849,73 @@ public class PackageParser { lname = lname.intern(); // We allow ":" delimiters in the SHA declaration as this is the format // emitted by the certtool making it easy for developers to copy/paste. certSha256 = certSha256.replace(":", "").toLowerCase(); certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); // Fot apps targeting O-MR1 we require explicit enumeration of all certs. String[] additionalCertSha256Digests = EmptyArray.STRING; if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.O) { additionalCertSha256Digests = parseAdditionalCertificates(res, parser, outError); if (additionalCertSha256Digests == null) { return false; } } else { XmlUtils.skipCurrentTag(parser); } final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1]; certSha256Digests[0] = certSha256Digest; System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests, 1, additionalCertSha256Digests.length); pkg.usesStaticLibraries = ArrayUtils.add(pkg.usesStaticLibraries, lname); pkg.usesStaticLibrariesVersions = ArrayUtils.appendInt( pkg.usesStaticLibrariesVersions, version, true); pkg.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String.class, pkg.usesStaticLibrariesCertDigests, certSha256, true); pkg.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class, pkg.usesStaticLibrariesCertDigests, certSha256Digests, true); return true; } private String[] parseAdditionalCertificates(Resources resources, XmlResourceParser parser, String[] outError) throws XmlPullParserException, IOException { String[] certSha256Digests = EmptyArray.STRING; int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } final String nodeName = parser.getName(); if (nodeName.equals("additional-certificate")) { final TypedArray sa = resources.obtainAttributes(parser, com.android.internal. R.styleable.AndroidManifestAdditionalCertificate); String certSha256Digest = sa.getNonResourceString(com.android.internal. R.styleable.AndroidManifestAdditionalCertificate_certDigest); sa.recycle(); if (TextUtils.isEmpty(certSha256Digest)) { outError[0] = "Bad additional-certificate declaration with empty" + " certDigest:" + certSha256Digest; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; XmlUtils.skipCurrentTag(parser); sa.recycle(); return null; } return true; // We allow ":" delimiters in the SHA declaration as this is the format // emitted by the certtool making it easy for developers to copy/paste. certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); certSha256Digests = ArrayUtils.appendElement(String.class, certSha256Digests, certSha256Digest); } else { XmlUtils.skipCurrentTag(parser); } } return certSha256Digests; } private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser) Loading Loading @@ -5826,7 +5884,7 @@ public class PackageParser { public ArrayList<String> usesLibraries = null; public ArrayList<String> usesStaticLibraries = null; public int[] usesStaticLibrariesVersions = null; public String[] usesStaticLibrariesCertDigests = null; public String[][] usesStaticLibrariesCertDigests = null; public ArrayList<String> usesOptionalLibraries = null; public String[] usesLibraryFiles = null; Loading Loading @@ -6324,8 +6382,10 @@ public class PackageParser { internStringArrayList(usesStaticLibraries); usesStaticLibrariesVersions = new int[libCount]; dest.readIntArray(usesStaticLibrariesVersions); usesStaticLibrariesCertDigests = new String[libCount]; dest.readStringArray(usesStaticLibrariesCertDigests); usesStaticLibrariesCertDigests = new String[libCount][]; for (int i = 0; i < libCount; i++) { usesStaticLibrariesCertDigests[i] = dest.createStringArray(); } } preferredActivityFilters = new ArrayList<>(); Loading Loading @@ -6471,7 +6531,9 @@ public class PackageParser { dest.writeInt(usesStaticLibraries.size()); dest.writeStringList(usesStaticLibraries); dest.writeIntArray(usesStaticLibrariesVersions); dest.writeStringArray(usesStaticLibrariesCertDigests); for (String[] usesStaticLibrariesCertDigest : usesStaticLibrariesCertDigests) { dest.writeStringArray(usesStaticLibrariesCertDigest); } } dest.writeParcelableList(preferredActivityFilters, flags); Loading
core/java/android/util/PackageUtils.java +58 −22 Original line number Diff line number Diff line Loading @@ -18,12 +18,13 @@ package android.util; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.Signature; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; /** * Helper functions applicable to packages. Loading @@ -36,32 +37,67 @@ public final class PackageUtils { } /** * Computes the SHA256 digest of the signing cert for a package. * @param packageManager The package manager. * @param packageName The package for which to generate the digest. * @param userId The user for which to generate the digest. * @return The digest or null if the package does not exist for this user. * Computes the SHA256 digests of a list of signatures. Items in the * resulting array of hashes correspond to the signatures in the * input array. * @param signatures The signatures. * @return The digest array. */ public static @Nullable String computePackageCertSha256Digest( @NonNull PackageManager packageManager, @NonNull String packageName, int userId) { final PackageInfo packageInfo; try { packageInfo = packageManager.getPackageInfoAsUser(packageName, PackageManager.GET_SIGNATURES, userId); } catch (PackageManager.NameNotFoundException e) { return null; public static @NonNull String[] computeSignaturesSha256Digests( @NonNull Signature[] signatures) { final int signatureCount = signatures.length; final String[] digests = new String[signatureCount]; for (int i = 0; i < signatureCount; i++) { digests[i] = computeSha256Digest(signatures[i].toByteArray()); } return computeCertSha256Digest(packageInfo.signatures[0]); return digests; } /** * Computes a SHA256 digest of the signatures' SHA256 digests. First, * individual hashes for each signature is derived in a hexademical * form, then these strings are sorted based the natural ordering, and * finally a hash is derived from these strings' bytes. * @param signatures The signatures. * @return The digest. */ public static @NonNull String computeSignaturesSha256Digest( @NonNull Signature[] signatures) { // Shortcut for optimization - most apps singed by a single cert if (signatures.length == 1) { return computeSha256Digest(signatures[0].toByteArray()); } // Make sure these are sorted to handle reversed certificates final String[] sha256Digests = computeSignaturesSha256Digests(signatures); return computeSignaturesSha256Digest(sha256Digests); } /** * Computes the SHA256 digest of a cert. * @param signature The signature. * @return The digest or null if an error occurs. * Computes a SHA256 digest in of the signatures SHA256 digests. First, * the strings are sorted based the natural ordering, and then a hash is * derived from these strings' bytes. * @param sha256Digests Signature SHA256 hashes in hexademical form. * @return The digest. */ public static @Nullable String computeCertSha256Digest(@NonNull Signature signature) { return computeSha256Digest(signature.toByteArray()); public static @NonNull String computeSignaturesSha256Digest( @NonNull String[] sha256Digests) { // Shortcut for optimization - most apps singed by a single cert if (sha256Digests.length == 1) { return sha256Digests[0]; } // Make sure these are sorted to handle reversed certificates Arrays.sort(sha256Digests); final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); for (String sha256Digest : sha256Digests) { try { bytes.write(sha256Digest.getBytes()); } catch (IOException e) { /* ignore - can't happen */ } } return computeSha256Digest(bytes.toByteArray()); } /** Loading
core/res/res/values/attrs_manifest.xml +16 −0 Original line number Diff line number Diff line Loading @@ -1781,6 +1781,11 @@ the library at build time while it offers apps to share code defined in such libraries. Hence, static libraries are strictly required. <p>On devices running O MR1 or higher, if the library is singed with multiple signing certificates you must to specify the SHA-256 hashes of the additional certificates via adding {@link #AndroidManifestAdditionalCertificate additional-certificate} tags. <p>This appears as a child tag of the {@link #AndroidManifestApplication application} tag. --> <declare-styleable name="AndroidManifestUsesStaticLibrary" parent="AndroidManifestApplication"> Loading @@ -1792,6 +1797,17 @@ <attr name="certDigest" format="string" /> </declare-styleable> <!-- The <code>additional-certificate</code> specifies the SHA-256 digest of a static shared library's additional signing certificate. You need to use this tag if the library is singed with more than one certificate. <p>This appears as a child tag of the {@link #AndroidManifestUsesStaticLibrary uses-static-library} tag. --> <declare-styleable name="AndroidManifestAdditionalCertificate" parent="AndroidManifestUsesStaticLibrary"> <!-- The SHA-256 digest of the library signing certificate. --> <attr name="certDigest" /> </declare-styleable> <!-- The <code>supports-screens</code> specifies the screen dimensions an application supports. By default a modern application supports all screen sizes and must explicitly disable certain screen sizes here; Loading
services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java +25 −5 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.Signature; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.UserHandle; Loading @@ -30,6 +31,7 @@ import android.text.TextUtils; import android.util.Log; import android.util.PackageUtils; import android.util.Pair; import android.util.Slog; import android.util.Xml; import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; Loading Loading @@ -126,9 +128,18 @@ public final class AccountManagerBackupHelper { } catch (PackageManager.NameNotFoundException e) { return false; } String currentCertDigest = PackageUtils.computeCertSha256Digest( packageInfo.signatures[0]); if (!certDigest.equals(currentCertDigest)) { // Before we used only the first signature to compute the SHA 256 but some // apps could be singed by multiple certs and the cert order is undefined. // We prefer the modern computation procedure where all certs are taken // into account but also allow the value from the old computation to allow // restoring backed up grants on an older platform version. final String[] signaturesSha256Digests = PackageUtils.computeSignaturesSha256Digests( packageInfo.signatures); final String signaturesSha256Digest = PackageUtils.computeSignaturesSha256Digest( signaturesSha256Digests); if (!certDigest.equals(signaturesSha256Digest) && (packageInfo.signatures.length <= 1 || !certDigest.equals(signaturesSha256Digests[0]))) { return false; } final int uid = packageInfo.applicationInfo.uid; Loading Loading @@ -169,8 +180,17 @@ public final class AccountManagerBackupHelper { } for (String packageName : packageNames) { String digest = PackageUtils.computePackageCertSha256Digest( packageManager, packageName, userId); final PackageInfo packageInfo; try { packageInfo = packageManager.getPackageInfoAsUser(packageName, PackageManager.GET_SIGNATURES, userId); } catch (PackageManager.NameNotFoundException e) { Slog.i(TAG, "Skipping backup of account access grant for" + " non-existing package: " + packageName); continue; } final String digest = PackageUtils.computeSignaturesSha256Digest( packageInfo.signatures); if (digest != null) { serializer.startTag(null, TAG_PERMISSION); serializer.attribute(null, ATTR_ACCOUNT_SHA_256, Loading