diff options
15 files changed, 829 insertions, 271 deletions
diff --git a/api/current.txt b/api/current.txt index 6cc6956b8aba..9b9e258f23a2 100644 --- a/api/current.txt +++ b/api/current.txt @@ -11447,6 +11447,16 @@ package android.content.pm { field public final float widthFraction; } + public final class ApkChecksum implements android.os.Parcelable { + method public int describeContents(); + method public int getKind(); + method @Nullable public java.security.cert.Certificate getSourceCertificate() throws java.security.cert.CertificateException; + method @Nullable public String getSplitName(); + method @NonNull public byte[] getValue(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.ApkChecksum> CREATOR; + } + public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { ctor public ApplicationInfo(); ctor public ApplicationInfo(android.content.pm.ApplicationInfo); @@ -11548,6 +11558,21 @@ package android.content.pm { field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.ChangedPackages> CREATOR; } + public final class Checksum implements android.os.Parcelable { + method public int describeContents(); + method public int getKind(); + method @NonNull public byte[] getValue(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.Checksum> CREATOR; + field public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 32; // 0x20 + field public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 64; // 0x40 + field public static final int WHOLE_MD5 = 2; // 0x2 + field public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 1; // 0x1 + field public static final int WHOLE_SHA1 = 4; // 0x4 + field public static final int WHOLE_SHA256 = 8; // 0x8 + field public static final int WHOLE_SHA512 = 16; // 0x10 + } + public class ComponentInfo extends android.content.pm.PackageItemInfo { ctor public ComponentInfo(); ctor public ComponentInfo(android.content.pm.ComponentInfo); @@ -11619,16 +11644,6 @@ package android.content.pm { field public int version; } - public final class FileChecksum implements android.os.Parcelable { - method public int describeContents(); - method public int getKind(); - method @Nullable public java.security.cert.Certificate getSourceCertificate() throws java.security.cert.CertificateException; - method @Nullable public String getSplitName(); - method @NonNull public byte[] getValue(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.FileChecksum> CREATOR; - } - public final class InstallSourceInfo implements android.os.Parcelable { method public int describeContents(); method @Nullable public String getInitiatingPackageName(); @@ -11849,6 +11864,7 @@ package android.content.pm { public static class PackageInstaller.Session implements java.io.Closeable { method public void abandon(); + method public void addChecksums(@NonNull String, @NonNull java.util.List<android.content.pm.Checksum>) throws java.io.IOException; method public void addChildSessionId(int); method public void close(); method public void commit(@NonNull android.content.IntentSender); @@ -12250,8 +12266,6 @@ package android.content.pm { field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000 field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000 field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L - field public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 32; // 0x20 - field public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 64; // 0x40 field public static final int PERMISSION_DENIED = -1; // 0xffffffff field public static final int PERMISSION_GRANTED = 0; // 0x0 field public static final int SIGNATURE_FIRST_NOT_SIGNED = -1; // 0xffffffff @@ -12266,11 +12280,6 @@ package android.content.pm { field public static final int VERIFICATION_ALLOW = 1; // 0x1 field public static final int VERIFICATION_REJECT = -1; // 0xffffffff field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff - field public static final int WHOLE_MD5 = 2; // 0x2 - field public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 1; // 0x1 - field public static final int WHOLE_SHA1 = 4; // 0x4 - field public static final int WHOLE_SHA256 = 8; // 0x8 - field public static final int WHOLE_SHA512 = 16; // 0x10 } public static class PackageManager.NameNotFoundException extends android.util.AndroidException { diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 2780036d8102..066a00732965 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -16,6 +16,14 @@ package android.app; +import static android.content.pm.Checksum.PARTIAL_MERKLE_ROOT_1M_SHA256; +import static android.content.pm.Checksum.PARTIAL_MERKLE_ROOT_1M_SHA512; +import static android.content.pm.Checksum.WHOLE_MD5; +import static android.content.pm.Checksum.WHOLE_MERKLE_ROOT_4K_SHA256; +import static android.content.pm.Checksum.WHOLE_SHA1; +import static android.content.pm.Checksum.WHOLE_SHA256; +import static android.content.pm.Checksum.WHOLE_SHA512; + import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; @@ -32,6 +40,7 @@ import android.content.IntentSender; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ChangedPackages; +import android.content.pm.Checksum; import android.content.pm.ComponentInfo; import android.content.pm.FeatureInfo; import android.content.pm.IPackageDataObserver; @@ -973,7 +982,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public void getChecksums(@NonNull String packageName, boolean includeSplits, - @FileChecksumKind int required, @Nullable List<Certificate> trustedInstallers, + @Checksum.Kind int required, @Nullable List<Certificate> trustedInstallers, @NonNull IntentSender statusReceiver) throws CertificateEncodingException, IOException, NameNotFoundException { Objects.requireNonNull(packageName); diff --git a/core/java/android/content/pm/FileChecksum.aidl b/core/java/android/content/pm/ApkChecksum.aidl index 109f211033c1..46781fe26677 100644 --- a/core/java/android/content/pm/FileChecksum.aidl +++ b/core/java/android/content/pm/ApkChecksum.aidl @@ -16,5 +16,5 @@ package android.content.pm; -parcelable FileChecksum; +parcelable ApkChecksum; diff --git a/core/java/android/content/pm/FileChecksum.java b/core/java/android/content/pm/ApkChecksum.java index 55430c2b877b..e087c44d1ed1 100644 --- a/core/java/android/content/pm/FileChecksum.java +++ b/core/java/android/content/pm/ApkChecksum.java @@ -34,51 +34,71 @@ import java.security.cert.X509Certificate; import java.util.List; /** - * A typed checksum. + * A typed checksum of an APK. * * @see PackageManager#getChecksums(String, boolean, int, List, IntentSender) */ @DataClass(genHiddenConstructor = true) -public final class FileChecksum implements Parcelable { +@DataClass.Suppress({"getChecksum"}) +public final class ApkChecksum implements Parcelable { /** * Checksum for which split. Null indicates base.apk. */ private final @Nullable String mSplitName; /** - * Checksum kind. + * Checksum. */ - private final @PackageManager.FileChecksumKind int mKind; - /** - * Checksum value. - */ - private final @NonNull byte[] mValue; + private final @NonNull Checksum mChecksum; /** * For Installer-provided checksums, certificate of the Installer/AppStore. */ private final @Nullable byte[] mSourceCertificate; /** - * Constructor, internal use only + * Constructor, internal use only. * * @hide */ - public FileChecksum(@Nullable String splitName, @PackageManager.FileChecksumKind int kind, + public ApkChecksum(@Nullable String splitName, @Checksum.Kind int kind, @NonNull byte[] value) { - this(splitName, kind, value, (byte[]) null); + this(splitName, new Checksum(kind, value), (byte[]) null); } /** - * Constructor, internal use only + * Constructor, internal use only. * * @hide */ - public FileChecksum(@Nullable String splitName, @PackageManager.FileChecksumKind int kind, + public ApkChecksum(@Nullable String splitName, @Checksum.Kind int kind, @NonNull byte[] value, @Nullable Certificate sourceCertificate) throws CertificateEncodingException { - this(splitName, kind, value, + this(splitName, new Checksum(kind, value), (sourceCertificate != null) ? sourceCertificate.getEncoded() : null); } + + /** + * Checksum kind. + */ + public @Checksum.Kind int getKind() { + return mChecksum.getKind(); + } + + /** + * Checksum value. + */ + public @NonNull byte[] getValue() { + return mChecksum.getValue(); + } + + /** + * Returns raw bytes representing encoded certificate of the source of this checksum. + * @hide + */ + public @Nullable byte[] getSourceCertificateBytes() { + return mSourceCertificate; + } + /** * Certificate of the source of this checksum. * @throws CertificateException in case when certificate can't be re-created from serialized @@ -102,7 +122,7 @@ public final class FileChecksum implements Parcelable { // CHECKSTYLE:OFF Generated code // // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/FileChecksum.java + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/ApkChecksum.java // // To exclude the generated code from IntelliJ auto-formatting enable (one-time): // Settings > Editor > Code Style > Formatter Control @@ -110,31 +130,25 @@ public final class FileChecksum implements Parcelable { /** - * Creates a new FileChecksum. + * Creates a new ApkChecksum. * * @param splitName * Checksum for which split. Null indicates base.apk. - * @param kind - * Checksum kind. - * @param value - * Checksum value. + * @param checksum + * Checksum. * @param sourceCertificate * For Installer-provided checksums, certificate of the Installer/AppStore. * @hide */ @DataClass.Generated.Member - public FileChecksum( + public ApkChecksum( @Nullable String splitName, - @PackageManager.FileChecksumKind int kind, - @NonNull byte[] value, + @NonNull Checksum checksum, @Nullable byte[] sourceCertificate) { this.mSplitName = splitName; - this.mKind = kind; + this.mChecksum = checksum; com.android.internal.util.AnnotationValidations.validate( - PackageManager.FileChecksumKind.class, null, mKind); - this.mValue = value; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mValue); + NonNull.class, null, mChecksum); this.mSourceCertificate = sourceCertificate; // onConstructed(); // You can define this method to get a callback @@ -148,22 +162,6 @@ public final class FileChecksum implements Parcelable { return mSplitName; } - /** - * Checksum kind. - */ - @DataClass.Generated.Member - public @PackageManager.FileChecksumKind int getKind() { - return mKind; - } - - /** - * Checksum value. - */ - @DataClass.Generated.Member - public @NonNull byte[] getValue() { - return mValue; - } - @Override @DataClass.Generated.Member public void writeToParcel(@NonNull Parcel dest, int flags) { @@ -172,11 +170,10 @@ public final class FileChecksum implements Parcelable { byte flg = 0; if (mSplitName != null) flg |= 0x1; - if (mSourceCertificate != null) flg |= 0x8; + if (mSourceCertificate != null) flg |= 0x4; dest.writeByte(flg); if (mSplitName != null) dest.writeString(mSplitName); - dest.writeInt(mKind); - dest.writeByteArray(mValue); + dest.writeTypedObject(mChecksum, flags); if (mSourceCertificate != null) dest.writeByteArray(mSourceCertificate); } @@ -187,47 +184,43 @@ public final class FileChecksum implements Parcelable { /** @hide */ @SuppressWarnings({"unchecked", "RedundantCast"}) @DataClass.Generated.Member - /* package-private */ FileChecksum(@NonNull Parcel in) { + /* package-private */ ApkChecksum(@NonNull Parcel in) { // You can override field unparcelling by defining methods like: // static FieldType unparcelFieldName(Parcel in) { ... } byte flg = in.readByte(); String splitName = (flg & 0x1) == 0 ? null : in.readString(); - int kind = in.readInt(); - byte[] value = in.createByteArray(); - byte[] sourceCertificate = (flg & 0x8) == 0 ? null : in.createByteArray(); + Checksum checksum = (Checksum) in.readTypedObject(Checksum.CREATOR); + byte[] sourceCertificate = (flg & 0x4) == 0 ? null : in.createByteArray(); this.mSplitName = splitName; - this.mKind = kind; - com.android.internal.util.AnnotationValidations.validate( - PackageManager.FileChecksumKind.class, null, mKind); - this.mValue = value; + this.mChecksum = checksum; com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mValue); + NonNull.class, null, mChecksum); this.mSourceCertificate = sourceCertificate; // onConstructed(); // You can define this method to get a callback } @DataClass.Generated.Member - public static final @NonNull Parcelable.Creator<FileChecksum> CREATOR - = new Parcelable.Creator<FileChecksum>() { + public static final @NonNull Parcelable.Creator<ApkChecksum> CREATOR + = new Parcelable.Creator<ApkChecksum>() { @Override - public FileChecksum[] newArray(int size) { - return new FileChecksum[size]; + public ApkChecksum[] newArray(int size) { + return new ApkChecksum[size]; } @Override - public FileChecksum createFromParcel(@NonNull Parcel in) { - return new FileChecksum(in); + public ApkChecksum createFromParcel(@NonNull Parcel in) { + return new ApkChecksum(in); } }; @DataClass.Generated( - time = 1598322801861L, + time = 1599845645160L, codegenVersion = "1.0.15", - sourceFile = "frameworks/base/core/java/android/content/pm/FileChecksum.java", - inputSignatures = "private final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.content.pm.PackageManager.FileChecksumKind int mKind\nprivate final @android.annotation.NonNull byte[] mValue\nprivate final @android.annotation.Nullable byte[] mSourceCertificate\npublic @android.annotation.Nullable java.security.cert.Certificate getSourceCertificate()\nclass FileChecksum extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)") + sourceFile = "frameworks/base/core/java/android/content/pm/ApkChecksum.java", + inputSignatures = "private final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.NonNull android.content.pm.Checksum mChecksum\nprivate final @android.annotation.Nullable byte[] mSourceCertificate\npublic @android.content.pm.Checksum.Kind int getKind()\npublic @android.annotation.NonNull byte[] getValue()\npublic @android.annotation.Nullable byte[] getSourceCertificateBytes()\npublic @android.annotation.Nullable java.security.cert.Certificate getSourceCertificate()\nclass ApkChecksum extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/content/pm/Checksum.aidl b/core/java/android/content/pm/Checksum.aidl new file mode 100644 index 000000000000..f0ca206fad58 --- /dev/null +++ b/core/java/android/content/pm/Checksum.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2020 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; + +parcelable Checksum; + diff --git a/core/java/android/content/pm/Checksum.java b/core/java/android/content/pm/Checksum.java new file mode 100644 index 000000000000..123aaddda7ce --- /dev/null +++ b/core/java/android/content/pm/Checksum.java @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2020 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 android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; + +/** + * A typed checksum. + * + * @see PackageInstaller.Session#addChecksums(String, List) + */ +@DataClass(genHiddenConstructor = true, genConstDefs = false) +public final class Checksum implements Parcelable { + /** + * Root SHA256 hash of a 4K Merkle tree computed over all file bytes. + * <a href="https://source.android.com/security/apksigning/v4">See APK Signature Scheme V4</a>. + * <a href="https://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git/tree/Documentation/filesystems/fsverity.rst">See fs-verity</a>. + * + * @see PackageManager#getChecksums + */ + public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 0x00000001; + + /** + * MD5 hash computed over all file bytes. + * + * @see PackageManager#getChecksums + */ + public static final int WHOLE_MD5 = 0x00000002; + + /** + * SHA1 hash computed over all file bytes. + * + * @see PackageManager#getChecksums + */ + public static final int WHOLE_SHA1 = 0x00000004; + + /** + * SHA256 hash computed over all file bytes. + * + * @see PackageManager#getChecksums + */ + public static final int WHOLE_SHA256 = 0x00000008; + + /** + * SHA512 hash computed over all file bytes. + * + * @see PackageManager#getChecksums + */ + public static final int WHOLE_SHA512 = 0x00000010; + + /** + * Root SHA256 hash of a 1M Merkle tree computed over protected content. + * Excludes signing block. + * <a href="https://source.android.com/security/apksigning/v2">See APK Signature Scheme V2</a>. + * + * @see PackageManager#getChecksums + */ + public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 0x00000020; + + /** + * Root SHA512 hash of a 1M Merkle tree computed over protected content. + * Excludes signing block. + * <a href="https://source.android.com/security/apksigning/v2">See APK Signature Scheme V2</a>. + * + * @see PackageManager#getChecksums + */ + public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 0x00000040; + + /** @hide */ + @IntDef(flag = true, prefix = {"WHOLE_", "PARTIAL_"}, value = { + WHOLE_MERKLE_ROOT_4K_SHA256, + WHOLE_MD5, + WHOLE_SHA1, + WHOLE_SHA256, + WHOLE_SHA512, + PARTIAL_MERKLE_ROOT_1M_SHA256, + PARTIAL_MERKLE_ROOT_1M_SHA512, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Kind {} + + /** + * Checksum kind. + */ + private final @Checksum.Kind int mKind; + /** + * Checksum value. + */ + private final @NonNull byte[] mValue; + + + + // Code below generated by codegen v1.0.15. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/Checksum.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new Checksum. + * + * @param kind + * Checksum kind. + * @param value + * Checksum value. + * @hide + */ + @DataClass.Generated.Member + public Checksum( + @Checksum.Kind int kind, + @NonNull byte[] value) { + this.mKind = kind; + com.android.internal.util.AnnotationValidations.validate( + Checksum.Kind.class, null, mKind); + this.mValue = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mValue); + + // onConstructed(); // You can define this method to get a callback + } + + /** + * Checksum kind. + */ + @DataClass.Generated.Member + public @Checksum.Kind int getKind() { + return mKind; + } + + /** + * Checksum value. + */ + @DataClass.Generated.Member + public @NonNull byte[] getValue() { + return mValue; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeInt(mKind); + dest.writeByteArray(mValue); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ Checksum(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + int kind = in.readInt(); + byte[] value = in.createByteArray(); + + this.mKind = kind; + com.android.internal.util.AnnotationValidations.validate( + Checksum.Kind.class, null, mKind); + this.mValue = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mValue); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<Checksum> CREATOR + = new Parcelable.Creator<Checksum>() { + @Override + public Checksum[] newArray(int size) { + return new Checksum[size]; + } + + @Override + public Checksum createFromParcel(@NonNull Parcel in) { + return new Checksum(in); + } + }; + + @DataClass.Generated( + time = 1599845646883L, + codegenVersion = "1.0.15", + sourceFile = "frameworks/base/core/java/android/content/pm/Checksum.java", + inputSignatures = "public static final int WHOLE_MERKLE_ROOT_4K_SHA256\npublic static final int WHOLE_MD5\npublic static final int WHOLE_SHA1\npublic static final int WHOLE_SHA256\npublic static final int WHOLE_SHA512\npublic static final int PARTIAL_MERKLE_ROOT_1M_SHA256\npublic static final int PARTIAL_MERKLE_ROOT_1M_SHA512\nprivate final @android.content.pm.Checksum.Kind int mKind\nprivate final @android.annotation.NonNull byte[] mValue\nclass Checksum extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genConstDefs=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl index fc20263fe00a..6ccbc36e26f6 100644 --- a/core/java/android/content/pm/IPackageInstallerSession.aidl +++ b/core/java/android/content/pm/IPackageInstallerSession.aidl @@ -16,6 +16,7 @@ package android.content.pm; +import android.content.pm.Checksum; import android.content.pm.DataLoaderParamsParcel; import android.content.pm.IPackageInstallObserver2; import android.content.IntentSender; @@ -33,6 +34,8 @@ interface IPackageInstallerSession { void write(String name, long offsetBytes, long lengthBytes, in ParcelFileDescriptor fd); + void addChecksums(String name, in Checksum[] checksums); + void removeSplit(String splitName); void close(); diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index e6ea04433114..9eb95a3f6707 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1219,6 +1219,31 @@ public class PackageInstaller { } /** + * Adds installer-provided checksums for the APK file in session. + * + * @param name previously written as part of this session. + * @param checksums installer intends to make available via + * {@link PackageManager#getChecksums(String, boolean, int, List, + * IntentSender)}. + * @throws SecurityException if called after the session has been + * committed or abandoned. + */ + public void addChecksums(@NonNull String name, @NonNull List<Checksum> checksums) + throws IOException { + Objects.requireNonNull(name); + Objects.requireNonNull(checksums); + + try { + mSession.addChecksums(name, checksums.toArray(new Checksum[checksums.size()])); + } catch (RuntimeException e) { + ExceptionUtils.maybeUnwrapIOException(e); + throw e; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Attempt to commit everything staged in this session. This may require * user intervention, and so it may not happen immediately. The final * result of the commit will be reported through the given callback. diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index d2395ec9f69f..e68df3383642 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -7844,74 +7844,6 @@ public abstract class PackageManager { } /** - * Root SHA256 hash of a 4K Merkle tree computed over all file bytes. - * <a href="https://source.android.com/security/apksigning/v4">See APK Signature Scheme V4</a>. - * <a href="https://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git/tree/Documentation/filesystems/fsverity.rst">See fs-verity</a>. - * - * @see #getChecksums - */ - public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 0x00000001; - - /** - * MD5 hash computed over all file bytes. - * - * @see #getChecksums - */ - public static final int WHOLE_MD5 = 0x00000002; - - /** - * SHA1 hash computed over all file bytes. - * - * @see #getChecksums - */ - public static final int WHOLE_SHA1 = 0x00000004; - - /** - * SHA256 hash computed over all file bytes. - * - * @see #getChecksums - */ - public static final int WHOLE_SHA256 = 0x00000008; - - /** - * SHA512 hash computed over all file bytes. - * - * @see #getChecksums - */ - public static final int WHOLE_SHA512 = 0x00000010; - - /** - * Root SHA256 hash of a 1M Merkle tree computed over protected content. - * Excludes signing block. - * <a href="https://source.android.com/security/apksigning/v2">See APK Signature Scheme V2</a>. - * - * @see #getChecksums - */ - public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 0x00000020; - - /** - * Root SHA512 hash of a 1M Merkle tree computed over protected content. - * Excludes signing block. - * <a href="https://source.android.com/security/apksigning/v2">See APK Signature Scheme V2</a>. - * - * @see #getChecksums - */ - public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 0x00000040; - - /** @hide */ - @IntDef(flag = true, prefix = {"WHOLE_", "PARTIAL_"}, value = { - WHOLE_MERKLE_ROOT_4K_SHA256, - WHOLE_MD5, - WHOLE_SHA1, - WHOLE_SHA256, - WHOLE_SHA512, - PARTIAL_MERKLE_ROOT_1M_SHA256, - PARTIAL_MERKLE_ROOT_1M_SHA512, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface FileChecksumKind {} - - /** * Trust any Installer to provide checksums for the package. * @see #getChecksums */ @@ -7940,12 +7872,12 @@ public abstract class PackageManager { * {@link #TRUST_ALL} will return checksums from any Installer, * {@link #TRUST_NONE} disables optimized Installer-enforced checksums. * @param statusReceiver called once when the results are available as - * {@link #EXTRA_CHECKSUMS} of type FileChecksum[]. + * {@link #EXTRA_CHECKSUMS} of type ApkChecksum[]. * @throws CertificateEncodingException if an encoding error occurs for trustedInstallers. * @throws NameNotFoundException if a package with the given name cannot be found on the system. */ public void getChecksums(@NonNull String packageName, boolean includeSplits, - @FileChecksumKind int required, @Nullable List<Certificate> trustedInstallers, + @Checksum.Kind int required, @Nullable List<Certificate> trustedInstallers, @NonNull IntentSender statusReceiver) throws CertificateEncodingException, IOException, NameNotFoundException { throw new UnsupportedOperationException("getChecksums not implemented in subclass"); diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt index c0509445a54a..d62e132b5745 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -11447,6 +11447,16 @@ package android.content.pm { field public final float widthFraction; } + public final class ApkChecksum implements android.os.Parcelable { + method public int describeContents(); + method public int getKind(); + method @Nullable public java.security.cert.Certificate getSourceCertificate() throws java.security.cert.CertificateException; + method @Nullable public String getSplitName(); + method @NonNull public byte[] getValue(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.ApkChecksum> CREATOR; + } + public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { ctor public ApplicationInfo(); ctor public ApplicationInfo(android.content.pm.ApplicationInfo); @@ -11548,6 +11558,21 @@ package android.content.pm { field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.ChangedPackages> CREATOR; } + public final class Checksum implements android.os.Parcelable { + method public int describeContents(); + method public int getKind(); + method @NonNull public byte[] getValue(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.Checksum> CREATOR; + field public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 32; // 0x20 + field public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 64; // 0x40 + field public static final int WHOLE_MD5 = 2; // 0x2 + field public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 1; // 0x1 + field public static final int WHOLE_SHA1 = 4; // 0x4 + field public static final int WHOLE_SHA256 = 8; // 0x8 + field public static final int WHOLE_SHA512 = 16; // 0x10 + } + public class ComponentInfo extends android.content.pm.PackageItemInfo { ctor public ComponentInfo(); ctor public ComponentInfo(android.content.pm.ComponentInfo); @@ -11619,16 +11644,6 @@ package android.content.pm { field public int version; } - public final class FileChecksum implements android.os.Parcelable { - method public int describeContents(); - method public int getKind(); - method @Nullable public java.security.cert.Certificate getSourceCertificate() throws java.security.cert.CertificateException; - method @Nullable public String getSplitName(); - method @NonNull public byte[] getValue(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.FileChecksum> CREATOR; - } - public final class InstallSourceInfo implements android.os.Parcelable { method public int describeContents(); method @Nullable public String getInitiatingPackageName(); @@ -11849,6 +11864,7 @@ package android.content.pm { public static class PackageInstaller.Session implements java.io.Closeable { method public void abandon(); + method public void addChecksums(@NonNull String, @NonNull java.util.List<android.content.pm.Checksum>) throws java.io.IOException; method public void addChildSessionId(int); method public void close(); method public void commit(@NonNull android.content.IntentSender); @@ -12250,8 +12266,6 @@ package android.content.pm { field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000 field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000 field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L - field public static final int PARTIAL_MERKLE_ROOT_1M_SHA256 = 32; // 0x20 - field public static final int PARTIAL_MERKLE_ROOT_1M_SHA512 = 64; // 0x40 field public static final int PERMISSION_DENIED = -1; // 0xffffffff field public static final int PERMISSION_GRANTED = 0; // 0x0 field public static final int SIGNATURE_FIRST_NOT_SIGNED = -1; // 0xffffffff @@ -12266,11 +12280,6 @@ package android.content.pm { field public static final int VERIFICATION_ALLOW = 1; // 0x1 field public static final int VERIFICATION_REJECT = -1; // 0xffffffff field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff - field public static final int WHOLE_MD5 = 2; // 0x2 - field public static final int WHOLE_MERKLE_ROOT_4K_SHA256 = 1; // 0x1 - field public static final int WHOLE_SHA1 = 4; // 0x4 - field public static final int WHOLE_SHA256 = 8; // 0x8 - field public static final int WHOLE_SHA512 = 16; // 0x10 } public static class PackageManager.NameNotFoundException extends android.util.AndroidException { diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java index 0338ed802436..c6c80aef4432 100644 --- a/services/core/java/com/android/server/pm/ApkChecksums.java +++ b/services/core/java/com/android/server/pm/ApkChecksums.java @@ -16,14 +16,15 @@ package com.android.server.pm; +import static android.content.pm.Checksum.PARTIAL_MERKLE_ROOT_1M_SHA256; +import static android.content.pm.Checksum.PARTIAL_MERKLE_ROOT_1M_SHA512; +import static android.content.pm.Checksum.WHOLE_MD5; +import static android.content.pm.Checksum.WHOLE_MERKLE_ROOT_4K_SHA256; +import static android.content.pm.Checksum.WHOLE_SHA1; +import static android.content.pm.Checksum.WHOLE_SHA256; +import static android.content.pm.Checksum.WHOLE_SHA512; import static android.content.pm.PackageManager.EXTRA_CHECKSUMS; -import static android.content.pm.PackageManager.PARTIAL_MERKLE_ROOT_1M_SHA256; -import static android.content.pm.PackageManager.PARTIAL_MERKLE_ROOT_1M_SHA512; -import static android.content.pm.PackageManager.WHOLE_MD5; -import static android.content.pm.PackageManager.WHOLE_MERKLE_ROOT_4K_SHA256; -import static android.content.pm.PackageManager.WHOLE_SHA1; -import static android.content.pm.PackageManager.WHOLE_SHA256; -import static android.content.pm.PackageManager.WHOLE_SHA512; +import static android.content.pm.PackageParser.APK_FILE_EXTENSION; import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256; import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512; import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256; @@ -33,14 +34,16 @@ import android.annotation.Nullable; import android.content.Context; import android.content.Intent; import android.content.IntentSender; -import android.content.pm.FileChecksum; -import android.content.pm.PackageManager; +import android.content.pm.ApkChecksum; +import android.content.pm.Checksum; 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.util.ArrayMap; +import android.util.ArraySet; import android.util.Pair; import android.util.Slog; import android.util.apk.ApkSignatureSchemeV2Verifier; @@ -57,18 +60,26 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.security.VerityUtils; import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.security.DigestException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; /** * Provides checksums for APK. @@ -76,6 +87,8 @@ import java.util.Map; public class ApkChecksums { static final String TAG = "ApkChecksums"; + private static final String DIGESTS_FILE_EXTENSION = ".digests"; + // MessageDigest algorithms. static final String ALGO_MD5 = "MD5"; static final String ALGO_SHA1 = "SHA1"; @@ -131,6 +144,100 @@ public class ApkChecksums { } /** + * Return the digests path associated with the given code path + * (replaces '.apk' extension with '.digests') + * + * @throws IllegalArgumentException if the code path is not an .apk. + */ + public static String buildDigestsPathForApk(String codePath) { + if (!PackageParser.isApkPath(codePath)) { + throw new IllegalStateException("Code path is not an apk " + codePath); + } + return codePath.substring(0, codePath.length() - APK_FILE_EXTENSION.length()) + + DIGESTS_FILE_EXTENSION; + } + + /** + * Search for the digests file associated with the given target file. + * If it exists, the method returns the digests file; otherwise it returns null. + */ + public static File findDigestsForFile(File targetFile) { + String digestsPath = buildDigestsPathForApk(targetFile.getAbsolutePath()); + File digestsFile = new File(digestsPath); + return digestsFile.exists() ? digestsFile : null; + } + + /** + * Serialize checksums to file in binary format. + */ + public static void writeChecksums(File file, ApkChecksum[] checksums) + throws IOException, CertificateException { + try (OutputStream os = new FileOutputStream(file); + 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); + } + + dos.writeInt(checksum.getKind()); + + final byte[] valueBytes = checksum.getValue(); + dos.writeInt(valueBytes.length); + dos.write(valueBytes); + + final Certificate cert = checksum.getSourceCertificate(); + 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[])}. + */ + private static ApkChecksum[] 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]; + for (int i = 0; i < size; ++i) { + final String splitName; + if (dis.readInt() < 0) { + splitName = null; + } else { + splitName = dis.readUTF(); + } + final int kind = dis.readInt(); + final byte[] valueBytes = new byte[dis.readInt()]; + dis.read(valueBytes); + 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(kind, valueBytes), + certBytes); + } + return checksums; + } + } + + + /** * Fetch or calculate checksums for the collection of files. * * @param filesToChecksum split name, null for base and File to fetch checksums for @@ -142,20 +249,20 @@ public class ApkChecksums { * @param statusReceiver to receive the resulting checksums */ public static void getChecksums(List<Pair<String, File>> filesToChecksum, - @PackageManager.FileChecksumKind int optional, - @PackageManager.FileChecksumKind int required, + @Checksum.Kind int optional, + @Checksum.Kind int required, @Nullable Certificate[] trustedInstallers, @NonNull IntentSender statusReceiver, @NonNull Injector injector) { - List<Map<Integer, FileChecksum>> result = new ArrayList<>(filesToChecksum.size()); + List<Map<Integer, ApkChecksum>> result = new ArrayList<>(filesToChecksum.size()); for (int i = 0, size = filesToChecksum.size(); i < size; ++i) { final String split = filesToChecksum.get(i).first; final File file = filesToChecksum.get(i).second; - Map<Integer, FileChecksum> checksums = new ArrayMap<>(); + Map<Integer, ApkChecksum> checksums = new ArrayMap<>(); result.add(checksums); try { - getAvailableFileChecksums(split, file, optional | required, trustedInstallers, + getAvailableApkChecksums(split, file, optional | required, trustedInstallers, checksums); } catch (Throwable e) { Slog.e(TAG, "Preferred checksum calculation error", e); @@ -168,18 +275,18 @@ public class ApkChecksums { } private static void processRequiredChecksums(List<Pair<String, File>> filesToChecksum, - List<Map<Integer, FileChecksum>> result, - @PackageManager.FileChecksumKind int required, + List<Map<Integer, ApkChecksum>> result, + @Checksum.Kind int required, @NonNull IntentSender statusReceiver, @NonNull Injector injector, long startTime) { final boolean timeout = SystemClock.uptimeMillis() - startTime >= PROCESS_REQUIRED_CHECKSUMS_TIMEOUT_MILLIS; - List<FileChecksum> allChecksums = new ArrayList<>(); + List<ApkChecksum> allChecksums = new ArrayList<>(); for (int i = 0, size = filesToChecksum.size(); i < size; ++i) { final String split = filesToChecksum.get(i).first; final File file = filesToChecksum.get(i).second; - Map<Integer, FileChecksum> checksums = result.get(i); + Map<Integer, ApkChecksum> checksums = result.get(i); try { if (!timeout || required != 0) { @@ -192,7 +299,7 @@ public class ApkChecksums { return; } - getRequiredFileChecksums(split, file, required, checksums); + getRequiredApkChecksums(split, file, required, checksums); } allChecksums.addAll(checksums.values()); } catch (Throwable e) { @@ -202,7 +309,7 @@ public class ApkChecksums { final Intent intent = new Intent(); intent.putExtra(EXTRA_CHECKSUMS, - allChecksums.toArray(new FileChecksum[allChecksums.size()])); + allChecksums.toArray(new ApkChecksum[allChecksums.size()])); try { statusReceiver.sendIntent(injector.getContext(), 1, intent, null, null); @@ -222,16 +329,16 @@ public class ApkChecksums { * [] - trust nobody. * @param checksums resulting checksums */ - private static void getAvailableFileChecksums(String split, File file, - @PackageManager.FileChecksumKind int kinds, + private static void getAvailableApkChecksums(String split, File file, + @Checksum.Kind int kinds, @Nullable Certificate[] trustedInstallers, - Map<Integer, FileChecksum> checksums) { + Map<Integer, ApkChecksum> checksums) { final String filePath = file.getAbsolutePath(); // Always available: FSI or IncFs. if (isRequired(WHOLE_MERKLE_ROOT_4K_SHA256, kinds, checksums)) { // Hashes in fs-verity and IncFS are always verified. - FileChecksum checksum = extractHashFromFS(split, filePath); + ApkChecksum checksum = extractHashFromFS(split, filePath); if (checksum != null) { checksums.put(checksum.getKind(), checksum); } @@ -240,22 +347,40 @@ public class ApkChecksums { // System enforced: v2/v3. if (isRequired(PARTIAL_MERKLE_ROOT_1M_SHA256, kinds, checksums) || isRequired( PARTIAL_MERKLE_ROOT_1M_SHA512, kinds, checksums)) { - Map<Integer, FileChecksum> v2v3checksums = extractHashFromV2V3Signature( + Map<Integer, ApkChecksum> v2v3checksums = extractHashFromV2V3Signature( split, filePath, kinds); if (v2v3checksums != null) { checksums.putAll(v2v3checksums); } } - // TODO(b/160605420): Installer provided. + if (trustedInstallers == null || trustedInstallers.length > 0) { + final File digestsFile = new File(buildDigestsPathForApk(filePath)); + if (digestsFile.exists()) { + try { + final ApkChecksum[] digests = readChecksums(digestsFile); + final Set<Signature> trusted = convertToSet(trustedInstallers); + for (ApkChecksum digest : digests) { + if (isRequired(digest.getKind(), kinds, checksums) && isTrusted(digest, + trusted)) { + checksums.put(digest.getKind(), digest); + } + } + } catch (IOException e) { + Slog.e(TAG, "Error reading .digests", e); + } catch (CertificateEncodingException e) { + Slog.e(TAG, "Error encoding trustedInstallers", e); + } + } + } } /** * Whether the file is available for checksumming or we need to wait. */ private static boolean needToWait(File file, - @PackageManager.FileChecksumKind int kinds, - Map<Integer, FileChecksum> checksums, + @Checksum.Kind int kinds, + Map<Integer, ApkChecksum> checksums, @NonNull Injector injector) throws IOException { if (!isRequired(WHOLE_MERKLE_ROOT_4K_SHA256, kinds, checksums) && !isRequired(WHOLE_MD5, kinds, checksums) @@ -274,12 +399,13 @@ public class ApkChecksums { IncrementalManager manager = injector.getIncrementalManager(); if (manager == null) { - throw new IllegalStateException("IncrementalManager is missing."); + Slog.e(TAG, "IncrementalManager is missing."); + return false; } IncrementalStorage storage = manager.openStorage(filePath); if (storage == null) { - throw new IllegalStateException( - "IncrementalStorage is missing for a path on IncFs: " + filePath); + Slog.e(TAG, "IncrementalStorage is missing for a path on IncFs: " + filePath); + return false; } return !storage.isFileFullyLoaded(filePath); @@ -293,9 +419,9 @@ public class ApkChecksums { * @param kinds mask to forcefully calculate if not available * @param checksums resulting checksums */ - private static void getRequiredFileChecksums(String split, File file, - @PackageManager.FileChecksumKind int kinds, - Map<Integer, FileChecksum> checksums) { + private static void getRequiredApkChecksums(String split, File file, + @Checksum.Kind int kinds, + Map<Integer, ApkChecksum> checksums) { final String filePath = file.getAbsolutePath(); // Manually calculating required checksums if not readily available. @@ -310,7 +436,7 @@ public class ApkChecksums { } }); checksums.put(WHOLE_MERKLE_ROOT_4K_SHA256, - new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, generatedRootHash)); + new ApkChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, generatedRootHash)); } catch (IOException | NoSuchAlgorithmException | DigestException e) { Slog.e(TAG, "Error calculating WHOLE_MERKLE_ROOT_4K_SHA256", e); } @@ -324,8 +450,8 @@ public class ApkChecksums { calculatePartialChecksumsIfRequested(checksums, split, file, kinds); } - private static boolean isRequired(@PackageManager.FileChecksumKind int kind, - @PackageManager.FileChecksumKind int kinds, Map<Integer, FileChecksum> checksums) { + private static boolean isRequired(@Checksum.Kind int kind, + @Checksum.Kind int kinds, Map<Integer, ApkChecksum> checksums) { if ((kinds & kind) == 0) { return false; } @@ -335,12 +461,36 @@ public class ApkChecksums { return true; } - private static FileChecksum extractHashFromFS(String split, String filePath) { + /** + * Signature class provides a fast way to compare certificates using their hashes. + * The hash is exactly the same as in X509/Certificate. + */ + private static Set<Signature> convertToSet(@Nullable Certificate[] array) throws + CertificateEncodingException { + if (array == null) { + return null; + } + final Set<Signature> set = new ArraySet<>(array.length); + for (Certificate item : array) { + set.add(new Signature(item.getEncoded())); + } + return set; + } + + private static boolean isTrusted(ApkChecksum checksum, Set<Signature> trusted) { + if (trusted == null) { + return true; + } + final Signature signature = new Signature(checksum.getSourceCertificateBytes()); + return trusted.contains(signature); + } + + private static ApkChecksum extractHashFromFS(String split, String filePath) { // verity first { byte[] hash = VerityUtils.getFsverityRootHash(filePath); if (hash != null) { - return new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, hash); + return new ApkChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, hash); } } // v4 next @@ -350,7 +500,7 @@ public class ApkChecksums { byte[] hash = signer.contentDigests.getOrDefault(CONTENT_DIGEST_VERITY_CHUNKED_SHA256, null); if (hash != null) { - return new FileChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, hash); + return new ApkChecksum(split, WHOLE_MERKLE_ROOT_4K_SHA256, hash); } } catch (SignatureNotFoundException e) { // Nothing @@ -360,7 +510,7 @@ public class ApkChecksums { return null; } - private static Map<Integer, FileChecksum> extractHashFromV2V3Signature( + private static Map<Integer, ApkChecksum> extractHashFromV2V3Signature( String split, String filePath, int kinds) { Map<Integer, byte[]> contentDigests = null; try { @@ -377,19 +527,19 @@ public class ApkChecksums { return null; } - Map<Integer, FileChecksum> checksums = new ArrayMap<>(); + Map<Integer, ApkChecksum> checksums = new ArrayMap<>(); if ((kinds & PARTIAL_MERKLE_ROOT_1M_SHA256) != 0) { byte[] hash = contentDigests.getOrDefault(CONTENT_DIGEST_CHUNKED_SHA256, null); if (hash != null) { checksums.put(PARTIAL_MERKLE_ROOT_1M_SHA256, - new FileChecksum(split, PARTIAL_MERKLE_ROOT_1M_SHA256, hash)); + new ApkChecksum(split, PARTIAL_MERKLE_ROOT_1M_SHA256, hash)); } } if ((kinds & PARTIAL_MERKLE_ROOT_1M_SHA512) != 0) { byte[] hash = contentDigests.getOrDefault(CONTENT_DIGEST_CHUNKED_SHA512, null); if (hash != null) { checksums.put(PARTIAL_MERKLE_ROOT_1M_SHA512, - new FileChecksum(split, PARTIAL_MERKLE_ROOT_1M_SHA512, hash)); + new ApkChecksum(split, PARTIAL_MERKLE_ROOT_1M_SHA512, hash)); } } return checksums; @@ -411,17 +561,17 @@ public class ApkChecksums { } } - private static void calculateChecksumIfRequested(Map<Integer, FileChecksum> checksums, + private static void calculateChecksumIfRequested(Map<Integer, ApkChecksum> checksums, String split, File file, int required, int kind) { if ((required & kind) != 0 && !checksums.containsKey(kind)) { - final byte[] checksum = getFileChecksum(file, kind); + final byte[] checksum = getApkChecksum(file, kind); if (checksum != null) { - checksums.put(kind, new FileChecksum(split, kind, checksum)); + checksums.put(kind, new ApkChecksum(split, kind, checksum)); } } } - private static byte[] getFileChecksum(File file, int kind) { + private static byte[] getApkChecksum(File file, int kind) { try (FileInputStream fis = new FileInputStream(file); BufferedInputStream bis = new BufferedInputStream(fis)) { byte[] dataBytes = new byte[512 * 1024]; @@ -466,7 +616,7 @@ public class ApkChecksums { } } - private static void calculatePartialChecksumsIfRequested(Map<Integer, FileChecksum> checksums, + private static void calculatePartialChecksumsIfRequested(Map<Integer, ApkChecksum> checksums, String split, File file, int required) { boolean needSignatureSha256 = (required & PARTIAL_MERKLE_ROOT_1M_SHA256) != 0 && !checksums.containsKey( @@ -500,7 +650,7 @@ public class ApkChecksums { for (int i = 0, size = digestAlgos.length; i < size; ++i) { int checksumKind = getChecksumKindForContentDigestAlgo(digestAlgos[i]); if (checksumKind != -1) { - checksums.put(checksumKind, new FileChecksum(split, checksumKind, digests[i])); + checksums.put(checksumKind, new ApkChecksum(split, checksumKind, digests[i])); } } } catch (IOException | DigestException e) { diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 155af82289d4..f52db5fb5f2f 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -732,9 +732,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements installerAttributionTag); session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this, mInstallThread.getLooper(), mStagingManager, sessionId, userId, callingUid, - installSource, params, createdMillis, - stageDir, stageCid, null, false, false, false, false, null, SessionInfo.INVALID_ID, - false, false, false, SessionInfo.STAGED_SESSION_NO_ERROR, ""); + installSource, params, createdMillis, stageDir, stageCid, null, null, false, false, + false, false, null, SessionInfo.INVALID_ID, false, false, false, + SessionInfo.STAGED_SESSION_NO_ERROR, ""); synchronized (mSessions) { mSessions.put(sessionId, session); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 17cd8f58c3a3..87dedfe9c84a 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -27,6 +27,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR; import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; import static android.content.pm.PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE; import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING; import static android.content.pm.PackageParser.APEX_FILE_EXTENSION; import static android.content.pm.PackageParser.APK_FILE_EXTENSION; import static android.system.OsConstants.O_CREAT; @@ -61,7 +62,9 @@ import android.content.IIntentReceiver; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.ApkChecksum; import android.content.pm.ApplicationInfo; +import android.content.pm.Checksum; import android.content.pm.DataLoaderManager; import android.content.pm.DataLoaderParams; import android.content.pm.DataLoaderParamsParcel; @@ -84,6 +87,7 @@ 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; @@ -118,6 +122,7 @@ import android.system.Os; import android.system.OsConstants; import android.system.StructStat; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.ExceptionUtils; import android.util.MathUtils; @@ -153,6 +158,7 @@ import java.io.FileDescriptor; import java.io.FileFilter; import java.io.FileOutputStream; import java.io.IOException; +import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -176,6 +182,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { static final String TAG_SESSION = "session"; static final String TAG_CHILD_SESSION = "childSession"; static final String TAG_SESSION_FILE = "sessionFile"; + static final String TAG_SESSION_CHECKSUM = "sessionChecksum"; private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission"; private static final String TAG_WHITELISTED_RESTRICTED_PERMISSION = "whitelisted-restricted-permission"; @@ -230,10 +237,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String ATTR_LENGTH_BYTES = "lengthBytes"; private static final String ATTR_METADATA = "metadata"; 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_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; private static final InstallationFile[] EMPTY_INSTALLATION_FILE_ARRAY = {}; + private static final ApkChecksum[] EMPTY_FILE_CHECKSUM_ARRAY = {}; private static final String SYSTEM_DATA_LOADER_PACKAGE = "android"; @@ -380,6 +391,27 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private ArraySet<FileEntry> mFiles = new ArraySet<>(); + static class CertifiedChecksum { + final @NonNull Checksum mChecksum; + final @NonNull byte[] mCertificate; + + CertifiedChecksum(@NonNull Checksum checksum, @NonNull byte[] certificate) { + mChecksum = checksum; + mCertificate = certificate; + } + + Checksum getChecksum() { + return mChecksum; + } + + byte[] getCertificate() { + return mCertificate; + } + } + + @GuardedBy("mLock") + private ArrayMap<String, List<CertifiedChecksum>> mChecksums = new ArrayMap<>(); + @GuardedBy("mLock") private boolean mStagedSessionApplied; @GuardedBy("mLock") @@ -581,8 +613,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { PackageSessionProvider sessionProvider, Looper looper, StagingManager stagingManager, int sessionId, int userId, int installerUid, @NonNull InstallSource installSource, SessionParams params, long createdMillis, - File stageDir, String stageCid, InstallationFile[] files, boolean prepared, - boolean committed, boolean destroyed, boolean sealed, + File stageDir, String stageCid, InstallationFile[] files, + ArrayMap<String, List<CertifiedChecksum>> checksums, + boolean prepared, boolean committed, boolean destroyed, boolean sealed, @Nullable int[] childSessionIds, int parentSessionId, boolean isReady, boolean isFailed, boolean isApplied, int stagedSessionErrorCode, String stagedSessionErrorMessage) { @@ -615,6 +648,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { this.mParentSessionId = parentSessionId; if (files != null) { + mFiles.ensureCapacity(files.length); for (int i = 0, size = files.length; i < size; ++i) { InstallationFile file = files[i]; if (!mFiles.add(new FileEntry(i, file))) { @@ -624,6 +658,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + if (checksums != null) { + mChecksums.putAll(checksums); + } + if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) { throw new IllegalArgumentException( "Exactly one of stageDir or stageCid stage must be set"); @@ -907,6 +945,45 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } @Override + public void addChecksums(String name, @NonNull Checksum[] checksums) { + if (checksums.length == 0) { + return; + } + + final PackageManagerInternal pmi = LocalServices.getService( + PackageManagerInternal.class); + final AndroidPackage callingInstaller = pmi.getPackage(Binder.getCallingUid()); + + if (callingInstaller == null) { + throw new IllegalStateException("Can't obtain calling installer's package."); + } + + // Obtaining array of certificates used for signing the installer package. + // According to V2/V3 signing schema, the first certificate corresponds to public key + // in the signing block. + 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."); + } + byte[] mainCertificateBytes = certs[0].toByteArray(); + + synchronized (mLock) { + assertCallerIsOwnerOrRootLocked(); + assertPreparedAndNotCommittedOrDestroyedLocked("addChecksums"); + + for (Checksum checksum : checksums) { + List<CertifiedChecksum> fileChecksums = mChecksums.get(name); + if (fileChecksums == null) { + fileChecksums = new ArrayList<>(); + mChecksums.put(name, fileChecksums); + } + fileChecksums.add(new CertifiedChecksum(checksum, mainCertificateBytes)); + } + } + } + + @Override public void removeSplit(String splitName) { if (isDataLoaderInstallation()) { throw new IllegalStateException( @@ -2155,7 +2232,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } final File targetFile = new File(stageDir, targetName); - resolveAndStageFileLocked(addedFile, targetFile); + resolveAndStageFileLocked(addedFile, targetFile, null); mResolvedBaseFile = targetFile; // Populate package name of the apex session @@ -2174,6 +2251,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + private static String splitNameToFileName(String splitName) { + if (splitName == null) { + return "base"; + } + return "split_" + splitName; + } + /** * Validate install by confirming that all application packages are have * consistent package name, version code, and signing certificates. @@ -2259,37 +2343,21 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { assertApkConsistentLocked(String.valueOf(addedFile), apk); // Take this opportunity to enforce uniform naming - final String targetName; - if (apk.splitName == null) { - targetName = "base" + APK_FILE_EXTENSION; - } else { - targetName = "split_" + apk.splitName + APK_FILE_EXTENSION; - } + final String fileName = splitNameToFileName(apk.splitName); + final String targetName = fileName + APK_FILE_EXTENSION; if (!FileUtils.isValidExtFilename(targetName)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Invalid filename: " + targetName); } final File targetFile = new File(stageDir, targetName); - resolveAndStageFileLocked(addedFile, targetFile); + resolveAndStageFileLocked(addedFile, targetFile, apk.splitName); // Base is coming from session if (apk.splitName == null) { mResolvedBaseFile = targetFile; baseApk = apk; } - - // Validate and add Dex Metadata (.dm). - final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile); - if (dexMetadataFile != null) { - if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) { - throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, - "Invalid filename: " + dexMetadataFile); - } - final File targetDexMetadataFile = new File(stageDir, - DexMetadataHelper.buildDexMetadataPathForApk(targetName)); - resolveAndStageFileLocked(dexMetadataFile, targetDexMetadataFile); - } } if (removeSplitList.size() > 0) { @@ -2338,15 +2406,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + if (!mChecksums.isEmpty()) { + throw new PackageManagerException( + PackageManager.INSTALL_FAILED_SESSION_INVALID, + "Invalid checksum name(s): " + String.join(",", mChecksums.keySet())); + } + if (params.mode == SessionParams.MODE_FULL_INSTALL) { // Full installs must include a base package if (!stagedSplits.contains(null)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Full install must include a base package"); } - } else { - ApplicationInfo appInfo = pkgInfo.applicationInfo; + final ApplicationInfo appInfo = pkgInfo.applicationInfo; ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.parsePackageLite( input.reset(), new File(appInfo.getCodePath()), 0); if (pkgLiteResult.isError()) { @@ -2365,33 +2438,21 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { assertApkConsistentLocked("Existing base", existingBase); - // Inherit base if not overridden + // Inherit base if not overridden. if (mResolvedBaseFile == null) { mResolvedBaseFile = new File(appInfo.getBaseCodePath()); - resolveInheritedFileLocked(mResolvedBaseFile); - // Inherit the dex metadata if present. - final File baseDexMetadataFile = - DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile); - if (baseDexMetadataFile != null) { - resolveInheritedFileLocked(baseDexMetadataFile); - } + inheritFileLocked(mResolvedBaseFile); baseApk = existingBase; } - // Inherit splits if not overridden + // Inherit splits if not overridden. if (!ArrayUtils.isEmpty(existing.splitNames)) { for (int i = 0; i < existing.splitNames.length; i++) { final String splitName = existing.splitNames[i]; final File splitFile = new File(existing.splitCodePaths[i]); final boolean splitRemoved = removeSplitList.contains(splitName); if (!stagedSplits.contains(splitName) && !splitRemoved) { - resolveInheritedFileLocked(splitFile); - // Inherit the dex metadata if present. - final File splitDexMetadataFile = - DexMetadataHelper.findDexMetadataForFile(splitFile); - if (splitDexMetadataFile != null) { - resolveInheritedFileLocked(splitDexMetadataFile); - } + inheritFileLocked(splitFile); } } } @@ -2492,11 +2553,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } @GuardedBy("mLock") - private void resolveAndStageFileLocked(File origFile, File targetFile) + private void stageFileLocked(File origFile, File targetFile) throws PackageManagerException { mResolvedStagedFiles.add(targetFile); maybeRenameFile(origFile, targetFile); + } + @GuardedBy("mLock") + private void maybeStageFsveritySignatureLocked(File origFile, File targetFile) + throws PackageManagerException { final File originalSignature = new File( VerityUtils.getFsveritySignatureFilePath(origFile.getPath())); // Make sure .fsv_sig exists when it should, then resolve and stage it. @@ -2521,12 +2586,83 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final File stagedSignature = new File( VerityUtils.getFsveritySignatureFilePath(targetFile.getPath())); - maybeRenameFile(originalSignature, stagedSignature); - mResolvedStagedFiles.add(stagedSignature); + + stageFileLocked(originalSignature, stagedSignature); } @GuardedBy("mLock") - private void resolveInheritedFileLocked(File origFile) { + private void maybeStageDexMetadataLocked(File origFile, File targetFile) + throws PackageManagerException { + final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(origFile); + if (dexMetadataFile == null) { + return; + } + + if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Invalid filename: " + dexMetadataFile); + } + final File targetDexMetadataFile = new File(stageDir, + DexMetadataHelper.buildDexMetadataPathForApk(targetFile.getName())); + + stageFileLocked(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.getCertificate()); + } + return result; + } + + @GuardedBy("mLock") + private void maybeStageDigestsLocked(File origFile, File targetFile, String splitName) + throws PackageManagerException { + final List<CertifiedChecksum> checksums = mChecksums.get(origFile.getName()); + if (checksums == null) { + return; + } + mChecksums.remove(origFile.getName()); + + if (checksums.isEmpty()) { + return; + } + + final File targetDigestsFile = new File(stageDir, + ApkChecksums.buildDigestsPathForApk(targetFile.getName())); + try { + ApkChecksums.writeChecksums(targetDigestsFile, + createApkChecksums(splitName, checksums)); + } catch (CertificateException e) { + throw new PackageManagerException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING, + "Failed to encode certificate for " + mPackageName, e); + } catch (IOException e) { + throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE, + "Failed to store digests for " + mPackageName, e); + } + + stageFileLocked(targetDigestsFile, targetDigestsFile); + } + + @GuardedBy("mLock") + private void resolveAndStageFileLocked(File origFile, File targetFile, String splitName) + throws PackageManagerException { + stageFileLocked(origFile, targetFile); + + // Stage fsverity signature if present. + maybeStageFsveritySignatureLocked(origFile, targetFile); + // Stage dex metadata (.dm) if present. + maybeStageDexMetadataLocked(origFile, targetFile); + // Stage checksums (.digests) if present. + maybeStageDigestsLocked(origFile, targetFile, splitName); + } + + @GuardedBy("mLock") + private void inheritFileLocked(File origFile) { mResolvedInheritedFiles.add(origFile); // Inherit the fsverity signature file if present. @@ -2535,6 +2671,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (fsveritySignatureFile.exists()) { mResolvedInheritedFiles.add(fsveritySignatureFile); } + // Inherit the dex metadata if present. + final File dexMetadataFile = + DexMetadataHelper.findDexMetadataForFile(origFile); + if (dexMetadataFile != null) { + mResolvedInheritedFiles.add(dexMetadataFile); + } + // Inherit the digests if present. + final File digestsFile = ApkChecksums.findDigestsForFile(origFile); + if (digestsFile != null) { + mResolvedInheritedFiles.add(digestsFile); + } } @GuardedBy("mLock") @@ -3791,6 +3938,22 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { writeByteArrayAttribute(out, ATTR_SIGNATURE, file.getSignature()); out.endTag(null, TAG_SESSION_FILE); } + + 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); + out.startTag(null, TAG_SESSION_CHECKSUM); + writeStringAttribute(out, ATTR_NAME, fileName); + writeIntAttribute(out, ATTR_CHECKSUM_KIND, checksum.getChecksum().getKind()); + writeByteArrayAttribute(out, ATTR_CHECKSUM_VALUE, + checksum.getChecksum().getValue()); + writeByteArrayAttribute(out, ATTR_CHECKSUM_CERTIFICATE, + checksum.getCertificate()); + out.endTag(null, TAG_SESSION_CHECKSUM); + } + } } out.endTag(null, TAG_SESSION); @@ -3904,6 +4067,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<>(); int outerDepth = in.getDepth(); int type; while ((type = in.next()) != XmlPullParser.END_DOCUMENT @@ -3932,6 +4096,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { readByteArrayAttribute(in, ATTR_METADATA), readByteArrayAttribute(in, ATTR_SIGNATURE))); } + if (TAG_SESSION_CHECKSUM.equals(in.getName())) { + final String fileName = readStringAttribute(in, ATTR_NAME); + final CertifiedChecksum certifiedChecksum = new CertifiedChecksum( + new Checksum(readIntAttribute(in, ATTR_CHECKSUM_KIND, 0), + readByteArrayAttribute(in, ATTR_CHECKSUM_VALUE)), + readByteArrayAttribute(in, ATTR_CHECKSUM_CERTIFICATE)); + + List<CertifiedChecksum> certifiedChecksums = checksums.get(fileName); + if (certifiedChecksums == null) { + certifiedChecksums = new ArrayList<>(); + checksums.put(fileName, certifiedChecksums); + } + certifiedChecksums.add(certifiedChecksum); + } } if (grantedRuntimePermissions.size() > 0) { @@ -3964,7 +4142,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { installOriginatingPackageName, installerPackageName, installerAttributionTag); return new PackageInstallerSession(callback, context, pm, sessionProvider, installerThread, stagingManager, sessionId, userId, installerUid, - installSource, params, createdMillis, stageDir, stageCid, fileArray, + installSource, params, createdMillis, stageDir, stageCid, fileArray, checksums, prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId, isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 69e8e65166ac..999bbc9ecf4e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -164,6 +164,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.AuxiliaryResolveInfo; import android.content.pm.ChangedPackages; +import android.content.pm.Checksum; import android.content.pm.ComponentInfo; import android.content.pm.DataLoaderType; import android.content.pm.FallbackCategoryProvider; @@ -2459,8 +2460,8 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void getChecksums(@NonNull String packageName, boolean includeSplits, - @PackageManager.FileChecksumKind int optional, - @PackageManager.FileChecksumKind int required, @Nullable List trustedInstallers, + @Checksum.Kind int optional, + @Checksum.Kind int required, @Nullable List trustedInstallers, @NonNull IntentSender statusReceiver, int userId) { Objects.requireNonNull(packageName); Objects.requireNonNull(statusReceiver); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java index fe429c8823f8..4a6e11bca613 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java @@ -176,6 +176,7 @@ public class PackageInstallerSessionTest { /* stageDir */ mTmpDir, /* stageCid */ null, /* files */ null, + /* checksums */ null, /* prepared */ true, /* committed */ true, /* destroyed */ staged ? true : false, |