diff options
12 files changed, 370 insertions, 109 deletions
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 6e511f38f7e7..90293a48949f 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -62,6 +62,7 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -1561,13 +1562,7 @@ final class ApplicationPackageManager extends PackageManager { public @Nullable VolumeInfo getPrimaryStorageCurrentVolume() { final StorageManager storage = mContext.getSystemService(StorageManager.class); final String volumeUuid = storage.getPrimaryStorageUuid(); - if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) { - return storage.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL); - } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) { - return storage.getPrimaryPhysicalVolume(); - } else { - return storage.findVolumeByUuid(volumeUuid); - } + return storage.findVolumeByQualifiedUuid(volumeUuid); } @Override @@ -2055,7 +2050,8 @@ final class ApplicationPackageManager extends PackageManager { /** {@hide} */ private static class MoveCallbackDelegate extends IPackageMoveObserver.Stub implements Handler.Callback { - private static final int MSG_STATUS_CHANGED = 1; + private static final int MSG_CREATED = 1; + private static final int MSG_STATUS_CHANGED = 2; final MoveCallback mCallback; final Handler mHandler; @@ -2068,23 +2064,36 @@ final class ApplicationPackageManager extends PackageManager { @Override public boolean handleMessage(Message msg) { switch (msg.what) { - case MSG_STATUS_CHANGED: + case MSG_CREATED: { + final SomeArgs args = (SomeArgs) msg.obj; + mCallback.onCreated(args.argi1, (Bundle) args.arg2); + args.recycle(); + return true; + } + case MSG_STATUS_CHANGED: { final SomeArgs args = (SomeArgs) msg.obj; - mCallback.onStatusChanged(args.argi1, (String) args.arg2, args.argi3, - (long) args.arg4); + mCallback.onStatusChanged(args.argi1, args.argi2, (long) args.arg3); args.recycle(); return true; + } } return false; } @Override - public void onStatusChanged(int moveId, String moveTitle, int status, long estMillis) { + public void onCreated(int moveId, Bundle extras) { + final SomeArgs args = SomeArgs.obtain(); + args.argi1 = moveId; + args.arg2 = extras; + mHandler.obtainMessage(MSG_CREATED, args).sendToTarget(); + } + + @Override + public void onStatusChanged(int moveId, int status, long estMillis) { final SomeArgs args = SomeArgs.obtain(); args.argi1 = moveId; - args.arg2 = moveTitle; - args.argi3 = status; - args.arg4 = estMillis; + args.argi2 = status; + args.arg3 = estMillis; mHandler.obtainMessage(MSG_STATUS_CHANGED, args).sendToTarget(); } } diff --git a/core/java/android/content/pm/IPackageMoveObserver.aidl b/core/java/android/content/pm/IPackageMoveObserver.aidl index 155ed0bf57d8..86189fce1fd6 100644 --- a/core/java/android/content/pm/IPackageMoveObserver.aidl +++ b/core/java/android/content/pm/IPackageMoveObserver.aidl @@ -17,10 +17,13 @@ package android.content.pm; +import android.os.Bundle; + /** * Callback for moving package resources from the Package Manager. * @hide */ oneway interface IPackageMoveObserver { - void onStatusChanged(int moveId, String moveTitle, int status, long estMillis); + void onCreated(int moveId, in Bundle extras); + void onStatusChanged(int moveId, int status, long estMillis); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index a1ee7fcf83a9..7ff6ec38699f 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -4212,8 +4212,8 @@ public abstract class PackageManager { /** {@hide} */ public static abstract class MoveCallback { - public abstract void onStatusChanged(int moveId, String moveTitle, int status, - long estMillis); + public void onCreated(int moveId, Bundle extras) {} + public abstract void onStatusChanged(int moveId, int status, long estMillis); } /** {@hide} */ diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 2eb97f14fc81..e3e16eb1747b 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -758,7 +758,6 @@ public class Environment { * @hide */ public static File maybeTranslateEmulatedPathToInternal(File path) { - // TODO: bring back this optimization - return path; + return StorageManager.maybeTranslateEmulatedPathToInternal(path); } } diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 931cd3e6a1d5..021e5e4cdd6d 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -390,7 +390,7 @@ public class FileUtils { * attacks. */ public static boolean contains(File dir, File file) { - if (file == null) return false; + if (dir == null || file == null) return false; String dirPath = dir.getAbsolutePath(); String filePath = file.getAbsolutePath(); diff --git a/core/java/android/os/storage/IMountServiceListener.java b/core/java/android/os/storage/IMountServiceListener.java index 2d13e497d010..c958fb0bcd0d 100644 --- a/core/java/android/os/storage/IMountServiceListener.java +++ b/core/java/android/os/storage/IMountServiceListener.java @@ -91,10 +91,17 @@ public interface IMountServiceListener extends IInterface { reply.writeNoException(); return true; } - case TRANSACTION_onVolumeMetadataChanged: { + case TRANSACTION_onVolumeRecordChanged: { + data.enforceInterface(DESCRIPTOR); + final VolumeRecord rec = (VolumeRecord) data.readParcelable(null); + onVolumeRecordChanged(rec); + reply.writeNoException(); + return true; + } + case TRANSACTION_onVolumeForgotten: { data.enforceInterface(DESCRIPTOR); final String fsUuid = data.readString(); - onVolumeMetadataChanged(fsUuid); + onVolumeForgotten(fsUuid); reply.writeNoException(); return true; } @@ -192,13 +199,29 @@ public interface IMountServiceListener extends IInterface { } @Override - public void onVolumeMetadataChanged(String fsUuid) throws RemoteException { + public void onVolumeRecordChanged(VolumeRecord rec) throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeParcelable(rec, 0); + mRemote.transact(Stub.TRANSACTION_onVolumeRecordChanged, _data, _reply, + android.os.IBinder.FLAG_ONEWAY); + _reply.readException(); + } finally { + _reply.recycle(); + _data.recycle(); + } + } + + @Override + public void onVolumeForgotten(String fsUuid) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(fsUuid); - mRemote.transact(Stub.TRANSACTION_onVolumeMetadataChanged, _data, _reply, + mRemote.transact(Stub.TRANSACTION_onVolumeForgotten, _data, _reply, android.os.IBinder.FLAG_ONEWAY); _reply.readException(); } finally { @@ -228,8 +251,9 @@ public interface IMountServiceListener extends IInterface { static final int TRANSACTION_onUsbMassStorageConnectionChanged = (IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_onStorageStateChanged = (IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_onVolumeStateChanged = (IBinder.FIRST_CALL_TRANSACTION + 2); - static final int TRANSACTION_onVolumeMetadataChanged = (IBinder.FIRST_CALL_TRANSACTION + 3); - static final int TRANSACTION_onDiskScanned = (IBinder.FIRST_CALL_TRANSACTION + 4); + static final int TRANSACTION_onVolumeRecordChanged = (IBinder.FIRST_CALL_TRANSACTION + 3); + static final int TRANSACTION_onVolumeForgotten = (IBinder.FIRST_CALL_TRANSACTION + 4); + static final int TRANSACTION_onDiskScanned = (IBinder.FIRST_CALL_TRANSACTION + 5); } /** @@ -252,8 +276,8 @@ public interface IMountServiceListener extends IInterface { public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) throws RemoteException; - - public void onVolumeMetadataChanged(String fsUuid) throws RemoteException; + public void onVolumeRecordChanged(VolumeRecord rec) throws RemoteException; + public void onVolumeForgotten(String fsUuid) throws RemoteException; public void onDiskScanned(DiskInfo disk, int volumeCount) throws RemoteException; } diff --git a/core/java/android/os/storage/StorageEventListener.java b/core/java/android/os/storage/StorageEventListener.java index 536aca9b12c9..214c60d3bfb8 100644 --- a/core/java/android/os/storage/StorageEventListener.java +++ b/core/java/android/os/storage/StorageEventListener.java @@ -41,7 +41,10 @@ public class StorageEventListener { public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { } - public void onVolumeMetadataChanged(String fsUuid) { + public void onVolumeRecordChanged(VolumeRecord rec) { + } + + public void onVolumeForgotten(String fsUuid) { } public void onDiskScanned(DiskInfo disk, int volumeCount) { diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 29da4f1de64a..50e7d1c44718 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -93,8 +93,9 @@ public class StorageManager { Handler.Callback { private static final int MSG_STORAGE_STATE_CHANGED = 1; private static final int MSG_VOLUME_STATE_CHANGED = 2; - private static final int MSG_VOLUME_METADATA_CHANGED = 3; - private static final int MSG_DISK_SCANNED = 4; + private static final int MSG_VOLUME_RECORD_CHANGED = 3; + private static final int MSG_VOLUME_FORGOTTEN = 4; + private static final int MSG_DISK_SCANNED = 5; final StorageEventListener mCallback; final Handler mHandler; @@ -117,8 +118,12 @@ public class StorageManager { mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3); args.recycle(); return true; - case MSG_VOLUME_METADATA_CHANGED: - mCallback.onVolumeMetadataChanged((String) args.arg1); + case MSG_VOLUME_RECORD_CHANGED: + mCallback.onVolumeRecordChanged((VolumeRecord) args.arg1); + args.recycle(); + return true; + case MSG_VOLUME_FORGOTTEN: + mCallback.onVolumeForgotten((String) args.arg1); args.recycle(); return true; case MSG_DISK_SCANNED: @@ -154,10 +159,17 @@ public class StorageManager { } @Override - public void onVolumeMetadataChanged(String fsUuid) { + public void onVolumeRecordChanged(VolumeRecord rec) { + final SomeArgs args = SomeArgs.obtain(); + args.arg1 = rec; + mHandler.obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget(); + } + + @Override + public void onVolumeForgotten(String fsUuid) { final SomeArgs args = SomeArgs.obtain(); args.arg1 = fsUuid; - mHandler.obtainMessage(MSG_VOLUME_METADATA_CHANGED, args).sendToTarget(); + mHandler.obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget(); } @Override @@ -246,8 +258,9 @@ public class StorageManager { } /** {@hide} */ + @Deprecated public static StorageManager from(Context context) { - return (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); + return context.getSystemService(StorageManager.class); } /** @@ -536,6 +549,17 @@ public class StorageManager { } /** {@hide} */ + public @Nullable VolumeInfo findVolumeByQualifiedUuid(String volumeUuid) { + if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) { + return findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL); + } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) { + return getPrimaryPhysicalVolume(); + } else { + return findVolumeByUuid(volumeUuid); + } + } + + /** {@hide} */ public @NonNull List<VolumeInfo> getVolumes() { try { return Arrays.asList(mMountService.getVolumes(0)); @@ -555,6 +579,8 @@ public class StorageManager { /** {@hide} */ public @Nullable String getBestVolumeDescription(VolumeInfo vol) { + if (vol == null) return null; + // Nickname always takes precedence when defined if (!TextUtils.isEmpty(vol.fsUuid)) { final VolumeRecord rec = findRecordByUuid(vol.fsUuid); @@ -861,6 +887,27 @@ public class StorageManager { DEFAULT_FULL_THRESHOLD_BYTES); } + /** {@hide} */ + public static File maybeTranslateEmulatedPathToInternal(File path) { + final IMountService mountService = IMountService.Stub.asInterface( + ServiceManager.getService("mount")); + try { + final VolumeInfo[] vols = mountService.getVolumes(0); + for (VolumeInfo vol : vols) { + if ((vol.getType() == VolumeInfo.TYPE_EMULATED + || vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isMountedReadable()) { + final File internalPath = FileUtils.rewriteAfterRename(vol.getPath(), + vol.getInternalPath(), path); + if (internalPath != null) { + return internalPath; + } + } + } + } catch (RemoteException ignored) { + } + return path; + } + /// Consts to match the password types in cryptfs.h /** @hide */ public static final int CRYPT_TYPE_PASSWORD = 0; diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java index fd10cae780e3..2622ee04eaab 100644 --- a/core/java/android/os/storage/VolumeInfo.java +++ b/core/java/android/os/storage/VolumeInfo.java @@ -129,6 +129,7 @@ public class VolumeInfo implements Parcelable { public String fsUuid; public String fsLabel; public String path; + public String internalPath; /** Framework state */ public final int mtpIndex; @@ -155,6 +156,7 @@ public class VolumeInfo implements Parcelable { fsUuid = parcel.readString(); fsLabel = parcel.readString(); path = parcel.readString(); + internalPath = parcel.readString(); mtpIndex = parcel.readInt(); } @@ -248,7 +250,11 @@ public class VolumeInfo implements Parcelable { } public File getPath() { - return new File(path); + return (path != null) ? new File(path) : null; + } + + public File getInternalPath() { + return (internalPath != null) ? new File(internalPath) : null; } public File getPathForUser(int userId) { @@ -335,14 +341,11 @@ public class VolumeInfo implements Parcelable { final Uri uri; if (type == VolumeInfo.TYPE_PUBLIC) { uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY, fsUuid); - } else if (VolumeInfo.ID_EMULATED_INTERNAL.equals(id)) { + } else if (type == VolumeInfo.TYPE_EMULATED && isPrimary()) { uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY, DOCUMENT_ROOT_PRIMARY_EMULATED); - } else if (type == VolumeInfo.TYPE_EMULATED) { - // TODO: build intent once supported - uri = null; } else { - throw new IllegalArgumentException(); + return null; } final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT); @@ -372,6 +375,7 @@ public class VolumeInfo implements Parcelable { pw.printPair("fsLabel", fsLabel); pw.println(); pw.printPair("path", path); + pw.printPair("internalPath", internalPath); pw.printPair("mtpIndex", mtpIndex); pw.decreaseIndent(); pw.println(); @@ -437,6 +441,7 @@ public class VolumeInfo implements Parcelable { parcel.writeString(fsUuid); parcel.writeString(fsLabel); parcel.writeString(path); + parcel.writeString(internalPath); parcel.writeInt(mtpIndex); } } diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java index deed8957173d..e6c95b5dd1ea 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java +++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java @@ -26,6 +26,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.PackageManager.MoveCallback; +import android.os.Bundle; import android.os.Handler; import android.os.UserHandle; import android.os.storage.DiskInfo; @@ -36,6 +37,7 @@ import android.os.storage.VolumeRecord; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; +import android.util.SparseArray; import com.android.internal.R; import com.android.systemui.SystemUI; @@ -57,6 +59,16 @@ public class StorageNotification extends SystemUI { private NotificationManager mNotificationManager; private StorageManager mStorageManager; + private static class MoveInfo { + public int moveId; + public Bundle extras; + public String packageName; + public String label; + public String volumeUuid; + } + + private final SparseArray<MoveInfo> mMoves = new SparseArray<>(); + private final StorageEventListener mListener = new StorageEventListener() { @Override public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { @@ -64,20 +76,20 @@ public class StorageNotification extends SystemUI { } @Override - public void onVolumeMetadataChanged(String fsUuid) { + public void onVolumeRecordChanged(VolumeRecord rec) { // Avoid kicking notifications when getting early metadata before // mounted. If already mounted, we're being kicked because of a // nickname or init'ed change. - final VolumeInfo vol = mStorageManager.findVolumeByUuid(fsUuid); + final VolumeInfo vol = mStorageManager.findVolumeByUuid(rec.getFsUuid()); if (vol != null && vol.isMountedReadable()) { onVolumeStateChangedInternal(vol); } + } - final VolumeRecord rec = mStorageManager.findRecordByUuid(fsUuid); - if (rec == null) { - // Private volume was probably just forgotten - mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL); - } + @Override + public void onVolumeForgotten(String fsUuid) { + // Stop annoying the user + mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL); } @Override @@ -97,11 +109,30 @@ public class StorageNotification extends SystemUI { private final MoveCallback mMoveCallback = new MoveCallback() { @Override - public void onStatusChanged(int moveId, String moveTitle, int status, long estMillis) { + public void onCreated(int moveId, Bundle extras) { + final MoveInfo move = new MoveInfo(); + move.moveId = moveId; + move.extras = extras; + if (extras != null) { + move.packageName = extras.getString(Intent.EXTRA_PACKAGE_NAME); + move.label = extras.getString(Intent.EXTRA_TITLE); + move.volumeUuid = extras.getString(VolumeRecord.EXTRA_FS_UUID); + } + mMoves.put(moveId, move); + } + + @Override + public void onStatusChanged(int moveId, int status, long estMillis) { + final MoveInfo move = mMoves.get(moveId); + if (move == null) { + Log.w(TAG, "Ignoring unknown move " + moveId); + return; + } + if (PackageManager.isMoveStatusFinished(status)) { - onMoveFinished(moveId, moveTitle, status); + onMoveFinished(move, status); } else { - onMoveProgress(moveId, moveTitle, status, estMillis); + onMoveProgress(move, status, estMillis); } } }; @@ -149,10 +180,10 @@ public class StorageNotification extends SystemUI { .setColor(mContext.getColor(R.color.system_notification_accent_color)) .setContentTitle(title) .setContentText(text) + .setContentIntent(buildForgetPendingIntent(rec)) .setStyle(new Notification.BigTextStyle().bigText(text)) .setVisibility(Notification.VISIBILITY_PUBLIC) .setLocalOnly(true) - .setContentIntent(buildForgetPendingIntent(rec)) .setCategory(Notification.CATEGORY_SYSTEM) .setOngoing(true) .build(); @@ -175,10 +206,10 @@ public class StorageNotification extends SystemUI { .setColor(mContext.getColor(R.color.system_notification_accent_color)) .setContentTitle(title) .setContentText(text) + .setContentIntent(buildInitPendingIntent(disk)) .setStyle(new Notification.BigTextStyle().bigText(text)) .setVisibility(Notification.VISIBILITY_PUBLIC) .setLocalOnly(true) - .setContentIntent(buildInitPendingIntent(disk)) .setCategory(Notification.CATEGORY_ERROR) .build(); @@ -280,13 +311,13 @@ public class StorageNotification extends SystemUI { final CharSequence text = mContext.getString( R.string.ext_media_new_notification_message, disk.getDescription()); - final PendingIntent initAction = buildInitPendingIntent(vol); + final PendingIntent initIntent = buildInitPendingIntent(vol); return buildNotificationBuilder(vol, title, text) .addAction(new Action(0, mContext.getString(R.string.ext_media_init_action), - initAction)) + initIntent)) .addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action), buildUnmountPendingIntent(vol))) - .setContentIntent(initAction) + .setContentIntent(initIntent) .setDeleteIntent(buildSnoozeIntent(vol)) .setCategory(Notification.CATEGORY_SYSTEM) .build(); @@ -296,13 +327,13 @@ public class StorageNotification extends SystemUI { final CharSequence text = mContext.getString( R.string.ext_media_ready_notification_message, disk.getDescription()); - final PendingIntent browseAction = buildBrowsePendingIntent(vol); + final PendingIntent browseIntent = buildBrowsePendingIntent(vol); return buildNotificationBuilder(vol, title, text) .addAction(new Action(0, mContext.getString(R.string.ext_media_browse_action), - browseAction)) + browseIntent)) .addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action), buildUnmountPendingIntent(vol))) - .setContentIntent(browseAction) + .setContentIntent(browseIntent) .setDeleteIntent(buildSnoozeIntent(vol)) .setCategory(Notification.CATEGORY_SYSTEM) .setPriority(Notification.PRIORITY_LOW) @@ -337,7 +368,7 @@ public class StorageNotification extends SystemUI { R.string.ext_media_unmountable_notification_message, disk.getDescription()); return buildNotificationBuilder(vol, title, text) - .setContentIntent(buildDetailsPendingIntent(vol)) + .setContentIntent(buildVolumeSettingsPendingIntent(vol)) .setCategory(Notification.CATEGORY_ERROR) .build(); } @@ -376,10 +407,10 @@ public class StorageNotification extends SystemUI { .build(); } - private void onMoveProgress(int moveId, String moveTitle, int status, long estMillis) { + private void onMoveProgress(MoveInfo move, int status, long estMillis) { final CharSequence title; - if (!TextUtils.isEmpty(moveTitle)) { - title = mContext.getString(R.string.ext_media_move_specific_title, moveTitle); + if (!TextUtils.isEmpty(move.label)) { + title = mContext.getString(R.string.ext_media_move_specific_title, move.label); } else { title = mContext.getString(R.string.ext_media_move_title); } @@ -391,11 +422,19 @@ public class StorageNotification extends SystemUI { text = DateUtils.formatDuration(estMillis); } + final PendingIntent intent; + if (move.packageName != null) { + intent = buildWizardMovePendingIntent(move); + } else { + intent = buildWizardMigratePendingIntent(move); + } + final Notification notif = new Notification.Builder(mContext) .setSmallIcon(R.drawable.stat_notify_sdcard) .setColor(mContext.getColor(R.color.system_notification_accent_color)) .setContentTitle(title) .setContentText(text) + .setContentIntent(intent) .setStyle(new Notification.BigTextStyle().bigText(text)) .setVisibility(Notification.VISIBILITY_PUBLIC) .setLocalOnly(true) @@ -405,19 +444,19 @@ public class StorageNotification extends SystemUI { .setOngoing(true) .build(); - mNotificationManager.notifyAsUser(moveTitle, MOVE_ID, notif, UserHandle.ALL); + mNotificationManager.notifyAsUser(move.packageName, MOVE_ID, notif, UserHandle.ALL); } - private void onMoveFinished(int moveId, String moveTitle, int status) { - if (!TextUtils.isEmpty(moveTitle)) { + private void onMoveFinished(MoveInfo move, int status) { + if (move.packageName != null) { // We currently ignore finished app moves; just clear the last // published progress - mNotificationManager.cancelAsUser(moveTitle, MOVE_ID, UserHandle.ALL); + mNotificationManager.cancelAsUser(move.packageName, MOVE_ID, UserHandle.ALL); return; } - final VolumeInfo vol = mContext.getPackageManager().getPrimaryStorageCurrentVolume(); - final String descrip = mStorageManager.getBestVolumeDescription(vol); + final VolumeInfo privateVol = mContext.getPackageManager().getPrimaryStorageCurrentVolume(); + final String descrip = mStorageManager.getBestVolumeDescription(privateVol); final CharSequence title; final CharSequence text; @@ -429,19 +468,29 @@ public class StorageNotification extends SystemUI { text = mContext.getString(R.string.ext_media_move_failure_message); } + // Jump back into the wizard flow if we moved to a real disk + final PendingIntent intent; + if (privateVol != null && privateVol.getDisk() != null) { + intent = buildWizardReadyPendingIntent(privateVol.getDisk()); + } else { + intent = buildVolumeSettingsPendingIntent(privateVol); + } + final Notification notif = new Notification.Builder(mContext) .setSmallIcon(R.drawable.stat_notify_sdcard) .setColor(mContext.getColor(R.color.system_notification_accent_color)) .setContentTitle(title) .setContentText(text) + .setContentIntent(intent) .setStyle(new Notification.BigTextStyle().bigText(text)) .setVisibility(Notification.VISIBILITY_PUBLIC) .setLocalOnly(true) .setCategory(Notification.CATEGORY_SYSTEM) .setPriority(Notification.PRIORITY_LOW) + .setAutoCancel(true) .build(); - mNotificationManager.notifyAsUser(moveTitle, MOVE_ID, notif, UserHandle.ALL); + mNotificationManager.notifyAsUser(move.packageName, MOVE_ID, notif, UserHandle.ALL); } private int getSmallIcon(DiskInfo disk, int state) { @@ -513,10 +562,20 @@ public class StorageNotification extends SystemUI { PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT); } - private PendingIntent buildDetailsPendingIntent(VolumeInfo vol) { + private PendingIntent buildVolumeSettingsPendingIntent(VolumeInfo vol) { final Intent intent = new Intent(); - intent.setClassName("com.android.settings", - "com.android.settings.Settings$PublicVolumeSettingsActivity"); + switch (vol.getType()) { + case VolumeInfo.TYPE_PRIVATE: + intent.setClassName("com.android.settings", + "com.android.settings.Settings$PrivateVolumeSettingsActivity"); + break; + case VolumeInfo.TYPE_PUBLIC: + intent.setClassName("com.android.settings", + "com.android.settings.Settings$PublicVolumeSettingsActivity"); + break; + default: + return null; + } intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId()); final int requestKey = vol.getId().hashCode(); @@ -543,4 +602,38 @@ public class StorageNotification extends SystemUI { return PendingIntent.getActivityAsUser(mContext, requestKey, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT); } + + private PendingIntent buildWizardMigratePendingIntent(MoveInfo move) { + final Intent intent = new Intent(); + intent.setClassName("com.android.settings", + "com.android.settings.deviceinfo.StorageWizardMigrateProgress"); + intent.putExtra(PackageManager.EXTRA_MOVE_ID, move.moveId); + + final VolumeInfo vol = mStorageManager.findVolumeByQualifiedUuid(move.volumeUuid); + intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId()); + + return PendingIntent.getActivityAsUser(mContext, move.moveId, intent, + PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT); + } + + private PendingIntent buildWizardMovePendingIntent(MoveInfo move) { + final Intent intent = new Intent(); + intent.setClassName("com.android.settings", + "com.android.settings.deviceinfo.StorageWizardMoveProgress"); + intent.putExtra(PackageManager.EXTRA_MOVE_ID, move.moveId); + + return PendingIntent.getActivityAsUser(mContext, move.moveId, intent, + PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT); + } + + private PendingIntent buildWizardReadyPendingIntent(DiskInfo disk) { + final Intent intent = new Intent(); + intent.setClassName("com.android.settings", + "com.android.settings.deviceinfo.StorageWizardReady"); + intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.getId()); + + final int requestKey = disk.getId().hashCode(); + return PendingIntent.getActivityAsUser(mContext, requestKey, intent, + PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT); + } } diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index 74adeb7f5b96..0925fa52e524 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -229,6 +229,7 @@ class MountService extends IMountService.Stub public static final int VOLUME_FS_UUID_CHANGED = 653; public static final int VOLUME_FS_LABEL_CHANGED = 654; public static final int VOLUME_PATH_CHANGED = 655; + public static final int VOLUME_INTERNAL_PATH_CHANGED = 656; public static final int VOLUME_DESTROYED = 659; public static final int MOVE_STATUS = 660; @@ -661,6 +662,9 @@ class MountService extends IMountService.Stub try { mConnector.execute("volume", "reset"); + for (int userId : mStartedUsers) { + mConnector.execute("volume", "start_user", userId); + } } catch (NativeDaemonConnectorException e) { Slog.w(TAG, "Failed to reset vold", e); } @@ -902,6 +906,14 @@ class MountService extends IMountService.Stub } break; } + case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: { + if (cooked.length != 3) break; + final VolumeInfo vol = mVolumes.get(cooked[1]); + if (vol != null) { + vol.internalPath = cooked[2]; + } + break; + } case VoldResponseCode.VOLUME_DESTROYED: { if (cooked.length != 2) break; mVolumes.remove(cooked[1]); @@ -1076,7 +1088,7 @@ class MountService extends IMountService.Stub // TODO: estimate remaining time try { - mMoveCallback.onStatusChanged(-1, null, status, -1); + mMoveCallback.onStatusChanged(-1, status, -1); } catch (RemoteException ignored) { } @@ -1433,10 +1445,11 @@ class MountService extends IMountService.Stub enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); waitForReady(); + Preconditions.checkNotNull(fsUuid); synchronized (mLock) { final VolumeRecord rec = mRecords.get(fsUuid); rec.nickname = nickname; - mCallbacks.notifyVolumeMetadataChanged(fsUuid); + mCallbacks.notifyVolumeRecordChanged(rec); writeSettingsLocked(); } } @@ -1446,10 +1459,11 @@ class MountService extends IMountService.Stub enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); waitForReady(); + Preconditions.checkNotNull(fsUuid); synchronized (mLock) { final VolumeRecord rec = mRecords.get(fsUuid); rec.userFlags = (rec.userFlags & ~mask) | (flags & mask); - mCallbacks.notifyVolumeMetadataChanged(fsUuid); + mCallbacks.notifyVolumeRecordChanged(rec); writeSettingsLocked(); } } @@ -1459,10 +1473,36 @@ class MountService extends IMountService.Stub enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); waitForReady(); + Preconditions.checkNotNull(fsUuid); synchronized (mLock) { mRecords.remove(fsUuid); - mCallbacks.notifyVolumeMetadataChanged(fsUuid); + + // TODO: tell vold to forget keys + + // If this had been primary storage, revert back to internal and + // reset vold so we bind into new volume into place. + if (Objects.equals(mPrimaryStorageUuid, fsUuid)) { + mPrimaryStorageUuid = StorageManager.UUID_PRIVATE_INTERNAL; + resetIfReadyAndConnected(); + } + + mCallbacks.notifyVolumeForgotten(fsUuid); + writeSettingsLocked(); + } + } + + private void forgetAll() { + synchronized (mLock) { + for (int i = 0; i < mRecords.size(); i++) { + final String fsUuid = mRecords.keyAt(i); + mCallbacks.notifyVolumeForgotten(fsUuid); + } + + mRecords.clear(); writeSettingsLocked(); + + mPrimaryStorageUuid = StorageManager.UUID_PRIVATE_INTERNAL; + resetIfReadyAndConnected(); } } @@ -2818,8 +2858,9 @@ class MountService extends IMountService.Stub private static class Callbacks extends Handler { private static final int MSG_STORAGE_STATE_CHANGED = 1; private static final int MSG_VOLUME_STATE_CHANGED = 2; - private static final int MSG_VOLUME_METADATA_CHANGED = 3; - private static final int MSG_DISK_SCANNED = 4; + private static final int MSG_VOLUME_RECORD_CHANGED = 3; + private static final int MSG_VOLUME_FORGOTTEN = 4; + private static final int MSG_DISK_SCANNED = 5; private final RemoteCallbackList<IMountServiceListener> mCallbacks = new RemoteCallbackList<>(); @@ -2863,8 +2904,12 @@ class MountService extends IMountService.Stub callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3); break; } - case MSG_VOLUME_METADATA_CHANGED: { - callback.onVolumeMetadataChanged((String) args.arg1); + case MSG_VOLUME_RECORD_CHANGED: { + callback.onVolumeRecordChanged((VolumeRecord) args.arg1); + break; + } + case MSG_VOLUME_FORGOTTEN: { + callback.onVolumeForgotten((String) args.arg1); break; } case MSG_DISK_SCANNED: { @@ -2890,10 +2935,16 @@ class MountService extends IMountService.Stub obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget(); } - private void notifyVolumeMetadataChanged(String fsUuid) { + private void notifyVolumeRecordChanged(VolumeRecord rec) { + final SomeArgs args = SomeArgs.obtain(); + args.arg1 = rec.clone(); + obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget(); + } + + private void notifyVolumeForgotten(String fsUuid) { final SomeArgs args = SomeArgs.obtain(); args.arg1 = fsUuid; - obtainMessage(MSG_VOLUME_METADATA_CHANGED, args).sendToTarget(); + obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget(); } private void notifyDiskScanned(DiskInfo disk, int volumeCount) { @@ -2909,11 +2960,8 @@ class MountService extends IMountService.Stub mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); for (String arg : args) { - if ("--clear".equals(arg)) { - synchronized (mLock) { - mRecords.clear(); - writeSettingsLocked(); - } + if ("--forget-all".equals(arg)) { + forgetAll(); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 8a190568509f..453b8177ee20 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -155,6 +155,7 @@ import android.os.storage.IMountService; import android.os.storage.StorageEventListener; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; +import android.os.storage.VolumeRecord; import android.security.KeyStore; import android.security.SystemKeyStore; import android.system.ErrnoException; @@ -1558,6 +1559,11 @@ public class PackageManagerService extends IPackageManager.Stub { } } } + + @Override + public void onVolumeForgotten(String fsUuid) { + // TODO: remove all packages hosted on this uuid + } }; private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int userId) { @@ -14203,7 +14209,7 @@ public class PackageManagerService extends IPackageManager.Stub { movePackageInternal(packageName, volumeUuid, moveId); } catch (PackageManagerException e) { Slog.d(TAG, "Failed to move " + packageName, e); - mMoveCallbacks.notifyStatusChanged(moveId, null, + mMoveCallbacks.notifyStatusChanged(moveId, PackageManager.MOVE_FAILED_INTERNAL_ERROR); } return moveId; @@ -14221,7 +14227,7 @@ public class PackageManagerService extends IPackageManager.Stub { final String packageAbiOverride; final int appId; final String seinfo; - final String moveTitle; + final String label; // reader synchronized (mPackages) { @@ -14251,9 +14257,14 @@ public class PackageManagerService extends IPackageManager.Stub { packageAbiOverride = ps.cpuAbiOverrideString; appId = UserHandle.getAppId(pkg.applicationInfo.uid); seinfo = pkg.applicationInfo.seinfo; - moveTitle = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo)); + label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo)); } + final Bundle extras = new Bundle(); + extras.putString(Intent.EXTRA_PACKAGE_NAME, packageName); + extras.putString(Intent.EXTRA_TITLE, label); + mMoveCallbacks.notifyCreated(moveId, extras); + int installFlags; final boolean moveData; @@ -14279,7 +14290,7 @@ public class PackageManagerService extends IPackageManager.Stub { } Slog.d(TAG, "Moving " + packageName + " from " + currentVolumeUuid + " to " + volumeUuid); - mMoveCallbacks.notifyStatusChanged(moveId, moveTitle, 10); + mMoveCallbacks.notifyStatusChanged(moveId, 10); if (moveData) { synchronized (mInstallLock) { @@ -14299,7 +14310,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } - mMoveCallbacks.notifyStatusChanged(moveId, moveTitle, 50); + mMoveCallbacks.notifyStatusChanged(moveId, 50); final IPackageInstallObserver2 installObserver = new IPackageInstallObserver2.Stub() { @Override @@ -14326,15 +14337,15 @@ public class PackageManagerService extends IPackageManager.Stub { final int status = PackageManager.installStatusToPublicStatus(returnCode); switch (status) { case PackageInstaller.STATUS_SUCCESS: - mMoveCallbacks.notifyStatusChanged(moveId, moveTitle, + mMoveCallbacks.notifyStatusChanged(moveId, PackageManager.MOVE_SUCCEEDED); break; case PackageInstaller.STATUS_FAILURE_STORAGE: - mMoveCallbacks.notifyStatusChanged(moveId, moveTitle, + mMoveCallbacks.notifyStatusChanged(moveId, PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE); break; default: - mMoveCallbacks.notifyStatusChanged(moveId, moveTitle, + mMoveCallbacks.notifyStatusChanged(moveId, PackageManager.MOVE_FAILED_INTERNAL_ERROR); break; } @@ -14357,12 +14368,19 @@ public class PackageManagerService extends IPackageManager.Stub { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null); final int realMoveId = mNextMoveId.getAndIncrement(); - final String realTitle = null; + final Bundle extras = new Bundle(); + extras.putString(VolumeRecord.EXTRA_FS_UUID, volumeUuid); + mMoveCallbacks.notifyCreated(realMoveId, extras); final IPackageMoveObserver callback = new IPackageMoveObserver.Stub() { @Override - public void onStatusChanged(int moveId, String title, int status, long estMillis) { - mMoveCallbacks.notifyStatusChanged(realMoveId, realTitle, status, estMillis); + public void onCreated(int moveId, Bundle extras) { + // Ignored + } + + @Override + public void onStatusChanged(int moveId, int status, long estMillis) { + mMoveCallbacks.notifyStatusChanged(realMoveId, status, estMillis); } }; @@ -14717,6 +14735,7 @@ public class PackageManagerService extends IPackageManager.Stub { } private static class MoveCallbacks extends Handler { + private static final int MSG_CREATED = 1; private static final int MSG_STATUS_CHANGED = 2; private final RemoteCallbackList<IPackageMoveObserver> @@ -14754,26 +14773,37 @@ public class PackageManagerService extends IPackageManager.Stub { private void invokeCallback(IPackageMoveObserver callback, int what, SomeArgs args) throws RemoteException { switch (what) { + case MSG_CREATED: { + callback.onCreated(args.argi1, (Bundle) args.arg2); + break; + } case MSG_STATUS_CHANGED: { - callback.onStatusChanged(args.argi1, (String) args.arg2, args.argi3, - (long) args.arg4); + callback.onStatusChanged(args.argi1, args.argi2, (long) args.arg3); break; } } } - private void notifyStatusChanged(int moveId, String moveTitle, int status) { - notifyStatusChanged(moveId, moveTitle, status, -1); + private void notifyCreated(int moveId, Bundle extras) { + Slog.v(TAG, "Move " + moveId + " created " + extras.toString()); + + final SomeArgs args = SomeArgs.obtain(); + args.argi1 = moveId; + args.arg2 = extras; + obtainMessage(MSG_CREATED, args).sendToTarget(); + } + + private void notifyStatusChanged(int moveId, int status) { + notifyStatusChanged(moveId, status, -1); } - private void notifyStatusChanged(int moveId, String moveTitle, int status, long estMillis) { + private void notifyStatusChanged(int moveId, int status, long estMillis) { Slog.v(TAG, "Move " + moveId + " status " + status); final SomeArgs args = SomeArgs.obtain(); args.argi1 = moveId; - args.arg2 = moveTitle; - args.argi3 = status; - args.arg4 = estMillis; + args.argi2 = status; + args.arg3 = estMillis; obtainMessage(MSG_STATUS_CHANGED, args).sendToTarget(); synchronized (mLastStatus) { |