Merge "Introduce revision codes for split APKs." into lmp-mr1-dev
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -41,14 +41,30 @@ public class PackageInfo implements Parcelable {
|
||||
* attribute.
|
||||
*/
|
||||
public int versionCode;
|
||||
|
||||
|
||||
/**
|
||||
* The version name of this package, as specified by the <manifest>
|
||||
* tag's {@link android.R.styleable#AndroidManifest_versionName versionName}
|
||||
* attribute.
|
||||
*/
|
||||
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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -4222,7 +4242,7 @@ public class PackageParser {
|
||||
|
||||
// The version code declared for this package.
|
||||
public int mVersionCode;
|
||||
|
||||
|
||||
// The version name declared for this package.
|
||||
public String mVersionName;
|
||||
|
||||
|
||||
@@ -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 — such as the socket(s) passed to {@link #protect(int)} —
|
||||
* 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>
|
||||
|
||||
@@ -260,9 +260,18 @@
|
||||
released, or define it however else you want, as long as each
|
||||
successive version has a higher number. This is not a version
|
||||
number generally shown to the user, that is usually supplied
|
||||
with {@link android.R.attr#versionName}. -->
|
||||
with {@link android.R.attr#versionName}. When an app is delivered
|
||||
as multiple split APKs, each APK must have the exact same versionCode. -->
|
||||
<attr name="versionCode" format="integer" />
|
||||
|
||||
|
||||
<!-- Internal revision code. This number is the number used to determine
|
||||
whether one APK is more recent than another: it has no other meaning
|
||||
than that higher numbers are more recent. This value is only meaningful
|
||||
when the two {@link android.R.attr#versionCode} values are already
|
||||
identical. When an app is delivered as multiple split APKs, each
|
||||
APK may have a different revisionCode value. -->
|
||||
<attr name="revisionCode" format="integer" />
|
||||
|
||||
<!-- The text shown to the user to indicate the version they have. This
|
||||
is used for no other purpose than display to the user; the actual
|
||||
significant version number is given by {@link android.R.attr#versionCode}. -->
|
||||
@@ -1025,6 +1034,7 @@
|
||||
<declare-styleable name="AndroidManifest">
|
||||
<attr name="versionCode" />
|
||||
<attr name="versionName" />
|
||||
<attr name="revisionCode" />
|
||||
<attr name="sharedUserId" />
|
||||
<attr name="sharedUserLabel" />
|
||||
<attr name="installLocation" />
|
||||
|
||||
@@ -2593,6 +2593,7 @@
|
||||
<public type="attr" name="accessibilityTraversalAfter" id="0x010104d2" />
|
||||
<public type="attr" name="dialogPreferredPadding" id="0x010104d3" />
|
||||
<public type="attr" name="searchHintIcon" id="0x010104d4" />
|
||||
<public type="attr" name="revisionCode" />
|
||||
|
||||
<public type="style" name="Theme.DeviceDefault.Dialog.Alert" />
|
||||
<public type="style" name="Theme.DeviceDefault.Light.Dialog.Alert" />
|
||||
|
||||
@@ -180,7 +180,10 @@ public class DefaultContainerService extends IntentService {
|
||||
}
|
||||
|
||||
ret.packageName = pkg.packageName;
|
||||
ret.splitNames = pkg.splitNames;
|
||||
ret.versionCode = pkg.versionCode;
|
||||
ret.baseRevisionCode = pkg.baseRevisionCode;
|
||||
ret.splitRevisionCodes = pkg.splitRevisionCodes;
|
||||
ret.installLocation = pkg.installLocation;
|
||||
ret.verifiers = pkg.verifiers;
|
||||
ret.recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
|
||||
|
||||
@@ -497,12 +497,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
// haven't been overridden.
|
||||
if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
|
||||
try {
|
||||
if (stageCid != null) {
|
||||
final List<File> fromFiles = mResolvedInheritedFiles;
|
||||
final File toDir = resolveStageDir();
|
||||
|
||||
if (isLinkPossible(fromFiles, toDir)) {
|
||||
linkFiles(fromFiles, toDir);
|
||||
} else {
|
||||
// TODO: this should delegate to DCS so the system process
|
||||
// avoids holding open FDs into containers.
|
||||
copyFiles(mResolvedInheritedFiles, resolveStageDir());
|
||||
} else {
|
||||
linkFiles(mResolvedInheritedFiles, resolveStageDir());
|
||||
copyFiles(fromFiles, toDir);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
|
||||
@@ -721,7 +724,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
// This is kind of hacky; we're creating a half-parsed package that is
|
||||
// straddled between the inherited and staged APKs.
|
||||
final PackageLite pkg = new PackageLite(null, baseApk, null,
|
||||
splitPaths.toArray(new String[splitPaths.size()]));
|
||||
splitPaths.toArray(new String[splitPaths.size()]), null);
|
||||
final boolean isForwardLocked =
|
||||
(params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
|
||||
|
||||
@@ -733,6 +736,26 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if creating hard links between source and destination is
|
||||
* possible. That is, do they all live on the same underlying device.
|
||||
*/
|
||||
private boolean isLinkPossible(List<File> fromFiles, File toDir) {
|
||||
try {
|
||||
final StructStat toStat = Os.stat(toDir.getAbsolutePath());
|
||||
for (File fromFile : fromFiles) {
|
||||
final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
|
||||
if (fromStat.st_dev != toStat.st_dev) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (ErrnoException e) {
|
||||
Slog.w(TAG, "Failed to detect if linking possible: " + e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void linkFiles(List<File> fromFiles, File toDir) throws IOException {
|
||||
for (File fromFile : fromFiles) {
|
||||
final File toFile = new File(toDir, fromFile.getName());
|
||||
@@ -760,7 +783,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
if (!FileUtils.copyFile(fromFile, tmpFile)) {
|
||||
throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
|
||||
}
|
||||
|
||||
try {
|
||||
Os.chmod(tmpFile.getAbsolutePath(), 0644);
|
||||
} catch (ErrnoException e) {
|
||||
throw new IOException("Failed to chmod " + tmpFile);
|
||||
}
|
||||
final File toFile = new File(toDir, fromFile.getName());
|
||||
if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
|
||||
if (!tmpFile.renameTo(toFile)) {
|
||||
|
||||
@@ -41,6 +41,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_UID_CHANGED;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_USER_RESTRICTED;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
|
||||
import static android.content.pm.PackageManager.INSTALL_FORWARD_LOCK;
|
||||
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
|
||||
import static android.content.pm.PackageParser.isApkFile;
|
||||
@@ -4275,7 +4276,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
// version of the new path against what we have stored to determine
|
||||
// what to do.
|
||||
if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath);
|
||||
if (pkg.mVersionCode < ps.versionCode) {
|
||||
if (pkg.mVersionCode <= ps.versionCode) {
|
||||
// The system package has been updated and the code path does not match
|
||||
// Ignore entry. Skip it.
|
||||
Slog.i(TAG, "Package " + ps.name + " at " + scanFile
|
||||
@@ -4366,7 +4367,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
* already installed version, hide it. It will be scanned later
|
||||
* and re-added like an update.
|
||||
*/
|
||||
if (pkg.mVersionCode < ps.versionCode) {
|
||||
if (pkg.mVersionCode <= ps.versionCode) {
|
||||
shouldHideSystemApp = true;
|
||||
logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + scanFile
|
||||
+ " but new version " + pkg.mVersionCode + " better than installed "
|
||||
@@ -8857,11 +8858,10 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
|
||||
// Check for downgrading.
|
||||
if ((installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) == 0) {
|
||||
if (pkgLite.versionCode < pkg.mVersionCode) {
|
||||
Slog.w(TAG, "Can't install update of " + packageName
|
||||
+ " update version " + pkgLite.versionCode
|
||||
+ " is older than installed version "
|
||||
+ pkg.mVersionCode);
|
||||
try {
|
||||
checkDowngrade(pkg, pkgLite);
|
||||
} catch (PackageManagerException e) {
|
||||
Slog.w(TAG, "Downgrade detected: " + e.getMessage());
|
||||
return PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE;
|
||||
}
|
||||
}
|
||||
@@ -13539,4 +13539,38 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check and throw if the given before/after packages would be considered a
|
||||
* downgrade.
|
||||
*/
|
||||
private static void checkDowngrade(PackageParser.Package before, PackageInfoLite after)
|
||||
throws PackageManagerException {
|
||||
if (after.versionCode < before.mVersionCode) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
|
||||
"Update version code " + after.versionCode + " is older than current "
|
||||
+ before.mVersionCode);
|
||||
} else if (after.versionCode == before.mVersionCode) {
|
||||
if (after.baseRevisionCode < before.baseRevisionCode) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
|
||||
"Update base revision code " + after.baseRevisionCode
|
||||
+ " is older than current " + before.baseRevisionCode);
|
||||
}
|
||||
|
||||
if (!ArrayUtils.isEmpty(after.splitNames)) {
|
||||
for (int i = 0; i < after.splitNames.length; i++) {
|
||||
final String splitName = after.splitNames[i];
|
||||
final int j = ArrayUtils.indexOf(before.splitNames, splitName);
|
||||
if (j != -1) {
|
||||
if (after.splitRevisionCodes[i] < before.splitRevisionCodes[j]) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
|
||||
"Update split " + splitName + " revision code "
|
||||
+ after.splitRevisionCodes[i] + " is older than current "
|
||||
+ before.splitRevisionCodes[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user