Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 88d2a3c0 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Introduce revision codes for split APKs.

Apps delivered as multiple split APKs must have identical package
names, version code, and signatures.  However, developers may want
to iterate quickly on a subset of splits without having to increment
the version code, which would require delivery of the entire app.

This change introduces "revision codes" which can vary between
split APKs belonging to the same app.  An install is valid as long
as the normal version code is identical across all splits.  Splits
can be added/removed to an app over time, but if a split is present
across an upgrade the revision code must not decrease.

Since system apps could have been updated with splits, only revert
to the built-in APKs if the version code is strictly greater than the
data version.  Also fix bug to enable inheriting from system apps
when adding splits.

Bug: 18481866
Change-Id: I34d8e14c141a8eb95c33ffe24b4e52d6af5c8260
parent 4dfce43e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1017,6 +1017,7 @@ package android {
    field public static final int restrictionType = 16843923; // 0x1010493
    field public static final int resumeWhilePausing = 16843954; // 0x10104b2
    field public static final int reversible = 16843851; // 0x101044b
    field public static final int revisionCode = 16843989; // 0x10104d5
    field public static final int right = 16843183; // 0x10101af
    field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
    field public static final int ringtoneType = 16843257; // 0x10101f9
@@ -8545,6 +8546,7 @@ package android.content.pm {
    field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
    field public android.content.pm.ActivityInfo[] activities;
    field public android.content.pm.ApplicationInfo applicationInfo;
    field public int baseRevisionCode;
    field public android.content.pm.ConfigurationInfo[] configPreferences;
    field public android.content.pm.FeatureGroupInfo[] featureGroups;
    field public long firstInstallTime;
@@ -8564,6 +8566,7 @@ package android.content.pm {
    field public int sharedUserLabel;
    field public android.content.pm.Signature[] signatures;
    field public java.lang.String[] splitNames;
    field public int[] splitRevisionCodes;
    field public int versionCode;
    field public java.lang.String versionName;
  }
+28 −3
Original line number Diff line number Diff line
@@ -49,6 +49,22 @@ public class PackageInfo implements Parcelable {
     */
    public String versionName;

    /**
     * The revision number of the base APK for this package, as specified by the
     * <manifest> tag's
     * {@link android.R.styleable#AndroidManifest_revisionCode revisionCode}
     * attribute.
     */
    public int baseRevisionCode;

    /**
     * The revision number of any split APKs for this package, as specified by
     * the <manifest> tag's
     * {@link android.R.styleable#AndroidManifest_revisionCode revisionCode}
     * attribute. Indexes are a 1:1 mapping against {@link #splitNames}.
     */
    public int[] splitRevisionCodes;

    /**
     * The shared user ID name of this package, as specified by the <manifest>
     * tag's {@link android.R.styleable#AndroidManifest_sharedUserId sharedUserId}
@@ -257,21 +273,26 @@ public class PackageInfo implements Parcelable {
    public PackageInfo() {
    }

    @Override
    public String toString() {
        return "PackageInfo{"
            + Integer.toHexString(System.identityHashCode(this))
            + " " + packageName + "}";
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int parcelableFlags) {
        dest.writeString(packageName);
        dest.writeStringArray(splitNames);
        dest.writeInt(versionCode);
        dest.writeString(versionName);
        dest.writeInt(baseRevisionCode);
        dest.writeIntArray(splitRevisionCodes);
        dest.writeString(sharedUserId);
        dest.writeInt(sharedUserLabel);
        if (applicationInfo != null) {
@@ -305,10 +326,12 @@ public class PackageInfo implements Parcelable {

    public static final Parcelable.Creator<PackageInfo> CREATOR
            = new Parcelable.Creator<PackageInfo>() {
        @Override
        public PackageInfo createFromParcel(Parcel source) {
            return new PackageInfo(source);
        }

        @Override
        public PackageInfo[] newArray(int size) {
            return new PackageInfo[size];
        }
@@ -316,9 +339,11 @@ public class PackageInfo implements Parcelable {

    private PackageInfo(Parcel source) {
        packageName = source.readString();
        splitNames = source.readStringArray();
        splitNames = source.createStringArray();
        versionCode = source.readInt();
        versionName = source.readString();
        baseRevisionCode = source.readInt();
        splitRevisionCodes = source.createIntArray();
        sharedUserId = source.readString();
        sharedUserLabel = source.readInt();
        int hasApp = source.readInt();
+16 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package android.content.pm;
import android.os.Parcel;
import android.os.Parcelable;

import com.android.internal.content.PackageHelper;

/**
 * Basic information about a package as specified in its manifest.
 * Utility class used in PackageManager methods
@@ -31,11 +33,19 @@ public class PackageInfoLite implements Parcelable {
     */
    public String packageName;

    /** Names of any split APKs, ordered by parsed splitName */
    public String[] splitNames;

    /**
     * The android:versionCode of the package.
     */
    public int versionCode;

    /** Revision code of base APK */
    public int baseRevisionCode;
    /** Revision codes of any split APKs, ordered by parsed splitName */
    public int[] splitRevisionCodes;

    /**
     * The android:multiArch flag from the package manifest. If set,
     * we will extract all native libraries for the given app, not just those
@@ -70,7 +80,10 @@ public class PackageInfoLite implements Parcelable {

    public void writeToParcel(Parcel dest, int parcelableFlags) {
        dest.writeString(packageName);
        dest.writeStringArray(splitNames);
        dest.writeInt(versionCode);
        dest.writeInt(baseRevisionCode);
        dest.writeIntArray(splitRevisionCodes);
        dest.writeInt(recommendedInstallLocation);
        dest.writeInt(installLocation);
        dest.writeInt(multiArch ? 1 : 0);
@@ -96,7 +109,10 @@ public class PackageInfoLite implements Parcelable {

    private PackageInfoLite(Parcel source) {
        packageName = source.readString();
        splitNames = source.createStringArray();
        versionCode = source.readInt();
        baseRevisionCode = source.readInt();
        splitRevisionCodes = source.createIntArray();
        recommendedInstallLocation = source.readInt();
        installLocation = source.readInt();
        multiArch = (source.readInt() != 0);
+35 −15
Original line number Diff line number Diff line
@@ -261,11 +261,16 @@ public class PackageParser {
        /** Paths of any split APKs, ordered by parsed splitName */
        public final String[] splitCodePaths;

        /** Revision code of base APK */
        public final int baseRevisionCode;
        /** Revision codes of any split APKs, ordered by parsed splitName */
        public final int[] splitRevisionCodes;

        public final boolean coreApp;
        public final boolean multiArch;

        public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
                String[] splitCodePaths) {
                String[] splitCodePaths, int[] splitRevisionCodes) {
            this.packageName = baseApk.packageName;
            this.versionCode = baseApk.versionCode;
            this.installLocation = baseApk.installLocation;
@@ -274,6 +279,8 @@ public class PackageParser {
            this.codePath = codePath;
            this.baseCodePath = baseApk.codePath;
            this.splitCodePaths = splitCodePaths;
            this.baseRevisionCode = baseApk.revisionCode;
            this.splitRevisionCodes = splitRevisionCodes;
            this.coreApp = baseApk.coreApp;
            this.multiArch = baseApk.multiArch;
        }
@@ -296,6 +303,7 @@ public class PackageParser {
        public final String packageName;
        public final String splitName;
        public final int versionCode;
        public final int revisionCode;
        public final int installLocation;
        public final VerifierInfo[] verifiers;
        public final Signature[] signatures;
@@ -303,12 +311,13 @@ public class PackageParser {
        public final boolean multiArch;

        public ApkLite(String codePath, String packageName, String splitName, int versionCode,
                int installLocation, List<VerifierInfo> verifiers, Signature[] signatures,
                boolean coreApp, boolean multiArch) {
                int revisionCode, int installLocation, List<VerifierInfo> verifiers,
                Signature[] signatures, boolean coreApp, boolean multiArch) {
            this.codePath = codePath;
            this.packageName = packageName;
            this.splitName = splitName;
            this.versionCode = versionCode;
            this.revisionCode = revisionCode;
            this.installLocation = installLocation;
            this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
            this.signatures = signatures;
@@ -409,6 +418,8 @@ public class PackageParser {
        pi.packageName = p.packageName;
        pi.splitNames = p.splitNames;
        pi.versionCode = p.mVersionCode;
        pi.baseRevisionCode = p.baseRevisionCode;
        pi.splitRevisionCodes = p.splitRevisionCodes;
        pi.versionName = p.mVersionName;
        pi.sharedUserId = p.mSharedUserId;
        pi.sharedUserLabel = p.mSharedUserLabel;
@@ -647,7 +658,7 @@ public class PackageParser {
            throws PackageParserException {
        final ApkLite baseApk = parseApkLite(packageFile, flags);
        final String packagePath = packageFile.getAbsolutePath();
        return new PackageLite(packagePath, baseApk, null, null);
        return new PackageLite(packagePath, baseApk, null, null, null);
    }

    private static PackageLite parseClusterPackageLite(File packageDir, int flags)
@@ -704,20 +715,24 @@ public class PackageParser {

        String[] splitNames = null;
        String[] splitCodePaths = null;
        int[] splitRevisionCodes = null;
        if (size > 0) {
            splitNames = new String[size];
            splitCodePaths = new String[size];
            splitRevisionCodes = new int[size];

            splitNames = apks.keySet().toArray(splitNames);
            Arrays.sort(splitNames, sSplitNameComparator);

            for (int i = 0; i < size; i++) {
                splitCodePaths[i] = apks.get(splitNames[i]).codePath;
                splitRevisionCodes[i] = apks.get(splitNames[i]).revisionCode;
            }
        }

        final String codePath = packageDir.getAbsolutePath();
        return new PackageLite(codePath, baseApk, splitNames, splitCodePaths);
        return new PackageLite(codePath, baseApk, splitNames, splitCodePaths,
                splitRevisionCodes);
    }

    /**
@@ -782,6 +797,7 @@ public class PackageParser {
                final int num = lite.splitNames.length;
                pkg.splitNames = lite.splitNames;
                pkg.splitCodePaths = lite.splitCodePaths;
                pkg.splitRevisionCodes = lite.splitRevisionCodes;
                pkg.splitFlags = new int[num];

                for (int i = 0; i < num; i++) {
@@ -1249,25 +1265,21 @@ public class PackageParser {

        int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
        int versionCode = 0;
        int revisionCode = 0;
        boolean coreApp = false;
        boolean multiArch = false;

        int numFound = 0;
        for (int i = 0; i < attrs.getAttributeCount(); i++) {
            String attr = attrs.getAttributeName(i);
            final String attr = attrs.getAttributeName(i);
            if (attr.equals("installLocation")) {
                installLocation = attrs.getAttributeIntValue(i,
                        PARSE_DEFAULT_INSTALL_LOCATION);
                numFound++;
            } else if (attr.equals("versionCode")) {
                versionCode = attrs.getAttributeIntValue(i, 0);
                numFound++;
            } else if (attr.equals("revisionCode")) {
                revisionCode = attrs.getAttributeIntValue(i, 0);
            } else if (attr.equals("coreApp")) {
                coreApp = attrs.getAttributeBooleanValue(i, false);
                numFound++;
            }
            if (numFound >= 3) {
                break;
            }
        }

@@ -1301,7 +1313,7 @@ public class PackageParser {
        }

        return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
                installLocation, verifiers, signatures, coreApp, multiArch);
                revisionCode, installLocation, verifiers, signatures, coreApp, multiArch);
    }

    /**
@@ -1359,6 +1371,8 @@ public class PackageParser {
                com.android.internal.R.styleable.AndroidManifest);
        pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
        pkg.baseRevisionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
        pkg.mVersionName = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_versionName, 0);
        if (pkg.mVersionName != null) {
@@ -4168,6 +4182,7 @@ public class PackageParser {
    public final static class Package {

        public String packageName;

        /** Names of any split APKs, ordered by parsed splitName */
        public String[] splitNames;

@@ -4185,6 +4200,11 @@ public class PackageParser {
        /** Paths of any split APKs, ordered by parsed splitName */
        public String[] splitCodePaths;

        /** Revision code of base APK */
        public int baseRevisionCode;
        /** Revision codes of any split APKs, ordered by parsed splitName */
        public int[] splitRevisionCodes;

        /** Flags of any split APKs; ordered by parsed splitName */
        public int[] splitFlags;

+3 −3
Original line number Diff line number Diff line
@@ -296,9 +296,9 @@ public class VpnService extends Service {
     *
     * This method only needs to be called if the VPN has explicitly bound its underlying
     * communications channels &mdash; such as the socket(s) passed to {@link #protect(int)} &mdash;
     * to a {@code Network} using APIs such as {@link Network#bindSocket} or {@link
     * Network#bindDatagramSocket}. The VPN should call this method every time the set of {@code
     * Network}s it is using changes.
     * to a {@code Network} using APIs such as {@link Network#bindSocket(Socket)} or
     * {@link Network#bindSocket(DatagramSocket)}. The VPN should call this method every time
     * the set of {@code Network}s it is using changes.
     *
     * {@code networks} is one of the following:
     * <ul>
Loading