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