Parcelable objects for Disk/Volume.
Will eventually be used by SystemUI and/or Settings.
Also fix SettingsProvider NPE.
Bug: 19993667, 19909433
Change-Id: Ie326849ac5f43ee35f728d9cc0e332b72292db70
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 2db976e..2eb97f1 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -80,11 +80,11 @@
public File[] getExternalDirs() {
final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId);
- final File[] dirs = new File[volumes.length];
+ final File[] files = new File[volumes.length];
for (int i = 0; i < volumes.length; i++) {
- dirs[i] = volumes[i].getPathFile();
+ files[i] = volumes[i].getPathFile();
}
- return dirs;
+ return files;
}
@Deprecated
diff --git a/core/java/android/os/storage/DiskInfo.aidl b/core/java/android/os/storage/DiskInfo.aidl
new file mode 100644
index 0000000..5126c19
--- /dev/null
+++ b/core/java/android/os/storage/DiskInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+parcelable DiskInfo;
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
new file mode 100644
index 0000000..d676b1e
--- /dev/null
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.DebugUtils;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Information about a physical disk which may contain one or more
+ * {@link VolumeInfo}.
+ *
+ * @hide
+ */
+public class DiskInfo implements Parcelable {
+ public static final int FLAG_ADOPTABLE = 1 << 0;
+ public static final int FLAG_DEFAULT_PRIMARY = 1 << 1;
+ public static final int FLAG_SD = 1 << 2;
+ public static final int FLAG_USB = 1 << 3;
+
+ public final String id;
+ public final int flags;
+ public long size;
+ public String label;
+ public String[] volumes;
+
+ public DiskInfo(String id, int flags) {
+ this.id = Preconditions.checkNotNull(id);
+ this.flags = flags;
+ }
+
+ public DiskInfo(Parcel parcel) {
+ id = parcel.readString();
+ flags = parcel.readInt();
+ size = parcel.readLong();
+ label = parcel.readString();
+ volumes = parcel.readStringArray();
+ }
+
+ public String getDescription(Context context) {
+ // TODO: splice vendor label into these strings
+ if ((flags & FLAG_SD) != 0) {
+ return context.getString(com.android.internal.R.string.storage_sd_card);
+ } else if ((flags & FLAG_USB) != 0) {
+ return context.getString(com.android.internal.R.string.storage_usb);
+ } else {
+ return null;
+ }
+ }
+
+// public void partitionPublic() throws NativeDaemonConnectorException {
+// mConnector.execute("volume", "partition", id, "public");
+// }
+//
+// public void partitionPrivate() throws NativeDaemonConnectorException {
+// mConnector.execute("volume", "partition", id, "private");
+// }
+//
+// public void partitionMixed(int frac) throws NativeDaemonConnectorException {
+// mConnector.execute("volume", "partition", id, "mixed", frac);
+// }
+
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("DiskInfo:");
+ pw.increaseIndent();
+ pw.printPair("id", id);
+ pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags));
+ pw.printPair("size", size);
+ pw.printPair("label", label);
+ pw.printPair("volumes", volumes);
+ pw.decreaseIndent();
+ pw.println();
+ }
+
+ public static final Creator<DiskInfo> CREATOR = new Creator<DiskInfo>() {
+ @Override
+ public DiskInfo createFromParcel(Parcel in) {
+ return new DiskInfo(in);
+ }
+
+ @Override
+ public DiskInfo[] newArray(int size) {
+ return new DiskInfo[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(id);
+ parcel.writeInt(flags);
+ parcel.writeLong(size);
+ parcel.writeString(label);
+ parcel.writeStringArray(volumes);
+ }
+}
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index fef12d1..4209ad4 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -904,6 +904,40 @@
}
return;
}
+
+ @Override
+ public DiskInfo[] getDisks() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ DiskInfo[] _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_getDisks, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.createTypedArray(DiskInfo.CREATOR);
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
+ @Override
+ public VolumeInfo[] getVolumes() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ VolumeInfo[] _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_getDisks, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.createTypedArray(VolumeInfo.CREATOR);
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
}
private static final String DESCRIPTOR = "IMountService";
@@ -996,6 +1030,10 @@
static final int TRANSACTION_waitForAsecScan = IBinder.FIRST_CALL_TRANSACTION + 43;
+ static final int TRANSACTION_getDisks = IBinder.FIRST_CALL_TRANSACTION + 44;
+
+ static final int TRANSACTION_getVolumes = IBinder.FIRST_CALL_TRANSACTION + 45;
+
/**
* Cast an IBinder object into an IMountService interface, generating a
* proxy if needed.
@@ -1421,6 +1459,20 @@
reply.writeNoException();
return true;
}
+ case TRANSACTION_getDisks: {
+ data.enforceInterface(DESCRIPTOR);
+ DiskInfo[] disks = getDisks();
+ reply.writeNoException();
+ reply.writeTypedArray(disks, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ return true;
+ }
+ case TRANSACTION_getVolumes: {
+ data.enforceInterface(DESCRIPTOR);
+ VolumeInfo[] volumes = getVolumes();
+ reply.writeNoException();
+ reply.writeTypedArray(volumes, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
}
@@ -1707,4 +1759,7 @@
public void runMaintenance() throws RemoteException;
public void waitForAsecScan() throws RemoteException;
+
+ public DiskInfo[] getDisks() throws RemoteException;
+ public VolumeInfo[] getVolumes() throws RemoteException;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 532bf2c..83559fa 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -33,14 +33,13 @@
import android.util.Log;
import android.util.SparseArray;
-import libcore.util.EmptyArray;
-
import com.android.internal.util.Preconditions;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@@ -64,6 +63,9 @@
public class StorageManager {
private static final String TAG = "StorageManager";
+ /** {@hide} */
+ public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
+
private final Context mContext;
private final ContentResolver mResolver;
@@ -555,6 +557,24 @@
}
/** {@hide} */
+ public @NonNull List<DiskInfo> getDisks() {
+ try {
+ return Arrays.asList(mMountService.getDisks());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /** {@hide} */
+ public @NonNull List<VolumeInfo> getVolumes() {
+ try {
+ return Arrays.asList(mMountService.getVolumes());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /** {@hide} */
public @Nullable StorageVolume getStorageVolume(File file) {
return getStorageVolume(getVolumeList(), file);
}
@@ -597,16 +617,9 @@
}
}
- /**
- * Returns list of all mountable volumes.
- * @hide
- */
+ /** {@hide} */
public @NonNull StorageVolume[] getVolumeList() {
- try {
- return mMountService.getVolumeList(mContext.getUserId());
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
- }
+ return getVolumeList(mContext.getUserId());
}
/** {@hide} */
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 0c391ca..d66e228 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -23,13 +23,17 @@
import android.os.UserHandle;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
import java.io.CharArrayWriter;
import java.io.File;
/**
- * Description of a storage volume and its capabilities, including the
- * filesystem path where it may be mounted.
+ * Information about a storage volume that may be mounted. This is a legacy
+ * specialization of {@link VolumeInfo} which describes the volume for a
+ * specific user.
+ * <p>
+ * This class may be deprecated in the future.
*
* @hide
*/
@@ -37,21 +41,16 @@
private final String mId;
private final int mStorageId;
-
private final File mPath;
- private final int mDescriptionId;
+ private final String mDescription;
private final boolean mPrimary;
private final boolean mRemovable;
private final boolean mEmulated;
private final long mMtpReserveSize;
private final boolean mAllowMassStorage;
- /** Maximum file size for the storage, or zero for no limit */
private final long mMaxFileSize;
- /** When set, indicates exclusive ownership of this volume */
private final UserHandle mOwner;
-
- private final String mUuid;
- private final String mUserLabel;
+ private final String mFsUuid;
private final String mState;
// StorageVolume extra for ACTION_MEDIA_REMOVED, ACTION_MEDIA_UNMOUNTED, ACTION_MEDIA_CHECKING,
@@ -59,30 +58,29 @@
// ACTION_MEDIA_BAD_REMOVAL, ACTION_MEDIA_UNMOUNTABLE and ACTION_MEDIA_EJECT broadcasts.
public static final String EXTRA_STORAGE_VOLUME = "storage_volume";
- public StorageVolume(String id, int storageId, File path, int descriptionId, boolean primary,
+ public StorageVolume(String id, int storageId, File path, String description, boolean primary,
boolean removable, boolean emulated, long mtpReserveSize, boolean allowMassStorage,
- long maxFileSize, UserHandle owner, String uuid, String userLabel, String state) {
- mId = id;
+ long maxFileSize, UserHandle owner, String fsUuid, String state) {
+ mId = Preconditions.checkNotNull(id);
mStorageId = storageId;
- mPath = path;
- mDescriptionId = descriptionId;
+ mPath = Preconditions.checkNotNull(path);
+ mDescription = Preconditions.checkNotNull(description);
mPrimary = primary;
mRemovable = removable;
mEmulated = emulated;
mMtpReserveSize = mtpReserveSize;
mAllowMassStorage = allowMassStorage;
mMaxFileSize = maxFileSize;
- mOwner = owner;
- mUuid = uuid;
- mUserLabel = userLabel;
- mState = state;
+ mOwner = Preconditions.checkNotNull(owner);
+ mFsUuid = fsUuid;
+ mState = Preconditions.checkNotNull(state);
}
private StorageVolume(Parcel in) {
mId = in.readString();
mStorageId = in.readInt();
mPath = new File(in.readString());
- mDescriptionId = in.readInt();
+ mDescription = in.readString();
mPrimary = in.readInt() != 0;
mRemovable = in.readInt() != 0;
mEmulated = in.readInt() != 0;
@@ -90,8 +88,7 @@
mAllowMassStorage = in.readInt() != 0;
mMaxFileSize = in.readLong();
mOwner = in.readParcelable(null);
- mUuid = in.readString();
- mUserLabel = in.readString();
+ mFsUuid = in.readString();
mState = in.readString();
}
@@ -118,11 +115,7 @@
* @return the volume description
*/
public String getDescription(Context context) {
- return context.getResources().getString(mDescriptionId);
- }
-
- public int getDescriptionId() {
- return mDescriptionId;
+ return mDescription;
}
public boolean isPrimary() {
@@ -196,7 +189,7 @@
}
public String getUuid() {
- return mUuid;
+ return mFsUuid;
}
/**
@@ -204,18 +197,18 @@
* parse or UUID is unknown.
*/
public int getFatVolumeId() {
- if (mUuid == null || mUuid.length() != 9) {
+ if (mFsUuid == null || mFsUuid.length() != 9) {
return -1;
}
try {
- return (int)Long.parseLong(mUuid.replace("-", ""), 16);
+ return (int) Long.parseLong(mFsUuid.replace("-", ""), 16);
} catch (NumberFormatException e) {
return -1;
}
}
public String getUserLabel() {
- return mUserLabel;
+ return mDescription;
}
public String getState() {
@@ -249,7 +242,7 @@
pw.printPair("mId", mId);
pw.printPair("mStorageId", mStorageId);
pw.printPair("mPath", mPath);
- pw.printPair("mDescriptionId", mDescriptionId);
+ pw.printPair("mDescription", mDescription);
pw.printPair("mPrimary", mPrimary);
pw.printPair("mRemovable", mRemovable);
pw.printPair("mEmulated", mEmulated);
@@ -257,8 +250,7 @@
pw.printPair("mAllowMassStorage", mAllowMassStorage);
pw.printPair("mMaxFileSize", mMaxFileSize);
pw.printPair("mOwner", mOwner);
- pw.printPair("mUuid", mUuid);
- pw.printPair("mUserLabel", mUserLabel);
+ pw.printPair("mFsUuid", mFsUuid);
pw.printPair("mState", mState);
pw.decreaseIndent();
}
@@ -285,7 +277,7 @@
parcel.writeString(mId);
parcel.writeInt(mStorageId);
parcel.writeString(mPath.toString());
- parcel.writeInt(mDescriptionId);
+ parcel.writeString(mDescription);
parcel.writeInt(mPrimary ? 1 : 0);
parcel.writeInt(mRemovable ? 1 : 0);
parcel.writeInt(mEmulated ? 1 : 0);
@@ -293,8 +285,7 @@
parcel.writeInt(mAllowMassStorage ? 1 : 0);
parcel.writeLong(mMaxFileSize);
parcel.writeParcelable(mOwner, flags);
- parcel.writeString(mUuid);
- parcel.writeString(mUserLabel);
+ parcel.writeString(mFsUuid);
parcel.writeString(mState);
}
}
diff --git a/core/java/android/os/storage/VolumeInfo.aidl b/core/java/android/os/storage/VolumeInfo.aidl
new file mode 100644
index 0000000..32d12da
--- /dev/null
+++ b/core/java/android/os/storage/VolumeInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+parcelable VolumeInfo;
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
new file mode 100644
index 0000000..22bf1e4
--- /dev/null
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+import android.content.Context;
+import android.content.Intent;
+import android.mtp.MtpStorage;
+import android.os.Environment;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.DebugUtils;
+import android.util.SparseArray;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
+
+import java.io.File;
+
+/**
+ * Information about a storage volume that may be mounted. A volume may be a
+ * partition on a physical {@link DiskInfo}, an emulated volume above some other
+ * storage medium, or a standalone container like an ASEC or OBB.
+ *
+ * @hide
+ */
+public class VolumeInfo implements Parcelable {
+ public static final String ID_EMULATED_INTERNAL = "emulated";
+
+ public static final int TYPE_PUBLIC = 0;
+ public static final int TYPE_PRIVATE = 1;
+ public static final int TYPE_EMULATED = 2;
+ public static final int TYPE_ASEC = 3;
+ public static final int TYPE_OBB = 4;
+
+ public static final int STATE_UNMOUNTED = 0;
+ public static final int STATE_MOUNTING = 1;
+ public static final int STATE_MOUNTED = 2;
+ public static final int STATE_FORMATTING = 3;
+ public static final int STATE_UNMOUNTING = 4;
+
+ public static final int FLAG_PRIMARY = 1 << 0;
+ public static final int FLAG_VISIBLE = 1 << 1;
+
+ public static SparseArray<String> sStateToEnvironment = new SparseArray<>();
+ public static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>();
+
+ static {
+ sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTED, Environment.MEDIA_UNMOUNTED);
+ sStateToEnvironment.put(VolumeInfo.STATE_MOUNTING, Environment.MEDIA_CHECKING);
+ sStateToEnvironment.put(VolumeInfo.STATE_MOUNTED, Environment.MEDIA_MOUNTED);
+ sStateToEnvironment.put(VolumeInfo.STATE_FORMATTING, Environment.MEDIA_UNMOUNTED);
+ sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTING, Environment.MEDIA_EJECTING);
+
+ sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTED, Intent.ACTION_MEDIA_UNMOUNTED);
+ sEnvironmentToBroadcast.put(Environment.MEDIA_CHECKING, Intent.ACTION_MEDIA_CHECKING);
+ sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED, Intent.ACTION_MEDIA_MOUNTED);
+ sEnvironmentToBroadcast.put(Environment.MEDIA_EJECTING, Intent.ACTION_MEDIA_EJECT);
+ }
+
+ /** vold state */
+ public final String id;
+ public final int type;
+ public int flags = 0;
+ public int userId = -1;
+ public int state = STATE_UNMOUNTED;
+ public String fsType;
+ public String fsUuid;
+ public String fsLabel;
+ public String path;
+
+ /** Framework state */
+ public final int mtpIndex;
+ public String nickname;
+
+ public DiskInfo disk;
+
+ public VolumeInfo(String id, int type, int mtpIndex) {
+ this.id = Preconditions.checkNotNull(id);
+ this.type = type;
+ this.mtpIndex = mtpIndex;
+ }
+
+ public VolumeInfo(Parcel parcel) {
+ id = parcel.readString();
+ type = parcel.readInt();
+ flags = parcel.readInt();
+ userId = parcel.readInt();
+ state = parcel.readInt();
+ fsType = parcel.readString();
+ fsUuid = parcel.readString();
+ fsLabel = parcel.readString();
+ path = parcel.readString();
+ mtpIndex = parcel.readInt();
+ nickname = parcel.readString();
+ }
+
+ public String getDescription(Context context) {
+ if (ID_EMULATED_INTERNAL.equals(id)) {
+ return context.getString(com.android.internal.R.string.storage_internal);
+ } else if (!TextUtils.isEmpty(nickname)) {
+ return nickname;
+ } else if (!TextUtils.isEmpty(fsLabel)) {
+ return fsLabel;
+ } else {
+ return null;
+ }
+ }
+
+ public boolean isPrimary() {
+ return (flags & FLAG_PRIMARY) != 0;
+ }
+
+ public boolean isVisible() {
+ return (flags & FLAG_VISIBLE) != 0;
+ }
+
+ public boolean isVisibleToUser(int userId) {
+ if (type == TYPE_PUBLIC && userId == this.userId) {
+ return isVisible();
+ } else if (type == TYPE_EMULATED) {
+ return isVisible();
+ } else {
+ return false;
+ }
+ }
+
+ public File getPathForUser(int userId) {
+ if (type == TYPE_PUBLIC && userId == this.userId) {
+ return new File(path);
+ } else if (type == TYPE_EMULATED) {
+ return new File(path, Integer.toString(userId));
+ } else {
+ return null;
+ }
+ }
+
+ public StorageVolume buildStorageVolume(Context context, int userId) {
+ final boolean removable;
+ final boolean emulated;
+ final boolean allowMassStorage = false;
+ final int mtpStorageId = MtpStorage.getStorageIdForIndex(mtpIndex);
+
+ File userPath = getPathForUser(userId);
+ if (userPath == null) {
+ userPath = new File("/dev/null");
+ }
+
+ String description = getDescription(context);
+ if (description == null) {
+ description = context.getString(android.R.string.unknownName);
+ }
+
+ String envState = sStateToEnvironment.get(state);
+ if (envState == null) {
+ envState = Environment.MEDIA_UNKNOWN;
+ }
+
+ long mtpReserveSize = 0;
+ long maxFileSize = 0;
+
+ if (type == TYPE_EMULATED) {
+ emulated = true;
+ mtpReserveSize = StorageManager.from(context).getStorageLowBytes(userPath);
+
+ if (ID_EMULATED_INTERNAL.equals(id)) {
+ removable = false;
+ } else {
+ removable = true;
+ }
+
+ } else if (type == TYPE_PUBLIC) {
+ emulated = false;
+ removable = true;
+
+ if ("vfat".equals(fsType)) {
+ maxFileSize = 4294967295L;
+ }
+
+ } else {
+ throw new IllegalStateException("Unexpected volume type " + type);
+ }
+
+ return new StorageVolume(id, mtpStorageId, userPath, description, isPrimary(), removable,
+ emulated, mtpReserveSize, allowMassStorage, maxFileSize, new UserHandle(userId),
+ fsUuid, envState);
+ }
+
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("VolumeInfo:");
+ pw.increaseIndent();
+ pw.printPair("id", id);
+ pw.printPair("type", DebugUtils.valueToString(getClass(), "TYPE_", type));
+ pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags));
+ pw.printPair("userId", userId);
+ pw.printPair("state", DebugUtils.valueToString(getClass(), "STATE_", state));
+ pw.println();
+ pw.printPair("fsType", fsType);
+ pw.printPair("fsUuid", fsUuid);
+ pw.printPair("fsLabel", fsLabel);
+ pw.println();
+ pw.printPair("path", path);
+ pw.printPair("mtpIndex", mtpIndex);
+ pw.decreaseIndent();
+ pw.println();
+ }
+
+ public static final Creator<VolumeInfo> CREATOR = new Creator<VolumeInfo>() {
+ @Override
+ public VolumeInfo createFromParcel(Parcel in) {
+ return new VolumeInfo(in);
+ }
+
+ @Override
+ public VolumeInfo[] newArray(int size) {
+ return new VolumeInfo[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(id);
+ parcel.writeInt(type);
+ parcel.writeInt(flags);
+ parcel.writeInt(userId);
+ parcel.writeInt(state);
+ parcel.writeString(fsType);
+ parcel.writeString(fsUuid);
+ parcel.writeString(fsLabel);
+ parcel.writeString(path);
+ parcel.writeInt(mtpIndex);
+ parcel.writeString(nickname);
+ }
+}
diff --git a/core/java/com/android/internal/util/IndentingPrintWriter.java b/core/java/com/android/internal/util/IndentingPrintWriter.java
index 6fddd09..f1add27 100644
--- a/core/java/com/android/internal/util/IndentingPrintWriter.java
+++ b/core/java/com/android/internal/util/IndentingPrintWriter.java
@@ -18,6 +18,7 @@
import java.io.PrintWriter;
import java.io.Writer;
+import java.util.Arrays;
/**
* Lightweight wrapper around {@link PrintWriter} that automatically indents
@@ -68,6 +69,10 @@
print(key + "=" + String.valueOf(value) + " ");
}
+ public void printPair(String key, Object[] value) {
+ print(key + "=" + Arrays.toString(value) + " ");
+ }
+
public void printHexPair(String key, int value) {
print(key + "=0x" + Integer.toHexString(value) + " ");
}
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index 7b8102b..3641ff5 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -38,7 +38,7 @@
public MtpStorage(StorageVolume volume, Context context) {
mStorageId = volume.getStorageId();
mPath = volume.getPath();
- mDescription = context.getResources().getString(volume.getDescriptionId());
+ mDescription = volume.getDescription(context);
mReserveSpace = volume.getMtpReserveSpace() * 1024L * 1024L;
mRemovable = volume.isRemovable();
mMaxFileSize = volume.getMaxFileSize();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 126b4aa..0d61606 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1502,15 +1502,15 @@
public void onPackageRemovedLocked(String packageName, int userId) {
final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
SettingsState globalSettings = mSettingsStates.get(globalKey);
- globalSettings.onPackageRemovedLocked(packageName);
+ if (globalSettings != null) globalSettings.onPackageRemovedLocked(packageName);
final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
SettingsState secureSettings = mSettingsStates.get(secureKey);
- secureSettings.onPackageRemovedLocked(packageName);
+ if (secureSettings != null) secureSettings.onPackageRemovedLocked(packageName);
final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
SettingsState systemSettings = mSettingsStates.get(systemKey);
- systemSettings.onPackageRemovedLocked(packageName);
+ if (systemSettings != null) systemSettings.onPackageRemovedLocked(packageName);
}
private SettingsState peekSettingsStateLocked(int key) {
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 61286e8..4d8cb90 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -42,6 +42,7 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.DiskInfo;
import android.os.storage.IMountService;
import android.os.storage.IMountServiceListener;
import android.os.storage.IMountShutdownObserver;
@@ -50,11 +51,11 @@
import android.os.storage.StorageManager;
import android.os.storage.StorageResultCode;
import android.os.storage.StorageVolume;
+import android.os.storage.VolumeInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
-import android.util.DebugUtils;
+import android.util.Log;
import android.util.Slog;
-import android.util.SparseArray;
import libcore.util.EmptyArray;
import libcore.util.HexEncoding;
@@ -68,7 +69,6 @@
import com.android.server.NativeDaemonConnector.Command;
import com.android.server.NativeDaemonConnector.SensitiveArg;
import com.android.server.pm.PackageManagerService;
-import com.google.android.collect.Lists;
import java.io.File;
import java.io.FileDescriptor;
@@ -143,7 +143,6 @@
}
private static final boolean LOCAL_LOGD = false;
- private static final boolean DEBUG_UNMOUNT = false;
private static final boolean DEBUG_EVENTS = false;
private static final boolean DEBUG_OBB = false;
@@ -157,8 +156,6 @@
/** Maximum number of ASEC containers allowed to be mounted. */
private static final int MAX_CONTAINERS = 250;
- private static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
-
/*
* Internal vold response code constants
*/
@@ -213,22 +210,6 @@
public static final int FstrimCompleted = 700;
}
- private static SparseArray<String> sStateToEnvironment = new SparseArray<>();
- private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>();
-
- static {
- sStateToEnvironment.put(Volume.STATE_UNMOUNTED, Environment.MEDIA_UNMOUNTED);
- sStateToEnvironment.put(Volume.STATE_MOUNTING, Environment.MEDIA_CHECKING);
- sStateToEnvironment.put(Volume.STATE_MOUNTED, Environment.MEDIA_MOUNTED);
- sStateToEnvironment.put(Volume.STATE_FORMATTING, Environment.MEDIA_UNMOUNTED);
- sStateToEnvironment.put(Volume.STATE_UNMOUNTING, Environment.MEDIA_EJECTING);
-
- sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTED, Intent.ACTION_MEDIA_UNMOUNTED);
- sEnvironmentToBroadcast.put(Environment.MEDIA_CHECKING, Intent.ACTION_MEDIA_CHECKING);
- sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED, Intent.ACTION_MEDIA_MOUNTED);
- sEnvironmentToBroadcast.put(Environment.MEDIA_EJECTING, Intent.ACTION_MEDIA_EJECT);
- }
-
/**
* <em>Never</em> hold the lock while performing downcalls into vold, since
* unsolicited events can suddenly appear to update data structures.
@@ -238,14 +219,15 @@
@GuardedBy("mLock")
private int[] mStartedUsers = EmptyArray.INT;
@GuardedBy("mLock")
- private ArrayMap<String, Disk> mDisks = new ArrayMap<>();
+ private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
@GuardedBy("mLock")
- private ArrayMap<String, Volume> mVolumes = new ArrayMap<>();
+ private ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
@Deprecated
- private Volume findVolumeByLegacyPath(String legacyPath) {
+ private VolumeInfo findVolumeByLegacyPath(String legacyPath) {
synchronized (mLock) {
- for (Volume vol : mVolumes.values()) {
+ for (int i = 0; i < mVolumes.size(); i++) {
+ final VolumeInfo vol = mVolumes.valueAt(i);
if (vol.path != null && legacyPath.startsWith(vol.path)) {
return vol;
}
@@ -255,198 +237,13 @@
return null;
}
- /**
- * Framework-side twin of android::vold::Disk
- */
- private class Disk {
- public static final int FLAG_ADOPTABLE = 1 << 0;
- public static final int FLAG_DEFAULT_PRIMARY = 1 << 1;
- public static final int FLAG_SD = 1 << 2;
- public static final int FLAG_USB = 1 << 3;
-
- public final String id;
- public final int flags;
- public long size;
- public String label;
-
- public ArrayList<Volume> volumes = new ArrayList<>();
-
- public Disk(String id, int flags) {
- this.id = id;
- this.flags = flags;
- }
-
- public void partitionPublic() throws NativeDaemonConnectorException {
- mConnector.execute("volume", "partition", id, "public");
- }
-
- public void partitionPrivate() throws NativeDaemonConnectorException {
- mConnector.execute("volume", "partition", id, "private");
- }
-
- public void partitionMixed(int frac) throws NativeDaemonConnectorException {
- mConnector.execute("volume", "partition", id, "mixed", frac);
- }
-
- public void dump(IndentingPrintWriter pw) {
- pw.println("Disk:");
- pw.increaseIndent();
- pw.printPair("id", id);
- pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags));
- pw.printPair("size", size);
- pw.printPair("label", label);
- pw.decreaseIndent();
- pw.println();
- }
- }
-
private static int sNextMtpIndex = 1;
- /**
- * Framework-side twin of android::vold::VolumeBase
- */
- private class Volume {
- public static final String ID_EMULATED_INTERNAL = "emulated";
-
- public static final int TYPE_PUBLIC = 0;
- public static final int TYPE_PRIVATE = 1;
- public static final int TYPE_EMULATED = 2;
- public static final int TYPE_ASEC = 3;
- public static final int TYPE_OBB = 4;
-
- public static final int STATE_UNMOUNTED = 0;
- public static final int STATE_MOUNTING = 1;
- public static final int STATE_MOUNTED = 2;
- public static final int STATE_FORMATTING = 3;
- public static final int STATE_UNMOUNTING = 4;
-
- public static final int FLAG_PRIMARY = 1 << 0;
- public static final int FLAG_VISIBLE = 1 << 1;
-
- /** vold state */
- public final String id;
- public final int type;
- public int flags = 0;
- public int userId = -1;
- public int state = STATE_UNMOUNTED;
- public String fsType;
- public String fsUuid;
- public String fsLabel;
- public String path = "/dev/null";
-
- /** Framework state */
- public final int mtpIndex;
-
- public Disk disk;
-
- public Volume(String id, int type) {
- this.id = id;
- this.type = type;
-
- if (ID_EMULATED_INTERNAL.equals(id)) {
- mtpIndex = 0;
- } else {
- mtpIndex = sNextMtpIndex++;
- }
- }
-
- public boolean isPrimary() {
- return (flags & FLAG_PRIMARY) != 0;
- }
-
- public boolean isVisible() {
- return (flags & FLAG_VISIBLE) != 0;
- }
-
- public boolean isVisibleToUser(int userId) {
- if (type == TYPE_PUBLIC && this.userId == userId) {
- return isVisible();
- } else if (type == TYPE_EMULATED) {
- return isVisible();
- } else {
- return false;
- }
- }
-
- public void mount() throws NativeDaemonConnectorException {
- mConnector.execute("volume", "mount", id, flags, userId);
- }
-
- public void unmount() throws NativeDaemonConnectorException {
- mConnector.execute("volume", "unmount", id);
- }
-
- public void format() throws NativeDaemonConnectorException {
- mConnector.execute("volume", "format", id);
- }
-
- public StorageVolume buildVolumeForUser(int userId) {
- final File userPath;
- final boolean removable;
- final boolean emulated;
- final boolean allowMassStorage = false;
- final int mtpStorageId = MtpStorage.getStorageIdForIndex(mtpIndex);
- final String envState = sStateToEnvironment.get(state);
-
- int descriptionId = com.android.internal.R.string.unknownName;
- long mtpReserveSize = 0;
- long maxFileSize = 0;
-
- if (type == TYPE_EMULATED) {
- userPath = new File(path, Integer.toString(userId));
- emulated = true;
- mtpReserveSize = StorageManager.from(mContext).getStorageLowBytes(userPath);
- descriptionId = com.android.internal.R.string.storage_internal;
-
- if (ID_EMULATED_INTERNAL.equals(id)) {
- removable = false;
- } else {
- removable = true;
- }
-
- } else if (type == TYPE_PUBLIC) {
- userPath = new File(path);
- emulated = false;
- removable = true;
-
- if (disk != null) {
- if ((disk.flags & Disk.FLAG_SD) != 0) {
- descriptionId = com.android.internal.R.string.storage_sd_card;
- } else if ((disk.flags & Disk.FLAG_USB) != 0) {
- descriptionId = com.android.internal.R.string.storage_usb;
- }
- }
-
- if ("vfat".equals(fsType)) {
- maxFileSize = 4294967295L;
- }
-
- } else {
- throw new IllegalStateException("Unexpected volume type " + type);
- }
-
- return new StorageVolume(id, mtpStorageId, userPath, descriptionId, isPrimary(),
- removable, emulated, mtpReserveSize, allowMassStorage, maxFileSize,
- new UserHandle(userId), fsUuid, fsLabel, envState);
- }
-
- public void dump(IndentingPrintWriter pw) {
- pw.println("Volume:");
- pw.increaseIndent();
- pw.printPair("id", id);
- pw.printPair("type", DebugUtils.valueToString(getClass(), "TYPE_", type));
- pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags));
- pw.printPair("userId", userId);
- pw.printPair("state", DebugUtils.valueToString(getClass(), "STATE_", state));
- pw.println();
- pw.printPair("fsType", fsType);
- pw.printPair("fsUuid", fsUuid);
- pw.printPair("fsLabel", fsLabel);
- pw.println();
- pw.printPair("path", path);
- pw.printPair("mtpIndex", mtpIndex);
- pw.decreaseIndent();
- pw.println();
+ private static int allocateMtpIndex(String volId) {
+ if (VolumeInfo.ID_EMULATED_INTERNAL.equals(volId)) {
+ return 0;
+ } else {
+ return sNextMtpIndex++;
}
}
@@ -672,9 +469,9 @@
break;
}
case H_VOLUME_MOUNT: {
- final Volume vol = (Volume) msg.obj;
+ final VolumeInfo vol = (VolumeInfo) msg.obj;
try {
- vol.mount();
+ mConnector.execute("volume", "mount", vol.id, vol.flags, vol.userId);
} catch (NativeDaemonConnectorException ignored) {
}
break;
@@ -685,7 +482,7 @@
Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + state + " to "
+ userVol.getOwner());
- final String action = sEnvironmentToBroadcast.get(state);
+ final String action = VolumeInfo.sEnvironmentToBroadcast.get(state);
if (action != null) {
final Intent intent = new Intent(action,
Uri.fromFile(userVol.getPathFile()));
@@ -769,9 +566,10 @@
// Record user as started so newly mounted volumes kick off events
// correctly, then synthesize events for any already-mounted volumes.
synchronized (mVolumes) {
- for (Volume vol : mVolumes.values()) {
- if (vol.isVisibleToUser(userId) && vol.state == Volume.STATE_MOUNTED) {
- final StorageVolume userVol = vol.buildVolumeForUser(userId);
+ for (int i = 0; i < mVolumes.size(); i++) {
+ final VolumeInfo vol = mVolumes.valueAt(i);
+ if (vol.isVisibleToUser(userId) && vol.state == VolumeInfo.STATE_MOUNTED) {
+ final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
}
}
@@ -906,12 +704,12 @@
if (cooked.length != 3) break;
final String id = cooked[1];
final int flags = Integer.parseInt(cooked[2]);
- mDisks.put(id, new Disk(id, flags));
+ mDisks.put(id, new DiskInfo(id, flags));
break;
}
case VoldResponseCode.DISK_SIZE_CHANGED: {
if (cooked.length != 3) break;
- final Disk disk = mDisks.get(cooked[1]);
+ final DiskInfo disk = mDisks.get(cooked[1]);
if (disk != null) {
disk.size = Long.parseLong(cooked[2]);
}
@@ -919,7 +717,7 @@
}
case VoldResponseCode.DISK_LABEL_CHANGED: {
if (cooked.length != 3) break;
- final Disk disk = mDisks.get(cooked[1]);
+ final DiskInfo disk = mDisks.get(cooked[1]);
if (disk != null) {
disk.label = cooked[2];
}
@@ -927,10 +725,10 @@
}
case VoldResponseCode.DISK_VOLUME_CREATED: {
if (cooked.length != 3) break;
- final Disk disk = mDisks.get(cooked[1]);
- final Volume vol = mVolumes.get(cooked[2]);
- if (disk != null && vol != null) {
- disk.volumes.add(vol);
+ final DiskInfo disk = mDisks.get(cooked[1]);
+ final String volId = cooked[2];
+ if (disk != null) {
+ disk.volumes = ArrayUtils.appendElement(String.class, disk.volumes, volId);
}
break;
}
@@ -944,14 +742,15 @@
if (cooked.length != 3) break;
final String id = cooked[1];
final int type = Integer.parseInt(cooked[2]);
- final Volume vol = new Volume(id, type);
+ final int mtpIndex = allocateMtpIndex(id);
+ final VolumeInfo vol = new VolumeInfo(id, type, mtpIndex);
mVolumes.put(id, vol);
onVolumeCreatedLocked(vol);
break;
}
case VoldResponseCode.VOLUME_STATE_CHANGED: {
if (cooked.length != 3) break;
- final Volume vol = mVolumes.get(cooked[1]);
+ final VolumeInfo vol = mVolumes.get(cooked[1]);
if (vol != null) {
final int oldState = vol.state;
final int newState = Integer.parseInt(cooked[2]);
@@ -962,7 +761,7 @@
}
case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
if (cooked.length != 3) break;
- final Volume vol = mVolumes.get(cooked[1]);
+ final VolumeInfo vol = mVolumes.get(cooked[1]);
if (vol != null) {
vol.fsType = cooked[2];
}
@@ -970,7 +769,7 @@
}
case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
if (cooked.length != 3) break;
- final Volume vol = mVolumes.get(cooked[1]);
+ final VolumeInfo vol = mVolumes.get(cooked[1]);
if (vol != null) {
vol.fsUuid = cooked[2];
}
@@ -978,7 +777,7 @@
}
case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
if (cooked.length != 3) break;
- final Volume vol = mVolumes.get(cooked[1]);
+ final VolumeInfo vol = mVolumes.get(cooked[1]);
if (vol != null) {
vol.fsLabel = cooked[2];
}
@@ -986,13 +785,14 @@
}
case VoldResponseCode.VOLUME_PATH_CHANGED: {
if (cooked.length != 3) break;
- final Volume vol = mVolumes.get(cooked[1]);
+ final VolumeInfo vol = mVolumes.get(cooked[1]);
if (vol != null) {
vol.path = cooked[2];
}
break;
}
case VoldResponseCode.VOLUME_DESTROYED: {
+ // TODO: send ACTION_MEDIA_REMOVED broadcast
if (cooked.length != 2) break;
mVolumes.remove(cooked[1]);
break;
@@ -1010,18 +810,19 @@
return true;
}
- private void onVolumeCreatedLocked(Volume vol) {
- final boolean primaryPhysical = SystemProperties.getBoolean(PROP_PRIMARY_PHYSICAL, false);
- if (vol.type == Volume.TYPE_EMULATED && !primaryPhysical) {
- vol.flags |= Volume.FLAG_PRIMARY;
- vol.flags |= Volume.FLAG_VISIBLE;
+ private void onVolumeCreatedLocked(VolumeInfo vol) {
+ final boolean primaryPhysical = SystemProperties.getBoolean(
+ StorageManager.PROP_PRIMARY_PHYSICAL, false);
+ if (vol.type == VolumeInfo.TYPE_EMULATED && !primaryPhysical) {
+ vol.flags |= VolumeInfo.FLAG_PRIMARY;
+ vol.flags |= VolumeInfo.FLAG_VISIBLE;
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
- } else if (vol.type == Volume.TYPE_PUBLIC) {
+ } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
if (primaryPhysical) {
- vol.flags |= Volume.FLAG_PRIMARY;
+ vol.flags |= VolumeInfo.FLAG_PRIMARY;
}
- vol.flags |= Volume.FLAG_VISIBLE;
+ vol.flags |= VolumeInfo.FLAG_VISIBLE;
vol.userId = UserHandle.USER_OWNER;
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
@@ -1030,24 +831,24 @@
}
}
- private void onVolumeStateChangedLocked(Volume vol, int oldState, int newState) {
+ private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
// Kick state changed event towards all started users. Any users
// started after this point will trigger additional
// user-specific broadcasts.
for (int userId : mStartedUsers) {
if (vol.isVisibleToUser(userId)) {
- final StorageVolume userVol = vol.buildVolumeForUser(userId);
+ final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
}
}
// Tell PackageManager about changes to primary volume state, but only
// when not emulated.
- if (vol.isPrimary() && vol.type == Volume.TYPE_PUBLIC) {
- if (vol.state == Volume.STATE_MOUNTED) {
+ if (vol.isPrimary() && vol.type == VolumeInfo.TYPE_PUBLIC) {
+ if (vol.state == VolumeInfo.STATE_MOUNTED) {
mPms.updateExternalMediaStatus(true, false);
- } else if (vol.state == Volume.STATE_UNMOUNTING) {
+ } else if (vol.state == VolumeInfo.STATE_UNMOUNTING) {
mPms.updateExternalMediaStatus(false, false);
// TODO: this should eventually be handled by new ObbVolume state changes
@@ -1061,8 +862,8 @@
}
}
- final String oldEnvState = sStateToEnvironment.get(oldState);
- final String newEnvState = sStateToEnvironment.get(newState);
+ final String oldEnvState = VolumeInfo.sStateToEnvironment.get(oldState);
+ final String newEnvState = VolumeInfo.sStateToEnvironment.get(newState);
synchronized (mListeners) {
for (int i = mListeners.size() -1; i >= 0; i--) {
@@ -1203,22 +1004,16 @@
return false;
}
- /**
- * @return state of the volume at the specified mount point
- */
@Override
@Deprecated
public String getVolumeState(String mountPoint) {
- // TODO: pretend that we're unmounted when encrypting?
- // SystemProperties.get("vold.encrypt_progress")
-
- final Volume vol = findVolumeByLegacyPath(mountPoint);
- return sStateToEnvironment.get(vol.state);
+ throw new UnsupportedOperationException();
}
@Override
+ @Deprecated
public boolean isExternalStorageEmulated() {
- return Environment.isExternalStorageEmulated();
+ throw new UnsupportedOperationException();
}
@Override
@@ -1226,13 +1021,13 @@
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();
- final Volume vol = findVolumeByLegacyPath(path);
+ final VolumeInfo vol = findVolumeByLegacyPath(path);
if (vol != null) {
- if (vol.type == Volume.TYPE_PUBLIC || vol.type == Volume.TYPE_PRIVATE) {
+ if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
enforceUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
}
try {
- vol.mount();
+ mConnector.execute("volume", "mount", vol.id, vol.flags, vol.userId);
return 0;
} catch (NativeDaemonConnectorException ignored) {
}
@@ -1247,7 +1042,7 @@
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();
- final Volume vol = findVolumeByLegacyPath(path);
+ final VolumeInfo vol = findVolumeByLegacyPath(path);
if (vol != null) {
// TODO: expand PMS to know about multiple volumes
if (vol.isPrimary()) {
@@ -1260,7 +1055,7 @@
}
try {
- vol.unmount();
+ mConnector.execute("volume", "unmount", vol.id);
} catch (NativeDaemonConnectorException ignored) {
}
} else {
@@ -1273,10 +1068,10 @@
enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
waitForReady();
- final Volume vol = findVolumeByLegacyPath(path);
+ final VolumeInfo vol = findVolumeByLegacyPath(path);
if (vol != null) {
try {
- vol.format();
+ mConnector.execute("volume", "format", vol.id);
return 0;
} catch (NativeDaemonConnectorException ignored) {
}
@@ -1315,8 +1110,9 @@
private void warnOnNotMounted() {
synchronized (mLock) {
- for (Volume vol : mVolumes.values()) {
- if (vol.isPrimary() && vol.state == Volume.STATE_MOUNTED) {
+ for (int i = 0; i < mVolumes.size(); i++) {
+ final VolumeInfo vol = mVolumes.valueAt(i);
+ if (vol.isPrimary() && vol.state == VolumeInfo.STATE_MOUNTED) {
// Cool beans, we have a mounted primary volume
return;
}
@@ -2012,17 +1808,14 @@
@Override
public StorageVolume[] getVolumeList(int userId) {
- if (UserHandle.getCallingUserId() != userId) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE, "getVolumeList");
- }
-
- final ArrayList<StorageVolume> res = Lists.newArrayList();
+ final ArrayList<StorageVolume> res = new ArrayList<>();
boolean foundPrimary = false;
+
synchronized (mLock) {
- for (Volume vol : mVolumes.values()) {
+ for (int i = 0; i < mVolumes.size(); i++) {
+ final VolumeInfo vol = mVolumes.valueAt(i);
if (vol.isVisibleToUser(userId)) {
- final StorageVolume userVol = vol.buildVolumeForUser(userId);
+ final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
if (vol.isPrimary()) {
res.add(0, userVol);
foundPrimary = true;
@@ -2034,14 +1827,14 @@
}
if (!foundPrimary) {
- Slog.w(TAG, "No primary storage defined yet; hacking together a stub");
+ Log.w(TAG, "No primary storage defined yet; hacking together a stub");
final boolean primaryPhysical = SystemProperties.getBoolean(
- PROP_PRIMARY_PHYSICAL, false);
+ StorageManager.PROP_PRIMARY_PHYSICAL, false);
final String id = "stub_primary";
final File path = Environment.getLegacyExternalStorageDirectory();
- final int descriptionId = android.R.string.unknownName;
+ final String description = mContext.getString(android.R.string.unknownName);
final boolean primary = true;
final boolean removable = primaryPhysical;
final boolean emulated = !primaryPhysical;
@@ -2050,17 +1843,38 @@
final long maxFileSize = 0L;
final UserHandle owner = new UserHandle(userId);
final String uuid = null;
- final String userLabel = null;
final String state = Environment.MEDIA_REMOVED;
res.add(0, new StorageVolume(id, MtpStorage.getStorageIdForIndex(0), path,
- descriptionId, primary, removable, emulated, mtpReserveSize,
- allowMassStorage, maxFileSize, owner, uuid, userLabel, state));
+ description, primary, removable, emulated, mtpReserveSize,
+ allowMassStorage, maxFileSize, owner, uuid, state));
}
return res.toArray(new StorageVolume[res.size()]);
}
+ @Override
+ public DiskInfo[] getDisks() {
+ synchronized (mLock) {
+ final DiskInfo[] res = new DiskInfo[mDisks.size()];
+ for (int i = 0; i < mDisks.size(); i++) {
+ res[i] = mDisks.valueAt(i);
+ }
+ return res;
+ }
+ }
+
+ @Override
+ public VolumeInfo[] getVolumes() {
+ synchronized (mLock) {
+ final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
+ for (int i = 0; i < mVolumes.size(); i++) {
+ res[i] = mVolumes.valueAt(i);
+ }
+ return res;
+ }
+ }
+
private void addObbStateLocked(ObbState obbState) throws RemoteException {
final IBinder binder = obbState.getBinder();
List<ObbState> obbStates = mObbMounts.get(binder);
@@ -2601,7 +2415,8 @@
pw.println();
pw.println("Disks:");
pw.increaseIndent();
- for (Disk disk : mDisks.values()) {
+ for (int i = 0; i < mDisks.size(); i++) {
+ final DiskInfo disk = mDisks.valueAt(i);
disk.dump(pw);
}
pw.decreaseIndent();
@@ -2609,7 +2424,8 @@
pw.println();
pw.println("Volumes:");
pw.increaseIndent();
- for (Volume vol : mVolumes.values()) {
+ for (int i = 0; i < mVolumes.size(); i++) {
+ final VolumeInfo vol = mVolumes.valueAt(i);
vol.dump(pw);
}
pw.decreaseIndent();