OSDN Git Service

Handle public volumes and otherwise invalid UUIDs.
[android-x86/frameworks-base.git] / core / java / android / os / storage / StorageManager.java
1 /*
2  * Copyright (C) 2008 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 android.annotation.BytesLong;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.RequiresPermission;
24 import android.annotation.SdkConstant;
25 import android.annotation.SuppressLint;
26 import android.annotation.SystemApi;
27 import android.annotation.SystemService;
28 import android.annotation.WorkerThread;
29 import android.app.Activity;
30 import android.app.ActivityThread;
31 import android.content.ContentResolver;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.content.pm.ApplicationInfo;
35 import android.content.pm.IPackageMoveObserver;
36 import android.content.pm.PackageManager;
37 import android.os.Binder;
38 import android.os.Environment;
39 import android.os.FileUtils;
40 import android.os.Handler;
41 import android.os.IVold;
42 import android.os.IVoldTaskListener;
43 import android.os.Looper;
44 import android.os.Message;
45 import android.os.ParcelFileDescriptor;
46 import android.os.ParcelableException;
47 import android.os.PersistableBundle;
48 import android.os.ProxyFileDescriptorCallback;
49 import android.os.RemoteException;
50 import android.os.ServiceManager;
51 import android.os.ServiceManager.ServiceNotFoundException;
52 import android.os.SystemProperties;
53 import android.provider.Settings;
54 import android.system.ErrnoException;
55 import android.system.Os;
56 import android.system.OsConstants;
57 import android.text.TextUtils;
58 import android.util.DataUnit;
59 import android.util.Log;
60 import android.util.Pair;
61 import android.util.Slog;
62 import android.util.SparseArray;
63
64 import com.android.internal.annotations.GuardedBy;
65 import com.android.internal.annotations.VisibleForTesting;
66 import com.android.internal.logging.MetricsLogger;
67 import com.android.internal.os.AppFuseMount;
68 import com.android.internal.os.FuseAppLoop;
69 import com.android.internal.os.FuseUnavailableMountException;
70 import com.android.internal.os.RoSystemProperties;
71 import com.android.internal.os.SomeArgs;
72 import com.android.internal.util.Preconditions;
73
74 import java.io.File;
75 import java.io.FileDescriptor;
76 import java.io.FileNotFoundException;
77 import java.io.IOException;
78 import java.lang.annotation.Retention;
79 import java.lang.annotation.RetentionPolicy;
80 import java.lang.ref.WeakReference;
81 import java.nio.charset.StandardCharsets;
82 import java.util.ArrayList;
83 import java.util.Arrays;
84 import java.util.Collections;
85 import java.util.Iterator;
86 import java.util.List;
87 import java.util.Objects;
88 import java.util.UUID;
89 import java.util.concurrent.CompletableFuture;
90 import java.util.concurrent.ThreadFactory;
91 import java.util.concurrent.TimeUnit;
92 import java.util.concurrent.atomic.AtomicInteger;
93
94 /**
95  * StorageManager is the interface to the systems storage service. The storage
96  * manager handles storage-related items such as Opaque Binary Blobs (OBBs).
97  * <p>
98  * OBBs contain a filesystem that maybe be encrypted on disk and mounted
99  * on-demand from an application. OBBs are a good way of providing large amounts
100  * of binary assets without packaging them into APKs as they may be multiple
101  * gigabytes in size. However, due to their size, they're most likely stored in
102  * a shared storage pool accessible from all programs. The system does not
103  * guarantee the security of the OBB file itself: if any program modifies the
104  * OBB, there is no guarantee that a read from that OBB will produce the
105  * expected output.
106  */
107 @SystemService(Context.STORAGE_SERVICE)
108 public class StorageManager {
109     private static final String TAG = "StorageManager";
110
111     /** {@hide} */
112     public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
113     /** {@hide} */
114     public static final String PROP_HAS_ADOPTABLE = "vold.has_adoptable";
115     /** {@hide} */
116     public static final String PROP_HAS_RESERVED = "vold.has_reserved";
117     /** {@hide} */
118     public static final String PROP_FORCE_ADOPTABLE = "persist.fw.force_adoptable";
119     /** {@hide} */
120     public static final String PROP_EMULATE_FBE = "persist.sys.emulate_fbe";
121     /** {@hide} */
122     public static final String PROP_SDCARDFS = "persist.sys.sdcardfs";
123     /** {@hide} */
124     public static final String PROP_VIRTUAL_DISK = "persist.sys.virtual_disk";
125
126     /** {@hide} */
127     public static final String UUID_PRIVATE_INTERNAL = null;
128     /** {@hide} */
129     public static final String UUID_PRIMARY_PHYSICAL = "primary_physical";
130     /** {@hide} */
131     public static final String UUID_SYSTEM = "system";
132
133     // NOTE: UUID constants below are namespaced
134     // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad default
135     // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad primary_physical
136     // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad system
137
138     /**
139      * UUID representing the default internal storage of this device which
140      * provides {@link Environment#getDataDirectory()}.
141      * <p>
142      * This value is constant across all devices and it will never change, and
143      * thus it cannot be used to uniquely identify a particular physical device.
144      *
145      * @see #getUuidForPath(File)
146      * @see ApplicationInfo#storageUuid
147      */
148     public static final UUID UUID_DEFAULT = UUID
149             .fromString("41217664-9172-527a-b3d5-edabb50a7d69");
150
151     /** {@hide} */
152     public static final UUID UUID_PRIMARY_PHYSICAL_ = UUID
153             .fromString("0f95a519-dae7-5abf-9519-fbd6209e05fd");
154
155     /** {@hide} */
156     public static final UUID UUID_SYSTEM_ = UUID
157             .fromString("5d258386-e60d-59e3-826d-0089cdd42cc0");
158
159     /**
160      * Activity Action: Allows the user to manage their storage. This activity
161      * provides the ability to free up space on the device by deleting data such
162      * as apps.
163      * <p>
164      * If the sending application has a specific storage device or allocation
165      * size in mind, they can optionally define {@link #EXTRA_UUID} or
166      * {@link #EXTRA_REQUESTED_BYTES}, respectively.
167      * <p>
168      * This intent should be launched using
169      * {@link Activity#startActivityForResult(Intent, int)} so that the user
170      * knows which app is requesting the storage space. The returned result will
171      * be {@link Activity#RESULT_OK} if the requested space was made available,
172      * or {@link Activity#RESULT_CANCELED} otherwise.
173      */
174     @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
175     public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
176
177     /**
178      * Extra {@link UUID} used to indicate the storage volume where an
179      * application is interested in allocating or managing disk space.
180      *
181      * @see #ACTION_MANAGE_STORAGE
182      * @see #UUID_DEFAULT
183      * @see #getUuidForPath(File)
184      * @see Intent#putExtra(String, java.io.Serializable)
185      */
186     public static final String EXTRA_UUID = "android.os.storage.extra.UUID";
187
188     /**
189      * Extra used to indicate the total size (in bytes) that an application is
190      * interested in allocating.
191      * <p>
192      * When defined, the management UI will help guide the user to free up
193      * enough disk space to reach this requested value.
194      *
195      * @see #ACTION_MANAGE_STORAGE
196      */
197     public static final String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES";
198
199     /** {@hide} */
200     public static final int DEBUG_FORCE_ADOPTABLE = 1 << 0;
201     /** {@hide} */
202     public static final int DEBUG_EMULATE_FBE = 1 << 1;
203     /** {@hide} */
204     public static final int DEBUG_SDCARDFS_FORCE_ON = 1 << 2;
205     /** {@hide} */
206     public static final int DEBUG_SDCARDFS_FORCE_OFF = 1 << 3;
207     /** {@hide} */
208     public static final int DEBUG_VIRTUAL_DISK = 1 << 4;
209
210     // NOTE: keep in sync with installd
211     /** {@hide} */
212     public static final int FLAG_STORAGE_DE = 1 << 0;
213     /** {@hide} */
214     public static final int FLAG_STORAGE_CE = 1 << 1;
215
216     /** {@hide} */
217     public static final int FLAG_FOR_WRITE = 1 << 8;
218     /** {@hide} */
219     public static final int FLAG_REAL_STATE = 1 << 9;
220     /** {@hide} */
221     public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10;
222
223     /** {@hide} */
224     public static final int FSTRIM_FLAG_DEEP = IVold.FSTRIM_FLAG_DEEP_TRIM;
225
226     /** @hide The volume is not encrypted. */
227     public static final int ENCRYPTION_STATE_NONE =
228             IVold.ENCRYPTION_STATE_NONE;
229
230     /** @hide The volume has been encrypted succesfully. */
231     public static final int ENCRYPTION_STATE_OK =
232             IVold.ENCRYPTION_STATE_OK;
233
234     /** @hide The volume is in a bad state. */
235     public static final int ENCRYPTION_STATE_ERROR_UNKNOWN =
236             IVold.ENCRYPTION_STATE_ERROR_UNKNOWN;
237
238     /** @hide Encryption is incomplete */
239     public static final int ENCRYPTION_STATE_ERROR_INCOMPLETE =
240             IVold.ENCRYPTION_STATE_ERROR_INCOMPLETE;
241
242     /** @hide Encryption is incomplete and irrecoverable */
243     public static final int ENCRYPTION_STATE_ERROR_INCONSISTENT =
244             IVold.ENCRYPTION_STATE_ERROR_INCONSISTENT;
245
246     /** @hide Underlying data is corrupt */
247     public static final int ENCRYPTION_STATE_ERROR_CORRUPT =
248             IVold.ENCRYPTION_STATE_ERROR_CORRUPT;
249
250     private static volatile IStorageManager sStorageManager = null;
251
252     private final Context mContext;
253     private final ContentResolver mResolver;
254
255     private final IStorageManager mStorageManager;
256     private final Looper mLooper;
257     private final AtomicInteger mNextNonce = new AtomicInteger(0);
258
259     private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>();
260
261     private static class StorageEventListenerDelegate extends IStorageEventListener.Stub implements
262             Handler.Callback {
263         private static final int MSG_STORAGE_STATE_CHANGED = 1;
264         private static final int MSG_VOLUME_STATE_CHANGED = 2;
265         private static final int MSG_VOLUME_RECORD_CHANGED = 3;
266         private static final int MSG_VOLUME_FORGOTTEN = 4;
267         private static final int MSG_DISK_SCANNED = 5;
268         private static final int MSG_DISK_DESTROYED = 6;
269
270         final StorageEventListener mCallback;
271         final Handler mHandler;
272
273         public StorageEventListenerDelegate(StorageEventListener callback, Looper looper) {
274             mCallback = callback;
275             mHandler = new Handler(looper, this);
276         }
277
278         @Override
279         public boolean handleMessage(Message msg) {
280             final SomeArgs args = (SomeArgs) msg.obj;
281             switch (msg.what) {
282                 case MSG_STORAGE_STATE_CHANGED:
283                     mCallback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
284                             (String) args.arg3);
285                     args.recycle();
286                     return true;
287                 case MSG_VOLUME_STATE_CHANGED:
288                     mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
289                     args.recycle();
290                     return true;
291                 case MSG_VOLUME_RECORD_CHANGED:
292                     mCallback.onVolumeRecordChanged((VolumeRecord) args.arg1);
293                     args.recycle();
294                     return true;
295                 case MSG_VOLUME_FORGOTTEN:
296                     mCallback.onVolumeForgotten((String) args.arg1);
297                     args.recycle();
298                     return true;
299                 case MSG_DISK_SCANNED:
300                     mCallback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
301                     args.recycle();
302                     return true;
303                 case MSG_DISK_DESTROYED:
304                     mCallback.onDiskDestroyed((DiskInfo) args.arg1);
305                     args.recycle();
306                     return true;
307             }
308             args.recycle();
309             return false;
310         }
311
312         @Override
313         public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException {
314             // Ignored
315         }
316
317         @Override
318         public void onStorageStateChanged(String path, String oldState, String newState) {
319             final SomeArgs args = SomeArgs.obtain();
320             args.arg1 = path;
321             args.arg2 = oldState;
322             args.arg3 = newState;
323             mHandler.obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
324         }
325
326         @Override
327         public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
328             final SomeArgs args = SomeArgs.obtain();
329             args.arg1 = vol;
330             args.argi2 = oldState;
331             args.argi3 = newState;
332             mHandler.obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
333         }
334
335         @Override
336         public void onVolumeRecordChanged(VolumeRecord rec) {
337             final SomeArgs args = SomeArgs.obtain();
338             args.arg1 = rec;
339             mHandler.obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
340         }
341
342         @Override
343         public void onVolumeForgotten(String fsUuid) {
344             final SomeArgs args = SomeArgs.obtain();
345             args.arg1 = fsUuid;
346             mHandler.obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
347         }
348
349         @Override
350         public void onDiskScanned(DiskInfo disk, int volumeCount) {
351             final SomeArgs args = SomeArgs.obtain();
352             args.arg1 = disk;
353             args.argi2 = volumeCount;
354             mHandler.obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
355         }
356
357         @Override
358         public void onDiskDestroyed(DiskInfo disk) throws RemoteException {
359             final SomeArgs args = SomeArgs.obtain();
360             args.arg1 = disk;
361             mHandler.obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
362         }
363     }
364
365     /**
366      * Binder listener for OBB action results.
367      */
368     private final ObbActionListener mObbActionListener = new ObbActionListener();
369
370     private class ObbActionListener extends IObbActionListener.Stub {
371         @SuppressWarnings("hiding")
372         private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>();
373
374         @Override
375         public void onObbResult(String filename, int nonce, int status) {
376             final ObbListenerDelegate delegate;
377             synchronized (mListeners) {
378                 delegate = mListeners.get(nonce);
379                 if (delegate != null) {
380                     mListeners.remove(nonce);
381                 }
382             }
383
384             if (delegate != null) {
385                 delegate.sendObbStateChanged(filename, status);
386             }
387         }
388
389         public int addListener(OnObbStateChangeListener listener) {
390             final ObbListenerDelegate delegate = new ObbListenerDelegate(listener);
391
392             synchronized (mListeners) {
393                 mListeners.put(delegate.nonce, delegate);
394             }
395
396             return delegate.nonce;
397         }
398     }
399
400     private int getNextNonce() {
401         return mNextNonce.getAndIncrement();
402     }
403
404     /**
405      * Private class containing sender and receiver code for StorageEvents.
406      */
407     private class ObbListenerDelegate {
408         private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef;
409         private final Handler mHandler;
410
411         private final int nonce;
412
413         ObbListenerDelegate(OnObbStateChangeListener listener) {
414             nonce = getNextNonce();
415             mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener);
416             mHandler = new Handler(mLooper) {
417                 @Override
418                 public void handleMessage(Message msg) {
419                     final OnObbStateChangeListener changeListener = getListener();
420                     if (changeListener == null) {
421                         return;
422                     }
423
424                     changeListener.onObbStateChange((String) msg.obj, msg.arg1);
425                 }
426             };
427         }
428
429         OnObbStateChangeListener getListener() {
430             if (mObbEventListenerRef == null) {
431                 return null;
432             }
433             return mObbEventListenerRef.get();
434         }
435
436         void sendObbStateChanged(String path, int state) {
437             mHandler.obtainMessage(0, state, 0, path).sendToTarget();
438         }
439     }
440
441     /** {@hide} */
442     @Deprecated
443     public static StorageManager from(Context context) {
444         return context.getSystemService(StorageManager.class);
445     }
446
447     /**
448      * Constructs a StorageManager object through which an application can
449      * can communicate with the systems mount service.
450      *
451      * @param looper The {@link android.os.Looper} which events will be received on.
452      *
453      * <p>Applications can get instance of this class by calling
454      * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
455      * of {@link android.content.Context#STORAGE_SERVICE}.
456      *
457      * @hide
458      */
459     public StorageManager(Context context, Looper looper) throws ServiceNotFoundException {
460         mContext = context;
461         mResolver = context.getContentResolver();
462         mLooper = looper;
463         mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getServiceOrThrow("mount"));
464     }
465
466     /**
467      * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
468      *
469      * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
470      *
471      * @hide
472      */
473     public void registerListener(StorageEventListener listener) {
474         synchronized (mDelegates) {
475             final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener,
476                     mLooper);
477             try {
478                 mStorageManager.registerListener(delegate);
479             } catch (RemoteException e) {
480                 throw e.rethrowFromSystemServer();
481             }
482             mDelegates.add(delegate);
483         }
484     }
485
486     /**
487      * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}.
488      *
489      * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
490      *
491      * @hide
492      */
493     public void unregisterListener(StorageEventListener listener) {
494         synchronized (mDelegates) {
495             for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
496                 final StorageEventListenerDelegate delegate = i.next();
497                 if (delegate.mCallback == listener) {
498                     try {
499                         mStorageManager.unregisterListener(delegate);
500                     } catch (RemoteException e) {
501                         throw e.rethrowFromSystemServer();
502                     }
503                     i.remove();
504                 }
505             }
506         }
507     }
508
509     /**
510      * Enables USB Mass Storage (UMS) on the device.
511      *
512      * @hide
513      */
514     @Deprecated
515     public void enableUsbMassStorage() {
516     }
517
518     /**
519      * Disables USB Mass Storage (UMS) on the device.
520      *
521      * @hide
522      */
523     @Deprecated
524     public void disableUsbMassStorage() {
525     }
526
527     /**
528      * Query if a USB Mass Storage (UMS) host is connected.
529      * @return true if UMS host is connected.
530      *
531      * @hide
532      */
533     @Deprecated
534     public boolean isUsbMassStorageConnected() {
535         return false;
536     }
537
538     /**
539      * Query if a USB Mass Storage (UMS) is enabled on the device.
540      * @return true if UMS host is enabled.
541      *
542      * @hide
543      */
544     @Deprecated
545     public boolean isUsbMassStorageEnabled() {
546         return false;
547     }
548
549     /**
550      * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is
551      * specified, it is supplied to the mounting process to be used in any
552      * encryption used in the OBB.
553      * <p>
554      * The OBB will remain mounted for as long as the StorageManager reference
555      * is held by the application. As soon as this reference is lost, the OBBs
556      * in use will be unmounted. The {@link OnObbStateChangeListener} registered
557      * with this call will receive the success or failure of this operation.
558      * <p>
559      * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
560      * file matches a package ID that is owned by the calling program's UID.
561      * That is, shared UID applications can attempt to mount any other
562      * application's OBB that shares its UID.
563      *
564      * @param rawPath the path to the OBB file
565      * @param key secret used to encrypt the OBB; may be <code>null</code> if no
566      *            encryption was used on the OBB.
567      * @param listener will receive the success or failure of the operation
568      * @return whether the mount call was successfully queued or not
569      */
570     public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) {
571         Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
572         Preconditions.checkNotNull(listener, "listener cannot be null");
573
574         try {
575             final String canonicalPath = new File(rawPath).getCanonicalPath();
576             final int nonce = mObbActionListener.addListener(listener);
577             mStorageManager.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce);
578             return true;
579         } catch (IOException e) {
580             throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e);
581         } catch (RemoteException e) {
582             throw e.rethrowFromSystemServer();
583         }
584     }
585
586     /**
587      * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the
588      * <code>force</code> flag is true, it will kill any application needed to
589      * unmount the given OBB (even the calling application).
590      * <p>
591      * The {@link OnObbStateChangeListener} registered with this call will
592      * receive the success or failure of this operation.
593      * <p>
594      * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
595      * file matches a package ID that is owned by the calling program's UID.
596      * That is, shared UID applications can obtain access to any other
597      * application's OBB that shares its UID.
598      * <p>
599      *
600      * @param rawPath path to the OBB file
601      * @param force whether to kill any programs using this in order to unmount
602      *            it
603      * @param listener will receive the success or failure of the operation
604      * @return whether the unmount call was successfully queued or not
605      */
606     public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) {
607         Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
608         Preconditions.checkNotNull(listener, "listener cannot be null");
609
610         try {
611             final int nonce = mObbActionListener.addListener(listener);
612             mStorageManager.unmountObb(rawPath, force, mObbActionListener, nonce);
613             return true;
614         } catch (RemoteException e) {
615             throw e.rethrowFromSystemServer();
616         }
617     }
618
619     /**
620      * Check whether an Opaque Binary Blob (OBB) is mounted or not.
621      *
622      * @param rawPath path to OBB image
623      * @return true if OBB is mounted; false if not mounted or on error
624      */
625     public boolean isObbMounted(String rawPath) {
626         Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
627
628         try {
629             return mStorageManager.isObbMounted(rawPath);
630         } catch (RemoteException e) {
631             throw e.rethrowFromSystemServer();
632         }
633     }
634
635     /**
636      * Check the mounted path of an Opaque Binary Blob (OBB) file. This will
637      * give you the path to where you can obtain access to the internals of the
638      * OBB.
639      *
640      * @param rawPath path to OBB image
641      * @return absolute path to mounted OBB image data or <code>null</code> if
642      *         not mounted or exception encountered trying to read status
643      */
644     public String getMountedObbPath(String rawPath) {
645         Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
646
647         try {
648             return mStorageManager.getMountedObbPath(rawPath);
649         } catch (RemoteException e) {
650             throw e.rethrowFromSystemServer();
651         }
652     }
653
654     /** {@hide} */
655     public @NonNull List<DiskInfo> getDisks() {
656         try {
657             return Arrays.asList(mStorageManager.getDisks());
658         } catch (RemoteException e) {
659             throw e.rethrowFromSystemServer();
660         }
661     }
662
663     /** {@hide} */
664     public @Nullable DiskInfo findDiskById(String id) {
665         Preconditions.checkNotNull(id);
666         // TODO; go directly to service to make this faster
667         for (DiskInfo disk : getDisks()) {
668             if (Objects.equals(disk.id, id)) {
669                 return disk;
670             }
671         }
672         return null;
673     }
674
675     /** {@hide} */
676     public @Nullable VolumeInfo findVolumeById(String id) {
677         Preconditions.checkNotNull(id);
678         // TODO; go directly to service to make this faster
679         for (VolumeInfo vol : getVolumes()) {
680             if (Objects.equals(vol.id, id)) {
681                 return vol;
682             }
683         }
684         return null;
685     }
686
687     /** {@hide} */
688     public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) {
689         Preconditions.checkNotNull(fsUuid);
690         // TODO; go directly to service to make this faster
691         for (VolumeInfo vol : getVolumes()) {
692             if (Objects.equals(vol.fsUuid, fsUuid)) {
693                 return vol;
694             }
695         }
696         return null;
697     }
698
699     /** {@hide} */
700     public @Nullable VolumeRecord findRecordByUuid(String fsUuid) {
701         Preconditions.checkNotNull(fsUuid);
702         // TODO; go directly to service to make this faster
703         for (VolumeRecord rec : getVolumeRecords()) {
704             if (Objects.equals(rec.fsUuid, fsUuid)) {
705                 return rec;
706             }
707         }
708         return null;
709     }
710
711     /** {@hide} */
712     public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
713         if (emulatedVol != null) {
714             return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
715         } else {
716             return null;
717         }
718     }
719
720     /** {@hide} */
721     public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) {
722         if (privateVol != null) {
723             return findVolumeById(privateVol.getId().replace("private", "emulated"));
724         } else {
725             return null;
726         }
727     }
728
729     /** {@hide} */
730     public @Nullable VolumeInfo findVolumeByQualifiedUuid(String volumeUuid) {
731         if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
732             return findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
733         } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
734             return getPrimaryPhysicalVolume();
735         } else {
736             return findVolumeByUuid(volumeUuid);
737         }
738     }
739
740     /**
741      * Return a UUID identifying the storage volume that hosts the given
742      * filesystem path.
743      * <p>
744      * If this path is hosted by the default internal storage of the device at
745      * {@link Environment#getDataDirectory()}, the returned value will be
746      * {@link #UUID_DEFAULT}.
747      *
748      * @throws IOException when the storage device hosting the given path isn't
749      *             present, or when it doesn't have a valid UUID.
750      */
751     public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException {
752         Preconditions.checkNotNull(path);
753         final String pathString = path.getCanonicalPath();
754         if (FileUtils.contains(Environment.getDataDirectory().getAbsolutePath(), pathString)) {
755             return UUID_DEFAULT;
756         }
757         try {
758             for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
759                 if (vol.path != null && FileUtils.contains(vol.path, pathString)
760                         && vol.type != VolumeInfo.TYPE_PUBLIC) {
761                     // TODO: verify that emulated adopted devices have UUID of
762                     // underlying volume
763                     try {
764                         return convert(vol.fsUuid);
765                     } catch (IllegalArgumentException e) {
766                         continue;
767                     }
768                 }
769             }
770         } catch (RemoteException e) {
771             throw e.rethrowFromSystemServer();
772         }
773         throw new FileNotFoundException("Failed to find a storage device for " + path);
774     }
775
776     /** {@hide} */
777     public @NonNull File findPathForUuid(String volumeUuid) throws FileNotFoundException {
778         final VolumeInfo vol = findVolumeByQualifiedUuid(volumeUuid);
779         if (vol != null) {
780             return vol.getPath();
781         }
782         throw new FileNotFoundException("Failed to find a storage device for " + volumeUuid);
783     }
784
785     /**
786      * Test if the given file descriptor supports allocation of disk space using
787      * {@link #allocateBytes(FileDescriptor, long)}.
788      */
789     public boolean isAllocationSupported(@NonNull FileDescriptor fd) {
790         try {
791             getUuidForPath(ParcelFileDescriptor.getFile(fd));
792             return true;
793         } catch (IOException e) {
794             return false;
795         }
796     }
797
798     /** {@hide} */
799     public @NonNull List<VolumeInfo> getVolumes() {
800         try {
801             return Arrays.asList(mStorageManager.getVolumes(0));
802         } catch (RemoteException e) {
803             throw e.rethrowFromSystemServer();
804         }
805     }
806
807     /** {@hide} */
808     public @NonNull List<VolumeInfo> getWritablePrivateVolumes() {
809         try {
810             final ArrayList<VolumeInfo> res = new ArrayList<>();
811             for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
812                 if (vol.getType() == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) {
813                     res.add(vol);
814                 }
815             }
816             return res;
817         } catch (RemoteException e) {
818             throw e.rethrowFromSystemServer();
819         }
820     }
821
822     /** {@hide} */
823     public @NonNull List<VolumeRecord> getVolumeRecords() {
824         try {
825             return Arrays.asList(mStorageManager.getVolumeRecords(0));
826         } catch (RemoteException e) {
827             throw e.rethrowFromSystemServer();
828         }
829     }
830
831     /** {@hide} */
832     public @Nullable String getBestVolumeDescription(VolumeInfo vol) {
833         if (vol == null) return null;
834
835         // Nickname always takes precedence when defined
836         if (!TextUtils.isEmpty(vol.fsUuid)) {
837             final VolumeRecord rec = findRecordByUuid(vol.fsUuid);
838             if (rec != null && !TextUtils.isEmpty(rec.nickname)) {
839                 return rec.nickname;
840             }
841         }
842
843         if (!TextUtils.isEmpty(vol.getDescription())) {
844             return vol.getDescription();
845         }
846
847         if (vol.disk != null) {
848             return vol.disk.getDescription();
849         }
850
851         return null;
852     }
853
854     /** {@hide} */
855     public @Nullable VolumeInfo getPrimaryPhysicalVolume() {
856         final List<VolumeInfo> vols = getVolumes();
857         for (VolumeInfo vol : vols) {
858             if (vol.isPrimaryPhysical()) {
859                 return vol;
860             }
861         }
862         return null;
863     }
864
865     /** {@hide} */
866     public void mount(String volId) {
867         try {
868             mStorageManager.mount(volId);
869         } catch (RemoteException e) {
870             throw e.rethrowFromSystemServer();
871         }
872     }
873
874     /** {@hide} */
875     public void unmount(String volId) {
876         try {
877             mStorageManager.unmount(volId);
878         } catch (RemoteException e) {
879             throw e.rethrowFromSystemServer();
880         }
881     }
882
883     /** {@hide} */
884     public void format(String volId) {
885         try {
886             mStorageManager.format(volId);
887         } catch (RemoteException e) {
888             throw e.rethrowFromSystemServer();
889         }
890     }
891
892     /** {@hide} */
893     @Deprecated
894     public long benchmark(String volId) {
895         final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
896         benchmark(volId, new IVoldTaskListener.Stub() {
897             @Override
898             public void onStatus(int status, PersistableBundle extras) {
899                 // Ignored
900             }
901
902             @Override
903             public void onFinished(int status, PersistableBundle extras) {
904                 result.complete(extras);
905             }
906         });
907         try {
908             // Convert ms to ns
909             return result.get(3, TimeUnit.MINUTES).getLong("run", Long.MAX_VALUE) * 1000000;
910         } catch (Exception e) {
911             return Long.MAX_VALUE;
912         }
913     }
914
915     /** {@hide} */
916     public void benchmark(String volId, IVoldTaskListener listener) {
917         try {
918             mStorageManager.benchmark(volId, listener);
919         } catch (RemoteException e) {
920             throw e.rethrowFromSystemServer();
921         }
922     }
923
924     /** {@hide} */
925     public void partitionPublic(String diskId) {
926         try {
927             mStorageManager.partitionPublic(diskId);
928         } catch (RemoteException e) {
929             throw e.rethrowFromSystemServer();
930         }
931     }
932
933     /** {@hide} */
934     public void partitionPrivate(String diskId) {
935         try {
936             mStorageManager.partitionPrivate(diskId);
937         } catch (RemoteException e) {
938             throw e.rethrowFromSystemServer();
939         }
940     }
941
942     /** {@hide} */
943     public void partitionMixed(String diskId, int ratio) {
944         try {
945             mStorageManager.partitionMixed(diskId, ratio);
946         } catch (RemoteException e) {
947             throw e.rethrowFromSystemServer();
948         }
949     }
950
951     /** {@hide} */
952     public void wipeAdoptableDisks() {
953         // We only wipe devices in "adoptable" locations, which are in a
954         // long-term stable slot/location on the device, where apps have a
955         // reasonable chance of storing sensitive data. (Apps need to go through
956         // SAF to write to transient volumes.)
957         final List<DiskInfo> disks = getDisks();
958         for (DiskInfo disk : disks) {
959             final String diskId = disk.getId();
960             if (disk.isAdoptable()) {
961                 Slog.d(TAG, "Found adoptable " + diskId + "; wiping");
962                 try {
963                     // TODO: switch to explicit wipe command when we have it,
964                     // for now rely on the fact that vfat format does a wipe
965                     mStorageManager.partitionPublic(diskId);
966                 } catch (Exception e) {
967                     Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e);
968                 }
969             } else {
970                 Slog.d(TAG, "Ignorning non-adoptable disk " + disk.getId());
971             }
972         }
973     }
974
975     /** {@hide} */
976     public void setVolumeNickname(String fsUuid, String nickname) {
977         try {
978             mStorageManager.setVolumeNickname(fsUuid, nickname);
979         } catch (RemoteException e) {
980             throw e.rethrowFromSystemServer();
981         }
982     }
983
984     /** {@hide} */
985     public void setVolumeInited(String fsUuid, boolean inited) {
986         try {
987             mStorageManager.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0,
988                     VolumeRecord.USER_FLAG_INITED);
989         } catch (RemoteException e) {
990             throw e.rethrowFromSystemServer();
991         }
992     }
993
994     /** {@hide} */
995     public void setVolumeSnoozed(String fsUuid, boolean snoozed) {
996         try {
997             mStorageManager.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0,
998                     VolumeRecord.USER_FLAG_SNOOZED);
999         } catch (RemoteException e) {
1000             throw e.rethrowFromSystemServer();
1001         }
1002     }
1003
1004     /** {@hide} */
1005     public void forgetVolume(String fsUuid) {
1006         try {
1007             mStorageManager.forgetVolume(fsUuid);
1008         } catch (RemoteException e) {
1009             throw e.rethrowFromSystemServer();
1010         }
1011     }
1012
1013     /**
1014      * This is not the API you're looking for.
1015      *
1016      * @see PackageManager#getPrimaryStorageCurrentVolume()
1017      * @hide
1018      */
1019     public String getPrimaryStorageUuid() {
1020         try {
1021             return mStorageManager.getPrimaryStorageUuid();
1022         } catch (RemoteException e) {
1023             throw e.rethrowFromSystemServer();
1024         }
1025     }
1026
1027     /**
1028      * This is not the API you're looking for.
1029      *
1030      * @see PackageManager#movePrimaryStorage(VolumeInfo)
1031      * @hide
1032      */
1033     public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
1034         try {
1035             mStorageManager.setPrimaryStorageUuid(volumeUuid, callback);
1036         } catch (RemoteException e) {
1037             throw e.rethrowFromSystemServer();
1038         }
1039     }
1040
1041     /**
1042      * Return the {@link StorageVolume} that contains the given file, or {@code null} if none.
1043      */
1044     public @Nullable StorageVolume getStorageVolume(File file) {
1045         return getStorageVolume(getVolumeList(), file);
1046     }
1047
1048     /** {@hide} */
1049     public static @Nullable StorageVolume getStorageVolume(File file, int userId) {
1050         return getStorageVolume(getVolumeList(userId, 0), file);
1051     }
1052
1053     /** {@hide} */
1054     private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) {
1055         if (file == null) {
1056             return null;
1057         }
1058         try {
1059             file = file.getCanonicalFile();
1060         } catch (IOException ignored) {
1061             Slog.d(TAG, "Could not get canonical path for " + file);
1062             return null;
1063         }
1064         for (StorageVolume volume : volumes) {
1065             File volumeFile = volume.getPathFile();
1066             try {
1067                 volumeFile = volumeFile.getCanonicalFile();
1068             } catch (IOException ignored) {
1069                 continue;
1070             }
1071             if (FileUtils.contains(volumeFile, file)) {
1072                 return volume;
1073             }
1074         }
1075         return null;
1076     }
1077
1078     /**
1079      * Gets the state of a volume via its mountpoint.
1080      * @hide
1081      */
1082     @Deprecated
1083     public @NonNull String getVolumeState(String mountPoint) {
1084         final StorageVolume vol = getStorageVolume(new File(mountPoint));
1085         if (vol != null) {
1086             return vol.getState();
1087         } else {
1088             return Environment.MEDIA_UNKNOWN;
1089         }
1090     }
1091
1092     /**
1093      * Return the list of shared/external storage volumes available to the
1094      * current user. This includes both the primary shared storage device and
1095      * any attached external volumes including SD cards and USB drives.
1096      *
1097      * @see Environment#getExternalStorageDirectory()
1098      * @see StorageVolume#createAccessIntent(String)
1099      */
1100     public @NonNull List<StorageVolume> getStorageVolumes() {
1101         final ArrayList<StorageVolume> res = new ArrayList<>();
1102         Collections.addAll(res,
1103                 getVolumeList(mContext.getUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE));
1104         return res;
1105     }
1106
1107     /**
1108      * Return the primary shared/external storage volume available to the
1109      * current user. This volume is the same storage device returned by
1110      * {@link Environment#getExternalStorageDirectory()} and
1111      * {@link Context#getExternalFilesDir(String)}.
1112      */
1113     public @NonNull StorageVolume getPrimaryStorageVolume() {
1114         return getVolumeList(mContext.getUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE)[0];
1115     }
1116
1117     /** {@hide} */
1118     public static Pair<String, Long> getPrimaryStoragePathAndSize() {
1119         return Pair.create(null,
1120                 FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()
1121                     + Environment.getRootDirectory().getTotalSpace()));
1122     }
1123
1124     /** {@hide} */
1125     public long getPrimaryStorageSize() {
1126         return FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()
1127                 + Environment.getRootDirectory().getTotalSpace());
1128     }
1129
1130     /** {@hide} */
1131     public void mkdirs(File file) {
1132         try {
1133             mStorageManager.mkdirs(mContext.getOpPackageName(), file.getAbsolutePath());
1134         } catch (RemoteException e) {
1135             throw e.rethrowFromSystemServer();
1136         }
1137     }
1138
1139     /** @removed */
1140     public @NonNull StorageVolume[] getVolumeList() {
1141         return getVolumeList(mContext.getUserId(), 0);
1142     }
1143
1144     /** {@hide} */
1145     public static @NonNull StorageVolume[] getVolumeList(int userId, int flags) {
1146         final IStorageManager storageManager = IStorageManager.Stub.asInterface(
1147                 ServiceManager.getService("mount"));
1148         try {
1149             String packageName = ActivityThread.currentOpPackageName();
1150             if (packageName == null) {
1151                 // Package name can be null if the activity thread is running but the app
1152                 // hasn't bound yet. In this case we fall back to the first package in the
1153                 // current UID. This works for runtime permissions as permission state is
1154                 // per UID and permission realted app ops are updated for all UID packages.
1155                 String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid(
1156                         android.os.Process.myUid());
1157                 if (packageNames == null || packageNames.length <= 0) {
1158                     return new StorageVolume[0];
1159                 }
1160                 packageName = packageNames[0];
1161             }
1162             final int uid = ActivityThread.getPackageManager().getPackageUid(packageName,
1163                     PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
1164             if (uid <= 0) {
1165                 return new StorageVolume[0];
1166             }
1167             return storageManager.getVolumeList(uid, packageName, flags);
1168         } catch (RemoteException e) {
1169             throw e.rethrowFromSystemServer();
1170         }
1171     }
1172
1173     /**
1174      * Returns list of paths for all mountable volumes.
1175      * @hide
1176      */
1177     @Deprecated
1178     public @NonNull String[] getVolumePaths() {
1179         StorageVolume[] volumes = getVolumeList();
1180         int count = volumes.length;
1181         String[] paths = new String[count];
1182         for (int i = 0; i < count; i++) {
1183             paths[i] = volumes[i].getPath();
1184         }
1185         return paths;
1186     }
1187
1188     /** @removed */
1189     public @NonNull StorageVolume getPrimaryVolume() {
1190         return getPrimaryVolume(getVolumeList());
1191     }
1192
1193     /** {@hide} */
1194     public static @NonNull StorageVolume getPrimaryVolume(StorageVolume[] volumes) {
1195         for (StorageVolume volume : volumes) {
1196             if (volume.isPrimary()) {
1197                 return volume;
1198             }
1199         }
1200         throw new IllegalStateException("Missing primary storage");
1201     }
1202
1203     private static final int DEFAULT_THRESHOLD_PERCENTAGE = 5;
1204     private static final long DEFAULT_THRESHOLD_MAX_BYTES = DataUnit.MEBIBYTES.toBytes(500);
1205
1206     private static final int DEFAULT_CACHE_PERCENTAGE = 10;
1207     private static final long DEFAULT_CACHE_MAX_BYTES = DataUnit.GIBIBYTES.toBytes(5);
1208
1209     private static final long DEFAULT_FULL_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(1);
1210
1211     /**
1212      * Return the number of available bytes until the given path is considered
1213      * running low on storage.
1214      *
1215      * @hide
1216      */
1217     public long getStorageBytesUntilLow(File path) {
1218         return path.getUsableSpace() - getStorageFullBytes(path);
1219     }
1220
1221     /**
1222      * Return the number of available bytes at which the given path is
1223      * considered running low on storage.
1224      *
1225      * @hide
1226      */
1227     public long getStorageLowBytes(File path) {
1228         final long lowPercent = Settings.Global.getInt(mResolver,
1229                 Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);
1230         final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;
1231
1232         final long maxLowBytes = Settings.Global.getLong(mResolver,
1233                 Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES);
1234
1235         return Math.min(lowBytes, maxLowBytes);
1236     }
1237
1238     /**
1239      * Return the minimum number of bytes of storage on the device that should
1240      * be reserved for cached data.
1241      *
1242      * @hide
1243      */
1244     public long getStorageCacheBytes(File path, @AllocateFlags int flags) {
1245         final long cachePercent = Settings.Global.getInt(mResolver,
1246                 Settings.Global.SYS_STORAGE_CACHE_PERCENTAGE, DEFAULT_CACHE_PERCENTAGE);
1247         final long cacheBytes = (path.getTotalSpace() * cachePercent) / 100;
1248
1249         final long maxCacheBytes = Settings.Global.getLong(mResolver,
1250                 Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES, DEFAULT_CACHE_MAX_BYTES);
1251
1252         final long result = Math.min(cacheBytes, maxCacheBytes);
1253         if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
1254             return 0;
1255         } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED) != 0) {
1256             return 0;
1257         } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED) != 0) {
1258             return result / 2;
1259         } else {
1260             return result;
1261         }
1262     }
1263
1264     /**
1265      * Return the number of available bytes at which the given path is
1266      * considered full.
1267      *
1268      * @hide
1269      */
1270     public long getStorageFullBytes(File path) {
1271         return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
1272                 DEFAULT_FULL_THRESHOLD_BYTES);
1273     }
1274
1275     /** {@hide} */
1276     public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
1277         try {
1278             mStorageManager.createUserKey(userId, serialNumber, ephemeral);
1279         } catch (RemoteException e) {
1280             throw e.rethrowFromSystemServer();
1281         }
1282     }
1283
1284     /** {@hide} */
1285     public void destroyUserKey(int userId) {
1286         try {
1287             mStorageManager.destroyUserKey(userId);
1288         } catch (RemoteException e) {
1289             throw e.rethrowFromSystemServer();
1290         }
1291     }
1292
1293     /** {@hide} */
1294     public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
1295         try {
1296             mStorageManager.unlockUserKey(userId, serialNumber, token, secret);
1297         } catch (RemoteException e) {
1298             throw e.rethrowFromSystemServer();
1299         }
1300     }
1301
1302     /** {@hide} */
1303     public void lockUserKey(int userId) {
1304         try {
1305             mStorageManager.lockUserKey(userId);
1306         } catch (RemoteException e) {
1307             throw e.rethrowFromSystemServer();
1308         }
1309     }
1310
1311     /** {@hide} */
1312     public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
1313         try {
1314             mStorageManager.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
1315         } catch (RemoteException e) {
1316             throw e.rethrowFromSystemServer();
1317         }
1318     }
1319
1320     /** {@hide} */
1321     public void destroyUserStorage(String volumeUuid, int userId, int flags) {
1322         try {
1323             mStorageManager.destroyUserStorage(volumeUuid, userId, flags);
1324         } catch (RemoteException e) {
1325             throw e.rethrowFromSystemServer();
1326         }
1327     }
1328
1329     /** {@hide} */
1330     public static boolean isUserKeyUnlocked(int userId) {
1331         if (sStorageManager == null) {
1332             sStorageManager = IStorageManager.Stub
1333                     .asInterface(ServiceManager.getService("mount"));
1334         }
1335         if (sStorageManager == null) {
1336             Slog.w(TAG, "Early during boot, assuming locked");
1337             return false;
1338         }
1339         final long token = Binder.clearCallingIdentity();
1340         try {
1341             return sStorageManager.isUserKeyUnlocked(userId);
1342         } catch (RemoteException e) {
1343             throw e.rethrowAsRuntimeException();
1344         } finally {
1345             Binder.restoreCallingIdentity(token);
1346         }
1347     }
1348
1349     /**
1350      * Return if data stored at or under the given path will be encrypted while
1351      * at rest. This can help apps avoid the overhead of double-encrypting data.
1352      */
1353     public boolean isEncrypted(File file) {
1354         if (FileUtils.contains(Environment.getDataDirectory(), file)) {
1355             return isEncrypted();
1356         } else if (FileUtils.contains(Environment.getExpandDirectory(), file)) {
1357             return true;
1358         }
1359         // TODO: extend to support shared storage
1360         return false;
1361     }
1362
1363     /** {@hide}
1364      * Is this device encryptable or already encrypted?
1365      * @return true for encryptable or encrypted
1366      *         false not encrypted and not encryptable
1367      */
1368     public static boolean isEncryptable() {
1369         return RoSystemProperties.CRYPTO_ENCRYPTABLE;
1370     }
1371
1372     /** {@hide}
1373      * Is this device already encrypted?
1374      * @return true for encrypted. (Implies isEncryptable() == true)
1375      *         false not encrypted
1376      */
1377     public static boolean isEncrypted() {
1378         return RoSystemProperties.CRYPTO_ENCRYPTED;
1379     }
1380
1381     /** {@hide}
1382      * Is this device file encrypted?
1383      * @return true for file encrypted. (Implies isEncrypted() == true)
1384      *         false not encrypted or block encrypted
1385      */
1386     public static boolean isFileEncryptedNativeOnly() {
1387         if (!isEncrypted()) {
1388             return false;
1389         }
1390         return RoSystemProperties.CRYPTO_FILE_ENCRYPTED;
1391     }
1392
1393     /** {@hide}
1394      * Is this device block encrypted?
1395      * @return true for block encrypted. (Implies isEncrypted() == true)
1396      *         false not encrypted or file encrypted
1397      */
1398     public static boolean isBlockEncrypted() {
1399         if (!isEncrypted()) {
1400             return false;
1401         }
1402         return RoSystemProperties.CRYPTO_BLOCK_ENCRYPTED;
1403     }
1404
1405     /** {@hide}
1406      * Is this device block encrypted with credentials?
1407      * @return true for crediential block encrypted.
1408      *         (Implies isBlockEncrypted() == true)
1409      *         false not encrypted, file encrypted or default block encrypted
1410      */
1411     public static boolean isNonDefaultBlockEncrypted() {
1412         if (!isBlockEncrypted()) {
1413             return false;
1414         }
1415
1416         try {
1417             IStorageManager storageManager = IStorageManager.Stub.asInterface(
1418                     ServiceManager.getService("mount"));
1419             return storageManager.getPasswordType() != CRYPT_TYPE_DEFAULT;
1420         } catch (RemoteException e) {
1421             Log.e(TAG, "Error getting encryption type");
1422             return false;
1423         }
1424     }
1425
1426     /** {@hide}
1427      * Is this device in the process of being block encrypted?
1428      * @return true for encrypting.
1429      *         false otherwise
1430      * Whether device isEncrypted at this point is undefined
1431      * Note that only system services and CryptKeeper will ever see this return
1432      * true - no app will ever be launched in this state.
1433      * Also note that this state will not change without a teardown of the
1434      * framework, so no service needs to check for changes during their lifespan
1435      */
1436     public static boolean isBlockEncrypting() {
1437         final String state = SystemProperties.get("vold.encrypt_progress", "");
1438         return !"".equalsIgnoreCase(state);
1439     }
1440
1441     /** {@hide}
1442      * Is this device non default block encrypted and in the process of
1443      * prompting for credentials?
1444      * @return true for prompting for credentials.
1445      *         (Implies isNonDefaultBlockEncrypted() == true)
1446      *         false otherwise
1447      * Note that only system services and CryptKeeper will ever see this return
1448      * true - no app will ever be launched in this state.
1449      * Also note that this state will not change without a teardown of the
1450      * framework, so no service needs to check for changes during their lifespan
1451      */
1452     public static boolean inCryptKeeperBounce() {
1453         final String status = SystemProperties.get("vold.decrypt");
1454         return "trigger_restart_min_framework".equals(status);
1455     }
1456
1457     /** {@hide} */
1458     public static boolean isFileEncryptedEmulatedOnly() {
1459         return SystemProperties.getBoolean(StorageManager.PROP_EMULATE_FBE, false);
1460     }
1461
1462     /** {@hide}
1463      * Is this device running in a file encrypted mode, either native or emulated?
1464      * @return true for file encrypted, false otherwise
1465      */
1466     public static boolean isFileEncryptedNativeOrEmulated() {
1467         return isFileEncryptedNativeOnly()
1468                || isFileEncryptedEmulatedOnly();
1469     }
1470
1471     /** {@hide} */
1472     public static boolean hasAdoptable() {
1473         return SystemProperties.getBoolean(PROP_HAS_ADOPTABLE, false);
1474     }
1475
1476     /** {@hide} */
1477     public static File maybeTranslateEmulatedPathToInternal(File path) {
1478         // Disabled now that FUSE has been replaced by sdcardfs
1479         return path;
1480     }
1481
1482     /** {@hide} */
1483     @VisibleForTesting
1484     public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
1485             int mode, ProxyFileDescriptorCallback callback, Handler handler, ThreadFactory factory)
1486                     throws IOException {
1487         Preconditions.checkNotNull(callback);
1488         MetricsLogger.count(mContext, "storage_open_proxy_file_descriptor", 1);
1489         // Retry is needed because the mount point mFuseAppLoop is using may be unmounted before
1490         // invoking StorageManagerService#openProxyFileDescriptor. In this case, we need to re-mount
1491         // the bridge by calling mountProxyFileDescriptorBridge.
1492         while (true) {
1493             try {
1494                 synchronized (mFuseAppLoopLock) {
1495                     boolean newlyCreated = false;
1496                     if (mFuseAppLoop == null) {
1497                         final AppFuseMount mount = mStorageManager.mountProxyFileDescriptorBridge();
1498                         if (mount == null) {
1499                             throw new IOException("Failed to mount proxy bridge");
1500                         }
1501                         mFuseAppLoop = new FuseAppLoop(mount.mountPointId, mount.fd, factory);
1502                         newlyCreated = true;
1503                     }
1504                     if (handler == null) {
1505                         handler = new Handler(Looper.getMainLooper());
1506                     }
1507                     try {
1508                         final int fileId = mFuseAppLoop.registerCallback(callback, handler);
1509                         final ParcelFileDescriptor pfd = mStorageManager.openProxyFileDescriptor(
1510                                 mFuseAppLoop.getMountPointId(), fileId, mode);
1511                         if (pfd == null) {
1512                             mFuseAppLoop.unregisterCallback(fileId);
1513                             throw new FuseUnavailableMountException(
1514                                     mFuseAppLoop.getMountPointId());
1515                         }
1516                         return pfd;
1517                     } catch (FuseUnavailableMountException exception) {
1518                         // The bridge is being unmounted. Tried to recreate it unless the bridge was
1519                         // just created.
1520                         if (newlyCreated) {
1521                             throw new IOException(exception);
1522                         }
1523                         mFuseAppLoop = null;
1524                         continue;
1525                     }
1526                 }
1527             } catch (RemoteException e) {
1528                 // Cannot recover from remote exception.
1529                 throw new IOException(e);
1530             }
1531         }
1532     }
1533
1534     /** {@hide} */
1535     public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
1536             int mode, ProxyFileDescriptorCallback callback)
1537                     throws IOException {
1538         return openProxyFileDescriptor(mode, callback, null, null);
1539     }
1540
1541     /**
1542      * Opens a seekable {@link ParcelFileDescriptor} that proxies all low-level
1543      * I/O requests back to the given {@link ProxyFileDescriptorCallback}.
1544      * <p>
1545      * This can be useful when you want to provide quick access to a large file
1546      * that isn't backed by a real file on disk, such as a file on a network
1547      * share, cloud storage service, etc. As an example, you could respond to a
1548      * {@link ContentResolver#openFileDescriptor(android.net.Uri, String)}
1549      * request by returning a {@link ParcelFileDescriptor} created with this
1550      * method, and then stream the content on-demand as requested.
1551      * <p>
1552      * Another useful example might be where you have an encrypted file that
1553      * you're willing to decrypt on-demand, but where you want to avoid
1554      * persisting the cleartext version.
1555      *
1556      * @param mode The desired access mode, must be one of
1557      *            {@link ParcelFileDescriptor#MODE_READ_ONLY},
1558      *            {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
1559      *            {@link ParcelFileDescriptor#MODE_READ_WRITE}
1560      * @param callback Callback to process file operation requests issued on
1561      *            returned file descriptor.
1562      * @param handler Handler that invokes callback methods.
1563      * @return Seekable ParcelFileDescriptor.
1564      * @throws IOException
1565      */
1566     public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
1567             int mode, ProxyFileDescriptorCallback callback, Handler handler)
1568                     throws IOException {
1569         Preconditions.checkNotNull(handler);
1570         return openProxyFileDescriptor(mode, callback, handler, null);
1571     }
1572
1573     /** {@hide} */
1574     @VisibleForTesting
1575     public int getProxyFileDescriptorMountPointId() {
1576         synchronized (mFuseAppLoopLock) {
1577             return mFuseAppLoop != null ? mFuseAppLoop.getMountPointId() : -1;
1578         }
1579     }
1580
1581     /**
1582      * Return quota size in bytes for all cached data belonging to the calling
1583      * app on the given storage volume.
1584      * <p>
1585      * If your app goes above this quota, your cached files will be some of the
1586      * first to be deleted when additional disk space is needed. Conversely, if
1587      * your app stays under this quota, your cached files will be some of the
1588      * last to be deleted when additional disk space is needed.
1589      * <p>
1590      * This quota will change over time depending on how frequently the user
1591      * interacts with your app, and depending on how much system-wide disk space
1592      * is used.
1593      * <p class="note">
1594      * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1595      * then cached data for all packages in your shared UID is tracked together
1596      * as a single unit.
1597      * </p>
1598      *
1599      * @param storageUuid the UUID of the storage volume that you're interested
1600      *            in. The UUID for a specific path can be obtained using
1601      *            {@link #getUuidForPath(File)}.
1602      * @throws IOException when the storage device isn't present, or when it
1603      *             doesn't support cache quotas.
1604      * @see #getCacheSizeBytes(UUID)
1605      */
1606     @WorkerThread
1607     public @BytesLong long getCacheQuotaBytes(@NonNull UUID storageUuid) throws IOException {
1608         try {
1609             final ApplicationInfo app = mContext.getApplicationInfo();
1610             return mStorageManager.getCacheQuotaBytes(convert(storageUuid), app.uid);
1611         } catch (ParcelableException e) {
1612             e.maybeRethrow(IOException.class);
1613             throw new RuntimeException(e);
1614         } catch (RemoteException e) {
1615             throw e.rethrowFromSystemServer();
1616         }
1617     }
1618
1619     /**
1620      * Return total size in bytes of all cached data belonging to the calling
1621      * app on the given storage volume.
1622      * <p>
1623      * Cached data tracked by this method always includes
1624      * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}, and
1625      * it also includes {@link Context#getExternalCacheDir()} if the primary
1626      * shared/external storage is hosted on the same storage device as your
1627      * private data.
1628      * <p class="note">
1629      * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1630      * then cached data for all packages in your shared UID is tracked together
1631      * as a single unit.
1632      * </p>
1633      *
1634      * @param storageUuid the UUID of the storage volume that you're interested
1635      *            in. The UUID for a specific path can be obtained using
1636      *            {@link #getUuidForPath(File)}.
1637      * @throws IOException when the storage device isn't present, or when it
1638      *             doesn't support cache quotas.
1639      * @see #getCacheQuotaBytes(UUID)
1640      */
1641     @WorkerThread
1642     public @BytesLong long getCacheSizeBytes(@NonNull UUID storageUuid) throws IOException {
1643         try {
1644             final ApplicationInfo app = mContext.getApplicationInfo();
1645             return mStorageManager.getCacheSizeBytes(convert(storageUuid), app.uid);
1646         } catch (ParcelableException e) {
1647             e.maybeRethrow(IOException.class);
1648             throw new RuntimeException(e);
1649         } catch (RemoteException e) {
1650             throw e.rethrowFromSystemServer();
1651         }
1652     }
1653
1654     /**
1655      * Flag indicating that a disk space allocation request should operate in an
1656      * aggressive mode. This flag should only be rarely used in situations that
1657      * are critical to system health or security.
1658      * <p>
1659      * When set, the system is more aggressive about the data that it considers
1660      * for possible deletion when allocating disk space.
1661      * <p class="note">
1662      * Note: your app must hold the
1663      * {@link android.Manifest.permission#ALLOCATE_AGGRESSIVE} permission for
1664      * this flag to take effect.
1665      * </p>
1666      *
1667      * @see #getAllocatableBytes(UUID, int)
1668      * @see #allocateBytes(UUID, long, int)
1669      * @see #allocateBytes(FileDescriptor, long, int)
1670      * @hide
1671      */
1672     @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE)
1673     @SystemApi
1674     public static final int FLAG_ALLOCATE_AGGRESSIVE = 1 << 0;
1675
1676     /**
1677      * Flag indicating that a disk space allocation request should be allowed to
1678      * clear up to all reserved disk space.
1679      *
1680      * @hide
1681      */
1682     public static final int FLAG_ALLOCATE_DEFY_ALL_RESERVED = 1 << 1;
1683
1684     /**
1685      * Flag indicating that a disk space allocation request should be allowed to
1686      * clear up to half of all reserved disk space.
1687      *
1688      * @hide
1689      */
1690     public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2;
1691
1692     /** @hide */
1693     @IntDef(flag = true, prefix = { "FLAG_ALLOCATE_" }, value = {
1694             FLAG_ALLOCATE_AGGRESSIVE,
1695             FLAG_ALLOCATE_DEFY_ALL_RESERVED,
1696             FLAG_ALLOCATE_DEFY_HALF_RESERVED,
1697     })
1698     @Retention(RetentionPolicy.SOURCE)
1699     public @interface AllocateFlags {}
1700
1701     /**
1702      * Return the maximum number of new bytes that your app can allocate for
1703      * itself on the given storage volume. This value is typically larger than
1704      * {@link File#getUsableSpace()}, since the system may be willing to delete
1705      * cached files to satisfy an allocation request. You can then allocate
1706      * space for yourself using {@link #allocateBytes(UUID, long)} or
1707      * {@link #allocateBytes(FileDescriptor, long)}.
1708      * <p>
1709      * This method is best used as a pre-flight check, such as deciding if there
1710      * is enough space to store an entire music album before you allocate space
1711      * for each audio file in the album. Attempts to allocate disk space beyond
1712      * the returned value will fail.
1713      * <p>
1714      * If the returned value is not large enough for the data you'd like to
1715      * persist, you can launch {@link #ACTION_MANAGE_STORAGE} with the
1716      * {@link #EXTRA_UUID} and {@link #EXTRA_REQUESTED_BYTES} options to help
1717      * involve the user in freeing up disk space.
1718      * <p>
1719      * If you're progressively allocating an unbounded amount of storage space
1720      * (such as when recording a video) you should avoid calling this method
1721      * more than once every 30 seconds.
1722      * <p class="note">
1723      * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1724      * then allocatable space for all packages in your shared UID is tracked
1725      * together as a single unit.
1726      * </p>
1727      *
1728      * @param storageUuid the UUID of the storage volume where you're
1729      *            considering allocating disk space, since allocatable space can
1730      *            vary widely depending on the underlying storage device. The
1731      *            UUID for a specific path can be obtained using
1732      *            {@link #getUuidForPath(File)}.
1733      * @return the maximum number of new bytes that the calling app can allocate
1734      *         using {@link #allocateBytes(UUID, long)} or
1735      *         {@link #allocateBytes(FileDescriptor, long)}.
1736      * @throws IOException when the storage device isn't present, or when it
1737      *             doesn't support allocating space.
1738      */
1739     @WorkerThread
1740     public @BytesLong long getAllocatableBytes(@NonNull UUID storageUuid)
1741             throws IOException {
1742         return getAllocatableBytes(storageUuid, 0);
1743     }
1744
1745     /** @hide */
1746     @SystemApi
1747     @WorkerThread
1748     @SuppressLint("Doclava125")
1749     public long getAllocatableBytes(@NonNull UUID storageUuid,
1750             @RequiresPermission @AllocateFlags int flags) throws IOException {
1751         try {
1752             return mStorageManager.getAllocatableBytes(convert(storageUuid), flags,
1753                     mContext.getOpPackageName());
1754         } catch (ParcelableException e) {
1755             e.maybeRethrow(IOException.class);
1756             throw new RuntimeException(e);
1757         } catch (RemoteException e) {
1758             throw e.rethrowFromSystemServer();
1759         }
1760     }
1761
1762     /**
1763      * Allocate the requested number of bytes for your application to use on the
1764      * given storage volume. This will cause the system to delete any cached
1765      * files necessary to satisfy your request.
1766      * <p>
1767      * Attempts to allocate disk space beyond the value returned by
1768      * {@link #getAllocatableBytes(UUID)} will fail.
1769      * <p>
1770      * Since multiple apps can be running simultaneously, this method may be
1771      * subject to race conditions. If possible, consider using
1772      * {@link #allocateBytes(FileDescriptor, long)} which will guarantee
1773      * that bytes are allocated to an opened file.
1774      * <p>
1775      * If you're progressively allocating an unbounded amount of storage space
1776      * (such as when recording a video) you should avoid calling this method
1777      * more than once every 60 seconds.
1778      *
1779      * @param storageUuid the UUID of the storage volume where you'd like to
1780      *            allocate disk space. The UUID for a specific path can be
1781      *            obtained using {@link #getUuidForPath(File)}.
1782      * @param bytes the number of bytes to allocate.
1783      * @throws IOException when the storage device isn't present, or when it
1784      *             doesn't support allocating space, or if the device had
1785      *             trouble allocating the requested space.
1786      * @see #getAllocatableBytes(UUID)
1787      */
1788     @WorkerThread
1789     public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes)
1790             throws IOException {
1791         allocateBytes(storageUuid, bytes, 0);
1792     }
1793
1794     /** @hide */
1795     @SystemApi
1796     @WorkerThread
1797     @SuppressLint("Doclava125")
1798     public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes,
1799             @RequiresPermission @AllocateFlags int flags) throws IOException {
1800         try {
1801             mStorageManager.allocateBytes(convert(storageUuid), bytes, flags,
1802                     mContext.getOpPackageName());
1803         } catch (ParcelableException e) {
1804             e.maybeRethrow(IOException.class);
1805         } catch (RemoteException e) {
1806             throw e.rethrowFromSystemServer();
1807         }
1808     }
1809
1810     /**
1811      * Allocate the requested number of bytes for your application to use in the
1812      * given open file. This will cause the system to delete any cached files
1813      * necessary to satisfy your request.
1814      * <p>
1815      * Attempts to allocate disk space beyond the value returned by
1816      * {@link #getAllocatableBytes(UUID)} will fail.
1817      * <p>
1818      * This method guarantees that bytes have been allocated to the opened file,
1819      * otherwise it will throw if fast allocation is not possible. Fast
1820      * allocation is typically only supported in private app data directories,
1821      * and on shared/external storage devices which are emulated.
1822      * <p>
1823      * If you're progressively allocating an unbounded amount of storage space
1824      * (such as when recording a video) you should avoid calling this method
1825      * more than once every 60 seconds.
1826      *
1827      * @param fd the open file that you'd like to allocate disk space for.
1828      * @param bytes the number of bytes to allocate. This is the desired final
1829      *            size of the open file. If the open file is smaller than this
1830      *            requested size, it will be extended without modifying any
1831      *            existing contents. If the open file is larger than this
1832      *            requested size, it will be truncated.
1833      * @throws IOException when the storage device isn't present, or when it
1834      *             doesn't support allocating space, or if the device had
1835      *             trouble allocating the requested space.
1836      * @see #getAllocatableBytes(UUID, int)
1837      * @see #isAllocationSupported(FileDescriptor)
1838      * @see Environment#isExternalStorageEmulated(File)
1839      */
1840     @WorkerThread
1841     public void allocateBytes(FileDescriptor fd, @BytesLong long bytes) throws IOException {
1842         allocateBytes(fd, bytes, 0);
1843     }
1844
1845     /** @hide */
1846     @SystemApi
1847     @WorkerThread
1848     @SuppressLint("Doclava125")
1849     public void allocateBytes(FileDescriptor fd, @BytesLong long bytes,
1850             @RequiresPermission @AllocateFlags int flags) throws IOException {
1851         final File file = ParcelFileDescriptor.getFile(fd);
1852         final UUID uuid = getUuidForPath(file);
1853         for (int i = 0; i < 3; i++) {
1854             try {
1855                 final long haveBytes = Os.fstat(fd).st_blocks * 512;
1856                 final long needBytes = bytes - haveBytes;
1857
1858                 if (needBytes > 0) {
1859                     allocateBytes(uuid, needBytes, flags);
1860                 }
1861
1862                 try {
1863                     Os.posix_fallocate(fd, 0, bytes);
1864                     return;
1865                 } catch (ErrnoException e) {
1866                     if (e.errno == OsConstants.ENOSYS || e.errno == OsConstants.ENOTSUP) {
1867                         Log.w(TAG, "fallocate() not supported; falling back to ftruncate()");
1868                         Os.ftruncate(fd, bytes);
1869                         return;
1870                     } else {
1871                         throw e;
1872                     }
1873                 }
1874             } catch (ErrnoException e) {
1875                 if (e.errno == OsConstants.ENOSPC) {
1876                     Log.w(TAG, "Odd, not enough space; let's try again?");
1877                     continue;
1878                 }
1879                 throw e.rethrowAsIOException();
1880             }
1881         }
1882         throw new IOException(
1883                 "Well this is embarassing; we can't allocate " + bytes + " for " + file);
1884     }
1885
1886     private static final String XATTR_CACHE_GROUP = "user.cache_group";
1887     private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone";
1888
1889     /** {@hide} */
1890     private static void setCacheBehavior(File path, String name, boolean enabled)
1891             throws IOException {
1892         if (!path.isDirectory()) {
1893             throw new IOException("Cache behavior can only be set on directories");
1894         }
1895         if (enabled) {
1896             try {
1897                 Os.setxattr(path.getAbsolutePath(), name,
1898                         "1".getBytes(StandardCharsets.UTF_8), 0);
1899             } catch (ErrnoException e) {
1900                 throw e.rethrowAsIOException();
1901             }
1902         } else {
1903             try {
1904                 Os.removexattr(path.getAbsolutePath(), name);
1905             } catch (ErrnoException e) {
1906                 if (e.errno != OsConstants.ENODATA) {
1907                     throw e.rethrowAsIOException();
1908                 }
1909             }
1910         }
1911     }
1912
1913     /** {@hide} */
1914     private static boolean isCacheBehavior(File path, String name) throws IOException {
1915         try {
1916             Os.getxattr(path.getAbsolutePath(), name);
1917             return true;
1918         } catch (ErrnoException e) {
1919             if (e.errno != OsConstants.ENODATA) {
1920                 throw e.rethrowAsIOException();
1921             } else {
1922                 return false;
1923             }
1924         }
1925     }
1926
1927     /**
1928      * Enable or disable special cache behavior that treats this directory and
1929      * its contents as an entire group.
1930      * <p>
1931      * When enabled and this directory is considered for automatic deletion by
1932      * the OS, all contained files will either be deleted together, or not at
1933      * all. This is useful when you have a directory that contains several
1934      * related metadata files that depend on each other, such as movie file and
1935      * a subtitle file.
1936      * <p>
1937      * When enabled, the <em>newest</em> {@link File#lastModified()} value of
1938      * any contained files is considered the modified time of the entire
1939      * directory.
1940      * <p>
1941      * This behavior can only be set on a directory, and it applies recursively
1942      * to all contained files and directories.
1943      */
1944     public void setCacheBehaviorGroup(File path, boolean group) throws IOException {
1945         setCacheBehavior(path, XATTR_CACHE_GROUP, group);
1946     }
1947
1948     /**
1949      * Read the current value set by
1950      * {@link #setCacheBehaviorGroup(File, boolean)}.
1951      */
1952     public boolean isCacheBehaviorGroup(File path) throws IOException {
1953         return isCacheBehavior(path, XATTR_CACHE_GROUP);
1954     }
1955
1956     /**
1957      * Enable or disable special cache behavior that leaves deleted cache files
1958      * intact as tombstones.
1959      * <p>
1960      * When enabled and a file contained in this directory is automatically
1961      * deleted by the OS, the file will be truncated to have a length of 0 bytes
1962      * instead of being fully deleted. This is useful if you need to distinguish
1963      * between a file that was deleted versus one that never existed.
1964      * <p>
1965      * This behavior can only be set on a directory, and it applies recursively
1966      * to all contained files and directories.
1967      * <p class="note">
1968      * Note: this behavior is ignored completely if the user explicitly requests
1969      * that all cached data be cleared.
1970      * </p>
1971      */
1972     public void setCacheBehaviorTombstone(File path, boolean tombstone) throws IOException {
1973         setCacheBehavior(path, XATTR_CACHE_TOMBSTONE, tombstone);
1974     }
1975
1976     /**
1977      * Read the current value set by
1978      * {@link #setCacheBehaviorTombstone(File, boolean)}.
1979      */
1980     public boolean isCacheBehaviorTombstone(File path) throws IOException {
1981         return isCacheBehavior(path, XATTR_CACHE_TOMBSTONE);
1982     }
1983
1984     /** {@hide} */
1985     public static UUID convert(String uuid) {
1986         if (Objects.equals(uuid, UUID_PRIVATE_INTERNAL)) {
1987             return UUID_DEFAULT;
1988         } else if (Objects.equals(uuid, UUID_PRIMARY_PHYSICAL)) {
1989             return UUID_PRIMARY_PHYSICAL_;
1990         } else if (Objects.equals(uuid, UUID_SYSTEM)) {
1991             return UUID_SYSTEM_;
1992         } else {
1993             return UUID.fromString(uuid);
1994         }
1995     }
1996
1997     /** {@hide} */
1998     public static String convert(UUID storageUuid) {
1999         if (UUID_DEFAULT.equals(storageUuid)) {
2000             return UUID_PRIVATE_INTERNAL;
2001         } else if (UUID_PRIMARY_PHYSICAL_.equals(storageUuid)) {
2002             return UUID_PRIMARY_PHYSICAL;
2003         } else if (UUID_SYSTEM_.equals(storageUuid)) {
2004             return UUID_SYSTEM;
2005         } else {
2006             return storageUuid.toString();
2007         }
2008     }
2009
2010     private final Object mFuseAppLoopLock = new Object();
2011
2012     @GuardedBy("mFuseAppLoopLock")
2013     private @Nullable FuseAppLoop mFuseAppLoop = null;
2014
2015     /// Consts to match the password types in cryptfs.h
2016     /** @hide */
2017     public static final int CRYPT_TYPE_PASSWORD = IVold.PASSWORD_TYPE_PASSWORD;
2018     /** @hide */
2019     public static final int CRYPT_TYPE_DEFAULT = IVold.PASSWORD_TYPE_DEFAULT;
2020     /** @hide */
2021     public static final int CRYPT_TYPE_PATTERN = IVold.PASSWORD_TYPE_PATTERN;
2022     /** @hide */
2023     public static final int CRYPT_TYPE_PIN = IVold.PASSWORD_TYPE_PIN;
2024
2025     // Constants for the data available via StorageManagerService.getField.
2026     /** @hide */
2027     public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
2028     /** @hide */
2029     public static final String OWNER_INFO_KEY = "OwnerInfo";
2030     /** @hide */
2031     public static final String PATTERN_VISIBLE_KEY = "PatternVisible";
2032     /** @hide */
2033     public static final String PASSWORD_VISIBLE_KEY = "PasswordVisible";
2034 }