VolumeInfo.java revision 1b8ef7e3165ff9aa52a4905dafc8d0f83e7403f9
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.os.storage; 18 19import android.content.Context; 20import android.content.Intent; 21import android.mtp.MtpStorage; 22import android.os.Environment; 23import android.os.Parcel; 24import android.os.Parcelable; 25import android.os.UserHandle; 26import android.text.TextUtils; 27import android.util.ArrayMap; 28import android.util.DebugUtils; 29import android.util.SparseArray; 30 31import com.android.internal.util.IndentingPrintWriter; 32import com.android.internal.util.Preconditions; 33 34import java.io.File; 35 36/** 37 * Information about a storage volume that may be mounted. A volume may be a 38 * partition on a physical {@link DiskInfo}, an emulated volume above some other 39 * storage medium, or a standalone container like an ASEC or OBB. 40 * 41 * @hide 42 */ 43public class VolumeInfo implements Parcelable { 44 public static final String ID_EMULATED_INTERNAL = "emulated"; 45 46 public static final int TYPE_PUBLIC = 0; 47 public static final int TYPE_PRIVATE = 1; 48 public static final int TYPE_EMULATED = 2; 49 public static final int TYPE_ASEC = 3; 50 public static final int TYPE_OBB = 4; 51 52 public static final int STATE_UNMOUNTED = 0; 53 public static final int STATE_MOUNTING = 1; 54 public static final int STATE_MOUNTED = 2; 55 public static final int STATE_FORMATTING = 3; 56 public static final int STATE_UNMOUNTING = 4; 57 58 public static final int FLAG_PRIMARY = 1 << 0; 59 public static final int FLAG_VISIBLE = 1 << 1; 60 61 public static SparseArray<String> sStateToEnvironment = new SparseArray<>(); 62 public static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>(); 63 64 static { 65 sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTED, Environment.MEDIA_UNMOUNTED); 66 sStateToEnvironment.put(VolumeInfo.STATE_MOUNTING, Environment.MEDIA_CHECKING); 67 sStateToEnvironment.put(VolumeInfo.STATE_MOUNTED, Environment.MEDIA_MOUNTED); 68 sStateToEnvironment.put(VolumeInfo.STATE_FORMATTING, Environment.MEDIA_UNMOUNTED); 69 sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTING, Environment.MEDIA_EJECTING); 70 71 sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTED, Intent.ACTION_MEDIA_UNMOUNTED); 72 sEnvironmentToBroadcast.put(Environment.MEDIA_CHECKING, Intent.ACTION_MEDIA_CHECKING); 73 sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED, Intent.ACTION_MEDIA_MOUNTED); 74 sEnvironmentToBroadcast.put(Environment.MEDIA_EJECTING, Intent.ACTION_MEDIA_EJECT); 75 } 76 77 /** vold state */ 78 public final String id; 79 public final int type; 80 public int flags = 0; 81 public int userId = -1; 82 public int state = STATE_UNMOUNTED; 83 public String fsType; 84 public String fsUuid; 85 public String fsLabel; 86 public String path; 87 88 /** Framework state */ 89 public final int mtpIndex; 90 public String nickname; 91 92 public DiskInfo disk; 93 94 public VolumeInfo(String id, int type, int mtpIndex) { 95 this.id = Preconditions.checkNotNull(id); 96 this.type = type; 97 this.mtpIndex = mtpIndex; 98 } 99 100 public VolumeInfo(Parcel parcel) { 101 id = parcel.readString(); 102 type = parcel.readInt(); 103 flags = parcel.readInt(); 104 userId = parcel.readInt(); 105 state = parcel.readInt(); 106 fsType = parcel.readString(); 107 fsUuid = parcel.readString(); 108 fsLabel = parcel.readString(); 109 path = parcel.readString(); 110 mtpIndex = parcel.readInt(); 111 nickname = parcel.readString(); 112 } 113 114 public String getDescription(Context context) { 115 if (ID_EMULATED_INTERNAL.equals(id)) { 116 return context.getString(com.android.internal.R.string.storage_internal); 117 } else if (!TextUtils.isEmpty(nickname)) { 118 return nickname; 119 } else if (!TextUtils.isEmpty(fsLabel)) { 120 return fsLabel; 121 } else { 122 return null; 123 } 124 } 125 126 public boolean isPrimary() { 127 return (flags & FLAG_PRIMARY) != 0; 128 } 129 130 public boolean isVisible() { 131 return (flags & FLAG_VISIBLE) != 0; 132 } 133 134 public boolean isVisibleToUser(int userId) { 135 if (type == TYPE_PUBLIC && userId == this.userId) { 136 return isVisible(); 137 } else if (type == TYPE_EMULATED) { 138 return isVisible(); 139 } else { 140 return false; 141 } 142 } 143 144 public File getPathForUser(int userId) { 145 if (type == TYPE_PUBLIC && userId == this.userId) { 146 return new File(path); 147 } else if (type == TYPE_EMULATED) { 148 return new File(path, Integer.toString(userId)); 149 } else { 150 return null; 151 } 152 } 153 154 public StorageVolume buildStorageVolume(Context context, int userId) { 155 final boolean removable; 156 final boolean emulated; 157 final boolean allowMassStorage = false; 158 final int mtpStorageId = MtpStorage.getStorageIdForIndex(mtpIndex); 159 160 File userPath = getPathForUser(userId); 161 if (userPath == null) { 162 userPath = new File("/dev/null"); 163 } 164 165 String description = getDescription(context); 166 if (description == null) { 167 description = context.getString(android.R.string.unknownName); 168 } 169 170 String envState = sStateToEnvironment.get(state); 171 if (envState == null) { 172 envState = Environment.MEDIA_UNKNOWN; 173 } 174 175 long mtpReserveSize = 0; 176 long maxFileSize = 0; 177 178 if (type == TYPE_EMULATED) { 179 emulated = true; 180 mtpReserveSize = StorageManager.from(context).getStorageLowBytes(userPath); 181 182 if (ID_EMULATED_INTERNAL.equals(id)) { 183 removable = false; 184 } else { 185 removable = true; 186 } 187 188 } else if (type == TYPE_PUBLIC) { 189 emulated = false; 190 removable = true; 191 192 if ("vfat".equals(fsType)) { 193 maxFileSize = 4294967295L; 194 } 195 196 } else { 197 throw new IllegalStateException("Unexpected volume type " + type); 198 } 199 200 return new StorageVolume(id, mtpStorageId, userPath, description, isPrimary(), removable, 201 emulated, mtpReserveSize, allowMassStorage, maxFileSize, new UserHandle(userId), 202 fsUuid, envState); 203 } 204 205 public void dump(IndentingPrintWriter pw) { 206 pw.println("VolumeInfo:"); 207 pw.increaseIndent(); 208 pw.printPair("id", id); 209 pw.printPair("type", DebugUtils.valueToString(getClass(), "TYPE_", type)); 210 pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags)); 211 pw.printPair("userId", userId); 212 pw.printPair("state", DebugUtils.valueToString(getClass(), "STATE_", state)); 213 pw.println(); 214 pw.printPair("fsType", fsType); 215 pw.printPair("fsUuid", fsUuid); 216 pw.printPair("fsLabel", fsLabel); 217 pw.println(); 218 pw.printPair("path", path); 219 pw.printPair("mtpIndex", mtpIndex); 220 pw.decreaseIndent(); 221 pw.println(); 222 } 223 224 public static final Creator<VolumeInfo> CREATOR = new Creator<VolumeInfo>() { 225 @Override 226 public VolumeInfo createFromParcel(Parcel in) { 227 return new VolumeInfo(in); 228 } 229 230 @Override 231 public VolumeInfo[] newArray(int size) { 232 return new VolumeInfo[size]; 233 } 234 }; 235 236 @Override 237 public int describeContents() { 238 return 0; 239 } 240 241 @Override 242 public void writeToParcel(Parcel parcel, int flags) { 243 parcel.writeString(id); 244 parcel.writeInt(type); 245 parcel.writeInt(flags); 246 parcel.writeInt(userId); 247 parcel.writeInt(state); 248 parcel.writeString(fsType); 249 parcel.writeString(fsUuid); 250 parcel.writeString(fsLabel); 251 parcel.writeString(path); 252 parcel.writeInt(mtpIndex); 253 parcel.writeString(nickname); 254 } 255} 256