summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java41
-rw-r--r--core/java/android/app/ApplicationPackageManager.java2
-rw-r--r--core/java/android/os/storage/IMountService.java12
-rw-r--r--core/java/android/os/storage/StorageManager.java20
-rw-r--r--services/core/java/com/android/server/MountService.java143
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java18
6 files changed, 198 insertions, 38 deletions
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index b84b1e2..39de1dc7 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -30,7 +30,6 @@ 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;
@@ -237,8 +236,12 @@ public final class Pm {
return runForceDexOpt();
}
- if ("move".equals(op)) {
- return runMove();
+ if ("move-package".equals(op)) {
+ return runMovePackage();
+ }
+
+ if ("move-primary-storage".equals(op)) {
+ return runMovePrimaryStorage();
}
try {
@@ -1285,7 +1288,7 @@ public final class Pm {
}
}
- public int runMove() {
+ public int runMovePackage() {
final String packageName = nextArg();
String volumeUuid = nextArg();
if ("internal".equals(volumeUuid)) {
@@ -1313,6 +1316,33 @@ public final class Pm {
}
}
+ public int runMovePrimaryStorage() {
+ String volumeUuid = nextArg();
+ if ("internal".equals(volumeUuid)) {
+ volumeUuid = null;
+ }
+
+ try {
+ final int moveId = mPm.movePrimaryStorage(volumeUuid);
+
+ int status = mPm.getMoveStatus(moveId);
+ while (!PackageManager.isMoveStatusFinished(status)) {
+ SystemClock.sleep(DateUtils.SECOND_IN_MILLIS);
+ status = mPm.getMoveStatus(moveId);
+ }
+
+ if (status == PackageManager.MOVE_SUCCEEDED) {
+ System.out.println("Success");
+ return 0;
+ } else {
+ System.err.println("Failure [" + status + "]");
+ return 1;
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
private int runUninstall() throws RemoteException {
int flags = 0;
int userId = UserHandle.USER_ALL;
@@ -1860,7 +1890,8 @@ 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 move-package PACKAGE [internal|UUID]");
+ System.err.println(" pm move-primary-storage [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 10f5960..16a2430 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1556,6 +1556,7 @@ final class ApplicationPackageManager extends PackageManager {
}
}
+ @Override
public @Nullable VolumeInfo getPrimaryStorageCurrentVolume() {
final StorageManager storage = mContext.getSystemService(StorageManager.class);
final String volumeUuid = storage.getPrimaryStorageUuid();
@@ -1568,6 +1569,7 @@ final class ApplicationPackageManager extends PackageManager {
}
}
+ @Override
public @NonNull List<VolumeInfo> getPrimaryStorageCandidateVolumes() {
final StorageManager storage = mContext.getSystemService(StorageManager.class);
final VolumeInfo currentVol = getPrimaryStorageCurrentVolume();
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 0b1031c..16e0bf7 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -16,6 +16,7 @@
package android.os.storage;
+import android.content.pm.IPackageMoveObserver;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
@@ -1082,12 +1083,14 @@ public interface IMountService extends IInterface {
}
@Override
- public void setPrimaryStorageUuid(String volumeUuid) throws RemoteException {
+ public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
+ throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(volumeUuid);
+ _data.writeStrongBinder((callback != null ? callback.asBinder() : null));
mRemote.transact(Stub.TRANSACTION_setPrimaryStorageUuid, _data, _reply, 0);
_reply.readException();
} finally {
@@ -1714,7 +1717,9 @@ public interface IMountService extends IInterface {
case TRANSACTION_setPrimaryStorageUuid: {
data.enforceInterface(DESCRIPTOR);
String volumeUuid = data.readString();
- setPrimaryStorageUuid(volumeUuid);
+ IPackageMoveObserver listener = IPackageMoveObserver.Stub.asInterface(
+ data.readStrongBinder());
+ setPrimaryStorageUuid(volumeUuid, listener);
reply.writeNoException();
return true;
}
@@ -2020,5 +2025,6 @@ public interface IMountService extends IInterface {
public void setVolumeUserFlags(String volId, int flags, int mask) throws RemoteException;
public String getPrimaryStorageUuid() throws RemoteException;
- public void setPrimaryStorageUuid(String volumeUuid) throws RemoteException;
+ public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
+ throws RemoteException;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 747fb40..6116aef 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -22,6 +22,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.IPackageMoveObserver;
+import android.content.pm.PackageManager;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
@@ -642,7 +644,12 @@ public class StorageManager {
}
}
- /** {@hide} */
+ /**
+ * This is not the API you're looking for.
+ *
+ * @see PackageManager#getPrimaryStorageCurrentVolume()
+ * @hide
+ */
public String getPrimaryStorageUuid() {
try {
return mMountService.getPrimaryStorageUuid();
@@ -651,10 +658,15 @@ public class StorageManager {
}
}
- /** {@hide} */
- public void setPrimaryStorageUuid(String volumeUuid) {
+ /**
+ * This is not the API you're looking for.
+ *
+ * @see PackageManager#movePrimaryStorage(VolumeInfo)
+ * @hide
+ */
+ public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
try {
- mMountService.setPrimaryStorageUuid(volumeUuid);
+ mMountService.setPrimaryStorageUuid(volumeUuid, callback);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 81088c4..7172ab7 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -30,6 +30,8 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.IPackageMoveObserver;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.ObbInfo;
import android.mtp.MtpStorage;
@@ -178,6 +180,9 @@ class MountService extends IMountService.Stub
/** Maximum number of ASEC containers allowed to be mounted. */
private static final int MAX_CONTAINERS = 250;
+ /** Magic value sent by MoveTask.cpp */
+ private static final int MOVE_STATUS_COPY_FINISHED = 82;
+
/*
* Internal vold response code constants
*/
@@ -226,6 +231,8 @@ class MountService extends IMountService.Stub
public static final int VOLUME_PATH_CHANGED = 655;
public static final int VOLUME_DESTROYED = 659;
+ public static final int MOVE_STATUS = 660;
+
/*
* 700 series - fstrim
*/
@@ -314,6 +321,11 @@ class MountService extends IMountService.Stub
@GuardedBy("mLock")
private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
+ @GuardedBy("mLock")
+ private IPackageMoveObserver mMoveCallback;
+ @GuardedBy("mLock")
+ private String mMoveTargetUuid;
+
private DiskInfo findDiskById(String id) {
synchronized (mLock) {
final DiskInfo disk = mDisks.get(id);
@@ -347,6 +359,17 @@ class MountService extends IMountService.Stub
throw new IllegalArgumentException("No volume found for path " + path);
}
+ private VolumeInfo findStorageForUuid(String volumeUuid) {
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
+ return findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
+ } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
+ return storage.getPrimaryPhysicalVolume();
+ } else {
+ return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
+ }
+ }
+
private VolumeMetadata findOrCreateMetadataLocked(VolumeInfo vol) {
VolumeMetadata meta = mMetadata.get(vol.fsUuid);
if (meta == null) {
@@ -937,6 +960,12 @@ class MountService extends IMountService.Stub
break;
}
+ case VoldResponseCode.MOVE_STATUS: {
+ final int status = Integer.parseInt(cooked[1]);
+ onMoveStatusLocked(status);
+ break;
+ }
+
case VoldResponseCode.FstrimCompleted: {
EventLogTags.writeFstrimFinish(SystemClock.elapsedRealtime());
break;
@@ -972,24 +1001,36 @@ class MountService extends IMountService.Stub
}
private void onVolumeCreatedLocked(VolumeInfo vol) {
- final boolean primaryPhysical = SystemProperties.getBoolean(
- StorageManager.PROP_PRIMARY_PHYSICAL, false);
- // TODO: enable switching to another emulated primary
- if (VolumeInfo.ID_EMULATED_INTERNAL.equals(vol.id) && !primaryPhysical) {
- vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
- vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
- mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
+ if (vol.type == VolumeInfo.TYPE_EMULATED) {
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
+
+ if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
+ && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
+ Slog.v(TAG, "Found primary storage at " + vol);
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
+
+ } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
+ Slog.v(TAG, "Found primary storage at " + vol);
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
+ }
} else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
- if (primaryPhysical) {
+ // TODO: only look at first public partition
+ if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
+ && vol.disk.isDefaultPrimary()) {
+ Slog.v(TAG, "Found primary storage at " + vol);
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
}
// Adoptable public disks are visible to apps, since they meet
// public API requirement of being in a stable location.
- final DiskInfo disk = mDisks.get(vol.getDiskId());
- if (disk != null && disk.isAdoptable()) {
+ if (vol.disk.isAdoptable()) {
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
}
@@ -1066,6 +1107,35 @@ class MountService extends IMountService.Stub
}
}
+ private void onMoveStatusLocked(int status) {
+ if (mMoveCallback == null) {
+ Slog.w(TAG, "Odd, status but no move requested");
+ return;
+ }
+
+ // TODO: estimate remaining time
+ try {
+ mMoveCallback.onStatusChanged(-1, status, -1);
+ } catch (RemoteException ignored) {
+ }
+
+ // We've finished copying and we're about to clean up old data, so
+ // remember that move was successful if we get rebooted
+ if (status == MOVE_STATUS_COPY_FINISHED) {
+ Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
+
+ mPrimaryStorageUuid = mMoveTargetUuid;
+ writeMetadataLocked();
+ }
+
+ if (PackageManager.isMoveStatusFinished(status)) {
+ Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
+
+ mMoveCallback = null;
+ mMoveTargetUuid = null;
+ }
+ }
+
/**
* Refresh latest metadata into any currently active {@link VolumeInfo}.
*/
@@ -1322,12 +1392,17 @@ class MountService extends IMountService.Stub
final VolumeInfo vol = findVolumeById(volId);
// TODO: expand PMS to know about multiple volumes
- if (vol.isPrimary()) {
- synchronized (mUnmountLock) {
- mUnmountSignal = new CountDownLatch(1);
- mPms.updateExternalMediaStatus(false, true);
- waitForLatch(mUnmountSignal, "mUnmountSignal");
- mUnmountSignal = null;
+ if (vol.isPrimaryPhysical()) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mUnmountLock) {
+ mUnmountSignal = new CountDownLatch(1);
+ mPms.updateExternalMediaStatus(false, true);
+ waitForLatch(mUnmountSignal, "mUnmountSignal");
+ mUnmountSignal = null;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -1424,20 +1499,41 @@ class MountService extends IMountService.Stub
}
@Override
- public String getPrimaryStorageUuid() throws RemoteException {
+ public String getPrimaryStorageUuid() {
+ enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+ waitForReady();
+
synchronized (mLock) {
return mPrimaryStorageUuid;
}
}
@Override
- public void setPrimaryStorageUuid(String volumeUuid) throws RemoteException {
+ public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
+ enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+ waitForReady();
+
synchronized (mLock) {
- Slog.d(TAG, "Changing primary storage UUID to " + volumeUuid);
- mPrimaryStorageUuid = volumeUuid;
- writeMetadataLocked();
+ final VolumeInfo from = Preconditions.checkNotNull(
+ findStorageForUuid(mPrimaryStorageUuid));
+ final VolumeInfo to = Preconditions.checkNotNull(
+ findStorageForUuid(volumeUuid));
- // TODO: reevaluate all volumes we know about!
+ if (Objects.equals(from, to)) {
+ throw new IllegalArgumentException("Primary storage already at " + from);
+ }
+
+ if (mMoveCallback != null) {
+ throw new IllegalStateException("Move already in progress");
+ }
+ mMoveCallback = callback;
+ mMoveTargetUuid = volumeUuid;
+
+ try {
+ mConnector.execute("volume", "move_storage", from.id, to.id);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
}
}
@@ -2875,6 +2971,9 @@ class MountService extends IMountService.Stub
meta.dump(pw);
}
pw.decreaseIndent();
+
+ pw.println();
+ pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
}
synchronized (mObbMounts) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bd22524..f087c33 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -14307,12 +14307,22 @@ public class PackageManagerService extends IPackageManager.Stub {
public int movePrimaryStorage(String volumeUuid) throws RemoteException {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
- final int moveId = mNextMoveId.getAndIncrement();
+ final int realMoveId = mNextMoveId.getAndIncrement();
+ final IPackageMoveObserver callback = new IPackageMoveObserver.Stub() {
+ @Override
+ public void onStarted(int moveId, String title) {
+ // Ignored
+ }
- // TODO: ask mountservice to take down both, connect over to DCS to
- // migrate, and then bring up new storage
+ @Override
+ public void onStatusChanged(int moveId, int status, long estMillis) {
+ mMoveCallbacks.notifyStatusChanged(realMoveId, status, estMillis);
+ }
+ };
- return moveId;
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ storage.setPrimaryStorageUuid(volumeUuid, callback);
+ return realMoveId;
}
@Override