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