summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java55
-rw-r--r--core/java/android/app/ApplicationPackageManager.java18
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java5
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl3
-rw-r--r--core/java/android/content/pm/PackageInstaller.java5
-rw-r--r--core/java/android/content/pm/PackageManager.java18
-rw-r--r--core/java/android/content/pm/PackageParser.java4
-rw-r--r--core/java/android/os/storage/StorageManager.java40
-rw-r--r--core/java/android/os/storage/VolumeInfo.java1
-rw-r--r--core/java/com/android/internal/content/PackageHelper.java125
-rw-r--r--services/core/java/com/android/server/MountService.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java107
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java10
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java409
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java16
-rw-r--r--services/core/java/com/android/server/pm/Settings.java40
-rw-r--r--test-runner/src/android/test/mock/MockPackageManager.java11
17 files changed, 622 insertions, 248 deletions
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 51152af..23a8629 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -30,6 +30,7 @@ import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageManager;
+import android.content.pm.IPackageMoveObserver;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
@@ -55,12 +56,12 @@ import android.os.UserManager;
import android.text.TextUtils;
import android.util.Log;
+import libcore.io.IoUtils;
+
import com.android.internal.content.PackageHelper;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.SizedInputStream;
-import libcore.io.IoUtils;
-
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -234,6 +235,10 @@ public final class Pm {
return runForceDexOpt();
}
+ if ("move".equals(op)) {
+ return runMove();
+ }
+
try {
if (args.length == 1) {
if (args[0].equalsIgnoreCase("-l")) {
@@ -1278,6 +1283,51 @@ public final class Pm {
}
}
+ class LocalPackageMoveObserver extends IPackageMoveObserver.Stub {
+ boolean finished;
+ int returnCode;
+
+ @Override
+ public void packageMoved(String packageName, int returnCode) throws RemoteException {
+ synchronized (this) {
+ this.finished = true;
+ this.returnCode = returnCode;
+ notifyAll();
+ }
+ }
+ }
+
+ public int runMove() {
+ final String packageName = nextArg();
+ String volumeUuid = nextArg();
+ if ("internal".equals(volumeUuid)) {
+ volumeUuid = null;
+ }
+
+ final LocalPackageMoveObserver obs = new LocalPackageMoveObserver();
+ try {
+ mPm.movePackageAndData(packageName, volumeUuid, obs);
+
+ synchronized (obs) {
+ while (!obs.finished) {
+ try {
+ obs.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ if (obs.returnCode == PackageManager.MOVE_SUCCEEDED) {
+ System.out.println("Success");
+ return 0;
+ } else {
+ System.err.println("Failure [" + obs.returnCode + "]");
+ return 1;
+ }
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
private int runUninstall() throws RemoteException {
int flags = 0;
int userId = UserHandle.USER_ALL;
@@ -1820,6 +1870,7 @@ public final class Pm {
System.err.println(" pm install-abandon SESSION_ID");
System.err.println(" pm uninstall [-k] [--user USER_ID] PACKAGE");
System.err.println(" pm set-installer PACKAGE INSTALLER");
+ System.err.println(" pm move PACKAGE [internal|UUID]");
System.err.println(" pm clear [--user USER_ID] PACKAGE");
System.err.println(" pm enable [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm disable [--user USER_ID] PACKAGE_OR_COMPONENT");
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 6ec5457..10dcd85 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -62,19 +62,19 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
import android.util.Log;
import android.view.Display;
-import android.os.SystemProperties;
+
+import dalvik.system.VMRuntime;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import com.android.internal.util.UserIcons;
-import dalvik.system.VMRuntime;
-
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -1363,7 +1363,17 @@ final class ApplicationPackageManager extends PackageManager {
try {
mPM.movePackage(packageName, observer, flags);
} catch (RemoteException e) {
- // Should never happen!
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ @Override
+ public void movePackageAndData(String packageName, String volumeUuid,
+ IPackageMoveObserver observer) {
+ try {
+ mPM.movePackageAndData(packageName, volumeUuid, observer);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
}
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 8567c01..5bdb7bb 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -459,6 +459,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public int largestWidthLimitDp = 0;
/** {@hide} */
+ public String volumeUuid;
+ /** {@hide} */
public String scanSourceDir;
/** {@hide} */
public String scanPublicSourceDir;
@@ -726,6 +728,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
requiresSmallestWidthDp = orig.requiresSmallestWidthDp;
compatibleWidthLimitDp = orig.compatibleWidthLimitDp;
largestWidthLimitDp = orig.largestWidthLimitDp;
+ volumeUuid = orig.volumeUuid;
scanSourceDir = orig.scanSourceDir;
scanPublicSourceDir = orig.scanPublicSourceDir;
sourceDir = orig.sourceDir;
@@ -778,6 +781,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeInt(requiresSmallestWidthDp);
dest.writeInt(compatibleWidthLimitDp);
dest.writeInt(largestWidthLimitDp);
+ dest.writeString(volumeUuid);
dest.writeString(scanSourceDir);
dest.writeString(scanPublicSourceDir);
dest.writeString(sourceDir);
@@ -829,6 +833,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
requiresSmallestWidthDp = source.readInt();
compatibleWidthLimitDp = source.readInt();
largestWidthLimitDp = source.readInt();
+ volumeUuid = source.readString();
scanSourceDir = source.readString();
scanPublicSourceDir = source.readString();
sourceDir = source.readString();
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 649bb47..eed0df5 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -432,7 +432,8 @@ interface IPackageManager {
PackageCleanItem nextPackageToClean(in PackageCleanItem lastPackage);
void movePackage(String packageName, IPackageMoveObserver observer, int flags);
-
+ void movePackageAndData(String packageName, String volumeUuid, IPackageMoveObserver observer);
+
boolean addPermissionAsync(in PermissionInfo info);
boolean setInstallLocation(int loc);
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 80efd0b..15a7bf9 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -887,6 +887,8 @@ public class PackageInstaller {
public Uri referrerUri;
/** {@hide} */
public String abiOverride;
+ /** {@hide} */
+ public String volumeUuid;
/**
* Construct parameters for a new package install session.
@@ -911,6 +913,7 @@ public class PackageInstaller {
originatingUri = source.readParcelable(null);
referrerUri = source.readParcelable(null);
abiOverride = source.readString();
+ volumeUuid = source.readString();
}
/**
@@ -1008,6 +1011,7 @@ public class PackageInstaller {
pw.printPair("originatingUri", originatingUri);
pw.printPair("referrerUri", referrerUri);
pw.printPair("abiOverride", abiOverride);
+ pw.printPair("volumeUuid", volumeUuid);
pw.println();
}
@@ -1028,6 +1032,7 @@ public class PackageInstaller {
dest.writeParcelable(originatingUri, flags);
dest.writeParcelable(referrerUri, flags);
dest.writeString(abiOverride);
+ dest.writeString(volumeUuid);
}
public static final Parcelable.Creator<SessionParams>
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 46d6ffb3..4c99d09 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -43,7 +43,9 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.storage.VolumeInfo;
import android.util.AndroidException;
+
import com.android.internal.util.ArrayUtils;
import java.io.File;
@@ -339,15 +341,17 @@ public abstract class PackageManager {
public static final int INSTALL_ALLOW_TEST = 0x00000004;
/**
- * Flag parameter for {@link #installPackage} to indicate that this
- * package has to be installed on the sdcard.
+ * Flag parameter for {@link #installPackage} to indicate that this package
+ * must be installed to an ASEC on a {@link VolumeInfo#TYPE_PUBLIC}.
+ *
* @hide
*/
public static final int INSTALL_EXTERNAL = 0x00000008;
/**
* Flag parameter for {@link #installPackage} to indicate that this package
- * has to be installed on the sdcard.
+ * must be installed to internal storage.
+ *
* @hide
*/
public static final int INSTALL_INTERNAL = 0x00000010;
@@ -4099,8 +4103,12 @@ public abstract class PackageManager {
*
* @hide
*/
- public abstract void movePackage(
- String packageName, IPackageMoveObserver observer, int flags);
+ @Deprecated
+ public abstract void movePackage(String packageName, IPackageMoveObserver observer, int flags);
+
+ /** {@hide} */
+ public abstract void movePackageAndData(String packageName, String volumeUuid,
+ IPackageMoveObserver observer);
/**
* Returns the device identity that verifiers can use to associate their scheme to a particular
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index f4ad434..c1e6a4d 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -604,7 +604,7 @@ public class PackageParser {
public final static int PARSE_MUST_BE_APK = 1<<2;
public final static int PARSE_IGNORE_PROCESSES = 1<<3;
public final static int PARSE_FORWARD_LOCK = 1<<4;
- public final static int PARSE_ON_SDCARD = 1<<5;
+ public final static int PARSE_EXTERNAL_STORAGE = 1<<5;
public final static int PARSE_IS_SYSTEM_DIR = 1<<6;
public final static int PARSE_IS_PRIVILEGED = 1<<7;
public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
@@ -1408,7 +1408,7 @@ public class PackageParser {
}
/* Set the global "on SD card" flag */
- if ((flags & PARSE_ON_SDCARD) != 0) {
+ if ((flags & PARSE_EXTERNAL_STORAGE) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 486f9b4..5a5d8b7 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -43,6 +43,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -231,8 +232,7 @@ public class StorageManager {
mLooper = looper;
mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
if (mMountService == null) {
- Log.e(TAG, "Unable to connect to mount service! - is it running yet?");
- return;
+ throw new IllegalStateException("Failed to find running mount service");
}
}
@@ -442,6 +442,42 @@ public class StorageManager {
}
/** {@hide} */
+ public @Nullable DiskInfo findDiskById(String id) {
+ Preconditions.checkNotNull(id);
+ // TODO; go directly to service to make this faster
+ for (DiskInfo disk : getDisks()) {
+ if (Objects.equals(disk.id, id)) {
+ return disk;
+ }
+ }
+ return null;
+ }
+
+ /** {@hide} */
+ public @Nullable VolumeInfo findVolumeById(String id) {
+ Preconditions.checkNotNull(id);
+ // TODO; go directly to service to make this faster
+ for (VolumeInfo vol : getVolumes()) {
+ if (Objects.equals(vol.id, id)) {
+ return vol;
+ }
+ }
+ return null;
+ }
+
+ /** {@hide} */
+ public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) {
+ Preconditions.checkNotNull(fsUuid);
+ // TODO; go directly to service to make this faster
+ for (VolumeInfo vol : getVolumes()) {
+ if (Objects.equals(vol.fsUuid, fsUuid)) {
+ return vol;
+ }
+ }
+ return null;
+ }
+
+ /** {@hide} */
public @NonNull List<VolumeInfo> getVolumes() {
try {
return Arrays.asList(mMountService.getVolumes());
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index c8c2f65..2dc0361 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -44,6 +44,7 @@ import java.io.File;
* @hide
*/
public class VolumeInfo implements Parcelable {
+ /** Real volume representing internal emulated storage */
public static final String ID_EMULATED_INTERNAL = "emulated";
public static final int TYPE_PUBLIC = 0;
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index 7bdb4be..255f1fd 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -25,15 +25,16 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageParser.PackageLite;
import android.os.Environment;
-import android.os.Environment.UserEnvironment;
import android.os.FileUtils;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.UserHandle;
import android.os.storage.IMountService;
import android.os.storage.StorageManager;
import android.os.storage.StorageResultCode;
+import android.os.storage.StorageVolume;
+import android.os.storage.VolumeInfo;
+import android.util.ArraySet;
import android.util.Log;
import libcore.io.IoUtils;
@@ -335,6 +336,94 @@ public class PackageHelper {
/**
* Given a requested {@link PackageInfo#installLocation} and calculated
+ * install size, pick the actual volume to install the app. Only considers
+ * internal and private volumes, and prefers to keep an existing package on
+ * its current volume.
+ *
+ * @return the {@link VolumeInfo#fsUuid} to install onto, or {@code null}
+ * for internal storage.
+ */
+ public static String resolveInstallVolume(Context context, String packageName,
+ int installLocation, long sizeBytes) throws IOException {
+ // TODO: handle existing apps installed in ASEC; currently assumes
+ // they'll end up back on internal storage
+ ApplicationInfo existingInfo = null;
+ try {
+ existingInfo = context.getPackageManager().getApplicationInfo(packageName,
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+ } catch (NameNotFoundException ignored) {
+ }
+
+ final StorageManager storageManager = context.getSystemService(StorageManager.class);
+ final boolean fitsOnInternal = fitsOnInternal(context, sizeBytes);
+
+ final ArraySet<String> allCandidates = new ArraySet<>();
+ VolumeInfo bestCandidate = null;
+ long bestCandidateAvailBytes = Long.MIN_VALUE;
+ for (VolumeInfo vol : storageManager.getVolumes()) {
+ if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.state == VolumeInfo.STATE_MOUNTED) {
+ final long availBytes = storageManager.getStorageBytesUntilLow(new File(vol.path));
+ if (availBytes >= sizeBytes) {
+ allCandidates.add(vol.fsUuid);
+ }
+ if (availBytes >= bestCandidateAvailBytes) {
+ bestCandidate = vol;
+ bestCandidateAvailBytes = availBytes;
+ }
+ }
+ }
+
+ // System apps always forced to internal storage
+ if (existingInfo != null && existingInfo.isSystemApp()) {
+ installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
+ }
+
+ // If app expresses strong desire for internal space, honor it
+ if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
+ if (fitsOnInternal) {
+ return null;
+ } else {
+ throw new IOException("Requested internal only, but not enough space");
+ }
+ }
+
+ // If app already exists somewhere, prefer to stay on that volume
+ if (existingInfo != null) {
+ if (existingInfo.volumeUuid == null && fitsOnInternal) {
+ return null;
+ }
+ if (allCandidates.contains(existingInfo.volumeUuid)) {
+ return existingInfo.volumeUuid;
+ }
+ }
+
+ // We're left with either preferring external or auto, so just pick
+ // volume with most space
+ if (bestCandidate != null) {
+ return bestCandidate.fsUuid;
+ } else if (fitsOnInternal) {
+ return null;
+ } else {
+ throw new IOException("No special requests, but no room anywhere");
+ }
+ }
+
+ public static boolean fitsOnInternal(Context context, long sizeBytes) {
+ final StorageManager storage = context.getSystemService(StorageManager.class);
+ final File target = Environment.getDataDirectory();
+ return (sizeBytes <= storage.getStorageBytesUntilLow(target));
+ }
+
+ public static boolean fitsOnExternal(Context context, long sizeBytes) {
+ final StorageManager storage = context.getSystemService(StorageManager.class);
+ final StorageVolume primary = storage.getPrimaryVolume();
+ return (sizeBytes > 0) && !primary.isEmulated()
+ && Environment.MEDIA_MOUNTED.equals(primary.getState())
+ && sizeBytes <= storage.getStorageBytesUntilLow(primary.getPathFile());
+ }
+
+ /**
+ * Given a requested {@link PackageInfo#installLocation} and calculated
* install size, pick the actual location to install the app.
*/
public static int resolveInstallLocation(Context context, String packageName,
@@ -363,6 +452,7 @@ public class PackageHelper {
} else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
// When app is already installed, prefer same medium
if (existingInfo != null) {
+ // TODO: distinguish if this is external ASEC
if ((existingInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
prefer = RECOMMEND_INSTALL_EXTERNAL;
} else {
@@ -377,30 +467,21 @@ public class PackageHelper {
checkBoth = false;
}
- final boolean emulated = Environment.isExternalStorageEmulated();
- final StorageManager storage = StorageManager.from(context);
-
boolean fitsOnInternal = false;
if (checkBoth || prefer == RECOMMEND_INSTALL_INTERNAL) {
- final File target = Environment.getDataDirectory();
- fitsOnInternal = (sizeBytes <= storage.getStorageBytesUntilLow(target));
+ fitsOnInternal = fitsOnInternal(context, sizeBytes);
}
boolean fitsOnExternal = false;
- if (!emulated && (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL)) {
- final File target = new UserEnvironment(UserHandle.USER_OWNER)
- .getExternalStorageDirectory();
- // External is only an option when size is known
- if (sizeBytes > 0) {
- fitsOnExternal = (sizeBytes <= storage.getStorageBytesUntilLow(target));
- }
+ if (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL) {
+ fitsOnExternal = fitsOnExternal(context, sizeBytes);
}
if (prefer == RECOMMEND_INSTALL_INTERNAL) {
if (fitsOnInternal) {
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
}
- } else if (!emulated && prefer == RECOMMEND_INSTALL_EXTERNAL) {
+ } else if (prefer == RECOMMEND_INSTALL_EXTERNAL) {
if (fitsOnExternal) {
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
@@ -409,22 +490,12 @@ public class PackageHelper {
if (checkBoth) {
if (fitsOnInternal) {
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
- } else if (!emulated && fitsOnExternal) {
+ } else if (fitsOnExternal) {
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
}
- /*
- * If they requested to be on the external media by default, return that
- * the media was unavailable. Otherwise, indicate there was insufficient
- * storage space available.
- */
- if (!emulated && (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL)
- && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
- return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE;
- } else {
- return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
- }
+ return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
public static long calculateInstalledSize(PackageLite pkg, boolean isForwardLocked,
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 456f1fb..a341c95 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -833,6 +833,9 @@ class MountService extends IMountService.Stub
vol.userId = UserHandle.USER_OWNER;
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
+ } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
+ mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
+
} else {
Slog.d(TAG, "Skipping automatic mounting of " + vol);
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 95d7a52..aafb7a9 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -63,6 +63,8 @@ import android.os.RemoteException;
import android.os.SELinux;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
@@ -75,6 +77,8 @@ import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.Xml;
+import libcore.io.IoUtils;
+
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageHelper;
import com.android.internal.util.FastXmlSerializer;
@@ -82,8 +86,6 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.server.IoThread;
import com.google.android.collect.Sets;
-import libcore.io.IoUtils;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -131,6 +133,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
private static final String ATTR_ORIGINATING_URI = "originatingUri";
private static final String ATTR_REFERRER_URI = "referrerUri";
private static final String ATTR_ABI_OVERRIDE = "abiOverride";
+ private static final String ATTR_VOLUME_UUID = "volumeUuid";
/** Automatically destroy sessions older than this */
private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
@@ -141,9 +144,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
private final Context mContext;
private final PackageManagerService mPm;
- private final AppOpsManager mAppOps;
- private final File mStagingDir;
+ private AppOpsManager mAppOps;
+ private StorageManager mStorage;
+
private final HandlerThread mInstallThread;
private final Handler mInstallHandler;
@@ -186,12 +190,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
};
- public PackageInstallerService(Context context, PackageManagerService pm, File stagingDir) {
+ public PackageInstallerService(Context context, PackageManagerService pm) {
mContext = context;
mPm = pm;
- mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
-
- mStagingDir = stagingDir;
mInstallThread = new HandlerThread(TAG);
mInstallThread.start();
@@ -208,8 +209,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
synchronized (mSessions) {
readSessionsLocked();
+ final File internalStagingDir = buildInternalStagingDir();
final ArraySet<File> unclaimedStages = Sets.newArraySet(
- mStagingDir.listFiles(sStageFilter));
+ internalStagingDir.listFiles(sStageFilter));
final ArraySet<File> unclaimedIcons = Sets.newArraySet(
mSessionsDir.listFiles());
@@ -238,6 +240,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
}
+ public void systemReady() {
+ mAppOps = mContext.getSystemService(AppOpsManager.class);
+ mStorage = mContext.getSystemService(StorageManager.class);
+ }
+
public void onSecureContainersAvailable() {
synchronized (mSessions) {
final ArraySet<String> unclaimed = new ArraySet<>();
@@ -275,13 +282,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
@Deprecated
- public File allocateInternalStageDirLegacy() throws IOException {
+ public File allocateStageDirLegacy(String volumeUuid) throws IOException {
synchronized (mSessions) {
try {
final int sessionId = allocateSessionIdLocked();
mLegacySessions.put(sessionId, true);
- final File stageDir = buildInternalStageDir(sessionId);
- prepareInternalStageDir(stageDir);
+ final File stageDir = buildStageDir(volumeUuid, sessionId);
+ prepareStageDir(stageDir);
return stageDir;
} catch (IllegalStateException e) {
throw new IOException(e);
@@ -322,11 +329,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
Slog.w(TAG, "Abandoning old session first created at "
+ session.createdMillis);
valid = false;
- } else if (session.stageDir != null
- && !session.stageDir.exists()) {
- Slog.w(TAG, "Abandoning internal session with missing stage "
- + session.stageDir);
- valid = false;
} else {
valid = true;
}
@@ -378,6 +380,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
+ params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
final File appIconFile = buildAppIconFile(sessionId);
if (appIconFile.exists()) {
@@ -448,6 +451,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
+ writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
// Persist app icon if changed since last written
final File appIconFile = buildAppIconFile(session.sessionId);
@@ -528,28 +532,40 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
}
- if (params.mode == SessionParams.MODE_FULL_INSTALL
- || params.mode == SessionParams.MODE_INHERIT_EXISTING) {
+ switch (params.mode) {
+ case SessionParams.MODE_FULL_INSTALL:
+ case SessionParams.MODE_INHERIT_EXISTING:
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid install mode: " + params.mode);
+ }
+
+ // If caller requested explicit location, sanity check it, otherwise
+ // resolve the best internal or adopted location.
+ if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
+ if (!PackageHelper.fitsOnInternal(mContext, params.sizeBytes)) {
+ throw new IOException("No suitable internal storage available");
+ }
+
+ } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
+ if (!PackageHelper.fitsOnExternal(mContext, params.sizeBytes)) {
+ throw new IOException("No suitable external storage available");
+ }
+
+ } else {
+ // For now, installs to adopted media are treated as internal from
+ // an install flag point-of-view.
+ params.setInstallFlagsInternal();
+
// Resolve best location for install, based on combination of
// requested install flags, delta size, and manifest settings.
final long ident = Binder.clearCallingIdentity();
try {
- final int resolved = PackageHelper.resolveInstallLocation(mContext,
- params.appPackageName, params.installLocation, params.sizeBytes,
- params.installFlags);
-
- if (resolved == PackageHelper.RECOMMEND_INSTALL_INTERNAL) {
- params.setInstallFlagsInternal();
- } else if (resolved == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
- params.setInstallFlagsExternal();
- } else {
- throw new IOException("No storage with enough free space; res=" + resolved);
- }
+ params.volumeUuid = PackageHelper.resolveInstallVolume(mContext,
+ params.appPackageName, params.installLocation, params.sizeBytes);
} finally {
Binder.restoreCallingIdentity(ident);
}
- } else {
- throw new IllegalArgumentException("Invalid install mode: " + params.mode);
}
final int sessionId;
@@ -574,7 +590,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
File stageDir = null;
String stageCid = null;
if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
- stageDir = buildInternalStageDir(sessionId);
+ stageDir = buildStageDir(params.volumeUuid, sessionId);
} else {
stageCid = buildExternalStageCid(sessionId);
}
@@ -673,11 +689,30 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
throw new IllegalStateException("Failed to allocate session ID");
}
- private File buildInternalStageDir(int sessionId) {
- return new File(mStagingDir, "vmdl" + sessionId + ".tmp");
+ private File buildInternalStagingDir() {
+ return new File(Environment.getDataDirectory(), "app");
+ }
+
+ private File buildStagingDir(String volumeUuid) throws FileNotFoundException {
+ if (volumeUuid == null) {
+ return buildInternalStagingDir();
+ } else {
+ final VolumeInfo vol = mStorage.findVolumeByUuid(volumeUuid);
+ if (vol != null && vol.type == VolumeInfo.TYPE_PRIVATE
+ && vol.state == VolumeInfo.STATE_MOUNTED) {
+ return new File(vol.path, "app");
+ } else {
+ throw new FileNotFoundException("Failed to find volume for UUID " + volumeUuid);
+ }
+ }
+ }
+
+ private File buildStageDir(String volumeUuid, int sessionId) throws FileNotFoundException {
+ final File stagingDir = buildStagingDir(volumeUuid);
+ return new File(stagingDir, "vmdl" + sessionId + ".tmp");
}
- static void prepareInternalStageDir(File stageDir) throws IOException {
+ static void prepareStageDir(File stageDir) throws IOException {
if (stageDir.exists()) {
throw new IOException("Session dir already exists: " + stageDir);
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index cc1b3ad..09e990c 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -25,7 +25,7 @@ import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDONLY;
import static android.system.OsConstants.O_WRONLY;
import static com.android.server.pm.PackageInstallerService.prepareExternalStageCid;
-import static com.android.server.pm.PackageInstallerService.prepareInternalStageDir;
+import static com.android.server.pm.PackageInstallerService.prepareStageDir;
import android.content.Context;
import android.content.Intent;
@@ -61,6 +61,9 @@ import android.util.ExceptionUtils;
import android.util.MathUtils;
import android.util.Slog;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
@@ -69,9 +72,6 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
-import libcore.io.IoUtils;
-import libcore.io.Libcore;
-
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -892,7 +892,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
synchronized (mLock) {
if (!mPrepared) {
if (stageDir != null) {
- prepareInternalStageDir(stageDir);
+ prepareStageDir(stageDir);
} else if (stageCid != null) {
prepareExternalStageCid(stageCid, params.sizeBytes);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2ff1718..84dc748 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -43,11 +43,17 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIB
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_INTERNAL;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.MOVE_EXTERNAL_MEDIA;
+import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
+import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
+import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
+import static android.content.pm.PackageManager.MOVE_INTERNAL;
import static android.content.pm.PackageParser.isApkFile;
import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
@@ -65,31 +71,7 @@ import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
import android.Manifest;
-import android.content.pm.IntentFilterVerificationInfo;
-import android.util.ArrayMap;
-
-import com.android.internal.R;
-import com.android.internal.app.IMediaContainerService;
-import com.android.internal.app.ResolverActivity;
-import com.android.internal.content.NativeLibraryHelper;
-import com.android.internal.content.PackageHelper;
-import com.android.internal.os.IParcelFileDescriptorFactory;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastPrintWriter;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.EventLogTags;
-import com.android.server.IntentResolver;
-import com.android.server.LocalServices;
-import com.android.server.ServiceThread;
-import com.android.server.SystemConfig;
-import com.android.server.Watchdog;
-import com.android.server.pm.Settings.DatabaseVersion;
-import com.android.server.storage.DeviceStorageMonitorInternal;
-
import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
-
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
@@ -119,6 +101,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
+import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
import android.content.pm.ManifestDigest;
import android.content.pm.PackageCleanItem;
@@ -127,10 +110,10 @@ import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
+import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ActivityIntentInfo;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser;
import android.content.pm.PackageStats;
import android.content.pm.PackageUserState;
import android.content.pm.ParceledListSlice;
@@ -150,13 +133,9 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.Debug;
import android.os.Environment;
import android.os.Environment.UserEnvironment;
-import android.os.storage.IMountService;
-import android.os.storage.StorageEventListener;
-import android.os.storage.StorageManager;
-import android.os.storage.VolumeInfo;
-import android.os.Debug;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
@@ -172,6 +151,10 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.IMountService;
+import android.os.storage.StorageEventListener;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
import android.security.KeyStore;
import android.security.SystemKeyStore;
import android.system.ErrnoException;
@@ -179,6 +162,7 @@ import android.system.Os;
import android.system.StructStat;
import android.text.TextUtils;
import android.text.format.DateUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.DisplayMetrics;
@@ -193,6 +177,33 @@ import android.util.SparseBooleanArray;
import android.util.Xml;
import android.view.Display;
+import dalvik.system.DexFile;
+import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
+import com.android.internal.R;
+import com.android.internal.app.IMediaContainerService;
+import com.android.internal.app.ResolverActivity;
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.content.PackageHelper;
+import com.android.internal.os.IParcelFileDescriptorFactory;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.EventLogTags;
+import com.android.server.IntentResolver;
+import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
+import com.android.server.SystemConfig;
+import com.android.server.Watchdog;
+import com.android.server.pm.Settings.DatabaseVersion;
+import com.android.server.storage.DeviceStorageMonitorInternal;
+
+import org.xmlpull.v1.XmlSerializer;
+
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
@@ -227,12 +238,6 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
-import dalvik.system.DexFile;
-import dalvik.system.VMRuntime;
-
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
-
/**
* Keep track of all those .apks everywhere.
*
@@ -1539,9 +1544,14 @@ public class PackageManagerService extends IPackageManager.Stub {
private StorageEventListener mStorageListener = new StorageEventListener() {
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
- Slog.v(TAG, vol.toString());
+ if (vol.type == VolumeInfo.TYPE_PRIVATE) {
+ if (vol.state == VolumeInfo.STATE_MOUNTED) {
+ loadPrivatePackages(vol);
+ } else if (vol.state == VolumeInfo.STATE_UNMOUNTING) {
+ unloadPrivatePackages(vol);
+ }
+ }
- // TODO: when private volume shows up, look for packages there too
if (vol.isPrimary() && vol.type == VolumeInfo.TYPE_PUBLIC) {
if (vol.state == VolumeInfo.STATE_MOUNTED) {
updateExternalMediaStatus(true, false);
@@ -2160,7 +2170,7 @@ public class PackageManagerService extends IPackageManager.Stub {
mRequiredVerifierPackage = getRequiredVerifierLPr();
- mInstallerService = new PackageInstallerService(context, this, mAppInstallDir);
+ mInstallerService = new PackageInstallerService(context, this);
mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
mIntentFilterVerifier = new IntentVerifierProxy(mContext,
@@ -8476,8 +8486,8 @@ public class PackageManagerService extends IPackageManager.Stub {
public void installPackage(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, VerificationParams verificationParams,
String packageAbiOverride) {
- installPackageAsUser(originPath, observer, installFlags, installerPackageName, verificationParams,
- packageAbiOverride, UserHandle.getCallingUserId());
+ installPackageAsUser(originPath, observer, installFlags, installerPackageName,
+ verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
}
@Override
@@ -8524,7 +8534,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(origin, observer, installFlags,
- installerPackageName, verificationParams, user, packageAbiOverride);
+ installerPackageName, null, verificationParams, user, packageAbiOverride);
mHandler.sendMessage(msg);
}
@@ -8543,7 +8553,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(origin, observer, params.installFlags,
- installerPackageName, verifParams, user, params.abiOverride);
+ installerPackageName, params.volumeUuid, verifParams, user, params.abiOverride);
mHandler.sendMessage(msg);
}
@@ -9345,19 +9355,21 @@ public class PackageManagerService extends IPackageManager.Stub {
final IPackageInstallObserver2 observer;
int installFlags;
final String installerPackageName;
+ final String volumeUuid;
final VerificationParams verificationParams;
private InstallArgs mArgs;
private int mRet;
final String packageAbiOverride;
InstallParams(OriginInfo origin, IPackageInstallObserver2 observer, int installFlags,
- String installerPackageName, VerificationParams verificationParams, UserHandle user,
- String packageAbiOverride) {
+ String installerPackageName, String volumeUuid,
+ VerificationParams verificationParams, UserHandle user, String packageAbiOverride) {
super(user);
this.origin = origin;
this.observer = observer;
this.installFlags = installFlags;
this.installerPackageName = installerPackageName;
+ this.volumeUuid = volumeUuid;
this.verificationParams = verificationParams;
this.packageAbiOverride = packageAbiOverride;
}
@@ -9711,7 +9723,7 @@ public class PackageManagerService extends IPackageManager.Stub {
* @param installFlags package installation flags
* @return true if should be installed on external storage
*/
- private static boolean installOnSd(int installFlags) {
+ private static boolean installOnExternalAsec(int installFlags) {
if ((installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
return false;
}
@@ -9732,7 +9744,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private InstallArgs createInstallArgs(InstallParams params) {
- if (installOnSd(params.installFlags) || params.isForwardLocked()) {
+ if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
return new AsecInstallArgs(params);
} else {
return new FileInstallArgs(params);
@@ -9746,7 +9758,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private InstallArgs createInstallArgsForExisting(int installFlags, String codePath,
String resourcePath, String nativeLibraryRoot, String[] instructionSets) {
final boolean isInAsec;
- if (installOnSd(installFlags)) {
+ if (installOnExternalAsec(installFlags)) {
/* Apps on SD card are always in ASEC containers. */
isInAsec = true;
} else if (installForwardLocked(installFlags)
@@ -9762,7 +9774,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (isInAsec) {
return new AsecInstallArgs(codePath, instructionSets,
- installOnSd(installFlags), installForwardLocked(installFlags));
+ installOnExternalAsec(installFlags), installForwardLocked(installFlags));
} else {
return new FileInstallArgs(codePath, resourcePath, nativeLibraryRoot,
instructionSets);
@@ -9777,6 +9789,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// Always refers to PackageManager flags only
final int installFlags;
final String installerPackageName;
+ final String volumeUuid;
final ManifestDigest manifestDigest;
final UserHandle user;
final String abiOverride;
@@ -9787,12 +9800,13 @@ public class PackageManagerService extends IPackageManager.Stub {
/* nullable */ String[] instructionSets;
InstallArgs(OriginInfo origin, IPackageInstallObserver2 observer, int installFlags,
- String installerPackageName, ManifestDigest manifestDigest, UserHandle user,
- String[] instructionSets, String abiOverride) {
+ String installerPackageName, String volumeUuid, ManifestDigest manifestDigest,
+ UserHandle user, String[] instructionSets, String abiOverride) {
this.origin = origin;
this.installFlags = installFlags;
this.observer = observer;
this.installerPackageName = installerPackageName;
+ this.volumeUuid = volumeUuid;
this.manifestDigest = manifestDigest;
this.user = user;
this.instructionSets = instructionSets;
@@ -9844,7 +9858,7 @@ public class PackageManagerService extends IPackageManager.Stub {
return (installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
}
- protected boolean isExternal() {
+ protected boolean isExternalAsec() {
return (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
}
@@ -9891,8 +9905,8 @@ public class PackageManagerService extends IPackageManager.Stub {
/** New install */
FileInstallArgs(InstallParams params) {
super(params.origin, params.observer, params.installFlags,
- params.installerPackageName, params.getManifestDigest(), params.getUser(),
- null /* instruction sets */, params.packageAbiOverride);
+ params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+ params.getUser(), null /* instruction sets */, params.packageAbiOverride);
if (isFwdLocked()) {
throw new IllegalArgumentException("Forward locking only supported in ASEC");
}
@@ -9901,7 +9915,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/** Existing install */
FileInstallArgs(String codePath, String resourcePath, String legacyNativeLibraryPath,
String[] instructionSets) {
- super(OriginInfo.fromNothing(), null, 0, null, null, null, instructionSets, null);
+ super(OriginInfo.fromNothing(), null, 0, null, null, null, null, instructionSets, null);
this.codeFile = (codePath != null) ? new File(codePath) : null;
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
this.legacyNativeLibraryPath = (legacyNativeLibraryPath != null) ?
@@ -9925,7 +9939,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
try {
- final File tempDir = mInstallerService.allocateInternalStageDirLegacy();
+ final File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid);
codeFile = tempDir;
resourceFile = tempDir;
} catch (IOException e) {
@@ -9986,8 +10000,9 @@ public class PackageManagerService extends IPackageManager.Stub {
cleanUp();
return false;
} else {
+ final File targetDir = codeFile.getParentFile();
final File beforeCodeFile = codeFile;
- final File afterCodeFile = getNextCodePath(pkg.packageName);
+ final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);
Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
try {
@@ -10137,16 +10152,15 @@ public class PackageManagerService extends IPackageManager.Stub {
/** New install */
AsecInstallArgs(InstallParams params) {
super(params.origin, params.observer, params.installFlags,
- params.installerPackageName, params.getManifestDigest(),
- params.getUser(), null /* instruction sets */,
- params.packageAbiOverride);
+ params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+ params.getUser(), null /* instruction sets */, params.packageAbiOverride);
}
/** Existing install */
AsecInstallArgs(String fullCodePath, String[] instructionSets,
boolean isExternal, boolean isForwardLocked) {
super(OriginInfo.fromNothing(), null, (isExternal ? INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
+ | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
instructionSets, null);
// Hackily pretend we're still looking at a full code path
if (!fullCodePath.endsWith(RES_FILE_NAME)) {
@@ -10163,7 +10177,7 @@ public class PackageManagerService extends IPackageManager.Stub {
AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
super(OriginInfo.fromNothing(), null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
+ | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
instructionSets, null);
this.cid = cid;
setMountPath(PackageHelper.getSdDir(cid));
@@ -10178,7 +10192,7 @@ public class PackageManagerService extends IPackageManager.Stub {
abiOverride);
final File target;
- if (isExternal()) {
+ if (isExternalAsec()) {
target = new UserEnvironment(UserHandle.USER_OWNER).getExternalStorageDirectory();
} else {
target = Environment.getDataDirectory();
@@ -10207,7 +10221,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
final String newMountPath = imcs.copyPackageToContainer(
- origin.file.getAbsolutePath(), cid, getEncryptKey(), isExternal(),
+ origin.file.getAbsolutePath(), cid, getEncryptKey(), isExternalAsec(),
isFwdLocked(), deriveAbiOverride(abiOverride, null /* settings */));
if (newMountPath != null) {
@@ -10488,11 +10502,11 @@ public class PackageManagerService extends IPackageManager.Stub {
return prefix + idxStr;
}
- private File getNextCodePath(String packageName) {
+ private File getNextCodePath(File targetDir, String packageName) {
int suffix = 1;
File result;
do {
- result = new File(mAppInstallDir, packageName + "-" + suffix);
+ result = new File(targetDir, packageName + "-" + suffix);
suffix++;
} while (result.exists());
return result;
@@ -10556,9 +10570,9 @@ public class PackageManagerService extends IPackageManager.Stub {
/*
* Install a non-existing package.
*/
- private void installNewPackageLI(PackageParser.Package pkg,
- int parseFlags, int scanFlags, UserHandle user,
- String installerPackageName, PackageInstalledInfo res) {
+ private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
+ UserHandle user, String installerPackageName, String volumeUuid,
+ PackageInstalledInfo res) {
// Remember this for later, in case we need to rollback this install
String pkgName = pkg.packageName;
@@ -10587,7 +10601,7 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
System.currentTimeMillis(), user);
- updateSettingsLI(newPackage, installerPackageName, null, null, res, user);
+ updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user);
// delete the partially installed application. the data directory will have to be
// restored if it was already existing
if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
@@ -10619,9 +10633,9 @@ public class PackageManagerService extends IPackageManager.Stub {
return false;
}
- private void replacePackageLI(PackageParser.Package pkg,
- int parseFlags, int scanFlags, UserHandle user,
- String installerPackageName, PackageInstalledInfo res) {
+ private void replacePackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
+ UserHandle user, String installerPackageName, String volumeUuid,
+ PackageInstalledInfo res) {
PackageParser.Package oldPackage;
String pkgName = pkg.packageName;
int[] allUsers;
@@ -10660,17 +10674,17 @@ public class PackageManagerService extends IPackageManager.Stub {
boolean sysPkg = (isSystemApp(oldPackage));
if (sysPkg) {
replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags,
- user, allUsers, perUserInstalled, installerPackageName, res);
+ user, allUsers, perUserInstalled, installerPackageName, volumeUuid, res);
} else {
replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags,
- user, allUsers, perUserInstalled, installerPackageName, res);
+ user, allUsers, perUserInstalled, installerPackageName, volumeUuid, res);
}
}
private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
- int[] allUsers, boolean[] perUserInstalled,
- String installerPackageName, PackageInstalledInfo res) {
+ int[] allUsers, boolean[] perUserInstalled, String installerPackageName,
+ String volumeUuid, PackageInstalledInfo res) {
String pkgName = deletedPackage.packageName;
boolean deletedPkg = true;
boolean updatedSettings = false;
@@ -10709,8 +10723,8 @@ public class PackageManagerService extends IPackageManager.Stub {
try {
final PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags,
scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
- updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res,
- user);
+ updateSettingsLI(newPackage, installerPackageName, volumeUuid, allUsers,
+ perUserInstalled, res, user);
updatedSettings = true;
} catch (PackageManagerException e) {
res.setError("Package couldn't be installed in " + pkg.codePath, e);
@@ -10735,10 +10749,10 @@ public class PackageManagerService extends IPackageManager.Stub {
if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + deletedPackage);
File restoreFile = new File(deletedPackage.codePath);
// Parse old package
- boolean oldOnSd = isExternal(deletedPackage);
+ boolean oldExternal = isExternal(deletedPackage);
int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY |
(deletedPackage.isForwardLocked() ? PackageParser.PARSE_FORWARD_LOCK : 0) |
- (oldOnSd ? PackageParser.PARSE_ON_SDCARD : 0);
+ (oldExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME;
try {
scanPackageLI(restoreFile, oldParseFlags, oldScanFlags, origUpdateTime, null);
@@ -10762,8 +10776,8 @@ public class PackageManagerService extends IPackageManager.Stub {
private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
- int[] allUsers, boolean[] perUserInstalled,
- String installerPackageName, PackageInstalledInfo res) {
+ int[] allUsers, boolean[] perUserInstalled, String installerPackageName,
+ String volumeUuid, PackageInstalledInfo res) {
if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
+ ", old=" + deletedPackage);
boolean disabledSystem = false;
@@ -10840,8 +10854,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res,
- user);
+ updateSettingsLI(newPackage, installerPackageName, volumeUuid, allUsers,
+ perUserInstalled, res, user);
updatedSettings = true;
}
@@ -10876,8 +10890,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
- int[] allUsers, boolean[] perUserInstalled,
- PackageInstalledInfo res, UserHandle user) {
+ String volumeUuid, int[] allUsers, boolean[] perUserInstalled, PackageInstalledInfo res,
+ UserHandle user) {
String pkgName = newPackage.packageName;
synchronized (mPackages) {
//write settings. the installStatus will be incomplete at this stage.
@@ -10935,6 +10949,7 @@ public class PackageManagerService extends IPackageManager.Stub {
res.pkg = newPackage;
mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
mSettings.setInstallerPackageName(pkgName, installerPackageName);
+ mSettings.setVolumeUuid(pkgName, volumeUuid);
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
//to update install status
mSettings.writeLPr();
@@ -10943,10 +10958,12 @@ public class PackageManagerService extends IPackageManager.Stub {
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
final int installFlags = args.installFlags;
- String installerPackageName = args.installerPackageName;
- File tmpPackageFile = new File(args.getCodePath());
- boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
- boolean onSd = ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0);
+ final String installerPackageName = args.installerPackageName;
+ final String volumeUuid = args.volumeUuid;
+ final File tmpPackageFile = new File(args.getCodePath());
+ final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
+ final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)
+ || (args.volumeUuid != null));
boolean replace = false;
final int scanFlags = SCAN_NEW_INSTALL | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE;
// Result object to be returned
@@ -10956,7 +10973,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// Retrieve PackageSettings and parse package
final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
- | (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
+ | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
@@ -11108,7 +11125,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
- if (systemApp && onSd) {
+ if (systemApp && onExternal) {
// Disable updates to system apps on sdcard
res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
"Cannot install updates to system apps on sdcard");
@@ -11134,10 +11151,10 @@ public class PackageManagerService extends IPackageManager.Stub {
if (replace) {
// Call replacePackageLI with SCAN_NO_DEX, since we already made dexopt
replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING | SCAN_NO_DEX, args.user,
- installerPackageName, res);
+ installerPackageName, volumeUuid, res);
} else {
installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
- args.user, installerPackageName, res);
+ args.user, installerPackageName, volumeUuid, res);
}
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
@@ -11265,7 +11282,9 @@ public class PackageManagerService extends IPackageManager.Stub {
private int packageFlagsToInstallFlags(PackageSetting ps) {
int installFlags = 0;
- if (isExternal(ps)) {
+ if (isExternal(ps) && TextUtils.isEmpty(ps.volumeUuid)) {
+ // This existing package was an external ASEC install when we have
+ // the external flag without a UUID
installFlags |= PackageManager.INSTALL_EXTERNAL;
}
if (ps.isForwardLocked()) {
@@ -12975,6 +12994,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// Watch for external volumes that come and go over time
final StorageManager storage = mContext.getSystemService(StorageManager.class);
storage.registerListener(mStorageListener);
+
+ mInstallerService.systemReady();
}
@Override
@@ -13713,13 +13734,32 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
+ ArrayList<ApplicationInfo> infos, IIntentReceiver finishedReceiver) {
+ final int size = infos.size();
+ final String[] packageNames = new String[size];
+ final int[] packageUids = new int[size];
+ for (int i = 0; i < size; i++) {
+ final ApplicationInfo info = infos.get(i);
+ packageNames[i] = info.packageName;
+ packageUids[i] = info.uid;
+ }
+ sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids,
+ finishedReceiver);
+ }
+
+ private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) {
- int size = pkgList.size();
+ sendResourcesChangedBroadcast(mediaStatus, replacing,
+ pkgList.toArray(new String[pkgList.size()]), uidArr, finishedReceiver);
+ }
+
+ private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
+ String[] pkgList, int uidArr[], IIntentReceiver finishedReceiver) {
+ int size = pkgList.length;
if (size > 0) {
// Send broadcasts here
Bundle extras = new Bundle();
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList
- .toArray(new String[size]));
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
if (uidArr != null) {
extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
}
@@ -13762,8 +13802,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
// Parse package
int parseFlags = mDefParseFlags;
- if (args.isExternal()) {
- parseFlags |= PackageParser.PARSE_ON_SDCARD;
+ if (args.isExternalAsec()) {
+ parseFlags |= PackageParser.PARSE_EXTERNAL_STORAGE;
}
if (args.isFwdLocked()) {
parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
@@ -13910,73 +13950,130 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- /** Binder call */
+ private void loadPrivatePackages(VolumeInfo vol) {
+ final ArrayList<ApplicationInfo> loaded = new ArrayList<>();
+ final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE;
+ synchronized (mPackages) {
+ final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid);
+ for (PackageSetting ps : packages) {
+ synchronized (mInstallLock) {
+ final PackageParser.Package pkg;
+ try {
+ pkg = scanPackageLI(ps.codePath, parseFlags, 0, 0, null);
+ loaded.add(pkg.applicationInfo);
+ } catch (PackageManagerException e) {
+ Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
+ }
+ }
+ }
+
+ // TODO: regrant any permissions that changed based since original install
+
+ mSettings.writeLPr();
+ }
+
+ Slog.d(TAG, "Loaded packages " + loaded);
+ sendResourcesChangedBroadcast(true, false, loaded, null);
+ }
+
+ private void unloadPrivatePackages(VolumeInfo vol) {
+ final ArrayList<ApplicationInfo> unloaded = new ArrayList<>();
+ synchronized (mPackages) {
+ final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid);
+ for (PackageSetting ps : packages) {
+ if (ps.pkg == null) continue;
+ synchronized (mInstallLock) {
+ final ApplicationInfo info = ps.pkg.applicationInfo;
+ final PackageRemovedInfo outInfo = new PackageRemovedInfo();
+ if (deletePackageLI(ps.name, null, false, null, null,
+ PackageManager.DELETE_KEEP_DATA, outInfo, false)) {
+ unloaded.add(info);
+ } else {
+ Slog.w(TAG, "Failed to unload " + ps.codePath);
+ }
+ }
+ }
+
+ mSettings.writeLPr();
+ }
+
+ Slog.d(TAG, "Unloaded packages " + unloaded);
+ sendResourcesChangedBroadcast(false, false, unloaded, null);
+ }
+
@Override
public void movePackage(final String packageName, final IPackageMoveObserver observer,
final int flags) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
- UserHandle user = new UserHandle(UserHandle.getCallingUserId());
- int returnCode = PackageManager.MOVE_SUCCEEDED;
- int currInstallFlags = 0;
- int newInstallFlags = 0;
+
+ final int installFlags;
+ if ((flags & MOVE_INTERNAL) != 0) {
+ installFlags = INSTALL_INTERNAL;
+ } else if ((flags & MOVE_EXTERNAL_MEDIA) != 0) {
+ installFlags = INSTALL_EXTERNAL;
+ } else {
+ throw new IllegalArgumentException("Unsupported move flags " + flags);
+ }
+
+ try {
+ movePackageInternal(packageName, null, installFlags, false, observer);
+ } catch (PackageManagerException e) {
+ Slog.d(TAG, "Failed to move " + packageName, e);
+ try {
+ observer.packageMoved(packageName, e.error);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ @Override
+ public void movePackageAndData(final String packageName, final String volumeUuid,
+ final IPackageMoveObserver observer) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
+ try {
+ movePackageInternal(packageName, volumeUuid, INSTALL_INTERNAL, true, observer);
+ } catch (PackageManagerException e) {
+ Slog.d(TAG, "Failed to move " + packageName, e);
+ try {
+ observer.packageMoved(packageName, e.error);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ private void movePackageInternal(final String packageName, String volumeUuid, int installFlags,
+ boolean andData, final IPackageMoveObserver observer) throws PackageManagerException {
+ final UserHandle user = new UserHandle(UserHandle.getCallingUserId());
File codeFile = null;
String installerPackageName = null;
String packageAbiOverride = null;
+ // TOOD: move app private data before installing
+
// reader
synchronized (mPackages) {
final PackageParser.Package pkg = mPackages.get(packageName);
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (pkg == null || ps == null) {
- returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
- } else {
- // Disable moving fwd locked apps and system packages
- if (pkg.applicationInfo != null && isSystemApp(pkg)) {
- Slog.w(TAG, "Cannot move system application");
- returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
- } else if (pkg.mOperationPending) {
- Slog.w(TAG, "Attempt to move package which has pending operations");
- returnCode = PackageManager.MOVE_FAILED_OPERATION_PENDING;
- } else {
- // Find install location first
- if ((flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0
- && (flags & PackageManager.MOVE_INTERNAL) != 0) {
- Slog.w(TAG, "Ambigous flags specified for move location.");
- returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
- } else {
- newInstallFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0
- ? PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL;
- currInstallFlags = isExternal(pkg)
- ? PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL;
-
- if (newInstallFlags == currInstallFlags) {
- Slog.w(TAG, "No move required. Trying to move to same location");
- returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
- } else {
- if (pkg.isForwardLocked()) {
- currInstallFlags |= PackageManager.INSTALL_FORWARD_LOCK;
- newInstallFlags |= PackageManager.INSTALL_FORWARD_LOCK;
- }
- }
- }
- if (returnCode == PackageManager.MOVE_SUCCEEDED) {
- pkg.mOperationPending = true;
- }
- }
-
- codeFile = new File(pkg.codePath);
- installerPackageName = ps.installerPackageName;
- packageAbiOverride = ps.cpuAbiOverrideString;
+ throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
}
- }
- if (returnCode != PackageManager.MOVE_SUCCEEDED) {
- try {
- observer.packageMoved(packageName, returnCode);
- } catch (RemoteException ignored) {
+ if (pkg.applicationInfo.isSystemApp()) {
+ throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
+ "Cannot move system application");
+ } else if (pkg.mOperationPending) {
+ throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
+ "Attempt to move package which has pending operations");
}
- return;
+
+ // TODO: yell if already in desired location
+
+ pkg.mOperationPending = true;
+
+ codeFile = new File(pkg.codePath);
+ installerPackageName = ps.installerPackageName;
+ packageAbiOverride = ps.cpuAbiOverrideString;
}
final IPackageInstallObserver2 installObserver = new IPackageInstallObserver2.Stub() {
@@ -14018,12 +14115,12 @@ public class PackageManagerService extends IPackageManager.Stub {
// Treat a move like reinstalling an existing app, which ensures that we
// process everythign uniformly, like unpacking native libraries.
- newInstallFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+ installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
final Message msg = mHandler.obtainMessage(INIT_COPY);
final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
- msg.obj = new InstallParams(origin, installObserver, newInstallFlags,
- installerPackageName, null, user, packageAbiOverride);
+ msg.obj = new InstallParams(origin, installObserver, installFlags,
+ installerPackageName, volumeUuid, null, user, packageAbiOverride);
mHandler.sendMessage(msg);
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index daa6d64..f294b32 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -23,6 +23,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageUserState;
+import android.os.storage.VolumeInfo;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -108,8 +109,10 @@ abstract class PackageSettingBase extends SettingBase {
PackageSettingBase origPackage;
- /* package name of the app that installed this package */
+ /** Package name of the app that installed this package */
String installerPackageName;
+ /** UUID of {@link VolumeInfo} hosting this app */
+ String volumeUuid;
IntentFilterVerificationInfo verificationInfo;
@@ -161,6 +164,7 @@ abstract class PackageSettingBase extends SettingBase {
origPackage = base.origPackage;
installerPackageName = base.installerPackageName;
+ volumeUuid = base.volumeUuid;
keySetData = new PackageKeySetData(base.keySetData);
}
@@ -183,10 +187,18 @@ abstract class PackageSettingBase extends SettingBase {
installerPackageName = packageName;
}
- String getInstallerPackageName() {
+ public String getInstallerPackageName() {
return installerPackageName;
}
+ public void setVolumeUuid(String volumeUuid) {
+ this.volumeUuid = volumeUuid;
+ }
+
+ public String getVolumeUuid() {
+ return volumeUuid;
+ }
+
public void setInstallStatus(int newStatus) {
installStatus = newStatus;
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6930965..6b7c35c 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -42,6 +42,7 @@ import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.VolumeInfo;
import android.util.AtomicFile;
import android.text.TextUtils;
import android.util.LogPrinter;
@@ -53,6 +54,7 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.backup.PreferredActivityBackupHelper;
import com.android.server.pm.PackageManagerService.DumpState;
@@ -333,14 +335,20 @@ final class Settings {
}
}
- void setInstallerPackageName(String pkgName,
- String installerPkgName) {
+ void setInstallerPackageName(String pkgName, String installerPkgName) {
PackageSetting p = mPackages.get(pkgName);
- if(p != null) {
+ if (p != null) {
p.setInstallerPackageName(installerPkgName);
}
}
+ void setVolumeUuid(String pkgName, String volumeUuid) {
+ PackageSetting p = mPackages.get(pkgName);
+ if (p != null) {
+ p.setVolumeUuid(volumeUuid);
+ }
+ }
+
SharedUserSetting getSharedUserLPw(String name,
int pkgFlags, int pkgPrivateFlags, boolean create) {
SharedUserSetting s = mSharedUsers.get(name);
@@ -2066,6 +2074,9 @@ final class Settings {
if (pkg.installerPackageName != null) {
serializer.attribute(null, "installer", pkg.installerPackageName);
}
+ if (pkg.volumeUuid != null) {
+ serializer.attribute(null, "volumeUuid", pkg.volumeUuid);
+ }
pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
if ((pkg.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
writePermissionsLPr(serializer, pkg.getPermissionsState().getInstallPermissions());
@@ -2908,6 +2919,7 @@ final class Settings {
String cpuAbiOverrideString = null;
String systemStr = null;
String installerPackageName = null;
+ String volumeUuid = null;
String uidError = null;
int pkgFlags = 0;
int pkgPrivateFlags = 0;
@@ -2945,6 +2957,7 @@ final class Settings {
}
}
installerPackageName = parser.getAttributeValue(null, "installer");
+ volumeUuid = parser.getAttributeValue(null, "volumeUuid");
systemStr = parser.getAttributeValue(null, "publicFlags");
if (systemStr != null) {
@@ -3093,6 +3106,7 @@ final class Settings {
if (packageSetting != null) {
packageSetting.uidError = "true".equals(uidError);
packageSetting.installerPackageName = installerPackageName;
+ packageSetting.volumeUuid = volumeUuid;
packageSetting.legacyNativeLibraryPathString = legacyNativeLibraryPathStr;
packageSetting.primaryCpuAbiString = primaryCpuAbiString;
packageSetting.secondaryCpuAbiString = secondaryCpuAbiString;
@@ -3549,6 +3563,22 @@ final class Settings {
return null;
}
+ /**
+ * Return all {@link PackageSetting} that are actively installed on the
+ * given {@link VolumeInfo#fsUuid}.
+ */
+ List<PackageSetting> getVolumePackagesLPr(String volumeUuid) {
+ Preconditions.checkNotNull(volumeUuid);
+ ArrayList<PackageSetting> res = new ArrayList<>();
+ for (int i = 0; i < mPackages.size(); i++) {
+ final PackageSetting setting = mPackages.valueAt(i);
+ if (Objects.equals(volumeUuid, setting.volumeUuid)) {
+ res.add(setting);
+ }
+ }
+ return res;
+ }
+
static void printFlags(PrintWriter pw, int val, Object[] spec) {
pw.print("[ ");
for (int i=0; i<spec.length; i+=2) {
@@ -3755,6 +3785,10 @@ final class Settings {
pw.print(prefix); pw.print(" installerPackageName=");
pw.println(ps.installerPackageName);
}
+ if (ps.volumeUuid != null) {
+ pw.print(prefix); pw.print(" volumeUuid=");
+ pw.println(ps.volumeUuid);
+ }
pw.print(prefix); pw.print(" signatures="); pw.println(ps.signatures);
pw.print(prefix); pw.print(" installPermissionsFixed=");
pw.print(ps.installPermissionsFixed);
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index a204376..c8b6846 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -485,14 +485,19 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
- /**
- * @hide - to match hiding in superclass
- */
+ /** {@hide} */
@Override
public void movePackage(String packageName, IPackageMoveObserver observer, int flags) {
throw new UnsupportedOperationException();
}
+ /** {@hide} */
+ @Override
+ public void movePackageAndData(String packageName, String volumeUuid,
+ IPackageMoveObserver observer) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public String getInstallerPackageName(String packageName) {
throw new UnsupportedOperationException();