diff options
Diffstat (limited to 'services/core/java/com/android/server/MountService.java')
-rw-r--r-- | services/core/java/com/android/server/MountService.java | 143 |
1 files changed, 121 insertions, 22 deletions
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) { |