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