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