Merge "Add API to expose signing certificate proof-of-rotation."
This commit is contained in:
committed by
Android (Google) Code Review
commit
064f16638b
@@ -10873,7 +10873,8 @@ package android.content.pm {
|
||||
field public android.content.pm.ServiceInfo[] services;
|
||||
field public java.lang.String sharedUserId;
|
||||
field public int sharedUserLabel;
|
||||
field public android.content.pm.Signature[] signatures;
|
||||
field public deprecated android.content.pm.Signature[] signatures;
|
||||
field public android.content.pm.Signature[][] signingCertificateHistory;
|
||||
field public java.lang.String[] splitNames;
|
||||
field public int[] splitRevisionCodes;
|
||||
field public deprecated int versionCode;
|
||||
@@ -11076,6 +11077,8 @@ package android.content.pm {
|
||||
method public abstract android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle);
|
||||
method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
|
||||
method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
|
||||
method public boolean hasSigningCertificate(java.lang.String, byte[], int);
|
||||
method public boolean hasSigningCertificate(int, byte[], int);
|
||||
method public abstract boolean hasSystemFeature(java.lang.String);
|
||||
method public abstract boolean hasSystemFeature(java.lang.String, int);
|
||||
method public abstract boolean isInstantApp();
|
||||
@@ -11101,6 +11104,8 @@ package android.content.pm {
|
||||
method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
|
||||
method public abstract void updateInstantAppCookie(byte[]);
|
||||
method public abstract void verifyPendingInstall(int, int);
|
||||
field public static final int CERT_INPUT_RAW_X509 = 0; // 0x0
|
||||
field public static final int CERT_INPUT_SHA256 = 1; // 0x1
|
||||
field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0
|
||||
field public static final int COMPONENT_ENABLED_STATE_DISABLED = 2; // 0x2
|
||||
field public static final int COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED = 4; // 0x4
|
||||
@@ -11219,7 +11224,8 @@ package android.content.pm {
|
||||
field public static final int GET_RESOLVED_FILTER = 64; // 0x40
|
||||
field public static final int GET_SERVICES = 4; // 0x4
|
||||
field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
|
||||
field public static final int GET_SIGNATURES = 64; // 0x40
|
||||
field public static final deprecated int GET_SIGNATURES = 64; // 0x40
|
||||
field public static final int GET_SIGNING_CERTIFICATES = 134217728; // 0x8000000
|
||||
field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
|
||||
field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
|
||||
field public static final int INSTALL_REASON_DEVICE_RESTORE = 2; // 0x2
|
||||
|
||||
@@ -698,6 +698,26 @@ public class ApplicationPackageManager extends PackageManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSigningCertificate(
|
||||
String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
|
||||
try {
|
||||
return mPM.hasSigningCertificate(packageName, certificate, type);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSigningCertificate(
|
||||
int uid, byte[] certificate, @PackageManager.CertificateInputType int type) {
|
||||
try {
|
||||
return mPM.hasUidSigningCertificate(uid, certificate, type);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPackagesForUid(int uid) {
|
||||
try {
|
||||
|
||||
@@ -656,4 +656,8 @@ interface IPackageManager {
|
||||
void setHarmfulAppWarning(String packageName, CharSequence warning, int userId);
|
||||
|
||||
CharSequence getHarmfulAppWarning(String packageName, int userId);
|
||||
|
||||
boolean hasSigningCertificate(String packageName, in byte[] signingCertificate, int flags);
|
||||
|
||||
boolean hasUidSigningCertificate(int uid, in byte[] signingCertificate, int flags);
|
||||
}
|
||||
|
||||
@@ -246,9 +246,44 @@ public class PackageInfo implements Parcelable {
|
||||
* 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.
|
||||
*
|
||||
* <strong>Deprecated</strong> This has been replaced by the
|
||||
* {@link PackageInfo#signingCertificateHistory} field, which takes into
|
||||
* account signing certificate rotation. For backwards compatibility in
|
||||
* the event of signing certificate rotation, this will return the oldest
|
||||
* reported signing certificate, so that an application will appear to
|
||||
* callers as though no rotation occurred.
|
||||
*
|
||||
* @deprecated use {@code signingCertificateHistory} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public Signature[] signatures;
|
||||
|
||||
|
||||
/**
|
||||
* Array of all signatures arrays read from the package file, potentially
|
||||
* including past signing certificates no longer used after signing
|
||||
* certificate rotation. Though signing certificate rotation is only
|
||||
* available for apps with a single signing certificate, this provides an
|
||||
* array of arrays so that packages signed with multiple signing
|
||||
* certificates can still return all signers. This is only filled in if
|
||||
* the flag {@link PackageManager#GET_SIGNING_CERTIFICATES} was set.
|
||||
*
|
||||
* A package must be singed with at least one certificate, which is at
|
||||
* position zero in the array. An application may be signed by multiple
|
||||
* certificates, which would be in the array at position zero in an
|
||||
* indeterminate order. A package may also have a history of certificates
|
||||
* due to signing certificate rotation. In this case, the array will be
|
||||
* populated by a series of single-entry arrays corresponding to a signing
|
||||
* certificate of the package.
|
||||
*
|
||||
* <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 will be the same across updates.
|
||||
*/
|
||||
public Signature[][] signingCertificateHistory;
|
||||
|
||||
/**
|
||||
* Application specified preferred configuration
|
||||
* {@link android.R.styleable#AndroidManifestUsesConfiguration
|
||||
|
||||
@@ -133,6 +133,7 @@ public abstract class PackageManager {
|
||||
GET_SERVICES,
|
||||
GET_SHARED_LIBRARY_FILES,
|
||||
GET_SIGNATURES,
|
||||
GET_SIGNING_CERTIFICATES,
|
||||
GET_URI_PERMISSION_PATTERNS,
|
||||
MATCH_UNINSTALLED_PACKAGES,
|
||||
MATCH_DISABLED_COMPONENTS,
|
||||
@@ -272,7 +273,10 @@ public abstract class PackageManager {
|
||||
/**
|
||||
* {@link PackageInfo} flag: return information about the
|
||||
* signatures included in the package.
|
||||
*
|
||||
* @deprecated use {@code GET_SIGNING_CERTIFICATES} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int GET_SIGNATURES = 0x00000040;
|
||||
|
||||
/**
|
||||
@@ -487,6 +491,14 @@ public abstract class PackageManager {
|
||||
*/
|
||||
public static final int MATCH_STATIC_SHARED_LIBRARIES = 0x04000000;
|
||||
|
||||
/**
|
||||
* {@link PackageInfo} flag: return the signing certificates associated with
|
||||
* this package. Each entry is a signing certificate that the package
|
||||
* has proven it is authorized to use, usually a past signing certificate from
|
||||
* which it has rotated.
|
||||
*/
|
||||
public static final int GET_SIGNING_CERTIFICATES = 0x08000000;
|
||||
|
||||
/**
|
||||
* Internal flag used to indicate that a system component has done their
|
||||
* homework and verified that they correctly handle packages and components
|
||||
@@ -3781,7 +3793,7 @@ public abstract class PackageManager {
|
||||
public abstract int getInstantAppCookieMaxBytes();
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* deprecated
|
||||
* @hide
|
||||
*/
|
||||
public abstract int getInstantAppCookieMaxSize();
|
||||
@@ -5914,4 +5926,60 @@ public abstract class PackageManager {
|
||||
public CharSequence getHarmfulAppWarning(@NonNull String packageName) {
|
||||
throw new UnsupportedOperationException("getHarmfulAppWarning not implemented in subclass");
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = { "CERT_INPUT_" }, value = {
|
||||
CERT_INPUT_RAW_X509,
|
||||
CERT_INPUT_SHA256
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface CertificateInputType {}
|
||||
|
||||
/**
|
||||
* Certificate input bytes: the input bytes represent an encoded X.509 Certificate which could
|
||||
* be generated using an {@code CertificateFactory}
|
||||
*/
|
||||
public static final int CERT_INPUT_RAW_X509 = 0;
|
||||
|
||||
/**
|
||||
* Certificate input bytes: the input bytes represent the SHA256 output of an encoded X.509
|
||||
* Certificate.
|
||||
*/
|
||||
public static final int CERT_INPUT_SHA256 = 1;
|
||||
|
||||
/**
|
||||
* Searches the set of signing certificates by which the given package has proven to have been
|
||||
* signed. This should be used instead of {@code getPackageInfo} with {@code GET_SIGNATURES}
|
||||
* since it takes into account the possibility of signing certificate rotation, except in the
|
||||
* case of packages that are signed by multiple certificates, for which signing certificate
|
||||
* rotation is not supported.
|
||||
*
|
||||
* @param packageName package whose signing certificates to check
|
||||
* @param certificate signing certificate for which to search
|
||||
* @param type representation of the {@code certificate}
|
||||
* @return true if this package was or is signed by exactly the certificate {@code certificate}
|
||||
*/
|
||||
public boolean hasSigningCertificate(
|
||||
String packageName, byte[] certificate, @CertificateInputType int type) {
|
||||
throw new UnsupportedOperationException(
|
||||
"hasSigningCertificate not implemented in subclass");
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the set of signing certificates by which the given uid has proven to have been
|
||||
* signed. This should be used instead of {@code getPackageInfo} with {@code GET_SIGNATURES}
|
||||
* since it takes into account the possibility of signing certificate rotation, except in the
|
||||
* case of packages that are signed by multiple certificates, for which signing certificate
|
||||
* rotation is not supported.
|
||||
*
|
||||
* @param uid package whose signing certificates to check
|
||||
* @param certificate signing certificate for which to search
|
||||
* @param type representation of the {@code certificate}
|
||||
* @return true if this package was or is signed by exactly the certificate {@code certificate}
|
||||
*/
|
||||
public boolean hasSigningCertificate(
|
||||
int uid, byte[] certificate, @CertificateInputType int type) {
|
||||
throw new UnsupportedOperationException(
|
||||
"hasSigningCertificate not implemented in subclass");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,13 +801,40 @@ public class PackageParser {
|
||||
}
|
||||
}
|
||||
}
|
||||
// deprecated method of getting signing certificates
|
||||
if ((flags&PackageManager.GET_SIGNATURES) != 0) {
|
||||
if (p.mSigningDetails.hasSignatures()) {
|
||||
if (p.mSigningDetails.hasPastSigningCertificates()) {
|
||||
// Package has included signing certificate rotation information. Return the oldest
|
||||
// cert so that programmatic checks keep working even if unaware of key rotation.
|
||||
pi.signatures = new Signature[1];
|
||||
pi.signatures[0] = p.mSigningDetails.pastSigningCertificates[0];
|
||||
} else if (p.mSigningDetails.hasSignatures()) {
|
||||
// otherwise keep old behavior
|
||||
int numberOfSigs = p.mSigningDetails.signatures.length;
|
||||
pi.signatures = new Signature[numberOfSigs];
|
||||
System.arraycopy(p.mSigningDetails.signatures, 0, pi.signatures, 0, numberOfSigs);
|
||||
}
|
||||
}
|
||||
|
||||
// replacement for GET_SIGNATURES
|
||||
if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
|
||||
if (p.mSigningDetails.hasPastSigningCertificates()) {
|
||||
// Package has included signing certificate rotation information. Convert each
|
||||
// entry to an array
|
||||
int numberOfSigs = p.mSigningDetails.pastSigningCertificates.length;
|
||||
pi.signingCertificateHistory = new Signature[numberOfSigs][];
|
||||
for (int i = 0; i < numberOfSigs; i++) {
|
||||
pi.signingCertificateHistory[i] =
|
||||
new Signature[] { p.mSigningDetails.pastSigningCertificates[i] };
|
||||
}
|
||||
} else if (p.mSigningDetails.hasSignatures()) {
|
||||
// otherwise keep old behavior
|
||||
int numberOfSigs = p.mSigningDetails.signatures.length;
|
||||
pi.signingCertificateHistory = new Signature[1][numberOfSigs];
|
||||
System.arraycopy(p.mSigningDetails.signatures, 0,
|
||||
pi.signingCertificateHistory[0], 0, numberOfSigs);
|
||||
}
|
||||
}
|
||||
return pi;
|
||||
}
|
||||
|
||||
@@ -5759,6 +5786,11 @@ public class PackageParser {
|
||||
return signatures != null && signatures.length > 0;
|
||||
}
|
||||
|
||||
/** Returns true if the signing details have past signing certificates. */
|
||||
public boolean hasPastSigningCertificates() {
|
||||
return pastSigningCertificates != null && pastSigningCertificates.length > 0;
|
||||
}
|
||||
|
||||
/** Returns true if the signatures in this and other match exactly. */
|
||||
public boolean signaturesMatchExactly(SigningDetails other) {
|
||||
return Signature.areExactMatch(this.signatures, other.signatures);
|
||||
|
||||
@@ -105,7 +105,7 @@ public final class PackageUtils {
|
||||
* @param data The data.
|
||||
* @return The digest or null if an error occurs.
|
||||
*/
|
||||
public static @Nullable String computeSha256Digest(@NonNull byte[] data) {
|
||||
public static @Nullable byte[] computeSha256DigestBytes(@NonNull byte[] data) {
|
||||
MessageDigest messageDigest;
|
||||
try {
|
||||
messageDigest = MessageDigest.getInstance("SHA256");
|
||||
@@ -116,6 +116,15 @@ public final class PackageUtils {
|
||||
|
||||
messageDigest.update(data);
|
||||
|
||||
return ByteStringUtils.toHexString(messageDigest.digest());
|
||||
return messageDigest.digest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the SHA256 digest of some data.
|
||||
* @param data The data.
|
||||
* @return The digest or null if an error occurs.
|
||||
*/
|
||||
public static @Nullable String computeSha256Digest(@NonNull byte[] data) {
|
||||
return ByteStringUtils.toHexString(computeSha256DigestBytes(data));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
|
||||
import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
|
||||
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
||||
import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
|
||||
import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509;
|
||||
import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
|
||||
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
|
||||
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
|
||||
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
|
||||
@@ -108,6 +110,8 @@ import static com.android.server.pm.PackageManagerServiceUtils.dumpCriticalInfo;
|
||||
import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFiles;
|
||||
import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
|
||||
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
|
||||
import static com.android.server.pm.PackageManagerServiceUtils.signingDetailsHasCertificate;
|
||||
import static com.android.server.pm.PackageManagerServiceUtils.signingDetailsHasSha256Certificate;
|
||||
import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
|
||||
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
|
||||
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS;
|
||||
@@ -5457,6 +5461,73 @@ Slog.e("TODD",
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSigningCertificate(
|
||||
String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
|
||||
|
||||
synchronized (mPackages) {
|
||||
final PackageParser.Package p = mPackages.get(packageName);
|
||||
if (p == null || p.mExtras == null) {
|
||||
return false;
|
||||
}
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int callingUserId = UserHandle.getUserId(callingUid);
|
||||
final PackageSetting ps = (PackageSetting) p.mExtras;
|
||||
if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
|
||||
return false;
|
||||
}
|
||||
switch (type) {
|
||||
case CERT_INPUT_RAW_X509:
|
||||
return signingDetailsHasCertificate(certificate, p.mSigningDetails);
|
||||
case CERT_INPUT_SHA256:
|
||||
return signingDetailsHasSha256Certificate(certificate, p.mSigningDetails);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUidSigningCertificate(
|
||||
int uid, byte[] certificate, @PackageManager.CertificateInputType int type) {
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int callingUserId = UserHandle.getUserId(callingUid);
|
||||
// Map to base uids.
|
||||
uid = UserHandle.getAppId(uid);
|
||||
// reader
|
||||
synchronized (mPackages) {
|
||||
final PackageParser.SigningDetails signingDetails;
|
||||
final Object obj = mSettings.getUserIdLPr(uid);
|
||||
if (obj != null) {
|
||||
if (obj instanceof SharedUserSetting) {
|
||||
final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
|
||||
if (isCallerInstantApp) {
|
||||
return false;
|
||||
}
|
||||
signingDetails = ((SharedUserSetting)obj).signatures.mSigningDetails;
|
||||
} else if (obj instanceof PackageSetting) {
|
||||
final PackageSetting ps = (PackageSetting) obj;
|
||||
if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
|
||||
return false;
|
||||
}
|
||||
signingDetails = ps.signatures.mSigningDetails;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
switch (type) {
|
||||
case CERT_INPUT_RAW_X509:
|
||||
return signingDetailsHasCertificate(certificate, signingDetails);
|
||||
case CERT_INPUT_SHA256:
|
||||
return signingDetailsHasSha256Certificate(certificate, signingDetails);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should typically only be used when granting or revoking
|
||||
* permissions, since the app may immediately restart after this call.
|
||||
|
||||
@@ -54,6 +54,7 @@ import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.PackageUtils;
|
||||
import android.util.Slog;
|
||||
import android.util.jar.StrictJarFile;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
@@ -74,6 +75,8 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.text.SimpleDateFormat;
|
||||
@@ -576,6 +579,69 @@ public class PackageManagerServiceUtils {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks the signing certificates to see if the provided certificate is a member. Invalid for
|
||||
* {@code SigningDetails} with multiple signing certificates.
|
||||
* @param certificate certificate to check for membership
|
||||
* @param signingDetails signing certificates record whose members are to be searched
|
||||
* @return true if {@code certificate} is in {@code signingDetails}
|
||||
*/
|
||||
public static boolean signingDetailsHasCertificate(
|
||||
byte[] certificate, PackageParser.SigningDetails signingDetails) {
|
||||
if (signingDetails == PackageParser.SigningDetails.UNKNOWN) {
|
||||
return false;
|
||||
}
|
||||
Signature signature = new Signature(certificate);
|
||||
if (signingDetails.hasPastSigningCertificates()) {
|
||||
for (int i = 0; i < signingDetails.pastSigningCertificates.length; i++) {
|
||||
if (signingDetails.pastSigningCertificates[i].equals(signature)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no signing history, just check the current signer
|
||||
if (signingDetails.signatures.length == 1
|
||||
&& signingDetails.signatures[0].equals(signature)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the signing certificates to see if the provided certificate is a member. Invalid for
|
||||
* {@code SigningDetails} with multiple signing certificaes.
|
||||
* @param sha256Certificate certificate to check for membership
|
||||
* @param signingDetails signing certificates record whose members are to be searched
|
||||
* @return true if {@code certificate} is in {@code signingDetails}
|
||||
*/
|
||||
public static boolean signingDetailsHasSha256Certificate(
|
||||
byte[] sha256Certificate, PackageParser.SigningDetails signingDetails ) {
|
||||
if (signingDetails == PackageParser.SigningDetails.UNKNOWN) {
|
||||
return false;
|
||||
}
|
||||
if (signingDetails.hasPastSigningCertificates()) {
|
||||
for (int i = 0; i < signingDetails.pastSigningCertificates.length; i++) {
|
||||
byte[] digest = PackageUtils.computeSha256DigestBytes(
|
||||
signingDetails.pastSigningCertificates[i].toByteArray());
|
||||
if (Arrays.equals(sha256Certificate, digest)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no signing history, just check the current signer
|
||||
if (signingDetails.signatures.length == 1) {
|
||||
byte[] digest = PackageUtils.computeSha256DigestBytes(
|
||||
signingDetails.signatures[0].toByteArray());
|
||||
if (Arrays.equals(sha256Certificate, digest)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns true to force apk verification if the updated package (in /data) is a priv app. */
|
||||
static boolean isApkVerificationForced(@Nullable PackageSetting disabledPs) {
|
||||
return disabledPs != null && disabledPs.isPrivileged() &&
|
||||
|
||||
@@ -1196,4 +1196,17 @@ public class MockPackageManager extends PackageManager {
|
||||
public CharSequence getHarmfulAppWarning(String packageName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSigningCertificate(
|
||||
String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSigningCertificate(
|
||||
int uid, byte[] certificate, @PackageManager.CertificateInputType int type) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user