• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 
17 package android.os.storage;
18 
19 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SuppressLint;
24 import android.annotation.SystemApi;
25 import android.annotation.TestApi;
26 import android.compat.annotation.UnsupportedAppUsage;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.net.Uri;
30 import android.os.Build;
31 import android.os.Environment;
32 import android.os.Parcel;
33 import android.os.Parcelable;
34 import android.os.UserHandle;
35 import android.provider.DocumentsContract;
36 import android.provider.MediaStore;
37 
38 import com.android.internal.util.IndentingPrintWriter;
39 import com.android.internal.util.Preconditions;
40 
41 import java.io.CharArrayWriter;
42 import java.io.File;
43 import java.util.Locale;
44 import java.util.UUID;
45 
46 /**
47  * Information about a shared/external storage volume for a specific user.
48  *
49  * <p>
50  * A device always has one (and one only) primary storage volume, but it could have extra volumes,
51  * like SD cards and USB drives. This object represents the logical view of a storage
52  * volume for a specific user: different users might have different views for the same physical
53  * volume (for example, if the volume is a built-in emulated storage).
54  *
55  * <p>
56  * The storage volume is not necessarily mounted, applications should use {@link #getState()} to
57  * verify its state.
58  *
59  * <p>
60  * Applications willing to read or write to this storage volume needs to get a permission from the
61  * user first, which can be achieved in the following ways:
62  *
63  * <ul>
64  * <li>To get access to standard directories (like the {@link Environment#DIRECTORY_PICTURES}), they
65  * can use the {@link #createAccessIntent(String)}. This is the recommend way, since it provides a
66  * simpler API and narrows the access to the given directory (and its descendants).
67  * <li>To get access to any directory (and its descendants), they can use the Storage Acess
68  * Framework APIs (such as {@link Intent#ACTION_OPEN_DOCUMENT} and
69  * {@link Intent#ACTION_OPEN_DOCUMENT_TREE}, although these APIs do not guarantee the user will
70  * select this specific volume.
71  * <li>To get read and write access to the primary storage volume, applications can declare the
72  * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} and
73  * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permissions respectively, with the
74  * latter including the former. This approach is discouraged, since users may be hesitant to grant
75  * broad access to all files contained on a storage device.
76  * </ul>
77  *
78  * <p>It can be obtained through {@link StorageManager#getStorageVolumes()} and
79  * {@link StorageManager#getPrimaryStorageVolume()} and also as an extra in some broadcasts
80  * (see {@link #EXTRA_STORAGE_VOLUME}).
81  *
82  * <p>
83  * See {@link Environment#getExternalStorageDirectory()} for more info about shared/external
84  * storage semantics.
85  */
86 // NOTE: This is a legacy specialization of VolumeInfo which describes the volume for a specific
87 // user, but is now part of the public API.
88 public final class StorageVolume implements Parcelable {
89 
90     @UnsupportedAppUsage
91     private final String mId;
92     @UnsupportedAppUsage
93     private final File mPath;
94     private final File mInternalPath;
95     @UnsupportedAppUsage
96     private final String mDescription;
97     @UnsupportedAppUsage
98     private final boolean mPrimary;
99     @UnsupportedAppUsage
100     private final boolean mRemovable;
101     private final boolean mEmulated;
102     private final boolean mAllowMassStorage;
103     private final long mMaxFileSize;
104     private final UserHandle mOwner;
105     private final UUID mUuid;
106     private final String mFsUuid;
107     private final String mState;
108 
109     /**
110      * Name of the {@link Parcelable} extra in the {@link Intent#ACTION_MEDIA_REMOVED},
111      * {@link Intent#ACTION_MEDIA_UNMOUNTED}, {@link Intent#ACTION_MEDIA_CHECKING},
112      * {@link Intent#ACTION_MEDIA_NOFS}, {@link Intent#ACTION_MEDIA_MOUNTED},
113      * {@link Intent#ACTION_MEDIA_SHARED}, {@link Intent#ACTION_MEDIA_BAD_REMOVAL},
114      * {@link Intent#ACTION_MEDIA_UNMOUNTABLE}, and {@link Intent#ACTION_MEDIA_EJECT} broadcast that
115      * contains a {@link StorageVolume}.
116      */
117     // Also sent on ACTION_MEDIA_UNSHARED, which is @hide
118     public static final String EXTRA_STORAGE_VOLUME = "android.os.storage.extra.STORAGE_VOLUME";
119 
120     /**
121      * Name of the String extra used by {@link #createAccessIntent(String) createAccessIntent}.
122      *
123      * @hide
124      */
125     public static final String EXTRA_DIRECTORY_NAME = "android.os.storage.extra.DIRECTORY_NAME";
126 
127     /**
128      * Name of the intent used by {@link #createAccessIntent(String) createAccessIntent}.
129      */
130     private static final String ACTION_OPEN_EXTERNAL_DIRECTORY =
131             "android.os.storage.action.OPEN_EXTERNAL_DIRECTORY";
132 
133     /** {@hide} */
134     public static final int STORAGE_ID_INVALID = 0x00000000;
135     /** {@hide} */
136     public static final int STORAGE_ID_PRIMARY = 0x00010001;
137 
138     /** {@hide} */
StorageVolume(String id, File path, File internalPath, String description, boolean primary, boolean removable, boolean emulated, boolean allowMassStorage, long maxFileSize, UserHandle owner, UUID uuid, String fsUuid, String state)139     public StorageVolume(String id, File path, File internalPath, String description,
140             boolean primary, boolean removable, boolean emulated, boolean allowMassStorage,
141             long maxFileSize, UserHandle owner, UUID uuid, String fsUuid, String state) {
142         mId = Preconditions.checkNotNull(id);
143         mPath = Preconditions.checkNotNull(path);
144         mInternalPath = Preconditions.checkNotNull(internalPath);
145         mDescription = Preconditions.checkNotNull(description);
146         mPrimary = primary;
147         mRemovable = removable;
148         mEmulated = emulated;
149         mAllowMassStorage = allowMassStorage;
150         mMaxFileSize = maxFileSize;
151         mOwner = Preconditions.checkNotNull(owner);
152         mUuid = uuid;
153         mFsUuid = fsUuid;
154         mState = Preconditions.checkNotNull(state);
155     }
156 
StorageVolume(Parcel in)157     private StorageVolume(Parcel in) {
158         mId = in.readString8();
159         mPath = new File(in.readString8());
160         mInternalPath = new File(in.readString8());
161         mDescription = in.readString8();
162         mPrimary = in.readInt() != 0;
163         mRemovable = in.readInt() != 0;
164         mEmulated = in.readInt() != 0;
165         mAllowMassStorage = in.readInt() != 0;
166         mMaxFileSize = in.readLong();
167         mOwner = in.readParcelable(null);
168         if (in.readInt() != 0) {
169             mUuid = StorageManager.convert(in.readString8());
170         } else {
171             mUuid = null;
172         }
173         mFsUuid = in.readString8();
174         mState = in.readString8();
175     }
176 
177     /**
178      * Return an opaque ID that can be used to identify this volume.
179      *
180      * @hide
181      */
182     @SystemApi
getId()183     public @NonNull String getId() {
184         return mId;
185     }
186 
187     /**
188      * Returns the mount path for the volume.
189      *
190      * @return the mount path
191      * @hide
192      */
193     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@link StorageVolume#getDirectory()}")
194     @TestApi
getPath()195     public String getPath() {
196         return mPath.toString();
197     }
198 
199     /**
200      * Returns the path of the underlying filesystem.
201      *
202      * @return the internal path
203      * @hide
204      */
getInternalPath()205     public String getInternalPath() {
206         return mInternalPath.toString();
207     }
208 
209     /** {@hide} */
210     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@link StorageVolume#getDirectory()}")
getPathFile()211     public File getPathFile() {
212         return mPath;
213     }
214 
215     /**
216      * Returns the directory where this volume is currently mounted.
217      * <p>
218      * Direct filesystem access via this path has significant emulation
219      * overhead, and apps are instead strongly encouraged to interact with media
220      * on storage volumes via the {@link MediaStore} APIs.
221      * <p>
222      * This directory does not give apps any additional access beyond what they
223      * already have via {@link MediaStore}.
224      *
225      * @return directory where this volume is mounted, or {@code null} if the
226      *         volume is not currently mounted.
227      */
getDirectory()228     public @Nullable File getDirectory() {
229         switch (mState) {
230             case Environment.MEDIA_MOUNTED:
231             case Environment.MEDIA_MOUNTED_READ_ONLY:
232                 return mPath;
233             default:
234                 return null;
235         }
236     }
237 
238     /**
239      * Returns a user-visible description of the volume.
240      *
241      * @return the volume description
242      */
getDescription(Context context)243     public String getDescription(Context context) {
244         return mDescription;
245     }
246 
247     /**
248      * Returns true if the volume is the primary shared/external storage, which is the volume
249      * backed by {@link Environment#getExternalStorageDirectory()}.
250      */
isPrimary()251     public boolean isPrimary() {
252         return mPrimary;
253     }
254 
255     /**
256      * Returns true if the volume is removable.
257      *
258      * @return is removable
259      */
isRemovable()260     public boolean isRemovable() {
261         return mRemovable;
262     }
263 
264     /**
265      * Returns true if the volume is emulated.
266      *
267      * @return is removable
268      */
isEmulated()269     public boolean isEmulated() {
270         return mEmulated;
271     }
272 
273     /**
274      * Returns true if this volume can be shared via USB mass storage.
275      *
276      * @return whether mass storage is allowed
277      * @hide
278      */
279     @UnsupportedAppUsage
allowMassStorage()280     public boolean allowMassStorage() {
281         return mAllowMassStorage;
282     }
283 
284     /**
285      * Returns maximum file size for the volume, or zero if it is unbounded.
286      *
287      * @return maximum file size
288      * @hide
289      */
290     @UnsupportedAppUsage
getMaxFileSize()291     public long getMaxFileSize() {
292         return mMaxFileSize;
293     }
294 
295     /**
296      * Returns the user that owns this volume
297      *
298      * {@hide}
299      */
300     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
301     @SystemApi(client = MODULE_LIBRARIES)
getOwner()302     public @NonNull UserHandle getOwner() {
303         return mOwner;
304     }
305 
306     /**
307      * Gets the converted volume UUID. If a valid UUID is returned, it is compatible with other
308      * APIs that make use of {@link UUID} like {@link StorageManager#allocateBytes} and
309      * {@link android.content.pm.ApplicationInfo#storageUuid}
310      *
311      * @return the UUID for the volume or {@code null} for "portable" storage devices which haven't
312      * been adopted.
313      *
314      * @see <a href="https://source.android.com/devices/storage/adoptable">Adoptable storage</a>
315      */
getStorageUuid()316     public @Nullable UUID getStorageUuid() {
317         return mUuid;
318     }
319 
320     /**
321      * Gets the volume UUID, if any.
322      */
getUuid()323     public @Nullable String getUuid() {
324         return mFsUuid;
325     }
326 
327     /**
328      * Return the volume name that can be used to interact with this storage
329      * device through {@link MediaStore}.
330      *
331      * @return opaque volume name, or {@code null} if this volume is not indexed
332      *         by {@link MediaStore}.
333      * @see android.provider.MediaStore.Audio.Media#getContentUri(String)
334      * @see android.provider.MediaStore.Video.Media#getContentUri(String)
335      * @see android.provider.MediaStore.Images.Media#getContentUri(String)
336      */
getMediaStoreVolumeName()337     public @Nullable String getMediaStoreVolumeName() {
338         if (isPrimary()) {
339             return MediaStore.VOLUME_EXTERNAL_PRIMARY;
340         } else {
341             return getNormalizedUuid();
342         }
343     }
344 
345     /** {@hide} */
normalizeUuid(@ullable String fsUuid)346     public static @Nullable String normalizeUuid(@Nullable String fsUuid) {
347         return fsUuid != null ? fsUuid.toLowerCase(Locale.US) : null;
348     }
349 
350     /** {@hide} */
getNormalizedUuid()351     public @Nullable String getNormalizedUuid() {
352         return normalizeUuid(mFsUuid);
353     }
354 
355     /**
356      * Parse and return volume UUID as FAT volume ID, or return -1 if unable to
357      * parse or UUID is unknown.
358      * @hide
359      */
360     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getFatVolumeId()361     public int getFatVolumeId() {
362         if (mFsUuid == null || mFsUuid.length() != 9) {
363             return -1;
364         }
365         try {
366             return (int) Long.parseLong(mFsUuid.replace("-", ""), 16);
367         } catch (NumberFormatException e) {
368             return -1;
369         }
370     }
371 
372     /** {@hide} */
373     @UnsupportedAppUsage
getUserLabel()374     public String getUserLabel() {
375         return mDescription;
376     }
377 
378     /**
379      * Returns the current state of the volume.
380      *
381      * @return one of {@link Environment#MEDIA_UNKNOWN}, {@link Environment#MEDIA_REMOVED},
382      *         {@link Environment#MEDIA_UNMOUNTED}, {@link Environment#MEDIA_CHECKING},
383      *         {@link Environment#MEDIA_NOFS}, {@link Environment#MEDIA_MOUNTED},
384      *         {@link Environment#MEDIA_MOUNTED_READ_ONLY}, {@link Environment#MEDIA_SHARED},
385      *         {@link Environment#MEDIA_BAD_REMOVAL}, or {@link Environment#MEDIA_UNMOUNTABLE}.
386      */
getState()387     public String getState() {
388         return mState;
389     }
390 
391     /**
392      * Builds an intent to give access to a standard storage directory or entire volume after
393      * obtaining the user's approval.
394      * <p>
395      * When invoked, the system will ask the user to grant access to the requested directory (and
396      * its descendants). The result of the request will be returned to the activity through the
397      * {@code onActivityResult} method.
398      * <p>
399      * To gain access to descendants (child, grandchild, etc) documents, use
400      * {@link DocumentsContract#buildDocumentUriUsingTree(Uri, String)}, or
401      * {@link DocumentsContract#buildChildDocumentsUriUsingTree(Uri, String)} with the returned URI.
402      * <p>
403      * If your application only needs to store internal data, consider using
404      * {@link Context#getExternalFilesDirs(String) Context.getExternalFilesDirs},
405      * {@link Context#getExternalCacheDirs()}, or {@link Context#getExternalMediaDirs()}, which
406      * require no permissions to read or write.
407      * <p>
408      * Access to the entire volume is only available for non-primary volumes (for the primary
409      * volume, apps can use the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} and
410      * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permissions) and should be used
411      * with caution, since users are more likely to deny access when asked for entire volume access
412      * rather than specific directories.
413      *
414      * @param directoryName must be one of {@link Environment#DIRECTORY_MUSIC},
415      *            {@link Environment#DIRECTORY_PODCASTS}, {@link Environment#DIRECTORY_RINGTONES},
416      *            {@link Environment#DIRECTORY_ALARMS}, {@link Environment#DIRECTORY_NOTIFICATIONS},
417      *            {@link Environment#DIRECTORY_PICTURES}, {@link Environment#DIRECTORY_MOVIES},
418      *            {@link Environment#DIRECTORY_DOWNLOADS}, {@link Environment#DIRECTORY_DCIM}, or
419      *            {@link Environment#DIRECTORY_DOCUMENTS}, or {@code null} to request access to the
420      *            entire volume.
421      * @return intent to request access, or {@code null} if the requested directory is invalid for
422      *         that volume.
423      * @see DocumentsContract
424      * @deprecated Callers should migrate to using {@link Intent#ACTION_OPEN_DOCUMENT_TREE} instead.
425      *             Launching this {@link Intent} on devices running
426      *             {@link android.os.Build.VERSION_CODES#Q} or higher, will immediately finish
427      *             with a result code of {@link android.app.Activity#RESULT_CANCELED}.
428      */
429     @Deprecated
createAccessIntent(String directoryName)430     public @Nullable Intent createAccessIntent(String directoryName) {
431         if ((isPrimary() && directoryName == null) ||
432                 (directoryName != null && !Environment.isStandardDirectory(directoryName))) {
433             return null;
434         }
435         final Intent intent = new Intent(ACTION_OPEN_EXTERNAL_DIRECTORY);
436         intent.putExtra(EXTRA_STORAGE_VOLUME, this);
437         intent.putExtra(EXTRA_DIRECTORY_NAME, directoryName);
438         return intent;
439     }
440 
441     /**
442      * Builds an {@link Intent#ACTION_OPEN_DOCUMENT_TREE} to allow the user to grant access to any
443      * directory subtree (or entire volume) from the {@link android.provider.DocumentsProvider}s
444      * available on the device. The initial location of the document navigation will be the root of
445      * this {@link StorageVolume}.
446      *
447      * Note that the returned {@link Intent} simply suggests that the user picks this {@link
448      * StorageVolume} by default, but the user may select a different location. Callers must respect
449      * the user's chosen location, even if it is different from the originally requested location.
450      *
451      * @return intent to {@link Intent#ACTION_OPEN_DOCUMENT_TREE} initially showing the contents
452      *         of this {@link StorageVolume}
453      * @see Intent#ACTION_OPEN_DOCUMENT_TREE
454      */
createOpenDocumentTreeIntent()455     @NonNull public Intent createOpenDocumentTreeIntent() {
456         final String rootId = isEmulated()
457                 ? DocumentsContract.EXTERNAL_STORAGE_PRIMARY_EMULATED_ROOT_ID
458                 : mFsUuid;
459         final Uri rootUri = DocumentsContract.buildRootUri(
460                 DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY, rootId);
461         final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
462                 .putExtra(DocumentsContract.EXTRA_INITIAL_URI, rootUri)
463                 .putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, true);
464         return intent;
465     }
466 
467     @Override
equals(@ullable Object obj)468     public boolean equals(@Nullable Object obj) {
469         if (obj instanceof StorageVolume && mPath != null) {
470             StorageVolume volume = (StorageVolume)obj;
471             return (mPath.equals(volume.mPath));
472         }
473         return false;
474     }
475 
476     @Override
hashCode()477     public int hashCode() {
478         return mPath.hashCode();
479     }
480 
481     @Override
toString()482     public String toString() {
483         final StringBuilder buffer = new StringBuilder("StorageVolume: ").append(mDescription);
484         if (mFsUuid != null) {
485             buffer.append(" (").append(mFsUuid).append(")");
486         }
487         return buffer.toString();
488     }
489 
490     /** {@hide} */
491     // TODO: find out where toString() is called internally and replace these calls by dump().
dump()492     public String dump() {
493         final CharArrayWriter writer = new CharArrayWriter();
494         dump(new IndentingPrintWriter(writer, "    ", 80));
495         return writer.toString();
496     }
497 
498     /** {@hide} */
dump(IndentingPrintWriter pw)499     public void dump(IndentingPrintWriter pw) {
500         pw.println("StorageVolume:");
501         pw.increaseIndent();
502         pw.printPair("mId", mId);
503         pw.printPair("mPath", mPath);
504         pw.printPair("mInternalPath", mInternalPath);
505         pw.printPair("mDescription", mDescription);
506         pw.printPair("mPrimary", mPrimary);
507         pw.printPair("mRemovable", mRemovable);
508         pw.printPair("mEmulated", mEmulated);
509         pw.printPair("mAllowMassStorage", mAllowMassStorage);
510         pw.printPair("mMaxFileSize", mMaxFileSize);
511         pw.printPair("mOwner", mOwner);
512         pw.printPair("mFsUuid", mFsUuid);
513         pw.printPair("mState", mState);
514         pw.decreaseIndent();
515     }
516 
517     public static final @android.annotation.NonNull Creator<StorageVolume> CREATOR = new Creator<StorageVolume>() {
518         @Override
519         public StorageVolume createFromParcel(Parcel in) {
520             return new StorageVolume(in);
521         }
522 
523         @Override
524         public StorageVolume[] newArray(int size) {
525             return new StorageVolume[size];
526         }
527     };
528 
529     @Override
describeContents()530     public int describeContents() {
531         return 0;
532     }
533 
534     @Override
writeToParcel(Parcel parcel, int flags)535     public void writeToParcel(Parcel parcel, int flags) {
536         parcel.writeString8(mId);
537         parcel.writeString8(mPath.toString());
538         parcel.writeString8(mInternalPath.toString());
539         parcel.writeString8(mDescription);
540         parcel.writeInt(mPrimary ? 1 : 0);
541         parcel.writeInt(mRemovable ? 1 : 0);
542         parcel.writeInt(mEmulated ? 1 : 0);
543         parcel.writeInt(mAllowMassStorage ? 1 : 0);
544         parcel.writeLong(mMaxFileSize);
545         parcel.writeParcelable(mOwner, flags);
546         if (mUuid != null) {
547             parcel.writeInt(1);
548             parcel.writeString8(StorageManager.convert(mUuid));
549         } else {
550             parcel.writeInt(0);
551         }
552         parcel.writeString8(mFsUuid);
553         parcel.writeString8(mState);
554     }
555 
556     /** @hide */
557     // This class is used by the mainline test suite, so we have to keep these APIs around across
558     // releases. Consider making this class public to help external developers to write tests as
559     // well.
560     @TestApi
561     public static final class Builder {
562         private String mId;
563         private File mPath;
564         private String mDescription;
565         private boolean mPrimary;
566         private boolean mRemovable;
567         private boolean mEmulated;
568         private UserHandle mOwner;
569         private UUID mStorageUuid;
570         private String mUuid;
571         private String mState;
572 
573         @SuppressLint("StreamFiles")
Builder( @onNull String id, @NonNull File path, @NonNull String description, @NonNull UserHandle owner, @NonNull String state)574         public Builder(
575                 @NonNull String id, @NonNull File path, @NonNull String description,
576                 @NonNull UserHandle owner, @NonNull String state) {
577             mId = id;
578             mPath = path;
579             mDescription = description;
580             mOwner = owner;
581             mState = state;
582         }
583 
584         @NonNull
setStorageUuid(@ullable UUID storageUuid)585         public Builder setStorageUuid(@Nullable UUID storageUuid) {
586             mStorageUuid = storageUuid;
587             return this;
588         }
589 
590         @NonNull
setUuid(@ullable String uuid)591         public Builder setUuid(@Nullable String uuid) {
592             mUuid = uuid;
593             return this;
594         }
595 
596         @NonNull
setPrimary(boolean primary)597         public Builder setPrimary(boolean primary) {
598             mPrimary = primary;
599             return this;
600         }
601 
602         @NonNull
setRemovable(boolean removable)603         public Builder setRemovable(boolean removable) {
604             mRemovable = removable;
605             return this;
606         }
607 
608         @NonNull
setEmulated(boolean emulated)609         public Builder setEmulated(boolean emulated) {
610             mEmulated = emulated;
611             return this;
612         }
613 
614         @NonNull
build()615         public StorageVolume build() {
616             return new StorageVolume(
617                     mId,
618                     mPath,
619                     /* internalPath= */ mPath,
620                     mDescription,
621                     mPrimary,
622                     mRemovable,
623                     mEmulated,
624                     /* allowMassStorage= */ false,
625                     /* maxFileSize= */ 0,
626                     mOwner,
627                     mStorageUuid,
628                     mUuid,
629                     mState);
630         }
631     }
632 
633 }
634