am 58b699c3: am 636baa0d: Merge "Introduce revision codes for split APKs." into lmp-mr1-dev

* commit '58b699c366dea7abc26f34c1e5f1cc6031c04e23':
  Introduce revision codes for split APKs.
This commit is contained in:
Jeff Sharkey
2014-11-25 17:39:16 +00:00
committed by Android Git Automerger
10 changed files with 175 additions and 36 deletions

View File

@@ -1017,6 +1017,7 @@ package android {
field public static final int restrictionType = 16843923; // 0x1010493 field public static final int restrictionType = 16843923; // 0x1010493
field public static final int resumeWhilePausing = 16843954; // 0x10104b2 field public static final int resumeWhilePausing = 16843954; // 0x10104b2
field public static final int reversible = 16843851; // 0x101044b 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 right = 16843183; // 0x10101af
field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093 field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
field public static final int ringtoneType = 16843257; // 0x10101f9 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 static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
field public android.content.pm.ActivityInfo[] activities; field public android.content.pm.ActivityInfo[] activities;
field public android.content.pm.ApplicationInfo applicationInfo; field public android.content.pm.ApplicationInfo applicationInfo;
field public int baseRevisionCode;
field public android.content.pm.ConfigurationInfo[] configPreferences; field public android.content.pm.ConfigurationInfo[] configPreferences;
field public android.content.pm.FeatureGroupInfo[] featureGroups; field public android.content.pm.FeatureGroupInfo[] featureGroups;
field public long firstInstallTime; field public long firstInstallTime;
@@ -8564,6 +8566,7 @@ package android.content.pm {
field public int sharedUserLabel; field public int sharedUserLabel;
field public android.content.pm.Signature[] signatures; field public android.content.pm.Signature[] signatures;
field public java.lang.String[] splitNames; field public java.lang.String[] splitNames;
field public int[] splitRevisionCodes;
field public int versionCode; field public int versionCode;
field public java.lang.String versionName; field public java.lang.String versionName;
} }

View File

@@ -41,14 +41,30 @@ public class PackageInfo implements Parcelable {
* attribute. * attribute.
*/ */
public int versionCode; public int versionCode;
/** /**
* The version name of this package, as specified by the <manifest> * The version name of this package, as specified by the <manifest>
* tag's {@link android.R.styleable#AndroidManifest_versionName versionName} * tag's {@link android.R.styleable#AndroidManifest_versionName versionName}
* attribute. * attribute.
*/ */
public String versionName; 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> * The shared user ID name of this package, as specified by the <manifest>
* tag's {@link android.R.styleable#AndroidManifest_sharedUserId sharedUserId} * tag's {@link android.R.styleable#AndroidManifest_sharedUserId sharedUserId}
@@ -257,21 +273,26 @@ public class PackageInfo implements Parcelable {
public PackageInfo() { public PackageInfo() {
} }
@Override
public String toString() { public String toString() {
return "PackageInfo{" return "PackageInfo{"
+ Integer.toHexString(System.identityHashCode(this)) + Integer.toHexString(System.identityHashCode(this))
+ " " + packageName + "}"; + " " + packageName + "}";
} }
@Override
public int describeContents() { public int describeContents() {
return 0; return 0;
} }
@Override
public void writeToParcel(Parcel dest, int parcelableFlags) { public void writeToParcel(Parcel dest, int parcelableFlags) {
dest.writeString(packageName); dest.writeString(packageName);
dest.writeStringArray(splitNames); dest.writeStringArray(splitNames);
dest.writeInt(versionCode); dest.writeInt(versionCode);
dest.writeString(versionName); dest.writeString(versionName);
dest.writeInt(baseRevisionCode);
dest.writeIntArray(splitRevisionCodes);
dest.writeString(sharedUserId); dest.writeString(sharedUserId);
dest.writeInt(sharedUserLabel); dest.writeInt(sharedUserLabel);
if (applicationInfo != null) { if (applicationInfo != null) {
@@ -305,10 +326,12 @@ public class PackageInfo implements Parcelable {
public static final Parcelable.Creator<PackageInfo> CREATOR public static final Parcelable.Creator<PackageInfo> CREATOR
= new Parcelable.Creator<PackageInfo>() { = new Parcelable.Creator<PackageInfo>() {
@Override
public PackageInfo createFromParcel(Parcel source) { public PackageInfo createFromParcel(Parcel source) {
return new PackageInfo(source); return new PackageInfo(source);
} }
@Override
public PackageInfo[] newArray(int size) { public PackageInfo[] newArray(int size) {
return new PackageInfo[size]; return new PackageInfo[size];
} }
@@ -316,9 +339,11 @@ public class PackageInfo implements Parcelable {
private PackageInfo(Parcel source) { private PackageInfo(Parcel source) {
packageName = source.readString(); packageName = source.readString();
splitNames = source.readStringArray(); splitNames = source.createStringArray();
versionCode = source.readInt(); versionCode = source.readInt();
versionName = source.readString(); versionName = source.readString();
baseRevisionCode = source.readInt();
splitRevisionCodes = source.createIntArray();
sharedUserId = source.readString(); sharedUserId = source.readString();
sharedUserLabel = source.readInt(); sharedUserLabel = source.readInt();
int hasApp = source.readInt(); int hasApp = source.readInt();

View File

@@ -19,6 +19,8 @@ package android.content.pm;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import com.android.internal.content.PackageHelper;
/** /**
* Basic information about a package as specified in its manifest. * Basic information about a package as specified in its manifest.
* Utility class used in PackageManager methods * Utility class used in PackageManager methods
@@ -31,11 +33,19 @@ public class PackageInfoLite implements Parcelable {
*/ */
public String packageName; public String packageName;
/** Names of any split APKs, ordered by parsed splitName */
public String[] splitNames;
/** /**
* The android:versionCode of the package. * The android:versionCode of the package.
*/ */
public int versionCode; 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, * The android:multiArch flag from the package manifest. If set,
* we will extract all native libraries for the given app, not just those * 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) { public void writeToParcel(Parcel dest, int parcelableFlags) {
dest.writeString(packageName); dest.writeString(packageName);
dest.writeStringArray(splitNames);
dest.writeInt(versionCode); dest.writeInt(versionCode);
dest.writeInt(baseRevisionCode);
dest.writeIntArray(splitRevisionCodes);
dest.writeInt(recommendedInstallLocation); dest.writeInt(recommendedInstallLocation);
dest.writeInt(installLocation); dest.writeInt(installLocation);
dest.writeInt(multiArch ? 1 : 0); dest.writeInt(multiArch ? 1 : 0);
@@ -96,7 +109,10 @@ public class PackageInfoLite implements Parcelable {
private PackageInfoLite(Parcel source) { private PackageInfoLite(Parcel source) {
packageName = source.readString(); packageName = source.readString();
splitNames = source.createStringArray();
versionCode = source.readInt(); versionCode = source.readInt();
baseRevisionCode = source.readInt();
splitRevisionCodes = source.createIntArray();
recommendedInstallLocation = source.readInt(); recommendedInstallLocation = source.readInt();
installLocation = source.readInt(); installLocation = source.readInt();
multiArch = (source.readInt() != 0); multiArch = (source.readInt() != 0);

View File

@@ -261,11 +261,16 @@ public class PackageParser {
/** Paths of any split APKs, ordered by parsed splitName */ /** Paths of any split APKs, ordered by parsed splitName */
public final String[] splitCodePaths; 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 coreApp;
public final boolean multiArch; public final boolean multiArch;
public PackageLite(String codePath, ApkLite baseApk, String[] splitNames, public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
String[] splitCodePaths) { String[] splitCodePaths, int[] splitRevisionCodes) {
this.packageName = baseApk.packageName; this.packageName = baseApk.packageName;
this.versionCode = baseApk.versionCode; this.versionCode = baseApk.versionCode;
this.installLocation = baseApk.installLocation; this.installLocation = baseApk.installLocation;
@@ -274,6 +279,8 @@ public class PackageParser {
this.codePath = codePath; this.codePath = codePath;
this.baseCodePath = baseApk.codePath; this.baseCodePath = baseApk.codePath;
this.splitCodePaths = splitCodePaths; this.splitCodePaths = splitCodePaths;
this.baseRevisionCode = baseApk.revisionCode;
this.splitRevisionCodes = splitRevisionCodes;
this.coreApp = baseApk.coreApp; this.coreApp = baseApk.coreApp;
this.multiArch = baseApk.multiArch; this.multiArch = baseApk.multiArch;
} }
@@ -296,6 +303,7 @@ public class PackageParser {
public final String packageName; public final String packageName;
public final String splitName; public final String splitName;
public final int versionCode; public final int versionCode;
public final int revisionCode;
public final int installLocation; public final int installLocation;
public final VerifierInfo[] verifiers; public final VerifierInfo[] verifiers;
public final Signature[] signatures; public final Signature[] signatures;
@@ -303,12 +311,13 @@ public class PackageParser {
public final boolean multiArch; public final boolean multiArch;
public ApkLite(String codePath, String packageName, String splitName, int versionCode, public ApkLite(String codePath, String packageName, String splitName, int versionCode,
int installLocation, List<VerifierInfo> verifiers, Signature[] signatures, int revisionCode, int installLocation, List<VerifierInfo> verifiers,
boolean coreApp, boolean multiArch) { Signature[] signatures, boolean coreApp, boolean multiArch) {
this.codePath = codePath; this.codePath = codePath;
this.packageName = packageName; this.packageName = packageName;
this.splitName = splitName; this.splitName = splitName;
this.versionCode = versionCode; this.versionCode = versionCode;
this.revisionCode = revisionCode;
this.installLocation = installLocation; this.installLocation = installLocation;
this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]); this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
this.signatures = signatures; this.signatures = signatures;
@@ -409,6 +418,8 @@ public class PackageParser {
pi.packageName = p.packageName; pi.packageName = p.packageName;
pi.splitNames = p.splitNames; pi.splitNames = p.splitNames;
pi.versionCode = p.mVersionCode; pi.versionCode = p.mVersionCode;
pi.baseRevisionCode = p.baseRevisionCode;
pi.splitRevisionCodes = p.splitRevisionCodes;
pi.versionName = p.mVersionName; pi.versionName = p.mVersionName;
pi.sharedUserId = p.mSharedUserId; pi.sharedUserId = p.mSharedUserId;
pi.sharedUserLabel = p.mSharedUserLabel; pi.sharedUserLabel = p.mSharedUserLabel;
@@ -647,7 +658,7 @@ public class PackageParser {
throws PackageParserException { throws PackageParserException {
final ApkLite baseApk = parseApkLite(packageFile, flags); final ApkLite baseApk = parseApkLite(packageFile, flags);
final String packagePath = packageFile.getAbsolutePath(); 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) private static PackageLite parseClusterPackageLite(File packageDir, int flags)
@@ -704,20 +715,24 @@ public class PackageParser {
String[] splitNames = null; String[] splitNames = null;
String[] splitCodePaths = null; String[] splitCodePaths = null;
int[] splitRevisionCodes = null;
if (size > 0) { if (size > 0) {
splitNames = new String[size]; splitNames = new String[size];
splitCodePaths = new String[size]; splitCodePaths = new String[size];
splitRevisionCodes = new int[size];
splitNames = apks.keySet().toArray(splitNames); splitNames = apks.keySet().toArray(splitNames);
Arrays.sort(splitNames, sSplitNameComparator); Arrays.sort(splitNames, sSplitNameComparator);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
splitCodePaths[i] = apks.get(splitNames[i]).codePath; splitCodePaths[i] = apks.get(splitNames[i]).codePath;
splitRevisionCodes[i] = apks.get(splitNames[i]).revisionCode;
} }
} }
final String codePath = packageDir.getAbsolutePath(); 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; final int num = lite.splitNames.length;
pkg.splitNames = lite.splitNames; pkg.splitNames = lite.splitNames;
pkg.splitCodePaths = lite.splitCodePaths; pkg.splitCodePaths = lite.splitCodePaths;
pkg.splitRevisionCodes = lite.splitRevisionCodes;
pkg.splitFlags = new int[num]; pkg.splitFlags = new int[num];
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
@@ -1249,25 +1265,21 @@ public class PackageParser {
int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
int versionCode = 0; int versionCode = 0;
int revisionCode = 0;
boolean coreApp = false; boolean coreApp = false;
boolean multiArch = false; boolean multiArch = false;
int numFound = 0;
for (int i = 0; i < attrs.getAttributeCount(); i++) { for (int i = 0; i < attrs.getAttributeCount(); i++) {
String attr = attrs.getAttributeName(i); final String attr = attrs.getAttributeName(i);
if (attr.equals("installLocation")) { if (attr.equals("installLocation")) {
installLocation = attrs.getAttributeIntValue(i, installLocation = attrs.getAttributeIntValue(i,
PARSE_DEFAULT_INSTALL_LOCATION); PARSE_DEFAULT_INSTALL_LOCATION);
numFound++;
} else if (attr.equals("versionCode")) { } else if (attr.equals("versionCode")) {
versionCode = attrs.getAttributeIntValue(i, 0); versionCode = attrs.getAttributeIntValue(i, 0);
numFound++; } else if (attr.equals("revisionCode")) {
revisionCode = attrs.getAttributeIntValue(i, 0);
} else if (attr.equals("coreApp")) { } else if (attr.equals("coreApp")) {
coreApp = attrs.getAttributeBooleanValue(i, false); 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, 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); com.android.internal.R.styleable.AndroidManifest);
pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger( pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_versionCode, 0); com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
pkg.baseRevisionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
pkg.mVersionName = sa.getNonConfigurationString( pkg.mVersionName = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_versionName, 0); com.android.internal.R.styleable.AndroidManifest_versionName, 0);
if (pkg.mVersionName != null) { if (pkg.mVersionName != null) {
@@ -4168,6 +4182,7 @@ public class PackageParser {
public final static class Package { public final static class Package {
public String packageName; public String packageName;
/** Names of any split APKs, ordered by parsed splitName */ /** Names of any split APKs, ordered by parsed splitName */
public String[] splitNames; public String[] splitNames;
@@ -4185,6 +4200,11 @@ public class PackageParser {
/** Paths of any split APKs, ordered by parsed splitName */ /** Paths of any split APKs, ordered by parsed splitName */
public String[] splitCodePaths; 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 */ /** Flags of any split APKs; ordered by parsed splitName */
public int[] splitFlags; public int[] splitFlags;
@@ -4222,7 +4242,7 @@ public class PackageParser {
// The version code declared for this package. // The version code declared for this package.
public int mVersionCode; public int mVersionCode;
// The version name declared for this package. // The version name declared for this package.
public String mVersionName; public String mVersionName;

View File

@@ -296,9 +296,9 @@ public class VpnService extends Service {
* *
* This method only needs to be called if the VPN has explicitly bound its underlying * 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; * 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 * to a {@code Network} using APIs such as {@link Network#bindSocket(Socket)} or
* Network#bindDatagramSocket}. The VPN should call this method every time the set of {@code * {@link Network#bindSocket(DatagramSocket)}. The VPN should call this method every time
* Network}s it is using changes. * the set of {@code Network}s it is using changes.
* *
* {@code networks} is one of the following: * {@code networks} is one of the following:
* <ul> * <ul>

View File

@@ -260,9 +260,18 @@
released, or define it however else you want, as long as each released, or define it however else you want, as long as each
successive version has a higher number. This is not a version successive version has a higher number. This is not a version
number generally shown to the user, that is usually supplied 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" /> <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 <!-- 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 is used for no other purpose than display to the user; the actual
significant version number is given by {@link android.R.attr#versionCode}. --> significant version number is given by {@link android.R.attr#versionCode}. -->
@@ -1025,6 +1034,7 @@
<declare-styleable name="AndroidManifest"> <declare-styleable name="AndroidManifest">
<attr name="versionCode" /> <attr name="versionCode" />
<attr name="versionName" /> <attr name="versionName" />
<attr name="revisionCode" />
<attr name="sharedUserId" /> <attr name="sharedUserId" />
<attr name="sharedUserLabel" /> <attr name="sharedUserLabel" />
<attr name="installLocation" /> <attr name="installLocation" />

View File

@@ -2593,6 +2593,7 @@
<public type="attr" name="accessibilityTraversalAfter" id="0x010104d2" /> <public type="attr" name="accessibilityTraversalAfter" id="0x010104d2" />
<public type="attr" name="dialogPreferredPadding" id="0x010104d3" /> <public type="attr" name="dialogPreferredPadding" id="0x010104d3" />
<public type="attr" name="searchHintIcon" id="0x010104d4" /> <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.Dialog.Alert" />
<public type="style" name="Theme.DeviceDefault.Light.Dialog.Alert" /> <public type="style" name="Theme.DeviceDefault.Light.Dialog.Alert" />

View File

@@ -180,7 +180,10 @@ public class DefaultContainerService extends IntentService {
} }
ret.packageName = pkg.packageName; ret.packageName = pkg.packageName;
ret.splitNames = pkg.splitNames;
ret.versionCode = pkg.versionCode; ret.versionCode = pkg.versionCode;
ret.baseRevisionCode = pkg.baseRevisionCode;
ret.splitRevisionCodes = pkg.splitRevisionCodes;
ret.installLocation = pkg.installLocation; ret.installLocation = pkg.installLocation;
ret.verifiers = pkg.verifiers; ret.verifiers = pkg.verifiers;
ret.recommendedInstallLocation = PackageHelper.resolveInstallLocation(context, ret.recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,

View File

@@ -497,12 +497,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// haven't been overridden. // haven't been overridden.
if (params.mode == SessionParams.MODE_INHERIT_EXISTING) { if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
try { 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 // TODO: this should delegate to DCS so the system process
// avoids holding open FDs into containers. // avoids holding open FDs into containers.
copyFiles(mResolvedInheritedFiles, resolveStageDir()); copyFiles(fromFiles, toDir);
} else {
linkFiles(mResolvedInheritedFiles, resolveStageDir());
} }
} catch (IOException e) { } catch (IOException e) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE, 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 // This is kind of hacky; we're creating a half-parsed package that is
// straddled between the inherited and staged APKs. // straddled between the inherited and staged APKs.
final PackageLite pkg = new PackageLite(null, baseApk, null, final PackageLite pkg = new PackageLite(null, baseApk, null,
splitPaths.toArray(new String[splitPaths.size()])); splitPaths.toArray(new String[splitPaths.size()]), null);
final boolean isForwardLocked = final boolean isForwardLocked =
(params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0; (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 { private static void linkFiles(List<File> fromFiles, File toDir) throws IOException {
for (File fromFile : fromFiles) { for (File fromFile : fromFiles) {
final File toFile = new File(toDir, fromFile.getName()); final File toFile = new File(toDir, fromFile.getName());
@@ -760,7 +783,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (!FileUtils.copyFile(fromFile, tmpFile)) { if (!FileUtils.copyFile(fromFile, tmpFile)) {
throw new IOException("Failed to copy " + fromFile + " to " + 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()); final File toFile = new File(toDir, fromFile.getName());
if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile); if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
if (!tmpFile.renameTo(toFile)) { if (!tmpFile.renameTo(toFile)) {

View File

@@ -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_UID_CHANGED;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE; 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_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_FORWARD_LOCK;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.PackageParser.isApkFile; 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 // version of the new path against what we have stored to determine
// what to do. // what to do.
if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath); 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 // The system package has been updated and the code path does not match
// Ignore entry. Skip it. // Ignore entry. Skip it.
Slog.i(TAG, "Package " + ps.name + " at " + scanFile Slog.i(TAG, "Package " + ps.name + " at " + scanFile
@@ -4368,7 +4369,7 @@ public class PackageManagerService extends IPackageManager.Stub {
* already installed version, hide it. It will be scanned later * already installed version, hide it. It will be scanned later
* and re-added like an update. * and re-added like an update.
*/ */
if (pkg.mVersionCode < ps.versionCode) { if (pkg.mVersionCode <= ps.versionCode) {
shouldHideSystemApp = true; shouldHideSystemApp = true;
logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + scanFile logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + scanFile
+ " but new version " + pkg.mVersionCode + " better than installed " + " but new version " + pkg.mVersionCode + " better than installed "
@@ -8859,11 +8860,10 @@ public class PackageManagerService extends IPackageManager.Stub {
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
// Check for downgrading. // Check for downgrading.
if ((installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) == 0) { if ((installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) == 0) {
if (pkgLite.versionCode < pkg.mVersionCode) { try {
Slog.w(TAG, "Can't install update of " + packageName checkDowngrade(pkg, pkgLite);
+ " update version " + pkgLite.versionCode } catch (PackageManagerException e) {
+ " is older than installed version " Slog.w(TAG, "Downgrade detected: " + e.getMessage());
+ pkg.mVersionCode);
return PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE; return PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE;
} }
} }
@@ -13541,4 +13541,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]);
}
}
}
}
}
}
} }