summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2015-04-05 21:10:42 -0700
committerJeff Sharkey <jsharkey@android.com>2015-04-06 21:17:58 -0700
commitb2b9ab8354da1485178cd8d8e9d89ac915b3f269 (patch)
tree3d58a32b4ef47c632e5aebebee34e143d1d8cc5a
parentb9223015261afdec7e8686b732b298b809bf87dc (diff)
downloadframeworks_base-b2b9ab8354da1485178cd8d8e9d89ac915b3f269.zip
frameworks_base-b2b9ab8354da1485178cd8d8e9d89ac915b3f269.tar.gz
frameworks_base-b2b9ab8354da1485178cd8d8e9d89ac915b3f269.tar.bz2
Installing packages to expanded storage.
PackageManager now offers to load/unload packages when expanded volumes are mounted/unmounted. Expanded storage volumes are still treated as FLAG_EXTERNAL_STORAGE from a public API point-of-view, but this change starts treating the INSTALL_EXTERNAL flag as exclusively meaning ASEC containers. Start tracking the UUID of the volume where a package is installed, giving us a quick way to find relevant packages. When resolving an install location, look across all expanded volumes and pick the one with the largest free space. When upgrading an existing package, continue preferring the existing volume. PackageInstaller now knows how to stage on these volumes. Add new movePackage() variant that accepts a target volume UUID as destination, it will eventually move data too. Expose this move command through "pm" command for testing. Automount expanded volumes when they appear. Bug: 19993667 Change-Id: I9ca2aa328b9977d34e8b3e153db4bea8b8d6f8e3
-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();