Loading services/core/java/com/android/server/pm/ApkChecksums.java +112 −95 Original line number Diff line number Diff line Loading @@ -36,12 +36,14 @@ import android.content.Intent; import android.content.IntentSender; import android.content.pm.ApkChecksum; import android.content.pm.Checksum; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; import android.content.pm.Signature; import android.os.Handler; import android.os.SystemClock; import android.os.incremental.IncrementalManager; import android.os.incremental.IncrementalStorage; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Pair; Loading @@ -57,6 +59,7 @@ import android.util.apk.SignatureNotFoundException; import android.util.apk.VerityBuilder; import com.android.internal.annotations.VisibleForTesting; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.security.VerityUtils; import java.io.BufferedInputStream; Loading Loading @@ -121,12 +124,15 @@ public class ApkChecksums { private final Producer<Context> mContext; private final Producer<Handler> mHandlerProducer; private final Producer<IncrementalManager> mIncrementalManagerProducer; private final Producer<PackageManagerInternal> mPackageManagerInternalProducer; Injector(Producer<Context> context, Producer<Handler> handlerProducer, Producer<IncrementalManager> incrementalManagerProducer) { Producer<IncrementalManager> incrementalManagerProducer, Producer<PackageManagerInternal> packageManagerInternalProducer) { mContext = context; mHandlerProducer = handlerProducer; mIncrementalManagerProducer = incrementalManagerProducer; mPackageManagerInternalProducer = packageManagerInternalProducer; } public Context getContext() { Loading @@ -140,6 +146,10 @@ public class ApkChecksums { public IncrementalManager getIncrementalManager() { return mIncrementalManagerProducer.produce(); } public PackageManagerInternal getPackageManagerInternal() { return mPackageManagerInternalProducer.produce(); } } /** Loading Loading @@ -169,96 +179,47 @@ public class ApkChecksums { /** * Serialize checksums to the stream in binary format. */ public static void writeChecksums(OutputStream os, ApkChecksum[] checksums) public static void writeChecksums(OutputStream os, Checksum[] checksums) throws IOException, CertificateException { try (DataOutputStream dos = new DataOutputStream(os)) { dos.writeInt(checksums.length); for (ApkChecksum checksum : checksums) { final String splitName = checksum.getSplitName(); if (splitName == null) { dos.writeInt(-1); } else { dos.writeInt(splitName.length()); dos.writeUTF(splitName); } for (Checksum checksum : checksums) { dos.writeInt(checksum.getType()); final byte[] valueBytes = checksum.getValue(); dos.writeInt(valueBytes.length); dos.write(valueBytes); final String packageName = checksum.getInstallerPackageName(); if (packageName == null) { dos.writeInt(-1); } else { dos.writeInt(packageName.length()); dos.writeUTF(packageName); } final Certificate cert = checksum.getInstallerCertificate(); final byte[] certBytes = (cert == null) ? null : cert.getEncoded(); if (certBytes == null) { dos.writeInt(-1); } else { dos.writeInt(certBytes.length); dos.write(certBytes); } } } } /** * Deserialize array of checksums previously stored in * {@link #writeChecksums(File, ApkChecksum[])}. * {@link #writeChecksums(OutputStream, Checksum[])}. */ private static ApkChecksum[] readChecksums(File file) throws IOException { private static Checksum[] readChecksums(File file) throws IOException { try (InputStream is = new FileInputStream(file); DataInputStream dis = new DataInputStream(is)) { final int size = dis.readInt(); ApkChecksum[] checksums = new ApkChecksum[size]; Checksum[] checksums = new Checksum[size]; for (int i = 0; i < size; ++i) { final String splitName; if (dis.readInt() < 0) { splitName = null; } else { splitName = dis.readUTF(); } final int type = dis.readInt(); final byte[] valueBytes = new byte[dis.readInt()]; dis.read(valueBytes); final String packageName; if (dis.readInt() < 0) { packageName = null; } else { packageName = dis.readUTF(); } final byte[] certBytes; final int certBytesLength = dis.readInt(); if (certBytesLength < 0) { certBytes = null; } else { certBytes = new byte[certBytesLength]; dis.read(certBytes); } checksums[i] = new ApkChecksum(splitName, new Checksum(type, valueBytes), packageName, certBytes); checksums[i] = new Checksum(type, valueBytes); } return checksums; } } /** * Fetch or calculate checksums for the collection of files. * * @param filesToChecksum split name, null for base and File to fetch checksums for * @param optional mask to fetch readily available checksums * @param required mask to forcefully calculate if not available * @param installerPackageName package name of the installer of the packages * @param trustedInstallers array of certificate to trust, two specific cases: * null - trust anybody, * [] - trust nobody. Loading @@ -267,6 +228,7 @@ public class ApkChecksums { public static void getChecksums(List<Pair<String, File>> filesToChecksum, @Checksum.Type int optional, @Checksum.Type int required, @Nullable String installerPackageName, @Nullable Certificate[] trustedInstallers, @NonNull IntentSender statusReceiver, @NonNull Injector injector) { Loading @@ -278,8 +240,8 @@ public class ApkChecksums { result.add(checksums); try { getAvailableApkChecksums(split, file, optional | required, trustedInstallers, checksums); getAvailableApkChecksums(split, file, optional | required, installerPackageName, trustedInstallers, checksums, injector); } catch (Throwable e) { Slog.e(TAG, "Preferred checksum calculation error", e); } Loading Loading @@ -340,6 +302,7 @@ public class ApkChecksums { * @param split split name, null for base * @param file to fetch checksums for * @param types mask to fetch checksums * @param installerPackageName package name of the installer of the packages * @param trustedInstallers array of certificate to trust, two specific cases: * null - trust anybody, * [] - trust nobody. Loading @@ -347,8 +310,10 @@ public class ApkChecksums { */ private static void getAvailableApkChecksums(String split, File file, @Checksum.Type int types, @Nullable String installerPackageName, @Nullable Certificate[] trustedInstallers, Map<Integer, ApkChecksum> checksums) { Map<Integer, ApkChecksum> checksums, @NonNull Injector injector) { final String filePath = file.getAbsolutePath(); // Always available: FSI or IncFs. Loading @@ -370,16 +335,66 @@ public class ApkChecksums { } } if (trustedInstallers == null || trustedInstallers.length > 0) { final File digestsFile = new File(buildDigestsPathForApk(filePath)); if (digestsFile.exists()) { getInstallerChecksums(split, file, types, installerPackageName, trustedInstallers, checksums, injector); } private static void getInstallerChecksums(String split, File file, @Checksum.Type int types, @Nullable String installerPackageName, @Nullable Certificate[] trustedInstallers, Map<Integer, ApkChecksum> checksums, @NonNull Injector injector) { if (TextUtils.isEmpty(installerPackageName)) { return; } if (trustedInstallers != null && trustedInstallers.length == 0) { return; } final File digestsFile = new File(buildDigestsPathForApk(file.getAbsolutePath())); if (!digestsFile.exists()) { return; } final AndroidPackage installer = injector.getPackageManagerInternal().getPackage( installerPackageName); if (installer == null) { Slog.e(TAG, "Installer package not found."); return; } // Obtaining array of certificates used for signing the installer package. final Signature[] certs = installer.getSigningDetails().signatures; final Signature[] pastCerts = installer.getSigningDetails().pastSigningCertificates; if (certs == null || certs.length == 0 || certs[0] == null) { Slog.e(TAG, "Can't obtain calling installer package's certificates."); return; } // According to V2/V3 signing schema, the first certificate corresponds to the public key // in the signing block. byte[] trustedCertBytes = certs[0].toByteArray(); try { final ApkChecksum[] digests = readChecksums(digestsFile); final Checksum[] digests = readChecksums(digestsFile); final Set<Signature> trusted = convertToSet(trustedInstallers); for (ApkChecksum digest : digests) { if (isRequired(digest.getType(), types, checksums) && isTrusted(digest, trusted)) { checksums.put(digest.getType(), digest); if (trusted != null && !trusted.isEmpty()) { // Obtaining array of certificates used for signing the installer package. Signature trustedCert = isTrusted(certs, trusted); if (trustedCert == null) { trustedCert = isTrusted(pastCerts, trusted); } if (trustedCert == null) { return; } trustedCertBytes = trustedCert.toByteArray(); } for (Checksum digest : digests) { if (isRequired(digest.getType(), types, checksums)) { checksums.put(digest.getType(), new ApkChecksum(split, digest, installerPackageName, trustedCertBytes)); } } } catch (IOException e) { Loading @@ -388,8 +403,6 @@ public class ApkChecksums { Slog.e(TAG, "Error encoding trustedInstallers", e); } } } } /** * Whether the file is available for checksumming or we need to wait. Loading Loading @@ -494,12 +507,16 @@ public class ApkChecksums { return set; } private static boolean isTrusted(ApkChecksum checksum, Set<Signature> trusted) { if (trusted == null) { return true; private static Signature isTrusted(Signature[] signatures, Set<Signature> trusted) { if (signatures == null) { return null; } final Signature signature = new Signature(checksum.getInstallerCertificateBytes()); return trusted.contains(signature); for (Signature signature : signatures) { if (trusted.contains(signature)) { return signature; } } return null; } private static ApkChecksum extractHashFromFS(String split, String filePath) { Loading services/core/java/com/android/server/pm/PackageInstallerSession.java +26 −84 Original line number Diff line number Diff line Loading @@ -85,7 +85,6 @@ import android.content.pm.PackageParser; import android.content.pm.PackageParser.ApkLite; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.Signature; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.parsing.ApkLiteParseUtils; import android.content.pm.parsing.result.ParseResult; Loading Loading @@ -245,8 +244,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String ATTR_SIGNATURE = "signature"; private static final String ATTR_CHECKSUM_KIND = "checksumKind"; private static final String ATTR_CHECKSUM_VALUE = "checksumValue"; private static final String ATTR_CHECKSUM_PACKAGE = "checksumPackage"; private static final String ATTR_CHECKSUM_CERTIFICATE = "checksumCertificate"; private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill"; private static final int[] EMPTY_CHILD_SESSION_ARRAY = EmptyArray.INT; Loading Loading @@ -402,33 +399,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private ArraySet<FileEntry> mFiles = new ArraySet<>(); static class CertifiedChecksum { final @NonNull Checksum mChecksum; final @NonNull String mPackageName; final @NonNull byte[] mCertificate; CertifiedChecksum(@NonNull Checksum checksum, @NonNull String packageName, @NonNull byte[] certificate) { mChecksum = checksum; mPackageName = packageName; mCertificate = certificate; } Checksum getChecksum() { return mChecksum; } String getPackageName() { return mPackageName; } byte[] getCertificate() { return mCertificate; } } @GuardedBy("mLock") private ArrayMap<String, List<CertifiedChecksum>> mChecksums = new ArrayMap<>(); private ArrayMap<String, Checksum[]> mChecksums = new ArrayMap<>(); @Nullable final StagedSession mStagedSession; Loading Loading @@ -946,7 +918,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { int sessionId, int userId, int installerUid, @NonNull InstallSource installSource, SessionParams params, long createdMillis, long committedMillis, File stageDir, String stageCid, InstallationFile[] files, ArrayMap<String, List<CertifiedChecksum>> checksums, ArrayMap<String, List<Checksum>> checksums, boolean prepared, boolean committed, boolean destroyed, boolean sealed, @Nullable int[] childSessionIds, int parentSessionId, boolean isReady, boolean isFailed, boolean isApplied, int stagedSessionErrorCode, Loading Loading @@ -992,7 +964,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } if (checksums != null) { mChecksums.putAll(checksums); for (int i = 0, isize = checksums.size(); i < isize; ++i) { final String fileName = checksums.keyAt(i); final List<Checksum> fileChecksums = checksums.valueAt(i); mChecksums.put(fileName, fileChecksums.toArray(new Checksum[fileChecksums.size()])); } } if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) { Loading Loading @@ -1290,16 +1266,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { throw new IllegalStateException("Can't obtain calling installer's package."); } // Obtaining array of certificates used for signing the installer package. final Signature[] certs = callingInstaller.getSigningDetails().signatures; if (certs == null || certs.length == 0 || certs[0] == null) { throw new IllegalStateException( "Can't obtain calling installer package's certificates."); } // According to V2/V3 signing schema, the first certificate corresponds to the public key // in the signing block. final byte[] mainCertificateBytes = certs[0].toByteArray(); synchronized (mLock) { assertCallerIsOwnerOrRootLocked(); assertPreparedAndNotCommittedOrDestroyedLocked("addChecksums"); Loading @@ -1308,13 +1274,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { throw new IllegalStateException("Duplicate checksums."); } List<CertifiedChecksum> fileChecksums = new ArrayList<>(); mChecksums.put(name, fileChecksums); for (Checksum checksum : checksums) { fileChecksums.add(new CertifiedChecksum(checksum, initiatingPackageName, mainCertificateBytes)); } mChecksums.put(name, checksums); } } Loading Loading @@ -3069,34 +3029,23 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { maybeStageFsveritySignatureLocked(dexMetadataFile, targetDexMetadataFile); } private static ApkChecksum[] createApkChecksums(String splitName, List<CertifiedChecksum> checksums) { ApkChecksum[] result = new ApkChecksum[checksums.size()]; for (int i = 0, size = checksums.size(); i < size; ++i) { CertifiedChecksum checksum = checksums.get(i); result[i] = new ApkChecksum(splitName, checksum.getChecksum(), checksum.getPackageName(), checksum.getCertificate()); } return result; } @GuardedBy("mLock") private void maybeStageDigestsLocked(File origFile, File targetFile, String splitName) throws PackageManagerException { final List<CertifiedChecksum> checksums = mChecksums.get(origFile.getName()); final Checksum[] checksums = mChecksums.get(origFile.getName()); if (checksums == null) { return; } mChecksums.remove(origFile.getName()); if (checksums.isEmpty()) { if (checksums.length == 0) { return; } final String targetDigestsPath = ApkChecksums.buildDigestsPathForApk(targetFile.getName()); final File targetDigestsFile = new File(stageDir, targetDigestsPath); try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { ApkChecksums.writeChecksums(os, createApkChecksums(splitName, checksums)); ApkChecksums.writeChecksums(os, checksums); final byte[] checksumsBytes = os.toByteArray(); if (!isIncrementalInstallation() || mIncrementalFileStorages == null) { Loading Loading @@ -4338,18 +4287,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } for (int i = 0, isize = mChecksums.size(); i < isize; ++i) { String fileName = mChecksums.keyAt(i); List<CertifiedChecksum> checksums = mChecksums.valueAt(i); for (int j = 0, jsize = checksums.size(); j < jsize; ++j) { CertifiedChecksum checksum = checksums.get(j); final String fileName = mChecksums.keyAt(i); final Checksum[] checksums = mChecksums.valueAt(i); for (Checksum checksum : checksums) { out.startTag(null, TAG_SESSION_CHECKSUM); writeStringAttribute(out, ATTR_NAME, fileName); out.attributeInt(null, ATTR_CHECKSUM_KIND, checksum.getChecksum().getType()); writeByteArrayAttribute(out, ATTR_CHECKSUM_VALUE, checksum.getChecksum().getValue()); writeStringAttribute(out, ATTR_CHECKSUM_PACKAGE, checksum.getPackageName()); writeByteArrayAttribute(out, ATTR_CHECKSUM_CERTIFICATE, checksum.getCertificate()); out.attributeInt(null, ATTR_CHECKSUM_KIND, checksum.getType()); writeByteArrayAttribute(out, ATTR_CHECKSUM_VALUE, checksum.getValue()); out.endTag(null, TAG_SESSION_CHECKSUM); } } Loading Loading @@ -4467,7 +4411,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { int autoRevokePermissionsMode = MODE_DEFAULT; List<Integer> childSessionIds = new ArrayList<>(); List<InstallationFile> files = new ArrayList<>(); ArrayMap<String, List<CertifiedChecksum>> checksums = new ArrayMap<>(); ArrayMap<String, List<Checksum>> checksums = new ArrayMap<>(); int outerDepth = in.getDepth(); int type; while ((type = in.next()) != XmlPullParser.END_DOCUMENT Loading Loading @@ -4499,18 +4443,16 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } if (TAG_SESSION_CHECKSUM.equals(in.getName())) { final String fileName = readStringAttribute(in, ATTR_NAME); final CertifiedChecksum certifiedChecksum = new CertifiedChecksum( new Checksum(in.getAttributeInt(null, ATTR_CHECKSUM_KIND, 0), readByteArrayAttribute(in, ATTR_CHECKSUM_VALUE)), readStringAttribute(in, ATTR_CHECKSUM_PACKAGE), readByteArrayAttribute(in, ATTR_CHECKSUM_CERTIFICATE)); List<CertifiedChecksum> certifiedChecksums = checksums.get(fileName); if (certifiedChecksums == null) { certifiedChecksums = new ArrayList<>(); checksums.put(fileName, certifiedChecksums); } certifiedChecksums.add(certifiedChecksum); final Checksum checksum = new Checksum( in.getAttributeInt(null, ATTR_CHECKSUM_KIND, 0), readByteArrayAttribute(in, ATTR_CHECKSUM_VALUE)); List<Checksum> fileChecksums = checksums.get(fileName); if (fileChecksums == null) { fileChecksums = new ArrayList<>(); checksums.put(fileName, fileChecksums); } fileChecksums.add(checksum); } } Loading services/core/java/com/android/server/pm/PackageManagerService.java +7 −3 Original line number Diff line number Diff line Loading @@ -5584,6 +5584,9 @@ public class PackageManagerService extends IPackageManager.Stub if (applicationInfo == null) { throw new ParcelableException(new PackageManager.NameNotFoundException(packageName)); } final InstallSourceInfo installSourceInfo = getInstallSourceInfo(packageName); final String installerPackageName = installSourceInfo != null ? installSourceInfo.getInitiatingPackageName() : null; List<Pair<String, File>> filesToChecksum = new ArrayList<>(); Loading @@ -5605,9 +5608,10 @@ public class PackageManagerService extends IPackageManager.Stub ApkChecksums.Injector injector = new ApkChecksums.Injector( () -> mContext, () -> handler, () -> mInjector.getIncrementalManager()); ApkChecksums.getChecksums(filesToChecksum, optional, required, trustedCerts, statusReceiver, injector); () -> mInjector.getIncrementalManager(), () -> mPmInternal); ApkChecksums.getChecksums(filesToChecksum, optional, required, installerPackageName, trustedCerts, statusReceiver, injector); }); } Loading
services/core/java/com/android/server/pm/ApkChecksums.java +112 −95 Original line number Diff line number Diff line Loading @@ -36,12 +36,14 @@ import android.content.Intent; import android.content.IntentSender; import android.content.pm.ApkChecksum; import android.content.pm.Checksum; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; import android.content.pm.Signature; import android.os.Handler; import android.os.SystemClock; import android.os.incremental.IncrementalManager; import android.os.incremental.IncrementalStorage; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Pair; Loading @@ -57,6 +59,7 @@ import android.util.apk.SignatureNotFoundException; import android.util.apk.VerityBuilder; import com.android.internal.annotations.VisibleForTesting; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.security.VerityUtils; import java.io.BufferedInputStream; Loading Loading @@ -121,12 +124,15 @@ public class ApkChecksums { private final Producer<Context> mContext; private final Producer<Handler> mHandlerProducer; private final Producer<IncrementalManager> mIncrementalManagerProducer; private final Producer<PackageManagerInternal> mPackageManagerInternalProducer; Injector(Producer<Context> context, Producer<Handler> handlerProducer, Producer<IncrementalManager> incrementalManagerProducer) { Producer<IncrementalManager> incrementalManagerProducer, Producer<PackageManagerInternal> packageManagerInternalProducer) { mContext = context; mHandlerProducer = handlerProducer; mIncrementalManagerProducer = incrementalManagerProducer; mPackageManagerInternalProducer = packageManagerInternalProducer; } public Context getContext() { Loading @@ -140,6 +146,10 @@ public class ApkChecksums { public IncrementalManager getIncrementalManager() { return mIncrementalManagerProducer.produce(); } public PackageManagerInternal getPackageManagerInternal() { return mPackageManagerInternalProducer.produce(); } } /** Loading Loading @@ -169,96 +179,47 @@ public class ApkChecksums { /** * Serialize checksums to the stream in binary format. */ public static void writeChecksums(OutputStream os, ApkChecksum[] checksums) public static void writeChecksums(OutputStream os, Checksum[] checksums) throws IOException, CertificateException { try (DataOutputStream dos = new DataOutputStream(os)) { dos.writeInt(checksums.length); for (ApkChecksum checksum : checksums) { final String splitName = checksum.getSplitName(); if (splitName == null) { dos.writeInt(-1); } else { dos.writeInt(splitName.length()); dos.writeUTF(splitName); } for (Checksum checksum : checksums) { dos.writeInt(checksum.getType()); final byte[] valueBytes = checksum.getValue(); dos.writeInt(valueBytes.length); dos.write(valueBytes); final String packageName = checksum.getInstallerPackageName(); if (packageName == null) { dos.writeInt(-1); } else { dos.writeInt(packageName.length()); dos.writeUTF(packageName); } final Certificate cert = checksum.getInstallerCertificate(); final byte[] certBytes = (cert == null) ? null : cert.getEncoded(); if (certBytes == null) { dos.writeInt(-1); } else { dos.writeInt(certBytes.length); dos.write(certBytes); } } } } /** * Deserialize array of checksums previously stored in * {@link #writeChecksums(File, ApkChecksum[])}. * {@link #writeChecksums(OutputStream, Checksum[])}. */ private static ApkChecksum[] readChecksums(File file) throws IOException { private static Checksum[] readChecksums(File file) throws IOException { try (InputStream is = new FileInputStream(file); DataInputStream dis = new DataInputStream(is)) { final int size = dis.readInt(); ApkChecksum[] checksums = new ApkChecksum[size]; Checksum[] checksums = new Checksum[size]; for (int i = 0; i < size; ++i) { final String splitName; if (dis.readInt() < 0) { splitName = null; } else { splitName = dis.readUTF(); } final int type = dis.readInt(); final byte[] valueBytes = new byte[dis.readInt()]; dis.read(valueBytes); final String packageName; if (dis.readInt() < 0) { packageName = null; } else { packageName = dis.readUTF(); } final byte[] certBytes; final int certBytesLength = dis.readInt(); if (certBytesLength < 0) { certBytes = null; } else { certBytes = new byte[certBytesLength]; dis.read(certBytes); } checksums[i] = new ApkChecksum(splitName, new Checksum(type, valueBytes), packageName, certBytes); checksums[i] = new Checksum(type, valueBytes); } return checksums; } } /** * Fetch or calculate checksums for the collection of files. * * @param filesToChecksum split name, null for base and File to fetch checksums for * @param optional mask to fetch readily available checksums * @param required mask to forcefully calculate if not available * @param installerPackageName package name of the installer of the packages * @param trustedInstallers array of certificate to trust, two specific cases: * null - trust anybody, * [] - trust nobody. Loading @@ -267,6 +228,7 @@ public class ApkChecksums { public static void getChecksums(List<Pair<String, File>> filesToChecksum, @Checksum.Type int optional, @Checksum.Type int required, @Nullable String installerPackageName, @Nullable Certificate[] trustedInstallers, @NonNull IntentSender statusReceiver, @NonNull Injector injector) { Loading @@ -278,8 +240,8 @@ public class ApkChecksums { result.add(checksums); try { getAvailableApkChecksums(split, file, optional | required, trustedInstallers, checksums); getAvailableApkChecksums(split, file, optional | required, installerPackageName, trustedInstallers, checksums, injector); } catch (Throwable e) { Slog.e(TAG, "Preferred checksum calculation error", e); } Loading Loading @@ -340,6 +302,7 @@ public class ApkChecksums { * @param split split name, null for base * @param file to fetch checksums for * @param types mask to fetch checksums * @param installerPackageName package name of the installer of the packages * @param trustedInstallers array of certificate to trust, two specific cases: * null - trust anybody, * [] - trust nobody. Loading @@ -347,8 +310,10 @@ public class ApkChecksums { */ private static void getAvailableApkChecksums(String split, File file, @Checksum.Type int types, @Nullable String installerPackageName, @Nullable Certificate[] trustedInstallers, Map<Integer, ApkChecksum> checksums) { Map<Integer, ApkChecksum> checksums, @NonNull Injector injector) { final String filePath = file.getAbsolutePath(); // Always available: FSI or IncFs. Loading @@ -370,16 +335,66 @@ public class ApkChecksums { } } if (trustedInstallers == null || trustedInstallers.length > 0) { final File digestsFile = new File(buildDigestsPathForApk(filePath)); if (digestsFile.exists()) { getInstallerChecksums(split, file, types, installerPackageName, trustedInstallers, checksums, injector); } private static void getInstallerChecksums(String split, File file, @Checksum.Type int types, @Nullable String installerPackageName, @Nullable Certificate[] trustedInstallers, Map<Integer, ApkChecksum> checksums, @NonNull Injector injector) { if (TextUtils.isEmpty(installerPackageName)) { return; } if (trustedInstallers != null && trustedInstallers.length == 0) { return; } final File digestsFile = new File(buildDigestsPathForApk(file.getAbsolutePath())); if (!digestsFile.exists()) { return; } final AndroidPackage installer = injector.getPackageManagerInternal().getPackage( installerPackageName); if (installer == null) { Slog.e(TAG, "Installer package not found."); return; } // Obtaining array of certificates used for signing the installer package. final Signature[] certs = installer.getSigningDetails().signatures; final Signature[] pastCerts = installer.getSigningDetails().pastSigningCertificates; if (certs == null || certs.length == 0 || certs[0] == null) { Slog.e(TAG, "Can't obtain calling installer package's certificates."); return; } // According to V2/V3 signing schema, the first certificate corresponds to the public key // in the signing block. byte[] trustedCertBytes = certs[0].toByteArray(); try { final ApkChecksum[] digests = readChecksums(digestsFile); final Checksum[] digests = readChecksums(digestsFile); final Set<Signature> trusted = convertToSet(trustedInstallers); for (ApkChecksum digest : digests) { if (isRequired(digest.getType(), types, checksums) && isTrusted(digest, trusted)) { checksums.put(digest.getType(), digest); if (trusted != null && !trusted.isEmpty()) { // Obtaining array of certificates used for signing the installer package. Signature trustedCert = isTrusted(certs, trusted); if (trustedCert == null) { trustedCert = isTrusted(pastCerts, trusted); } if (trustedCert == null) { return; } trustedCertBytes = trustedCert.toByteArray(); } for (Checksum digest : digests) { if (isRequired(digest.getType(), types, checksums)) { checksums.put(digest.getType(), new ApkChecksum(split, digest, installerPackageName, trustedCertBytes)); } } } catch (IOException e) { Loading @@ -388,8 +403,6 @@ public class ApkChecksums { Slog.e(TAG, "Error encoding trustedInstallers", e); } } } } /** * Whether the file is available for checksumming or we need to wait. Loading Loading @@ -494,12 +507,16 @@ public class ApkChecksums { return set; } private static boolean isTrusted(ApkChecksum checksum, Set<Signature> trusted) { if (trusted == null) { return true; private static Signature isTrusted(Signature[] signatures, Set<Signature> trusted) { if (signatures == null) { return null; } final Signature signature = new Signature(checksum.getInstallerCertificateBytes()); return trusted.contains(signature); for (Signature signature : signatures) { if (trusted.contains(signature)) { return signature; } } return null; } private static ApkChecksum extractHashFromFS(String split, String filePath) { Loading
services/core/java/com/android/server/pm/PackageInstallerSession.java +26 −84 Original line number Diff line number Diff line Loading @@ -85,7 +85,6 @@ import android.content.pm.PackageParser; import android.content.pm.PackageParser.ApkLite; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.Signature; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.parsing.ApkLiteParseUtils; import android.content.pm.parsing.result.ParseResult; Loading Loading @@ -245,8 +244,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String ATTR_SIGNATURE = "signature"; private static final String ATTR_CHECKSUM_KIND = "checksumKind"; private static final String ATTR_CHECKSUM_VALUE = "checksumValue"; private static final String ATTR_CHECKSUM_PACKAGE = "checksumPackage"; private static final String ATTR_CHECKSUM_CERTIFICATE = "checksumCertificate"; private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill"; private static final int[] EMPTY_CHILD_SESSION_ARRAY = EmptyArray.INT; Loading Loading @@ -402,33 +399,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private ArraySet<FileEntry> mFiles = new ArraySet<>(); static class CertifiedChecksum { final @NonNull Checksum mChecksum; final @NonNull String mPackageName; final @NonNull byte[] mCertificate; CertifiedChecksum(@NonNull Checksum checksum, @NonNull String packageName, @NonNull byte[] certificate) { mChecksum = checksum; mPackageName = packageName; mCertificate = certificate; } Checksum getChecksum() { return mChecksum; } String getPackageName() { return mPackageName; } byte[] getCertificate() { return mCertificate; } } @GuardedBy("mLock") private ArrayMap<String, List<CertifiedChecksum>> mChecksums = new ArrayMap<>(); private ArrayMap<String, Checksum[]> mChecksums = new ArrayMap<>(); @Nullable final StagedSession mStagedSession; Loading Loading @@ -946,7 +918,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { int sessionId, int userId, int installerUid, @NonNull InstallSource installSource, SessionParams params, long createdMillis, long committedMillis, File stageDir, String stageCid, InstallationFile[] files, ArrayMap<String, List<CertifiedChecksum>> checksums, ArrayMap<String, List<Checksum>> checksums, boolean prepared, boolean committed, boolean destroyed, boolean sealed, @Nullable int[] childSessionIds, int parentSessionId, boolean isReady, boolean isFailed, boolean isApplied, int stagedSessionErrorCode, Loading Loading @@ -992,7 +964,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } if (checksums != null) { mChecksums.putAll(checksums); for (int i = 0, isize = checksums.size(); i < isize; ++i) { final String fileName = checksums.keyAt(i); final List<Checksum> fileChecksums = checksums.valueAt(i); mChecksums.put(fileName, fileChecksums.toArray(new Checksum[fileChecksums.size()])); } } if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) { Loading Loading @@ -1290,16 +1266,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { throw new IllegalStateException("Can't obtain calling installer's package."); } // Obtaining array of certificates used for signing the installer package. final Signature[] certs = callingInstaller.getSigningDetails().signatures; if (certs == null || certs.length == 0 || certs[0] == null) { throw new IllegalStateException( "Can't obtain calling installer package's certificates."); } // According to V2/V3 signing schema, the first certificate corresponds to the public key // in the signing block. final byte[] mainCertificateBytes = certs[0].toByteArray(); synchronized (mLock) { assertCallerIsOwnerOrRootLocked(); assertPreparedAndNotCommittedOrDestroyedLocked("addChecksums"); Loading @@ -1308,13 +1274,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { throw new IllegalStateException("Duplicate checksums."); } List<CertifiedChecksum> fileChecksums = new ArrayList<>(); mChecksums.put(name, fileChecksums); for (Checksum checksum : checksums) { fileChecksums.add(new CertifiedChecksum(checksum, initiatingPackageName, mainCertificateBytes)); } mChecksums.put(name, checksums); } } Loading Loading @@ -3069,34 +3029,23 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { maybeStageFsveritySignatureLocked(dexMetadataFile, targetDexMetadataFile); } private static ApkChecksum[] createApkChecksums(String splitName, List<CertifiedChecksum> checksums) { ApkChecksum[] result = new ApkChecksum[checksums.size()]; for (int i = 0, size = checksums.size(); i < size; ++i) { CertifiedChecksum checksum = checksums.get(i); result[i] = new ApkChecksum(splitName, checksum.getChecksum(), checksum.getPackageName(), checksum.getCertificate()); } return result; } @GuardedBy("mLock") private void maybeStageDigestsLocked(File origFile, File targetFile, String splitName) throws PackageManagerException { final List<CertifiedChecksum> checksums = mChecksums.get(origFile.getName()); final Checksum[] checksums = mChecksums.get(origFile.getName()); if (checksums == null) { return; } mChecksums.remove(origFile.getName()); if (checksums.isEmpty()) { if (checksums.length == 0) { return; } final String targetDigestsPath = ApkChecksums.buildDigestsPathForApk(targetFile.getName()); final File targetDigestsFile = new File(stageDir, targetDigestsPath); try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { ApkChecksums.writeChecksums(os, createApkChecksums(splitName, checksums)); ApkChecksums.writeChecksums(os, checksums); final byte[] checksumsBytes = os.toByteArray(); if (!isIncrementalInstallation() || mIncrementalFileStorages == null) { Loading Loading @@ -4338,18 +4287,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } for (int i = 0, isize = mChecksums.size(); i < isize; ++i) { String fileName = mChecksums.keyAt(i); List<CertifiedChecksum> checksums = mChecksums.valueAt(i); for (int j = 0, jsize = checksums.size(); j < jsize; ++j) { CertifiedChecksum checksum = checksums.get(j); final String fileName = mChecksums.keyAt(i); final Checksum[] checksums = mChecksums.valueAt(i); for (Checksum checksum : checksums) { out.startTag(null, TAG_SESSION_CHECKSUM); writeStringAttribute(out, ATTR_NAME, fileName); out.attributeInt(null, ATTR_CHECKSUM_KIND, checksum.getChecksum().getType()); writeByteArrayAttribute(out, ATTR_CHECKSUM_VALUE, checksum.getChecksum().getValue()); writeStringAttribute(out, ATTR_CHECKSUM_PACKAGE, checksum.getPackageName()); writeByteArrayAttribute(out, ATTR_CHECKSUM_CERTIFICATE, checksum.getCertificate()); out.attributeInt(null, ATTR_CHECKSUM_KIND, checksum.getType()); writeByteArrayAttribute(out, ATTR_CHECKSUM_VALUE, checksum.getValue()); out.endTag(null, TAG_SESSION_CHECKSUM); } } Loading Loading @@ -4467,7 +4411,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { int autoRevokePermissionsMode = MODE_DEFAULT; List<Integer> childSessionIds = new ArrayList<>(); List<InstallationFile> files = new ArrayList<>(); ArrayMap<String, List<CertifiedChecksum>> checksums = new ArrayMap<>(); ArrayMap<String, List<Checksum>> checksums = new ArrayMap<>(); int outerDepth = in.getDepth(); int type; while ((type = in.next()) != XmlPullParser.END_DOCUMENT Loading Loading @@ -4499,18 +4443,16 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } if (TAG_SESSION_CHECKSUM.equals(in.getName())) { final String fileName = readStringAttribute(in, ATTR_NAME); final CertifiedChecksum certifiedChecksum = new CertifiedChecksum( new Checksum(in.getAttributeInt(null, ATTR_CHECKSUM_KIND, 0), readByteArrayAttribute(in, ATTR_CHECKSUM_VALUE)), readStringAttribute(in, ATTR_CHECKSUM_PACKAGE), readByteArrayAttribute(in, ATTR_CHECKSUM_CERTIFICATE)); List<CertifiedChecksum> certifiedChecksums = checksums.get(fileName); if (certifiedChecksums == null) { certifiedChecksums = new ArrayList<>(); checksums.put(fileName, certifiedChecksums); } certifiedChecksums.add(certifiedChecksum); final Checksum checksum = new Checksum( in.getAttributeInt(null, ATTR_CHECKSUM_KIND, 0), readByteArrayAttribute(in, ATTR_CHECKSUM_VALUE)); List<Checksum> fileChecksums = checksums.get(fileName); if (fileChecksums == null) { fileChecksums = new ArrayList<>(); checksums.put(fileName, fileChecksums); } fileChecksums.add(checksum); } } Loading
services/core/java/com/android/server/pm/PackageManagerService.java +7 −3 Original line number Diff line number Diff line Loading @@ -5584,6 +5584,9 @@ public class PackageManagerService extends IPackageManager.Stub if (applicationInfo == null) { throw new ParcelableException(new PackageManager.NameNotFoundException(packageName)); } final InstallSourceInfo installSourceInfo = getInstallSourceInfo(packageName); final String installerPackageName = installSourceInfo != null ? installSourceInfo.getInitiatingPackageName() : null; List<Pair<String, File>> filesToChecksum = new ArrayList<>(); Loading @@ -5605,9 +5608,10 @@ public class PackageManagerService extends IPackageManager.Stub ApkChecksums.Injector injector = new ApkChecksums.Injector( () -> mContext, () -> handler, () -> mInjector.getIncrementalManager()); ApkChecksums.getChecksums(filesToChecksum, optional, required, trustedCerts, statusReceiver, injector); () -> mInjector.getIncrementalManager(), () -> mPmInternal); ApkChecksums.getChecksums(filesToChecksum, optional, required, installerPackageName, trustedCerts, statusReceiver, injector); }); }