summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ApplicationPackageManager.java39
-rw-r--r--core/java/android/content/pm/IPackageMoveObserver.aidl5
-rw-r--r--core/java/android/content/pm/PackageManager.java4
-rw-r--r--core/java/android/os/Environment.java3
-rw-r--r--core/java/android/os/FileUtils.java2
-rw-r--r--core/java/android/os/storage/IMountServiceListener.java40
-rw-r--r--core/java/android/os/storage/StorageEventListener.java5
-rw-r--r--core/java/android/os/storage/StorageManager.java61
-rw-r--r--core/java/android/os/storage/VolumeInfo.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java157
-rw-r--r--services/core/java/com/android/server/MountService.java78
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java68
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) {