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.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
20 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
21 import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
22 import static android.app.AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE;
23 import static android.app.AppOpsManager.OP_READ_EXTERNAL_STORAGE;
24 import static android.app.AppOpsManager.OP_READ_MEDIA_IMAGES;
25 import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
26 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
27 import static android.os.UserHandle.PER_USER_RANGE;
28 
29 import android.annotation.BytesLong;
30 import android.annotation.CallbackExecutor;
31 import android.annotation.IntDef;
32 import android.annotation.NonNull;
33 import android.annotation.Nullable;
34 import android.annotation.RequiresPermission;
35 import android.annotation.SdkConstant;
36 import android.annotation.SuppressLint;
37 import android.annotation.SystemApi;
38 import android.annotation.SystemService;
39 import android.annotation.TestApi;
40 import android.annotation.WorkerThread;
41 import android.app.Activity;
42 import android.app.ActivityThread;
43 import android.app.AppGlobals;
44 import android.app.AppOpsManager;
45 import android.app.PendingIntent;
46 import android.compat.annotation.UnsupportedAppUsage;
47 import android.content.ContentResolver;
48 import android.content.Context;
49 import android.content.Intent;
50 import android.content.pm.ApplicationInfo;
51 import android.content.pm.IPackageMoveObserver;
52 import android.content.pm.PackageManager;
53 import android.content.res.ObbInfo;
54 import android.content.res.ObbScanner;
55 import android.database.Cursor;
56 import android.net.Uri;
57 import android.os.Binder;
58 import android.os.Build;
59 import android.os.Environment;
60 import android.os.FileUtils;
61 import android.os.Handler;
62 import android.os.IInstalld;
63 import android.os.IVold;
64 import android.os.IVoldTaskListener;
65 import android.os.Looper;
66 import android.os.Message;
67 import android.os.ParcelFileDescriptor;
68 import android.os.ParcelableException;
69 import android.os.PersistableBundle;
70 import android.os.ProxyFileDescriptorCallback;
71 import android.os.RemoteException;
72 import android.os.ServiceManager;
73 import android.os.ServiceManager.ServiceNotFoundException;
74 import android.os.SystemProperties;
75 import android.os.UserHandle;
76 import android.provider.DeviceConfig;
77 import android.provider.MediaStore;
78 import android.provider.Settings;
79 import android.system.ErrnoException;
80 import android.system.Os;
81 import android.system.OsConstants;
82 import android.text.TextUtils;
83 import android.util.DataUnit;
84 import android.util.Log;
85 import android.util.Pair;
86 import android.util.Slog;
87 import android.util.SparseArray;
88 
89 import com.android.internal.annotations.GuardedBy;
90 import com.android.internal.annotations.VisibleForTesting;
91 import com.android.internal.logging.MetricsLogger;
92 import com.android.internal.os.AppFuseMount;
93 import com.android.internal.os.FuseAppLoop;
94 import com.android.internal.os.FuseUnavailableMountException;
95 import com.android.internal.os.RoSystemProperties;
96 import com.android.internal.util.Preconditions;
97 
98 import dalvik.system.BlockGuard;
99 
100 import java.io.File;
101 import java.io.FileDescriptor;
102 import java.io.FileNotFoundException;
103 import java.io.IOException;
104 import java.lang.annotation.Retention;
105 import java.lang.annotation.RetentionPolicy;
106 import java.lang.ref.WeakReference;
107 import java.nio.charset.StandardCharsets;
108 import java.util.ArrayList;
109 import java.util.Arrays;
110 import java.util.Collections;
111 import java.util.Iterator;
112 import java.util.List;
113 import java.util.Locale;
114 import java.util.Objects;
115 import java.util.UUID;
116 import java.util.concurrent.CompletableFuture;
117 import java.util.concurrent.Executor;
118 import java.util.concurrent.ThreadFactory;
119 import java.util.concurrent.TimeUnit;
120 import java.util.concurrent.atomic.AtomicInteger;
121 
122 /**
123  * StorageManager is the interface to the systems storage service. The storage
124  * manager handles storage-related items such as Opaque Binary Blobs (OBBs).
125  * <p>
126  * OBBs contain a filesystem that maybe be encrypted on disk and mounted
127  * on-demand from an application. OBBs are a good way of providing large amounts
128  * of binary assets without packaging them into APKs as they may be multiple
129  * gigabytes in size. However, due to their size, they're most likely stored in
130  * a shared storage pool accessible from all programs. The system does not
131  * guarantee the security of the OBB file itself: if any program modifies the
132  * OBB, there is no guarantee that a read from that OBB will produce the
133  * expected output.
134  */
135 @SystemService(Context.STORAGE_SERVICE)
136 public class StorageManager {
137     private static final String TAG = "StorageManager";
138     private static final boolean LOCAL_LOGV = Log.isLoggable(TAG, Log.VERBOSE);
139 
140     /** {@hide} */
141     public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
142     /** {@hide} */
143     public static final String PROP_HAS_ADOPTABLE = "vold.has_adoptable";
144     /** {@hide} */
145     public static final String PROP_HAS_RESERVED = "vold.has_reserved";
146     /** {@hide} */
147     public static final String PROP_ADOPTABLE = "persist.sys.adoptable";
148     /** {@hide} */
149     public static final String PROP_SDCARDFS = "persist.sys.sdcardfs";
150     /** {@hide} */
151     public static final String PROP_VIRTUAL_DISK = "persist.sys.virtual_disk";
152     /** {@hide} */
153     public static final String PROP_FORCED_SCOPED_STORAGE_WHITELIST =
154             "forced_scoped_storage_whitelist";
155 
156     /** {@hide} */
157     public static final String UUID_PRIVATE_INTERNAL = null;
158     /** {@hide} */
159     public static final String UUID_PRIMARY_PHYSICAL = "primary_physical";
160     /** {@hide} */
161     public static final String UUID_SYSTEM = "system";
162 
163     // NOTE: See comments around #convert for more details.
164     private static final String FAT_UUID_PREFIX = "fafafafa-fafa-5afa-8afa-fafa";
165 
166     // NOTE: UUID constants below are namespaced
167     // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad default
168     // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad primary_physical
169     // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad system
170 
171     /**
172      * UUID representing the default internal storage of this device which
173      * provides {@link Environment#getDataDirectory()}.
174      * <p>
175      * This value is constant across all devices and it will never change, and
176      * thus it cannot be used to uniquely identify a particular physical device.
177      *
178      * @see #getUuidForPath(File)
179      * @see ApplicationInfo#storageUuid
180      */
181     public static final UUID UUID_DEFAULT = UUID
182             .fromString("41217664-9172-527a-b3d5-edabb50a7d69");
183 
184     /** {@hide} */
185     public static final UUID UUID_PRIMARY_PHYSICAL_ = UUID
186             .fromString("0f95a519-dae7-5abf-9519-fbd6209e05fd");
187 
188     /** {@hide} */
189     public static final UUID UUID_SYSTEM_ = UUID
190             .fromString("5d258386-e60d-59e3-826d-0089cdd42cc0");
191 
192     /**
193      * Activity Action: Allows the user to manage their storage. This activity
194      * provides the ability to free up space on the device by deleting data such
195      * as apps.
196      * <p>
197      * If the sending application has a specific storage device or allocation
198      * size in mind, they can optionally define {@link #EXTRA_UUID} or
199      * {@link #EXTRA_REQUESTED_BYTES}, respectively.
200      * <p>
201      * This intent should be launched using
202      * {@link Activity#startActivityForResult(Intent, int)} so that the user
203      * knows which app is requesting the storage space. The returned result will
204      * be {@link Activity#RESULT_OK} if the requested space was made available,
205      * or {@link Activity#RESULT_CANCELED} otherwise.
206      */
207     @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
208     public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
209 
210     /**
211      * Activity Action: Allows the user to free up space by clearing app external cache directories.
212      * The intent doesn't automatically clear cache, but shows a dialog and lets the user decide.
213      * <p>
214      * This intent should be launched using
215      * {@link Activity#startActivityForResult(Intent, int)} so that the user
216      * knows which app is requesting to clear cache. The returned result will be:
217      * {@link Activity#RESULT_OK} if the activity was launched and all cache was cleared,
218      * {@link OsConstants#EIO} if an error occurred while clearing the cache or
219      * {@link Activity#RESULT_CANCELED} otherwise.
220      */
221     @RequiresPermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE)
222     @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
223     public static final String ACTION_CLEAR_APP_CACHE = "android.os.storage.action.CLEAR_APP_CACHE";
224 
225     /**
226      * Extra {@link UUID} used to indicate the storage volume where an
227      * application is interested in allocating or managing disk space.
228      *
229      * @see #ACTION_MANAGE_STORAGE
230      * @see #UUID_DEFAULT
231      * @see #getUuidForPath(File)
232      * @see Intent#putExtra(String, java.io.Serializable)
233      */
234     public static final String EXTRA_UUID = "android.os.storage.extra.UUID";
235 
236     /**
237      * Extra used to indicate the total size (in bytes) that an application is
238      * interested in allocating.
239      * <p>
240      * When defined, the management UI will help guide the user to free up
241      * enough disk space to reach this requested value.
242      *
243      * @see #ACTION_MANAGE_STORAGE
244      */
245     public static final String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES";
246 
247     /** {@hide} */
248     public static final int DEBUG_ADOPTABLE_FORCE_ON = 1 << 0;
249     /** {@hide} */
250     public static final int DEBUG_ADOPTABLE_FORCE_OFF = 1 << 1;
251     /** {@hide} */
252     public static final int DEBUG_SDCARDFS_FORCE_ON = 1 << 2;
253     /** {@hide} */
254     public static final int DEBUG_SDCARDFS_FORCE_OFF = 1 << 3;
255     /** {@hide} */
256     public static final int DEBUG_VIRTUAL_DISK = 1 << 4;
257 
258     /** {@hide} */
259     public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE;
260     /** {@hide} */
261     public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE;
262     /** {@hide} */
263     public static final int FLAG_STORAGE_EXTERNAL = IInstalld.FLAG_STORAGE_EXTERNAL;
264     /** @hide */
265     public static final int FLAG_STORAGE_SDK = IInstalld.FLAG_STORAGE_SDK;
266 
267     /** {@hide} */
268     @IntDef(prefix = "FLAG_STORAGE_",  value = {
269             FLAG_STORAGE_DE,
270             FLAG_STORAGE_CE,
271             FLAG_STORAGE_EXTERNAL,
272             FLAG_STORAGE_SDK,
273     })
274     @Retention(RetentionPolicy.SOURCE)
275     public @interface StorageFlags {}
276 
277     /** {@hide} */
278     public static final int FLAG_FOR_WRITE = 1 << 8;
279     /** {@hide} */
280     public static final int FLAG_REAL_STATE = 1 << 9;
281     /** {@hide} */
282     public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10;
283     /** {@hide} */
284     public static final int FLAG_INCLUDE_RECENT = 1 << 11;
285     /** {@hide} */
286     public static final int FLAG_INCLUDE_SHARED_PROFILE = 1 << 12;
287 
288     /** {@hide} */
289     public static final int FSTRIM_FLAG_DEEP = IVold.FSTRIM_FLAG_DEEP_TRIM;
290 
291     /** @hide The volume is not encrypted. */
292     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
293     public static final int ENCRYPTION_STATE_NONE = 1;
294 
295     private static volatile IStorageManager sStorageManager = null;
296 
297     private final Context mContext;
298     private final ContentResolver mResolver;
299 
300     private final IStorageManager mStorageManager;
301     private final AppOpsManager mAppOps;
302     private final Looper mLooper;
303     private final AtomicInteger mNextNonce = new AtomicInteger(0);
304 
305     @GuardedBy("mDelegates")
306     private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>();
307 
308     private class StorageEventListenerDelegate extends IStorageEventListener.Stub {
309         final Executor mExecutor;
310         final StorageEventListener mListener;
311         final StorageVolumeCallback mCallback;
312 
StorageEventListenerDelegate(@onNull Executor executor, @NonNull StorageEventListener listener, @NonNull StorageVolumeCallback callback)313         public StorageEventListenerDelegate(@NonNull Executor executor,
314                 @NonNull StorageEventListener listener, @NonNull StorageVolumeCallback callback) {
315             mExecutor = executor;
316             mListener = listener;
317             mCallback = callback;
318         }
319 
320         @Override
onUsbMassStorageConnectionChanged(boolean connected)321         public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException {
322             mExecutor.execute(() -> {
323                 mListener.onUsbMassStorageConnectionChanged(connected);
324             });
325         }
326 
327         @Override
onStorageStateChanged(String path, String oldState, String newState)328         public void onStorageStateChanged(String path, String oldState, String newState) {
329             mExecutor.execute(() -> {
330                 mListener.onStorageStateChanged(path, oldState, newState);
331 
332                 if (path != null) {
333                     for (StorageVolume sv : getStorageVolumes()) {
334                         if (Objects.equals(path, sv.getPath())) {
335                             mCallback.onStateChanged(sv);
336                         }
337                     }
338                 }
339             });
340         }
341 
342         @Override
onVolumeStateChanged(VolumeInfo vol, int oldState, int newState)343         public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
344             mExecutor.execute(() -> {
345                 mListener.onVolumeStateChanged(vol, oldState, newState);
346 
347                 final File path = vol.getPathForUser(UserHandle.myUserId());
348                 if (path != null) {
349                     for (StorageVolume sv : getStorageVolumes()) {
350                         if (Objects.equals(path.getAbsolutePath(), sv.getPath())) {
351                             mCallback.onStateChanged(sv);
352                         }
353                     }
354                 }
355             });
356         }
357 
358         @Override
onVolumeRecordChanged(VolumeRecord rec)359         public void onVolumeRecordChanged(VolumeRecord rec) {
360             mExecutor.execute(() -> {
361                 mListener.onVolumeRecordChanged(rec);
362             });
363         }
364 
365         @Override
onVolumeForgotten(String fsUuid)366         public void onVolumeForgotten(String fsUuid) {
367             mExecutor.execute(() -> {
368                 mListener.onVolumeForgotten(fsUuid);
369             });
370         }
371 
372         @Override
onDiskScanned(DiskInfo disk, int volumeCount)373         public void onDiskScanned(DiskInfo disk, int volumeCount) {
374             mExecutor.execute(() -> {
375                 mListener.onDiskScanned(disk, volumeCount);
376             });
377         }
378 
379         @Override
onDiskDestroyed(DiskInfo disk)380         public void onDiskDestroyed(DiskInfo disk) throws RemoteException {
381             mExecutor.execute(() -> {
382                 mListener.onDiskDestroyed(disk);
383             });
384         }
385     }
386 
387     /**
388      * Binder listener for OBB action results.
389      */
390     private final ObbActionListener mObbActionListener = new ObbActionListener();
391 
392     private class ObbActionListener extends IObbActionListener.Stub {
393         @SuppressWarnings("hiding")
394         private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>();
395 
396         @Override
onObbResult(String filename, int nonce, int status)397         public void onObbResult(String filename, int nonce, int status) {
398             final ObbListenerDelegate delegate;
399             synchronized (mListeners) {
400                 delegate = mListeners.get(nonce);
401                 if (delegate != null) {
402                     mListeners.remove(nonce);
403                 }
404             }
405 
406             if (delegate != null) {
407                 delegate.sendObbStateChanged(filename, status);
408             }
409         }
410 
addListener(OnObbStateChangeListener listener)411         public int addListener(OnObbStateChangeListener listener) {
412             final ObbListenerDelegate delegate = new ObbListenerDelegate(listener);
413 
414             synchronized (mListeners) {
415                 mListeners.put(delegate.nonce, delegate);
416             }
417 
418             return delegate.nonce;
419         }
420     }
421 
getNextNonce()422     private int getNextNonce() {
423         return mNextNonce.getAndIncrement();
424     }
425 
426     /**
427      * Private class containing sender and receiver code for StorageEvents.
428      */
429     private class ObbListenerDelegate {
430         private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef;
431         private final Handler mHandler;
432 
433         private final int nonce;
434 
ObbListenerDelegate(OnObbStateChangeListener listener)435         ObbListenerDelegate(OnObbStateChangeListener listener) {
436             nonce = getNextNonce();
437             mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener);
438             mHandler = new Handler(mLooper) {
439                 @Override
440                 public void handleMessage(Message msg) {
441                     final OnObbStateChangeListener changeListener = getListener();
442                     if (changeListener == null) {
443                         return;
444                     }
445 
446                     changeListener.onObbStateChange((String) msg.obj, msg.arg1);
447                 }
448             };
449         }
450 
getListener()451         OnObbStateChangeListener getListener() {
452             if (mObbEventListenerRef == null) {
453                 return null;
454             }
455             return mObbEventListenerRef.get();
456         }
457 
sendObbStateChanged(String path, int state)458         void sendObbStateChanged(String path, int state) {
459             mHandler.obtainMessage(0, state, 0, path).sendToTarget();
460         }
461     }
462 
463     /** {@hide} */
464     @Deprecated
465     @UnsupportedAppUsage
from(Context context)466     public static StorageManager from(Context context) {
467         return context.getSystemService(StorageManager.class);
468     }
469 
470     /**
471      * Constructs a StorageManager object through which an application can
472      * can communicate with the systems mount service.
473      *
474      * @param looper The {@link android.os.Looper} which events will be received on.
475      *
476      * <p>Applications can get instance of this class by calling
477      * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
478      * of {@link android.content.Context#STORAGE_SERVICE}.
479      *
480      * @hide
481      */
482     @UnsupportedAppUsage
StorageManager(Context context, Looper looper)483     public StorageManager(Context context, Looper looper) throws ServiceNotFoundException {
484         mContext = context;
485         mResolver = context.getContentResolver();
486         mLooper = looper;
487         mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getServiceOrThrow("mount"));
488         mAppOps = mContext.getSystemService(AppOpsManager.class);
489     }
490 
491     /**
492      * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
493      *
494      * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
495      *
496      * @hide
497      */
498     @UnsupportedAppUsage
registerListener(StorageEventListener listener)499     public void registerListener(StorageEventListener listener) {
500         synchronized (mDelegates) {
501             final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(
502                     mContext.getMainExecutor(), listener, new StorageVolumeCallback());
503             try {
504                 mStorageManager.registerListener(delegate);
505             } catch (RemoteException e) {
506                 throw e.rethrowFromSystemServer();
507             }
508             mDelegates.add(delegate);
509         }
510     }
511 
512     /**
513      * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}.
514      *
515      * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
516      *
517      * @hide
518      */
519     @UnsupportedAppUsage
unregisterListener(StorageEventListener listener)520     public void unregisterListener(StorageEventListener listener) {
521         synchronized (mDelegates) {
522             for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
523                 final StorageEventListenerDelegate delegate = i.next();
524                 if (delegate.mListener == listener) {
525                     try {
526                         mStorageManager.unregisterListener(delegate);
527                     } catch (RemoteException e) {
528                         throw e.rethrowFromSystemServer();
529                     }
530                     i.remove();
531                 }
532             }
533         }
534     }
535 
536     /**
537      * Callback that delivers {@link StorageVolume} related events.
538      * <p>
539      * For example, this can be used to detect when a volume changes to the
540      * {@link Environment#MEDIA_MOUNTED} or {@link Environment#MEDIA_UNMOUNTED}
541      * states.
542      *
543      * @see StorageManager#registerStorageVolumeCallback
544      * @see StorageManager#unregisterStorageVolumeCallback
545      */
546     public static class StorageVolumeCallback {
547         /**
548          * Called when {@link StorageVolume#getState()} changes, such as
549          * changing to the {@link Environment#MEDIA_MOUNTED} or
550          * {@link Environment#MEDIA_UNMOUNTED} states.
551          * <p>
552          * The given argument is a snapshot in time and can be used to process
553          * events in the order they occurred, or you can call
554          * {@link StorageManager#getStorageVolumes()} to observe the latest
555          * value.
556          */
onStateChanged(@onNull StorageVolume volume)557         public void onStateChanged(@NonNull StorageVolume volume) { }
558     }
559 
560     /**
561      * Registers the given callback to listen for {@link StorageVolume} changes.
562      * <p>
563      * For example, this can be used to detect when a volume changes to the
564      * {@link Environment#MEDIA_MOUNTED} or {@link Environment#MEDIA_UNMOUNTED}
565      * states.
566      *
567      * @see StorageManager#unregisterStorageVolumeCallback
568      */
registerStorageVolumeCallback(@allbackExecutor @onNull Executor executor, @NonNull StorageVolumeCallback callback)569     public void registerStorageVolumeCallback(@CallbackExecutor @NonNull Executor executor,
570             @NonNull StorageVolumeCallback callback) {
571         synchronized (mDelegates) {
572             final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(
573                     executor, new StorageEventListener(), callback);
574             try {
575                 mStorageManager.registerListener(delegate);
576             } catch (RemoteException e) {
577                 throw e.rethrowFromSystemServer();
578             }
579             mDelegates.add(delegate);
580         }
581     }
582 
583     /**
584      * Unregisters the given callback from listening for {@link StorageVolume}
585      * changes.
586      *
587      * @see StorageManager#registerStorageVolumeCallback
588      */
unregisterStorageVolumeCallback(@onNull StorageVolumeCallback callback)589     public void unregisterStorageVolumeCallback(@NonNull StorageVolumeCallback callback) {
590         synchronized (mDelegates) {
591             for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
592                 final StorageEventListenerDelegate delegate = i.next();
593                 if (delegate.mCallback == callback) {
594                     try {
595                         mStorageManager.unregisterListener(delegate);
596                     } catch (RemoteException e) {
597                         throw e.rethrowFromSystemServer();
598                     }
599                     i.remove();
600                 }
601             }
602         }
603     }
604 
605     /**
606      * Enables USB Mass Storage (UMS) on the device.
607      *
608      * @hide
609      */
610     @Deprecated
611     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
enableUsbMassStorage()612     public void enableUsbMassStorage() {
613     }
614 
615     /**
616      * Disables USB Mass Storage (UMS) on the device.
617      *
618      * @hide
619      */
620     @Deprecated
621     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
disableUsbMassStorage()622     public void disableUsbMassStorage() {
623     }
624 
625     /**
626      * Query if a USB Mass Storage (UMS) host is connected.
627      * @return true if UMS host is connected.
628      *
629      * @hide
630      */
631     @Deprecated
632     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
isUsbMassStorageConnected()633     public boolean isUsbMassStorageConnected() {
634         return false;
635     }
636 
637     /**
638      * Query if a USB Mass Storage (UMS) is enabled on the device.
639      * @return true if UMS host is enabled.
640      *
641      * @hide
642      */
643     @Deprecated
644     @UnsupportedAppUsage
isUsbMassStorageEnabled()645     public boolean isUsbMassStorageEnabled() {
646         return false;
647     }
648 
649     /**
650      * Mount an Opaque Binary Blob (OBB) file.
651      * <p>
652      * The OBB will remain mounted for as long as the StorageManager reference
653      * is held by the application. As soon as this reference is lost, the OBBs
654      * in use will be unmounted. The {@link OnObbStateChangeListener} registered
655      * with this call will receive the success or failure of this operation.
656      * <p>
657      * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
658      * file matches a package ID that is owned by the calling program's UID.
659      * That is, shared UID applications can attempt to mount any other
660      * application's OBB that shares its UID.
661      *
662      * @param rawPath the path to the OBB file
663      * @param key must be <code>null</code>. Previously, some Android device
664      *            implementations accepted a non-<code>null</code> key to mount
665      *            an encrypted OBB file. However, this never worked reliably and
666      *            is no longer supported.
667      * @param listener will receive the success or failure of the operation
668      * @return whether the mount call was successfully queued or not
669      */
mountObb(String rawPath, String key, OnObbStateChangeListener listener)670     public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) {
671         Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
672         Preconditions.checkArgument(key == null, "mounting encrypted OBBs is no longer supported");
673         Preconditions.checkNotNull(listener, "listener cannot be null");
674 
675         try {
676             final String canonicalPath = new File(rawPath).getCanonicalPath();
677             final int nonce = mObbActionListener.addListener(listener);
678             mStorageManager.mountObb(rawPath, canonicalPath, mObbActionListener, nonce,
679                     getObbInfo(canonicalPath));
680             return true;
681         } catch (IOException e) {
682             throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e);
683         } catch (RemoteException e) {
684             throw e.rethrowFromSystemServer();
685         }
686     }
687 
688     /**
689      * Returns a {@link PendingIntent} that can be used by Apps with
690      * {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} permission
691      * to launch the manageSpaceActivity for any App that implements it, irrespective of its
692      * exported status.
693      * <p>
694      * Caller has the responsibility of supplying a valid packageName which has
695      * manageSpaceActivity implemented.
696      *
697      * @param packageName package name for the App for which manageSpaceActivity is to be launched
698      * @param requestCode for launching the activity
699      * @return PendingIntent to launch the manageSpaceActivity if successful, null if the
700      * packageName doesn't have a manageSpaceActivity.
701      * @throws IllegalArgumentException an invalid packageName is supplied.
702      */
703     @RequiresPermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE)
704     @Nullable
getManageSpaceActivityIntent( @onNull String packageName, int requestCode)705     public PendingIntent getManageSpaceActivityIntent(
706             @NonNull String packageName, int requestCode) {
707         try {
708             return mStorageManager.getManageSpaceActivityIntent(packageName,
709                     requestCode);
710         } catch (RemoteException e) {
711             throw e.rethrowFromSystemServer();
712         }
713     }
714 
getObbInfo(String canonicalPath)715     private ObbInfo getObbInfo(String canonicalPath) {
716         try {
717             final ObbInfo obbInfo = ObbScanner.getObbInfo(canonicalPath);
718             return obbInfo;
719         } catch (IOException e) {
720             throw new IllegalArgumentException("Couldn't get OBB info for " + canonicalPath, e);
721         }
722     }
723 
724     /**
725      * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the
726      * <code>force</code> flag is true, it will kill any application needed to
727      * unmount the given OBB (even the calling application).
728      * <p>
729      * The {@link OnObbStateChangeListener} registered with this call will
730      * receive the success or failure of this operation.
731      * <p>
732      * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
733      * file matches a package ID that is owned by the calling program's UID.
734      * That is, shared UID applications can obtain access to any other
735      * application's OBB that shares its UID.
736      * <p>
737      *
738      * @param rawPath path to the OBB file
739      * @param force whether to kill any programs using this in order to unmount
740      *            it
741      * @param listener will receive the success or failure of the operation
742      * @return whether the unmount call was successfully queued or not
743      */
unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener)744     public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) {
745         Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
746         Preconditions.checkNotNull(listener, "listener cannot be null");
747 
748         try {
749             final int nonce = mObbActionListener.addListener(listener);
750             mStorageManager.unmountObb(rawPath, force, mObbActionListener, nonce);
751             return true;
752         } catch (RemoteException e) {
753             throw e.rethrowFromSystemServer();
754         }
755     }
756 
757     /**
758      * Check whether an Opaque Binary Blob (OBB) is mounted or not.
759      *
760      * @param rawPath path to OBB image
761      * @return true if OBB is mounted; false if not mounted or on error
762      */
isObbMounted(String rawPath)763     public boolean isObbMounted(String rawPath) {
764         Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
765 
766         try {
767             return mStorageManager.isObbMounted(rawPath);
768         } catch (RemoteException e) {
769             throw e.rethrowFromSystemServer();
770         }
771     }
772 
773     /**
774      * Check the mounted path of an Opaque Binary Blob (OBB) file. This will
775      * give you the path to where you can obtain access to the internals of the
776      * OBB.
777      *
778      * @param rawPath path to OBB image
779      * @return absolute path to mounted OBB image data or <code>null</code> if
780      *         not mounted or exception encountered trying to read status
781      */
getMountedObbPath(String rawPath)782     public String getMountedObbPath(String rawPath) {
783         Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
784 
785         try {
786             return mStorageManager.getMountedObbPath(rawPath);
787         } catch (RemoteException e) {
788             throw e.rethrowFromSystemServer();
789         }
790     }
791 
792     /** {@hide} */
793     @UnsupportedAppUsage
getDisks()794     public @NonNull List<DiskInfo> getDisks() {
795         try {
796             return Arrays.asList(mStorageManager.getDisks());
797         } catch (RemoteException e) {
798             throw e.rethrowFromSystemServer();
799         }
800     }
801 
802     /** {@hide} */
803     @UnsupportedAppUsage
findDiskById(String id)804     public @Nullable DiskInfo findDiskById(String id) {
805         Preconditions.checkNotNull(id);
806         // TODO; go directly to service to make this faster
807         for (DiskInfo disk : getDisks()) {
808             if (Objects.equals(disk.id, id)) {
809                 return disk;
810             }
811         }
812         return null;
813     }
814 
815     /** {@hide} */
816     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
findVolumeById(String id)817     public @Nullable VolumeInfo findVolumeById(String id) {
818         Preconditions.checkNotNull(id);
819         // TODO; go directly to service to make this faster
820         for (VolumeInfo vol : getVolumes()) {
821             if (Objects.equals(vol.id, id)) {
822                 return vol;
823             }
824         }
825         return null;
826     }
827 
828     /** {@hide} */
829     @UnsupportedAppUsage
findVolumeByUuid(String fsUuid)830     public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) {
831         Preconditions.checkNotNull(fsUuid);
832         // TODO; go directly to service to make this faster
833         for (VolumeInfo vol : getVolumes()) {
834             if (Objects.equals(vol.fsUuid, fsUuid)) {
835                 return vol;
836             }
837         }
838         return null;
839     }
840 
841     /** {@hide} */
findRecordByUuid(String fsUuid)842     public @Nullable VolumeRecord findRecordByUuid(String fsUuid) {
843         Preconditions.checkNotNull(fsUuid);
844         // TODO; go directly to service to make this faster
845         for (VolumeRecord rec : getVolumeRecords()) {
846             if (Objects.equals(rec.fsUuid, fsUuid)) {
847                 return rec;
848             }
849         }
850         return null;
851     }
852 
853     /** {@hide} */
findPrivateForEmulated(VolumeInfo emulatedVol)854     public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
855         if (emulatedVol != null) {
856             String id = emulatedVol.getId();
857             int idx = id.indexOf(";");
858             if (idx != -1) {
859                 id = id.substring(0, idx);
860             }
861             return findVolumeById(id.replace("emulated", "private"));
862         } else {
863             return null;
864         }
865     }
866 
867     /** {@hide} */
868     @UnsupportedAppUsage
findEmulatedForPrivate(VolumeInfo privateVol)869     public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) {
870         if (privateVol != null) {
871             return findVolumeById(privateVol.getId().replace("private", "emulated") + ";"
872                     + mContext.getUserId());
873         } else {
874             return null;
875         }
876     }
877 
878     /** {@hide} */
findVolumeByQualifiedUuid(String volumeUuid)879     public @Nullable VolumeInfo findVolumeByQualifiedUuid(String volumeUuid) {
880         if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
881             return findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
882         } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
883             return getPrimaryPhysicalVolume();
884         } else {
885             return findVolumeByUuid(volumeUuid);
886         }
887     }
888 
889     /**
890      * Return a UUID identifying the storage volume that hosts the given
891      * filesystem path.
892      * <p>
893      * If this path is hosted by the default internal storage of the device at
894      * {@link Environment#getDataDirectory()}, the returned value will be
895      * {@link #UUID_DEFAULT}.
896      *
897      * @throws IOException when the storage device hosting the given path isn't
898      *             present, or when it doesn't have a valid UUID.
899      */
getUuidForPath(@onNull File path)900     public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException {
901         Preconditions.checkNotNull(path);
902         final String pathString = path.getCanonicalPath();
903         if (FileUtils.contains(Environment.getDataDirectory().getAbsolutePath(), pathString)) {
904             return UUID_DEFAULT;
905         }
906         try {
907             for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
908                 if (vol.path != null && FileUtils.contains(vol.path, pathString)
909                         && vol.type != VolumeInfo.TYPE_PUBLIC && vol.type != VolumeInfo.TYPE_STUB) {
910                     // TODO: verify that emulated adopted devices have UUID of
911                     // underlying volume
912                     try {
913                         return convert(vol.fsUuid);
914                     } catch (IllegalArgumentException e) {
915                         continue;
916                     }
917                 }
918             }
919         } catch (RemoteException e) {
920             throw e.rethrowFromSystemServer();
921         }
922         throw new FileNotFoundException("Failed to find a storage device for " + path);
923     }
924 
925     /** {@hide} */
findPathForUuid(String volumeUuid)926     public @NonNull File findPathForUuid(String volumeUuid) throws FileNotFoundException {
927         final VolumeInfo vol = findVolumeByQualifiedUuid(volumeUuid);
928         if (vol != null) {
929             return vol.getPath();
930         }
931         throw new FileNotFoundException("Failed to find a storage device for " + volumeUuid);
932     }
933 
934     /**
935      * Test if the given file descriptor supports allocation of disk space using
936      * {@link #allocateBytes(FileDescriptor, long)}.
937      */
isAllocationSupported(@onNull FileDescriptor fd)938     public boolean isAllocationSupported(@NonNull FileDescriptor fd) {
939         try {
940             getUuidForPath(ParcelFileDescriptor.getFile(fd));
941             return true;
942         } catch (IOException e) {
943             return false;
944         }
945     }
946 
947     /** {@hide} */
948     @UnsupportedAppUsage
getVolumes()949     public @NonNull List<VolumeInfo> getVolumes() {
950         try {
951             return Arrays.asList(mStorageManager.getVolumes(0));
952         } catch (RemoteException e) {
953             throw e.rethrowFromSystemServer();
954         }
955     }
956 
957     /** {@hide} */
getWritablePrivateVolumes()958     public @NonNull List<VolumeInfo> getWritablePrivateVolumes() {
959         try {
960             final ArrayList<VolumeInfo> res = new ArrayList<>();
961             for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
962                 if (vol.getType() == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) {
963                     res.add(vol);
964                 }
965             }
966             return res;
967         } catch (RemoteException e) {
968             throw e.rethrowFromSystemServer();
969         }
970     }
971 
972     /** {@hide} */
getVolumeRecords()973     public @NonNull List<VolumeRecord> getVolumeRecords() {
974         try {
975             return Arrays.asList(mStorageManager.getVolumeRecords(0));
976         } catch (RemoteException e) {
977             throw e.rethrowFromSystemServer();
978         }
979     }
980 
981     /** {@hide} */
982     @UnsupportedAppUsage
getBestVolumeDescription(VolumeInfo vol)983     public @Nullable String getBestVolumeDescription(VolumeInfo vol) {
984         if (vol == null) return null;
985 
986         // Nickname always takes precedence when defined
987         if (!TextUtils.isEmpty(vol.fsUuid)) {
988             final VolumeRecord rec = findRecordByUuid(vol.fsUuid);
989             if (rec != null && !TextUtils.isEmpty(rec.nickname)) {
990                 return rec.nickname;
991             }
992         }
993 
994         if (!TextUtils.isEmpty(vol.getDescription())) {
995             return vol.getDescription();
996         }
997 
998         if (vol.disk != null) {
999             return vol.disk.getDescription();
1000         }
1001 
1002         return null;
1003     }
1004 
1005     /** {@hide} */
1006     @UnsupportedAppUsage
getPrimaryPhysicalVolume()1007     public @Nullable VolumeInfo getPrimaryPhysicalVolume() {
1008         final List<VolumeInfo> vols = getVolumes();
1009         for (VolumeInfo vol : vols) {
1010             if (vol.isPrimaryPhysical()) {
1011                 return vol;
1012             }
1013         }
1014         return null;
1015     }
1016 
1017     /** {@hide} */
mount(String volId)1018     public void mount(String volId) {
1019         try {
1020             mStorageManager.mount(volId);
1021         } catch (RemoteException e) {
1022             throw e.rethrowFromSystemServer();
1023         }
1024     }
1025 
1026     /** {@hide} */
1027     @UnsupportedAppUsage
unmount(String volId)1028     public void unmount(String volId) {
1029         try {
1030             mStorageManager.unmount(volId);
1031         } catch (RemoteException e) {
1032             throw e.rethrowFromSystemServer();
1033         }
1034     }
1035 
1036     /** {@hide} */
1037     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
format(String volId)1038     public void format(String volId) {
1039         try {
1040             mStorageManager.format(volId);
1041         } catch (RemoteException e) {
1042             throw e.rethrowFromSystemServer();
1043         }
1044     }
1045 
1046     /** {@hide} */
1047     @Deprecated
benchmark(String volId)1048     public long benchmark(String volId) {
1049         final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
1050         benchmark(volId, new IVoldTaskListener.Stub() {
1051             @Override
1052             public void onStatus(int status, PersistableBundle extras) {
1053                 // Ignored
1054             }
1055 
1056             @Override
1057             public void onFinished(int status, PersistableBundle extras) {
1058                 result.complete(extras);
1059             }
1060         });
1061         try {
1062             // Convert ms to ns
1063             return result.get(3, TimeUnit.MINUTES).getLong("run", Long.MAX_VALUE) * 1000000;
1064         } catch (Exception e) {
1065             return Long.MAX_VALUE;
1066         }
1067     }
1068 
1069     /** {@hide} */
benchmark(String volId, IVoldTaskListener listener)1070     public void benchmark(String volId, IVoldTaskListener listener) {
1071         try {
1072             mStorageManager.benchmark(volId, listener);
1073         } catch (RemoteException e) {
1074             throw e.rethrowFromSystemServer();
1075         }
1076     }
1077 
1078     /** {@hide} */
1079     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
partitionPublic(String diskId)1080     public void partitionPublic(String diskId) {
1081         try {
1082             mStorageManager.partitionPublic(diskId);
1083         } catch (RemoteException e) {
1084             throw e.rethrowFromSystemServer();
1085         }
1086     }
1087 
1088     /** {@hide} */
partitionPrivate(String diskId)1089     public void partitionPrivate(String diskId) {
1090         try {
1091             mStorageManager.partitionPrivate(diskId);
1092         } catch (RemoteException e) {
1093             throw e.rethrowFromSystemServer();
1094         }
1095     }
1096 
1097     /** {@hide} */
partitionMixed(String diskId, int ratio)1098     public void partitionMixed(String diskId, int ratio) {
1099         try {
1100             mStorageManager.partitionMixed(diskId, ratio);
1101         } catch (RemoteException e) {
1102             throw e.rethrowFromSystemServer();
1103         }
1104     }
1105 
1106     /** {@hide} */
wipeAdoptableDisks()1107     public void wipeAdoptableDisks() {
1108         // We only wipe devices in "adoptable" locations, which are in a
1109         // long-term stable slot/location on the device, where apps have a
1110         // reasonable chance of storing sensitive data. (Apps need to go through
1111         // SAF to write to transient volumes.)
1112         final List<DiskInfo> disks = getDisks();
1113         for (DiskInfo disk : disks) {
1114             final String diskId = disk.getId();
1115             if (disk.isAdoptable()) {
1116                 Slog.d(TAG, "Found adoptable " + diskId + "; wiping");
1117                 try {
1118                     // TODO: switch to explicit wipe command when we have it,
1119                     // for now rely on the fact that vfat format does a wipe
1120                     mStorageManager.partitionPublic(diskId);
1121                 } catch (Exception e) {
1122                     Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e);
1123                 }
1124             } else {
1125                 Slog.d(TAG, "Ignorning non-adoptable disk " + disk.getId());
1126             }
1127         }
1128     }
1129 
1130     /** {@hide} */
setVolumeNickname(String fsUuid, String nickname)1131     public void setVolumeNickname(String fsUuid, String nickname) {
1132         try {
1133             mStorageManager.setVolumeNickname(fsUuid, nickname);
1134         } catch (RemoteException e) {
1135             throw e.rethrowFromSystemServer();
1136         }
1137     }
1138 
1139     /** {@hide} */
setVolumeInited(String fsUuid, boolean inited)1140     public void setVolumeInited(String fsUuid, boolean inited) {
1141         try {
1142             mStorageManager.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0,
1143                     VolumeRecord.USER_FLAG_INITED);
1144         } catch (RemoteException e) {
1145             throw e.rethrowFromSystemServer();
1146         }
1147     }
1148 
1149     /** {@hide} */
setVolumeSnoozed(String fsUuid, boolean snoozed)1150     public void setVolumeSnoozed(String fsUuid, boolean snoozed) {
1151         try {
1152             mStorageManager.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0,
1153                     VolumeRecord.USER_FLAG_SNOOZED);
1154         } catch (RemoteException e) {
1155             throw e.rethrowFromSystemServer();
1156         }
1157     }
1158 
1159     /** {@hide} */
forgetVolume(String fsUuid)1160     public void forgetVolume(String fsUuid) {
1161         try {
1162             mStorageManager.forgetVolume(fsUuid);
1163         } catch (RemoteException e) {
1164             throw e.rethrowFromSystemServer();
1165         }
1166     }
1167 
1168     /**
1169      * This is not the API you're looking for.
1170      *
1171      * @see PackageManager#getPrimaryStorageCurrentVolume()
1172      * @hide
1173      */
getPrimaryStorageUuid()1174     public String getPrimaryStorageUuid() {
1175         try {
1176             return mStorageManager.getPrimaryStorageUuid();
1177         } catch (RemoteException e) {
1178             throw e.rethrowFromSystemServer();
1179         }
1180     }
1181 
1182     /**
1183      * This is not the API you're looking for.
1184      *
1185      * @see PackageManager#movePrimaryStorage(VolumeInfo)
1186      * @hide
1187      */
setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)1188     public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
1189         try {
1190             mStorageManager.setPrimaryStorageUuid(volumeUuid, callback);
1191         } catch (RemoteException e) {
1192             throw e.rethrowFromSystemServer();
1193         }
1194     }
1195 
1196     /**
1197      * Return the {@link StorageVolume} that contains the given file, or
1198      * {@code null} if none.
1199      */
getStorageVolume(@onNull File file)1200     public @Nullable StorageVolume getStorageVolume(@NonNull File file) {
1201         return getStorageVolume(getVolumeList(), file);
1202     }
1203 
1204     /**
1205      * Return the {@link StorageVolume} that contains the given
1206      * {@link MediaStore} item.
1207      */
getStorageVolume(@onNull Uri uri)1208     public @NonNull StorageVolume getStorageVolume(@NonNull Uri uri) {
1209         String volumeName = MediaStore.getVolumeName(uri);
1210 
1211         // When Uri is pointing at a synthetic volume, we're willing to query to
1212         // resolve the actual volume name
1213         if (Objects.equals(volumeName, MediaStore.VOLUME_EXTERNAL)) {
1214             try (Cursor c = mContext.getContentResolver().query(uri,
1215                     new String[] { MediaStore.MediaColumns.VOLUME_NAME }, null, null)) {
1216                 if (c.moveToFirst()) {
1217                     volumeName = c.getString(0);
1218                 }
1219             }
1220         }
1221 
1222         switch (volumeName) {
1223             case MediaStore.VOLUME_EXTERNAL_PRIMARY:
1224                 return getPrimaryStorageVolume();
1225             default:
1226                 for (StorageVolume vol : getStorageVolumes()) {
1227                     if (Objects.equals(vol.getMediaStoreVolumeName(), volumeName)) {
1228                         return vol;
1229                     }
1230                 }
1231         }
1232         throw new IllegalStateException("Unknown volume for " + uri);
1233     }
1234 
1235     /** {@hide} */
getStorageVolume(File file, int userId)1236     public static @Nullable StorageVolume getStorageVolume(File file, int userId) {
1237         return getStorageVolume(getVolumeList(userId, 0), file);
1238     }
1239 
1240     /** {@hide} */
1241     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getStorageVolume(StorageVolume[] volumes, File file)1242     private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) {
1243         if (file == null) {
1244             return null;
1245         }
1246         final String path = file.getAbsolutePath();
1247         if (path.startsWith(DEPRECATE_DATA_PREFIX)) {
1248             final Uri uri = ContentResolver.translateDeprecatedDataPath(path);
1249             return AppGlobals.getInitialApplication().getSystemService(StorageManager.class)
1250                     .getStorageVolume(uri);
1251         }
1252         try {
1253             file = file.getCanonicalFile();
1254         } catch (IOException ignored) {
1255             Slog.d(TAG, "Could not get canonical path for " + file);
1256             return null;
1257         }
1258         for (StorageVolume volume : volumes) {
1259             File volumeFile = volume.getPathFile();
1260             try {
1261                 volumeFile = volumeFile.getCanonicalFile();
1262             } catch (IOException ignored) {
1263                 continue;
1264             }
1265             if (FileUtils.contains(volumeFile, file)) {
1266                 return volume;
1267             }
1268         }
1269         return null;
1270     }
1271 
1272     /**
1273      * Gets the state of a volume via its mountpoint.
1274      * @hide
1275      */
1276     @Deprecated
1277     @UnsupportedAppUsage
getVolumeState(String mountPoint)1278     public @NonNull String getVolumeState(String mountPoint) {
1279         final StorageVolume vol = getStorageVolume(new File(mountPoint));
1280         if (vol != null) {
1281             return vol.getState();
1282         } else {
1283             return Environment.MEDIA_UNKNOWN;
1284         }
1285     }
1286 
1287     /**
1288      * Return the list of shared/external storage volumes currently available to
1289      * the calling user.
1290      * <p>
1291      * These storage volumes are actively attached to the device, but may be in
1292      * any mount state, as returned by {@link StorageVolume#getState()}. Returns
1293      * both the primary shared storage device and any attached external volumes,
1294      * including SD cards and USB drives.
1295      */
getStorageVolumes()1296     public @NonNull List<StorageVolume> getStorageVolumes() {
1297         final ArrayList<StorageVolume> res = new ArrayList<>();
1298         Collections.addAll(res,
1299                 getVolumeList(mContext.getUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE));
1300         return res;
1301     }
1302 
1303     /**
1304      * Return the list of shared/external storage volumes currently available to
1305      * the calling user and the user it shares media with. Please refer to
1306      * <a href="https://source.android.com/compatibility/12/android-12-cdd#95_multi-user_support">
1307      *     multi-user support</a> for more details.
1308      *
1309      * <p>
1310      * This is similar to {@link StorageManager#getStorageVolumes()} except that the result also
1311      * includes the volumes belonging to any user it shares media with
1312      */
1313     @RequiresPermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE)
getStorageVolumesIncludingSharedProfiles()1314     public @NonNull List<StorageVolume> getStorageVolumesIncludingSharedProfiles() {
1315         final ArrayList<StorageVolume> res = new ArrayList<>();
1316         Collections.addAll(res,
1317                 getVolumeList(mContext.getUserId(),
1318                         FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE | FLAG_INCLUDE_SHARED_PROFILE));
1319         return res;
1320     }
1321 
1322     /**
1323      * Return the list of shared/external storage volumes both currently and
1324      * recently available to the calling user.
1325      * <p>
1326      * Recently available storage volumes are likely to reappear in the future,
1327      * so apps are encouraged to preserve any indexed metadata related to these
1328      * volumes to optimize user experiences.
1329      */
getRecentStorageVolumes()1330     public @NonNull List<StorageVolume> getRecentStorageVolumes() {
1331         final ArrayList<StorageVolume> res = new ArrayList<>();
1332         Collections.addAll(res,
1333                 getVolumeList(mContext.getUserId(),
1334                         FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE | FLAG_INCLUDE_RECENT));
1335         return res;
1336     }
1337 
1338     /**
1339      * Return the primary shared/external storage volume available to the
1340      * current user. This volume is the same storage device returned by
1341      * {@link Environment#getExternalStorageDirectory()} and
1342      * {@link Context#getExternalFilesDir(String)}.
1343      */
getPrimaryStorageVolume()1344     public @NonNull StorageVolume getPrimaryStorageVolume() {
1345         return getVolumeList(mContext.getUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE)[0];
1346     }
1347 
1348     /** {@hide} */
getPrimaryStoragePathAndSize()1349     public static Pair<String, Long> getPrimaryStoragePathAndSize() {
1350         return Pair.create(null,
1351                 FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()
1352                     + Environment.getRootDirectory().getTotalSpace()));
1353     }
1354 
1355     /** {@hide} */
getPrimaryStorageSize()1356     public long getPrimaryStorageSize() {
1357         return FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()
1358                 + Environment.getRootDirectory().getTotalSpace());
1359     }
1360 
1361     /** {@hide} */
getInternalStorageBlockDeviceSize()1362     public long getInternalStorageBlockDeviceSize() {
1363         try {
1364             return mStorageManager.getInternalStorageBlockDeviceSize();
1365         } catch (RemoteException e) {
1366             throw e.rethrowFromSystemServer();
1367         }
1368     }
1369 
1370     /** {@hide} */
mkdirs(File file)1371     public void mkdirs(File file) {
1372         BlockGuard.getVmPolicy().onPathAccess(file.getAbsolutePath());
1373         try {
1374             mStorageManager.mkdirs(mContext.getOpPackageName(), file.getAbsolutePath());
1375         } catch (RemoteException e) {
1376             throw e.rethrowFromSystemServer();
1377         }
1378     }
1379 
1380     /** @removed */
getVolumeList()1381     public @NonNull StorageVolume[] getVolumeList() {
1382         return getVolumeList(mContext.getUserId(), 0);
1383     }
1384 
1385     /** {@hide} */
1386     @UnsupportedAppUsage
getVolumeList(int userId, int flags)1387     public static @NonNull StorageVolume[] getVolumeList(int userId, int flags) {
1388         final IStorageManager storageManager = IStorageManager.Stub.asInterface(
1389                 ServiceManager.getService("mount"));
1390         try {
1391             String packageName = ActivityThread.currentOpPackageName();
1392             if (packageName == null) {
1393                 // Package name can be null if the activity thread is running but the app
1394                 // hasn't bound yet. In this case we fall back to the first package in the
1395                 // current UID. This works for runtime permissions as permission state is
1396                 // per UID and permission realted app ops are updated for all UID packages.
1397                 String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid(
1398                         android.os.Process.myUid());
1399                 if (packageNames == null || packageNames.length <= 0) {
1400                     Log.w(TAG, "Missing package names; no storage volumes available");
1401                     return new StorageVolume[0];
1402                 }
1403                 packageName = packageNames[0];
1404             }
1405             return storageManager.getVolumeList(userId, packageName, flags);
1406         } catch (RemoteException e) {
1407             throw e.rethrowFromSystemServer();
1408         }
1409     }
1410 
1411     /**
1412      * Returns list of paths for all mountable volumes.
1413      * @hide
1414      */
1415     @Deprecated
1416     @UnsupportedAppUsage
getVolumePaths()1417     public @NonNull String[] getVolumePaths() {
1418         StorageVolume[] volumes = getVolumeList();
1419         int count = volumes.length;
1420         String[] paths = new String[count];
1421         for (int i = 0; i < count; i++) {
1422             paths[i] = volumes[i].getPath();
1423         }
1424         return paths;
1425     }
1426 
1427     /** @removed */
getPrimaryVolume()1428     public @NonNull StorageVolume getPrimaryVolume() {
1429         return getPrimaryVolume(getVolumeList());
1430     }
1431 
1432     /** {@hide} */
getPrimaryVolume(StorageVolume[] volumes)1433     public static @NonNull StorageVolume getPrimaryVolume(StorageVolume[] volumes) {
1434         for (StorageVolume volume : volumes) {
1435             if (volume.isPrimary()) {
1436                 return volume;
1437             }
1438         }
1439         throw new IllegalStateException("Missing primary storage");
1440     }
1441 
1442     /**
1443      * Devices having above STORAGE_THRESHOLD_PERCENT_HIGH of total space free are considered to be
1444      * in high free space category.
1445      *
1446      * @hide
1447      */
1448     public static final int DEFAULT_STORAGE_THRESHOLD_PERCENT_HIGH = 20;
1449     /** {@hide} */
1450     @TestApi
1451     public static final String
1452             STORAGE_THRESHOLD_PERCENT_HIGH_KEY = "storage_threshold_percent_high";
1453     /**
1454      * Devices having below STORAGE_THRESHOLD_PERCENT_LOW of total space free are considered to be
1455      * in low free space category and can be configured via
1456      * Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE.
1457      *
1458      * @hide
1459      */
1460     public static final int DEFAULT_STORAGE_THRESHOLD_PERCENT_LOW = 5;
1461     /**
1462      * For devices in high free space category, CACHE_RESERVE_PERCENT_HIGH percent of total space is
1463      * allocated for cache.
1464      *
1465      * @hide
1466      */
1467     public static final int DEFAULT_CACHE_RESERVE_PERCENT_HIGH = 10;
1468     /** {@hide} */
1469     @TestApi
1470     public static final String CACHE_RESERVE_PERCENT_HIGH_KEY = "cache_reserve_percent_high";
1471     /**
1472      * For devices in low free space category, CACHE_RESERVE_PERCENT_LOW percent of total space is
1473      * allocated for cache.
1474      *
1475      * @hide
1476      */
1477     public static final int DEFAULT_CACHE_RESERVE_PERCENT_LOW = 2;
1478     /** {@hide} */
1479     @TestApi
1480     public static final String CACHE_RESERVE_PERCENT_LOW_KEY = "cache_reserve_percent_low";
1481 
1482     private static final long DEFAULT_THRESHOLD_MAX_BYTES = DataUnit.MEBIBYTES.toBytes(500);
1483 
1484     private static final long DEFAULT_FULL_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(1);
1485 
1486     /**
1487      * Return the number of available bytes until the given path is considered
1488      * running low on storage.
1489      *
1490      * @hide
1491      */
1492     @UnsupportedAppUsage
getStorageBytesUntilLow(File path)1493     public long getStorageBytesUntilLow(File path) {
1494         return path.getUsableSpace() - getStorageFullBytes(path);
1495     }
1496 
1497     /**
1498      * Return the number of available bytes at which the given path is
1499      * considered running low on storage.
1500      *
1501      * @hide
1502      */
1503     @UnsupportedAppUsage
getStorageLowBytes(File path)1504     public long getStorageLowBytes(File path) {
1505         final long lowPercent = Settings.Global.getInt(mResolver,
1506                 Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE,
1507                 DEFAULT_STORAGE_THRESHOLD_PERCENT_LOW);
1508         final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;
1509 
1510         final long maxLowBytes = Settings.Global.getLong(mResolver,
1511                 Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES);
1512 
1513         return Math.min(lowBytes, maxLowBytes);
1514     }
1515 
1516     /**
1517      * Compute the minimum number of bytes of storage on the device that could
1518      * be reserved for cached data depending on the device state which is then passed on
1519      * to getStorageCacheBytes.
1520      *
1521      * Input File path must point to a storage volume.
1522      *
1523      * @hide
1524      */
1525     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
1526     @TestApi
1527     @SuppressLint("StreamFiles")
computeStorageCacheBytes(@onNull File path)1528     public long computeStorageCacheBytes(@NonNull File path) {
1529         final int storageThresholdPercentHigh = DeviceConfig.getInt(
1530                 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
1531                 STORAGE_THRESHOLD_PERCENT_HIGH_KEY, DEFAULT_STORAGE_THRESHOLD_PERCENT_HIGH);
1532         final int cacheReservePercentHigh = DeviceConfig.getInt(
1533                 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
1534                 CACHE_RESERVE_PERCENT_HIGH_KEY, DEFAULT_CACHE_RESERVE_PERCENT_HIGH);
1535         final int cacheReservePercentLow = DeviceConfig.getInt(
1536                 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
1537                 CACHE_RESERVE_PERCENT_LOW_KEY, DEFAULT_CACHE_RESERVE_PERCENT_LOW);
1538         final long totalBytes = path.getTotalSpace();
1539         final long usableBytes = path.getUsableSpace();
1540         final long storageThresholdHighBytes = totalBytes * storageThresholdPercentHigh / 100;
1541         final long storageThresholdLowBytes = getStorageLowBytes(path);
1542         long result;
1543         if (usableBytes > storageThresholdHighBytes) {
1544             // If free space is >storageThresholdPercentHigh of total space,
1545             // reserve cacheReservePercentHigh of total space
1546             result = totalBytes * cacheReservePercentHigh / 100;
1547         } else if (usableBytes < storageThresholdLowBytes) {
1548             // If free space is <min(storageThresholdPercentLow of total space, 500MB),
1549             // reserve cacheReservePercentLow of total space
1550             result = totalBytes * cacheReservePercentLow / 100;
1551         } else {
1552             // Else, linearly interpolate the amount of space to reserve
1553             double slope = (cacheReservePercentHigh - cacheReservePercentLow) * totalBytes
1554                     / (100.0 * (storageThresholdHighBytes - storageThresholdLowBytes));
1555             double intercept = totalBytes * cacheReservePercentLow / 100.0
1556                     - storageThresholdLowBytes * slope;
1557             result = Math.round(slope * usableBytes + intercept);
1558         }
1559         return result;
1560     }
1561 
1562     /**
1563      * Return the minimum number of bytes of storage on the device that should
1564      * be reserved for cached data.
1565      *
1566      * @hide
1567      */
getStorageCacheBytes(@onNull File path, @AllocateFlags int flags)1568     public long getStorageCacheBytes(@NonNull File path, @AllocateFlags int flags) {
1569         if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
1570             return 0;
1571         } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED) != 0) {
1572             return 0;
1573         } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED) != 0) {
1574             return computeStorageCacheBytes(path) / 2;
1575         } else {
1576             return computeStorageCacheBytes(path);
1577         }
1578     }
1579 
1580     /**
1581      * Return the number of available bytes at which the given path is
1582      * considered full.
1583      *
1584      * @hide
1585      */
1586     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getStorageFullBytes(File path)1587     public long getStorageFullBytes(File path) {
1588         return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
1589                 DEFAULT_FULL_THRESHOLD_BYTES);
1590     }
1591 
1592     /** {@hide} */
createUserKey(int userId, int serialNumber, boolean ephemeral)1593     public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
1594         try {
1595             mStorageManager.createUserKey(userId, serialNumber, ephemeral);
1596         } catch (RemoteException e) {
1597             throw e.rethrowFromSystemServer();
1598         }
1599     }
1600 
1601     /** {@hide} */
destroyUserKey(int userId)1602     public void destroyUserKey(int userId) {
1603         try {
1604             mStorageManager.destroyUserKey(userId);
1605         } catch (RemoteException e) {
1606             throw e.rethrowFromSystemServer();
1607         }
1608     }
1609 
1610     /** {@hide} */
lockUserKey(int userId)1611     public void lockUserKey(int userId) {
1612         try {
1613             mStorageManager.lockUserKey(userId);
1614         } catch (RemoteException e) {
1615             throw e.rethrowFromSystemServer();
1616         }
1617     }
1618 
1619     /** {@hide} */
prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags)1620     public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
1621         try {
1622             mStorageManager.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
1623         } catch (RemoteException e) {
1624             throw e.rethrowFromSystemServer();
1625         }
1626     }
1627 
1628     /** {@hide} */
destroyUserStorage(String volumeUuid, int userId, int flags)1629     public void destroyUserStorage(String volumeUuid, int userId, int flags) {
1630         try {
1631             mStorageManager.destroyUserStorage(volumeUuid, userId, flags);
1632         } catch (RemoteException e) {
1633             throw e.rethrowFromSystemServer();
1634         }
1635     }
1636 
1637     /** {@hide} */
1638     @TestApi
isUserKeyUnlocked(int userId)1639     public static boolean isUserKeyUnlocked(int userId) {
1640         if (sStorageManager == null) {
1641             sStorageManager = IStorageManager.Stub
1642                     .asInterface(ServiceManager.getService("mount"));
1643         }
1644         if (sStorageManager == null) {
1645             Slog.w(TAG, "Early during boot, assuming locked");
1646             return false;
1647         }
1648         final long token = Binder.clearCallingIdentity();
1649         try {
1650             return sStorageManager.isUserKeyUnlocked(userId);
1651         } catch (RemoteException e) {
1652             throw e.rethrowAsRuntimeException();
1653         } finally {
1654             Binder.restoreCallingIdentity(token);
1655         }
1656     }
1657 
1658     /**
1659      * Return if data stored at or under the given path will be encrypted while
1660      * at rest. This can help apps avoid the overhead of double-encrypting data.
1661      */
isEncrypted(File file)1662     public boolean isEncrypted(File file) {
1663         if (FileUtils.contains(Environment.getDataDirectory(), file)) {
1664             return isEncrypted();
1665         } else if (FileUtils.contains(Environment.getExpandDirectory(), file)) {
1666             return true;
1667         }
1668         // TODO: extend to support shared storage
1669         return false;
1670     }
1671 
1672     /** {@hide}
1673      * Is this device encrypted?
1674      * <p>
1675      * Note: all devices launching with Android 10 (API level 29) or later are
1676      * required to be encrypted.  This should only ever return false for
1677      * in-development devices on which encryption has not yet been configured.
1678      *
1679      * @return true if encrypted, false if not encrypted
1680      */
isEncrypted()1681     public static boolean isEncrypted() {
1682         return RoSystemProperties.CRYPTO_ENCRYPTED;
1683     }
1684 
1685     /** {@hide}
1686      * Does this device have file-based encryption (FBE) enabled?
1687      * @return true if the device has file-based encryption enabled.
1688      */
isFileEncrypted()1689     public static boolean isFileEncrypted() {
1690         if (!isEncrypted()) {
1691             return false;
1692         }
1693         return RoSystemProperties.CRYPTO_FILE_ENCRYPTED;
1694     }
1695 
1696     /** {@hide}
1697      * @deprecated Use {@link #isFileEncrypted} instead, since emulated FBE is no longer supported.
1698      */
1699     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1700     @Deprecated
isFileEncryptedNativeOnly()1701     public static boolean isFileEncryptedNativeOnly() {
1702         return isFileEncrypted();
1703     }
1704 
1705     /** {@hide}
1706      * @deprecated Use {@link #isFileEncrypted} instead, since emulated FBE is no longer supported.
1707      */
1708     @Deprecated
isFileEncryptedNativeOrEmulated()1709     public static boolean isFileEncryptedNativeOrEmulated() {
1710         return isFileEncrypted();
1711     }
1712 
1713     /** {@hide} */
hasAdoptable()1714     public static boolean hasAdoptable() {
1715         switch (SystemProperties.get(PROP_ADOPTABLE)) {
1716             case "force_on":
1717                 return true;
1718             case "force_off":
1719                 return false;
1720             default:
1721                 return SystemProperties.getBoolean(PROP_HAS_ADOPTABLE, false);
1722         }
1723     }
1724 
1725     /**
1726      * Return if the currently booted device has the "isolated storage" feature
1727      * flag enabled.
1728      *
1729      * @hide
1730      */
1731     @SystemApi
hasIsolatedStorage()1732     public static boolean hasIsolatedStorage() {
1733         return false;
1734     }
1735 
1736     /**
1737      * @deprecated disabled now that FUSE has been replaced by sdcardfs
1738      * @hide
1739      */
1740     @Deprecated
maybeTranslateEmulatedPathToInternal(File path)1741     public static File maybeTranslateEmulatedPathToInternal(File path) {
1742         // Disabled now that FUSE has been replaced by sdcardfs
1743         return path;
1744     }
1745 
1746     /**
1747      * Translate given shared storage path from a path in an app sandbox
1748      * namespace to a path in the system namespace.
1749      *
1750      * @hide
1751      */
translateAppToSystem(File file, int pid, int uid)1752     public File translateAppToSystem(File file, int pid, int uid) {
1753         return file;
1754     }
1755 
1756     /**
1757      * Translate given shared storage path from a path in the system namespace
1758      * to a path in an app sandbox namespace.
1759      *
1760      * @hide
1761      */
translateSystemToApp(File file, int pid, int uid)1762     public File translateSystemToApp(File file, int pid, int uid) {
1763         return file;
1764     }
1765 
1766     /**
1767      * Check that given app holds both permission and appop.
1768      * @hide
1769      */
checkPermissionAndAppOp(Context context, boolean enforce, int pid, int uid, String packageName, @NonNull String featureId, String permission, int op)1770     public static boolean checkPermissionAndAppOp(Context context, boolean enforce, int pid,
1771             int uid, String packageName, @NonNull String featureId, String permission, int op) {
1772         return checkPermissionAndAppOp(context, enforce, pid, uid, packageName, featureId,
1773                 permission, op, true);
1774     }
1775 
1776     /**
1777      * Check that given app holds both permission and appop but do not noteOp.
1778      * @hide
1779      */
checkPermissionAndCheckOp(Context context, boolean enforce, int pid, int uid, String packageName, String permission, int op)1780     public static boolean checkPermissionAndCheckOp(Context context, boolean enforce,
1781             int pid, int uid, String packageName, String permission, int op) {
1782         return checkPermissionAndAppOp(context, enforce, pid, uid, packageName,
1783                 null /* featureId is not needed when not noting */, permission, op, false);
1784     }
1785 
1786     /**
1787      * Check that given app holds both permission and appop.
1788      * @hide
1789      */
checkPermissionAndAppOp(Context context, boolean enforce, int pid, int uid, String packageName, @Nullable String featureId, String permission, int op, boolean note)1790     private static boolean checkPermissionAndAppOp(Context context, boolean enforce, int pid,
1791             int uid, String packageName, @Nullable String featureId, String permission, int op,
1792             boolean note) {
1793         if (context.checkPermission(permission, pid, uid) != PERMISSION_GRANTED) {
1794             if (enforce) {
1795                 throw new SecurityException(
1796                         "Permission " + permission + " denied for package " + packageName);
1797             } else {
1798                 return false;
1799             }
1800         }
1801 
1802         AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
1803         final int mode;
1804         if (note) {
1805             mode = appOps.noteOpNoThrow(op, uid, packageName, featureId, null);
1806         } else {
1807             try {
1808                 appOps.checkPackage(uid, packageName);
1809             } catch (SecurityException e) {
1810                 if (enforce) {
1811                     throw e;
1812                 } else {
1813                     return false;
1814                 }
1815             }
1816             mode = appOps.checkOpNoThrow(op, uid, packageName);
1817         }
1818         switch (mode) {
1819             case AppOpsManager.MODE_ALLOWED:
1820                 return true;
1821             case AppOpsManager.MODE_DEFAULT:
1822             case AppOpsManager.MODE_IGNORED:
1823             case AppOpsManager.MODE_ERRORED:
1824                 if (enforce) {
1825                     throw new SecurityException("Op " + AppOpsManager.opToName(op) + " "
1826                             + AppOpsManager.modeToName(mode) + " for package " + packageName);
1827                 } else {
1828                     return false;
1829                 }
1830             default:
1831                 throw new IllegalStateException(
1832                         AppOpsManager.opToName(op) + " has unknown mode "
1833                                 + AppOpsManager.modeToName(mode));
1834         }
1835     }
1836 
checkPermissionAndAppOp(boolean enforce, int pid, int uid, String packageName, @Nullable String featureId, String permission, int op)1837     private boolean checkPermissionAndAppOp(boolean enforce, int pid, int uid, String packageName,
1838             @Nullable String featureId, String permission, int op) {
1839         return checkPermissionAndAppOp(mContext, enforce, pid, uid, packageName, featureId,
1840                 permission, op);
1841     }
1842 
noteAppOpAllowingLegacy(boolean enforce, int pid, int uid, String packageName, @Nullable String featureId, int op)1843     private boolean noteAppOpAllowingLegacy(boolean enforce,
1844             int pid, int uid, String packageName, @Nullable String featureId, int op) {
1845         final int mode = mAppOps.noteOpNoThrow(op, uid, packageName, featureId, null);
1846         switch (mode) {
1847             case AppOpsManager.MODE_ALLOWED:
1848                 return true;
1849             case AppOpsManager.MODE_DEFAULT:
1850             case AppOpsManager.MODE_IGNORED:
1851             case AppOpsManager.MODE_ERRORED:
1852                 // Legacy apps technically have the access granted by this op,
1853                 // even when the op is denied
1854                 if ((mAppOps.checkOpNoThrow(OP_LEGACY_STORAGE, uid,
1855                         packageName) == AppOpsManager.MODE_ALLOWED)) return true;
1856 
1857                 if (enforce) {
1858                     throw new SecurityException("Op " + AppOpsManager.opToName(op) + " "
1859                             + AppOpsManager.modeToName(mode) + " for package " + packageName);
1860                 } else {
1861                     return false;
1862                 }
1863             default:
1864                 throw new IllegalStateException(
1865                         AppOpsManager.opToName(op) + " has unknown mode "
1866                                 + AppOpsManager.modeToName(mode));
1867         }
1868     }
1869 
1870     // Callers must hold both the old and new permissions, so that we can
1871     // handle obscure cases like when an app targets Q but was installed on
1872     // a device that was originally running on P before being upgraded to Q.
1873 
1874     /**
1875      * @deprecated This method should not be used since it check slegacy permissions,
1876      * no longer valid. Clients should check the appropriate permissions directly
1877      * instead (e.g. READ_MEDIA_IMAGES).
1878      *
1879      * {@hide}
1880      */
1881     @Deprecated
checkPermissionReadImages(boolean enforce, int pid, int uid, String packageName, @Nullable String featureId)1882     public boolean checkPermissionReadImages(boolean enforce,
1883             int pid, int uid, String packageName, @Nullable String featureId) {
1884         if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId,
1885                 READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE)) {
1886             return false;
1887         }
1888         return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId,
1889                 OP_READ_MEDIA_IMAGES);
1890     }
1891 
checkExternalStoragePermissionAndAppOp(boolean enforce, int pid, int uid, String packageName, @Nullable String featureId, String permission, int op)1892     private boolean checkExternalStoragePermissionAndAppOp(boolean enforce,
1893             int pid, int uid, String packageName, @Nullable String featureId, String permission,
1894             int op) {
1895         // First check if app has MANAGE_EXTERNAL_STORAGE.
1896         final int mode = mAppOps.noteOpNoThrow(OP_MANAGE_EXTERNAL_STORAGE, uid, packageName,
1897                 featureId, null);
1898         if (mode == AppOpsManager.MODE_ALLOWED) {
1899             return true;
1900         }
1901         if (mode == AppOpsManager.MODE_DEFAULT && mContext.checkPermission(
1902                   MANAGE_EXTERNAL_STORAGE, pid, uid) == PERMISSION_GRANTED) {
1903             return true;
1904         }
1905         // If app doesn't have MANAGE_EXTERNAL_STORAGE, then check if it has requested granular
1906         // permission.
1907         return checkPermissionAndAppOp(enforce, pid, uid, packageName, featureId, permission, op);
1908     }
1909 
1910     /** {@hide} */
1911     @VisibleForTesting
openProxyFileDescriptor( int mode, ProxyFileDescriptorCallback callback, Handler handler, ThreadFactory factory)1912     public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
1913             int mode, ProxyFileDescriptorCallback callback, Handler handler, ThreadFactory factory)
1914                     throws IOException {
1915         Preconditions.checkNotNull(callback);
1916         MetricsLogger.count(mContext, "storage_open_proxy_file_descriptor", 1);
1917         // Retry is needed because the mount point mFuseAppLoop is using may be unmounted before
1918         // invoking StorageManagerService#openProxyFileDescriptor. In this case, we need to re-mount
1919         // the bridge by calling mountProxyFileDescriptorBridge.
1920         while (true) {
1921             try {
1922                 synchronized (mFuseAppLoopLock) {
1923                     boolean newlyCreated = false;
1924                     if (mFuseAppLoop == null) {
1925                         final AppFuseMount mount = mStorageManager.mountProxyFileDescriptorBridge();
1926                         if (mount == null) {
1927                             throw new IOException("Failed to mount proxy bridge");
1928                         }
1929                         mFuseAppLoop = new FuseAppLoop(mount.mountPointId, mount.fd, factory);
1930                         newlyCreated = true;
1931                     }
1932                     if (handler == null) {
1933                         handler = new Handler(Looper.getMainLooper());
1934                     }
1935                     try {
1936                         final int fileId = mFuseAppLoop.registerCallback(callback, handler);
1937                         final ParcelFileDescriptor pfd = mStorageManager.openProxyFileDescriptor(
1938                                 mFuseAppLoop.getMountPointId(), fileId, mode);
1939                         if (pfd == null) {
1940                             mFuseAppLoop.unregisterCallback(fileId);
1941                             throw new FuseUnavailableMountException(
1942                                     mFuseAppLoop.getMountPointId());
1943                         }
1944                         return pfd;
1945                     } catch (FuseUnavailableMountException exception) {
1946                         // The bridge is being unmounted. Tried to recreate it unless the bridge was
1947                         // just created.
1948                         if (newlyCreated) {
1949                             throw new IOException(exception);
1950                         }
1951                         mFuseAppLoop = null;
1952                         continue;
1953                     }
1954                 }
1955             } catch (RemoteException e) {
1956                 // Cannot recover from remote exception.
1957                 throw new IOException(e);
1958             }
1959         }
1960     }
1961 
1962     /** {@hide} */
openProxyFileDescriptor( int mode, ProxyFileDescriptorCallback callback)1963     public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
1964             int mode, ProxyFileDescriptorCallback callback)
1965                     throws IOException {
1966         return openProxyFileDescriptor(mode, callback, null, null);
1967     }
1968 
1969     /**
1970      * Opens a seekable {@link ParcelFileDescriptor} that proxies all low-level
1971      * I/O requests back to the given {@link ProxyFileDescriptorCallback}.
1972      * <p>
1973      * This can be useful when you want to provide quick access to a large file
1974      * that isn't backed by a real file on disk, such as a file on a network
1975      * share, cloud storage service, etc. As an example, you could respond to a
1976      * {@link ContentResolver#openFileDescriptor(android.net.Uri, String)}
1977      * request by returning a {@link ParcelFileDescriptor} created with this
1978      * method, and then stream the content on-demand as requested.
1979      * <p>
1980      * Another useful example might be where you have an encrypted file that
1981      * you're willing to decrypt on-demand, but where you want to avoid
1982      * persisting the cleartext version.
1983      *
1984      * @param mode The desired access mode, must be one of
1985      *            {@link ParcelFileDescriptor#MODE_READ_ONLY},
1986      *            {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
1987      *            {@link ParcelFileDescriptor#MODE_READ_WRITE}
1988      * @param callback Callback to process file operation requests issued on
1989      *            returned file descriptor.
1990      * @param handler Handler that invokes callback methods.
1991      * @return Seekable ParcelFileDescriptor.
1992      * @throws IOException
1993      */
openProxyFileDescriptor( int mode, ProxyFileDescriptorCallback callback, Handler handler)1994     public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
1995             int mode, ProxyFileDescriptorCallback callback, Handler handler)
1996                     throws IOException {
1997         Preconditions.checkNotNull(handler);
1998         return openProxyFileDescriptor(mode, callback, handler, null);
1999     }
2000 
2001     /** {@hide} */
2002     @VisibleForTesting
getProxyFileDescriptorMountPointId()2003     public int getProxyFileDescriptorMountPointId() {
2004         synchronized (mFuseAppLoopLock) {
2005             return mFuseAppLoop != null ? mFuseAppLoop.getMountPointId() : -1;
2006         }
2007     }
2008 
2009     /**
2010      * Return quota size in bytes for all cached data belonging to the calling
2011      * app on the given storage volume.
2012      * <p>
2013      * If your app goes above this quota, your cached files will be some of the
2014      * first to be deleted when additional disk space is needed. Conversely, if
2015      * your app stays under this quota, your cached files will be some of the
2016      * last to be deleted when additional disk space is needed.
2017      * <p>
2018      * This quota will change over time depending on how frequently the user
2019      * interacts with your app, and depending on how much system-wide disk space
2020      * is used.
2021      * <p class="note">
2022      * Note: if your app uses the {@code android:sharedUserId} manifest feature,
2023      * then cached data for all packages in your shared UID is tracked together
2024      * as a single unit.
2025      * </p>
2026      *
2027      * @param storageUuid the UUID of the storage volume that you're interested
2028      *            in. The UUID for a specific path can be obtained using
2029      *            {@link #getUuidForPath(File)}.
2030      * @throws IOException when the storage device isn't present, or when it
2031      *             doesn't support cache quotas.
2032      * @see #getCacheSizeBytes(UUID)
2033      */
2034     @WorkerThread
getCacheQuotaBytes(@onNull UUID storageUuid)2035     public @BytesLong long getCacheQuotaBytes(@NonNull UUID storageUuid) throws IOException {
2036         try {
2037             final ApplicationInfo app = mContext.getApplicationInfo();
2038             return mStorageManager.getCacheQuotaBytes(convert(storageUuid), app.uid);
2039         } catch (ParcelableException e) {
2040             e.maybeRethrow(IOException.class);
2041             throw new RuntimeException(e);
2042         } catch (RemoteException e) {
2043             throw e.rethrowFromSystemServer();
2044         }
2045     }
2046 
2047     /**
2048      * Return total size in bytes of all cached data belonging to the calling
2049      * app on the given storage volume.
2050      * <p>
2051      * Cached data tracked by this method always includes
2052      * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}, and
2053      * it also includes {@link Context#getExternalCacheDir()} if the primary
2054      * shared/external storage is hosted on the same storage device as your
2055      * private data.
2056      * <p class="note">
2057      * Note: if your app uses the {@code android:sharedUserId} manifest feature,
2058      * then cached data for all packages in your shared UID is tracked together
2059      * as a single unit.
2060      * </p>
2061      *
2062      * @param storageUuid the UUID of the storage volume that you're interested
2063      *            in. The UUID for a specific path can be obtained using
2064      *            {@link #getUuidForPath(File)}.
2065      * @throws IOException when the storage device isn't present, or when it
2066      *             doesn't support cache quotas.
2067      * @see #getCacheQuotaBytes(UUID)
2068      */
2069     @WorkerThread
getCacheSizeBytes(@onNull UUID storageUuid)2070     public @BytesLong long getCacheSizeBytes(@NonNull UUID storageUuid) throws IOException {
2071         try {
2072             final ApplicationInfo app = mContext.getApplicationInfo();
2073             return mStorageManager.getCacheSizeBytes(convert(storageUuid), app.uid);
2074         } catch (ParcelableException e) {
2075             e.maybeRethrow(IOException.class);
2076             throw new RuntimeException(e);
2077         } catch (RemoteException e) {
2078             throw e.rethrowFromSystemServer();
2079         }
2080     }
2081 
2082 
2083     /** @hide */
2084     @IntDef(prefix = { "MOUNT_MODE_" }, value = {
2085             MOUNT_MODE_EXTERNAL_NONE,
2086             MOUNT_MODE_EXTERNAL_DEFAULT,
2087             MOUNT_MODE_EXTERNAL_INSTALLER,
2088             MOUNT_MODE_EXTERNAL_PASS_THROUGH,
2089             MOUNT_MODE_EXTERNAL_ANDROID_WRITABLE
2090     })
2091     /** @hide */
2092     public @interface MountMode {}
2093 
2094     /**
2095      * No external storage should be mounted.
2096      * @hide
2097      */
2098     @SystemApi
2099     public static final int MOUNT_MODE_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
2100     /**
2101      * Default external storage should be mounted.
2102      * @hide
2103      */
2104     @SystemApi
2105     public static final int MOUNT_MODE_EXTERNAL_DEFAULT = IVold.REMOUNT_MODE_DEFAULT;
2106     /**
2107      * Mount mode for package installers which should give them access to
2108      * all obb dirs in addition to their package sandboxes
2109      * @hide
2110      */
2111     @SystemApi
2112     public static final int MOUNT_MODE_EXTERNAL_INSTALLER = IVold.REMOUNT_MODE_INSTALLER;
2113     /**
2114      * The lower file system should be bind mounted directly on external storage
2115      * @hide
2116      */
2117     @SystemApi
2118     public static final int MOUNT_MODE_EXTERNAL_PASS_THROUGH = IVold.REMOUNT_MODE_PASS_THROUGH;
2119 
2120     /**
2121      * Use the regular scoped storage filesystem, but Android/ should be writable.
2122      * Used to support the applications hosting DownloadManager and the MTP server.
2123      * @hide
2124      */
2125     @SystemApi
2126     public static final int MOUNT_MODE_EXTERNAL_ANDROID_WRITABLE =
2127             IVold.REMOUNT_MODE_ANDROID_WRITABLE;
2128     /**
2129      * Flag indicating that a disk space allocation request should operate in an
2130      * aggressive mode. This flag should only be rarely used in situations that
2131      * are critical to system health or security.
2132      * <p>
2133      * When set, the system is more aggressive about the data that it considers
2134      * for possible deletion when allocating disk space.
2135      * <p class="note">
2136      * Note: your app must hold the
2137      * {@link android.Manifest.permission#ALLOCATE_AGGRESSIVE} permission for
2138      * this flag to take effect.
2139      * </p>
2140      *
2141      * @see #getAllocatableBytes(UUID, int)
2142      * @see #allocateBytes(UUID, long, int)
2143      * @see #allocateBytes(FileDescriptor, long, int)
2144      * @hide
2145      */
2146     @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE)
2147     @SystemApi
2148     public static final int FLAG_ALLOCATE_AGGRESSIVE = 1 << 0;
2149 
2150     /**
2151      * Flag indicating that a disk space allocation request should be allowed to
2152      * clear up to all reserved disk space.
2153      *
2154      * @hide
2155      */
2156     public static final int FLAG_ALLOCATE_DEFY_ALL_RESERVED = 1 << 1;
2157 
2158     /**
2159      * Flag indicating that a disk space allocation request should be allowed to
2160      * clear up to half of all reserved disk space.
2161      *
2162      * @hide
2163      */
2164     public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2;
2165 
2166     /**
2167      * Flag indicating that a disk space check should not take into account
2168      * freeable cached space when determining allocatable space.
2169      *
2170      * Intended for use with {@link #getAllocatableBytes()}.
2171      * @hide
2172      */
2173     public static final int FLAG_ALLOCATE_NON_CACHE_ONLY = 1 << 3;
2174 
2175     /**
2176      * Flag indicating that a disk space check should only return freeable
2177      * cached space when determining allocatable space.
2178      *
2179      * Intended for use with {@link #getAllocatableBytes()}.
2180      * @hide
2181      */
2182     public static final int FLAG_ALLOCATE_CACHE_ONLY = 1 << 4;
2183 
2184     /** @hide */
2185     @IntDef(flag = true, prefix = { "FLAG_ALLOCATE_" }, value = {
2186             FLAG_ALLOCATE_AGGRESSIVE,
2187             FLAG_ALLOCATE_DEFY_ALL_RESERVED,
2188             FLAG_ALLOCATE_DEFY_HALF_RESERVED,
2189             FLAG_ALLOCATE_NON_CACHE_ONLY,
2190             FLAG_ALLOCATE_CACHE_ONLY,
2191     })
2192     @Retention(RetentionPolicy.SOURCE)
2193     public @interface AllocateFlags {}
2194 
2195     /**
2196      * Return the maximum number of new bytes that your app can allocate for
2197      * itself on the given storage volume. This value is typically larger than
2198      * {@link File#getUsableSpace()}, since the system may be willing to delete
2199      * cached files to satisfy an allocation request. You can then allocate
2200      * space for yourself using {@link #allocateBytes(UUID, long)} or
2201      * {@link #allocateBytes(FileDescriptor, long)}.
2202      * <p>
2203      * This method is best used as a pre-flight check, such as deciding if there
2204      * is enough space to store an entire music album before you allocate space
2205      * for each audio file in the album. Attempts to allocate disk space beyond
2206      * the returned value will fail.
2207      * <p>
2208      * If the returned value is not large enough for the data you'd like to
2209      * persist, you can launch {@link #ACTION_MANAGE_STORAGE} with the
2210      * {@link #EXTRA_UUID} and {@link #EXTRA_REQUESTED_BYTES} options to help
2211      * involve the user in freeing up disk space.
2212      * <p>
2213      * If you're progressively allocating an unbounded amount of storage space
2214      * (such as when recording a video) you should avoid calling this method
2215      * more than once every 30 seconds.
2216      * <p class="note">
2217      * Note: if your app uses the {@code android:sharedUserId} manifest feature,
2218      * then allocatable space for all packages in your shared UID is tracked
2219      * together as a single unit.
2220      * </p>
2221      *
2222      * @param storageUuid the UUID of the storage volume where you're
2223      *            considering allocating disk space, since allocatable space can
2224      *            vary widely depending on the underlying storage device. The
2225      *            UUID for a specific path can be obtained using
2226      *            {@link #getUuidForPath(File)}.
2227      * @return the maximum number of new bytes that the calling app can allocate
2228      *         using {@link #allocateBytes(UUID, long)} or
2229      *         {@link #allocateBytes(FileDescriptor, long)}.
2230      * @throws IOException when the storage device isn't present, or when it
2231      *             doesn't support allocating space.
2232      */
2233     @WorkerThread
getAllocatableBytes(@onNull UUID storageUuid)2234     public @BytesLong long getAllocatableBytes(@NonNull UUID storageUuid)
2235             throws IOException {
2236         return getAllocatableBytes(storageUuid, 0);
2237     }
2238 
2239     /** @hide */
2240     @SystemApi
2241     @WorkerThread
2242     @SuppressLint("RequiresPermission")
getAllocatableBytes(@onNull UUID storageUuid, @RequiresPermission @AllocateFlags int flags)2243     public long getAllocatableBytes(@NonNull UUID storageUuid,
2244             @RequiresPermission @AllocateFlags int flags) throws IOException {
2245         try {
2246             return mStorageManager.getAllocatableBytes(convert(storageUuid), flags,
2247                     mContext.getOpPackageName());
2248         } catch (ParcelableException e) {
2249             e.maybeRethrow(IOException.class);
2250             throw new RuntimeException(e);
2251         } catch (RemoteException e) {
2252             throw e.rethrowFromSystemServer();
2253         }
2254     }
2255 
2256     /**
2257      * Allocate the requested number of bytes for your application to use on the
2258      * given storage volume. This will cause the system to delete any cached
2259      * files necessary to satisfy your request.
2260      * <p>
2261      * Attempts to allocate disk space beyond the value returned by
2262      * {@link #getAllocatableBytes(UUID)} will fail.
2263      * <p>
2264      * Since multiple apps can be running simultaneously, this method may be
2265      * subject to race conditions. If possible, consider using
2266      * {@link #allocateBytes(FileDescriptor, long)} which will guarantee
2267      * that bytes are allocated to an opened file.
2268      * <p>
2269      * If you're progressively allocating an unbounded amount of storage space
2270      * (such as when recording a video) you should avoid calling this method
2271      * more than once every 60 seconds.
2272      *
2273      * @param storageUuid the UUID of the storage volume where you'd like to
2274      *            allocate disk space. The UUID for a specific path can be
2275      *            obtained using {@link #getUuidForPath(File)}.
2276      * @param bytes the number of bytes to allocate.
2277      * @throws IOException when the storage device isn't present, or when it
2278      *             doesn't support allocating space, or if the device had
2279      *             trouble allocating the requested space.
2280      * @see #getAllocatableBytes(UUID)
2281      */
2282     @WorkerThread
allocateBytes(@onNull UUID storageUuid, @BytesLong long bytes)2283     public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes)
2284             throws IOException {
2285         allocateBytes(storageUuid, bytes, 0);
2286     }
2287 
2288     /** @hide */
2289     @SystemApi
2290     @WorkerThread
2291     @SuppressLint("RequiresPermission")
allocateBytes(@onNull UUID storageUuid, @BytesLong long bytes, @RequiresPermission @AllocateFlags int flags)2292     public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes,
2293             @RequiresPermission @AllocateFlags int flags) throws IOException {
2294         try {
2295             mStorageManager.allocateBytes(convert(storageUuid), bytes, flags,
2296                     mContext.getOpPackageName());
2297         } catch (ParcelableException e) {
2298             e.maybeRethrow(IOException.class);
2299         } catch (RemoteException e) {
2300             throw e.rethrowFromSystemServer();
2301         }
2302     }
2303 
2304     /**
2305      * Returns the External Storage mount mode corresponding to the given uid and packageName.
2306      * These mount modes specify different views and access levels for
2307      * different apps on external storage.
2308      *
2309      * @params uid UID of the application
2310      * @params packageName name of the package
2311      * @return {@code MountMode} for the given uid and packageName.
2312      *
2313      * @hide
2314      */
2315     @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE)
2316     @SystemApi
2317     @MountMode
getExternalStorageMountMode(int uid, @NonNull String packageName)2318     public int getExternalStorageMountMode(int uid, @NonNull String packageName) {
2319         try {
2320             return mStorageManager.getExternalStorageMountMode(uid, packageName);
2321         } catch (RemoteException e) {
2322             throw e.rethrowFromSystemServer();
2323         }
2324     }
2325 
2326     /**
2327      * Allocate the requested number of bytes for your application to use in the
2328      * given open file. This will cause the system to delete any cached files
2329      * necessary to satisfy your request.
2330      * <p>
2331      * Attempts to allocate disk space beyond the value returned by
2332      * {@link #getAllocatableBytes(UUID)} will fail.
2333      * <p>
2334      * This method guarantees that bytes have been allocated to the opened file,
2335      * otherwise it will throw if fast allocation is not possible. Fast
2336      * allocation is typically only supported in private app data directories,
2337      * and on shared/external storage devices which are emulated.
2338      * <p>
2339      * If you're progressively allocating an unbounded amount of storage space
2340      * (such as when recording a video) you should avoid calling this method
2341      * more than once every 60 seconds.
2342      *
2343      * @param fd the open file that you'd like to allocate disk space for.
2344      * @param bytes the number of bytes to allocate. This is the desired final
2345      *            size of the open file. If the open file is smaller than this
2346      *            requested size, it will be extended without modifying any
2347      *            existing contents. If the open file is larger than this
2348      *            requested size, it will be truncated.
2349      * @throws IOException when the storage device isn't present, or when it
2350      *             doesn't support allocating space, or if the device had
2351      *             trouble allocating the requested space.
2352      * @see #isAllocationSupported(FileDescriptor)
2353      * @see Environment#isExternalStorageEmulated(File)
2354      */
2355     @WorkerThread
allocateBytes(FileDescriptor fd, @BytesLong long bytes)2356     public void allocateBytes(FileDescriptor fd, @BytesLong long bytes) throws IOException {
2357         allocateBytes(fd, bytes, 0);
2358     }
2359 
2360     /** @hide */
2361     @SystemApi
2362     @WorkerThread
2363     @SuppressLint("RequiresPermission")
allocateBytes(FileDescriptor fd, @BytesLong long bytes, @RequiresPermission @AllocateFlags int flags)2364     public void allocateBytes(FileDescriptor fd, @BytesLong long bytes,
2365             @RequiresPermission @AllocateFlags int flags) throws IOException {
2366         final File file = ParcelFileDescriptor.getFile(fd);
2367         final UUID uuid = getUuidForPath(file);
2368         for (int i = 0; i < 3; i++) {
2369             try {
2370                 final long haveBytes = Os.fstat(fd).st_blocks * 512;
2371                 final long needBytes = bytes - haveBytes;
2372 
2373                 if (needBytes > 0) {
2374                     allocateBytes(uuid, needBytes, flags);
2375                 }
2376 
2377                 try {
2378                     Os.posix_fallocate(fd, 0, bytes);
2379                     return;
2380                 } catch (ErrnoException e) {
2381                     if (e.errno == OsConstants.ENOSYS || e.errno == OsConstants.ENOTSUP) {
2382                         Log.w(TAG, "fallocate() not supported; falling back to ftruncate()");
2383                         Os.ftruncate(fd, bytes);
2384                         return;
2385                     } else {
2386                         throw e;
2387                     }
2388                 }
2389             } catch (ErrnoException e) {
2390                 if (e.errno == OsConstants.ENOSPC) {
2391                     Log.w(TAG, "Odd, not enough space; let's try again?");
2392                     continue;
2393                 }
2394                 throw e.rethrowAsIOException();
2395             }
2396         }
2397         throw new IOException(
2398                 "Well this is embarassing; we can't allocate " + bytes + " for " + file);
2399     }
2400 
2401     private static final String XATTR_CACHE_GROUP = "user.cache_group";
2402     private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone";
2403 
2404 
2405     // Project IDs below must match android_projectid_config.h
2406     /**
2407      * Default project ID for files on external storage
2408      *
2409      * {@hide}
2410      */
2411     public static final int PROJECT_ID_EXT_DEFAULT = 1000;
2412 
2413     /**
2414      * project ID for audio files on external storage
2415      *
2416      * {@hide}
2417      */
2418     public static final int PROJECT_ID_EXT_MEDIA_AUDIO = 1001;
2419 
2420     /**
2421      * project ID for video files on external storage
2422      *
2423      * {@hide}
2424      */
2425     public static final int PROJECT_ID_EXT_MEDIA_VIDEO = 1002;
2426 
2427     /**
2428      * project ID for image files on external storage
2429      *
2430      * {@hide}
2431      */
2432     public static final int PROJECT_ID_EXT_MEDIA_IMAGE = 1003;
2433 
2434     /**
2435      * Constant for use with
2436      * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file
2437      * is not a media file.
2438      *
2439      * @hide
2440      */
2441     @SystemApi
2442     public static final int QUOTA_TYPE_MEDIA_NONE = 0;
2443 
2444     /**
2445      * Constant for use with
2446      * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file
2447      * is an image file.
2448      *
2449      * @hide
2450      */
2451     @SystemApi
2452     public static final int QUOTA_TYPE_MEDIA_IMAGE = 1;
2453 
2454     /**
2455      * Constant for use with
2456      * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file
2457      * is an audio file.
2458      *
2459      * @hide
2460      */
2461     @SystemApi
2462     public static final int QUOTA_TYPE_MEDIA_AUDIO = 2;
2463 
2464     /**
2465      * Constant for use with
2466      * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file
2467      * is a video file.
2468      *
2469      * @hide
2470      */
2471     @SystemApi
2472     public static final int QUOTA_TYPE_MEDIA_VIDEO = 3;
2473 
2474     /** @hide */
2475     @Retention(RetentionPolicy.SOURCE)
2476     @IntDef(prefix = { "QUOTA_TYPE_" }, value = {
2477             QUOTA_TYPE_MEDIA_NONE,
2478             QUOTA_TYPE_MEDIA_AUDIO,
2479             QUOTA_TYPE_MEDIA_VIDEO,
2480             QUOTA_TYPE_MEDIA_IMAGE,
2481     })
2482     public @interface QuotaType {}
2483 
setQuotaProjectId(String path, long projectId)2484     private static native boolean setQuotaProjectId(String path, long projectId);
2485 
getProjectIdForUser(int userId, int projectId)2486     private static long getProjectIdForUser(int userId, int projectId) {
2487         // Much like UserHandle.getUid(), store the user ID in the upper bits
2488         return userId * PER_USER_RANGE + projectId;
2489     }
2490 
2491     /**
2492      * Let StorageManager know that the quota type for a file on external storage should
2493      * be updated. Android tracks quotas for various media types. Consequently, this should be
2494      * called on first creation of a new file on external storage, and whenever the
2495      * media type of the file is updated later.
2496      *
2497      * This API doesn't require any special permissions, though typical implementations
2498      * will require being called from an SELinux domain that allows setting file attributes
2499      * related to quota (eg the GID or project ID).
2500      * If the calling user has MANAGE_EXTERNAL_STORAGE permissions, quota for shared profile's
2501      * volumes is also updated.
2502      *
2503      * The default platform user of this API is the MediaProvider process, which is
2504      * responsible for managing all of external storage.
2505      *
2506      * @param path the path to the file for which we should update the quota type
2507      * @param quotaType the quota type of the file; this is based on the
2508      *                  {@code QuotaType} constants, eg
2509      *                  {@code StorageManager.QUOTA_TYPE_MEDIA_AUDIO}
2510      *
2511      * @throws IllegalArgumentException if {@code quotaType} does not correspond to a valid
2512      *                                  quota type.
2513      * @throws IOException              if the quota type could not be updated.
2514      *
2515      * @hide
2516      */
2517     @SystemApi
updateExternalStorageFileQuotaType(@onNull File path, @QuotaType int quotaType)2518     public void updateExternalStorageFileQuotaType(@NonNull File path,
2519             @QuotaType int quotaType) throws IOException {
2520         long projectId;
2521         final String filePath = path.getCanonicalPath();
2522         int volFlags = FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE;
2523         // If caller has MANAGE_EXTERNAL_STORAGE permission, results from User Profile(s) are also
2524         // returned by enabling FLAG_INCLUDE_SHARED_PROFILE.
2525         if (mContext.checkSelfPermission(MANAGE_EXTERNAL_STORAGE) == PERMISSION_GRANTED) {
2526             volFlags |= FLAG_INCLUDE_SHARED_PROFILE;
2527         }
2528         final StorageVolume[] availableVolumes = getVolumeList(mContext.getUserId(), volFlags);
2529         final StorageVolume volume = getStorageVolume(availableVolumes, path);
2530         if (volume == null) {
2531             Log.w(TAG, "Failed to update quota type for " + filePath);
2532             return;
2533         }
2534         if (!volume.isEmulated()) {
2535             // We only support quota tracking on emulated filesystems
2536             return;
2537         }
2538 
2539         final int userId = volume.getOwner().getIdentifier();
2540         if (userId < 0) {
2541             throw new IllegalStateException("Failed to update quota type for " + filePath);
2542         }
2543         switch (quotaType) {
2544             case QUOTA_TYPE_MEDIA_NONE:
2545                 projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_DEFAULT);
2546                 break;
2547             case QUOTA_TYPE_MEDIA_AUDIO:
2548                 projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_AUDIO);
2549                 break;
2550             case QUOTA_TYPE_MEDIA_VIDEO:
2551                 projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_VIDEO);
2552                 break;
2553             case QUOTA_TYPE_MEDIA_IMAGE:
2554                 projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_IMAGE);
2555                 break;
2556             default:
2557                 throw new IllegalArgumentException("Invalid quota type: " + quotaType);
2558         }
2559         if (!setQuotaProjectId(filePath, projectId)) {
2560             throw new IOException("Failed to update quota type for " + filePath);
2561         }
2562     }
2563 
2564     /**
2565      * Asks StorageManager to fixup the permissions of an application-private directory.
2566      *
2567      * On devices without sdcardfs, filesystem permissions aren't magically fixed up. This
2568      * is problematic mostly in application-private directories, which are owned by the
2569      * application itself; if another process with elevated permissions creates a file
2570      * in these directories, the UID will be wrong, and the owning package won't be able
2571      * to access the files.
2572      *
2573      * This API can be used to recursively fix up the permissions on the passed in path.
2574      * The default platform user of this API is the DownloadProvider, which can download
2575      * things in application-private directories on their behalf.
2576      *
2577      * This API doesn't require any special permissions, because it merely changes the
2578      * permissions of a directory to what they should anyway be.
2579      *
2580      * @param path the path for which we should fix up the permissions
2581      *
2582      * @hide
2583      */
fixupAppDir(@onNull File path)2584     public void fixupAppDir(@NonNull File path) {
2585         try {
2586             mStorageManager.fixupAppDir(path.getCanonicalPath());
2587         } catch (IOException e) {
2588             Log.e(TAG, "Failed to get canonical path for " + path.getPath(), e);
2589         } catch (RemoteException e) {
2590             throw e.rethrowFromSystemServer();
2591         }
2592     }
2593 
2594     /** {@hide} */
setCacheBehavior(File path, String name, boolean enabled)2595     private static void setCacheBehavior(File path, String name, boolean enabled)
2596             throws IOException {
2597         if (!path.isDirectory()) {
2598             throw new IOException("Cache behavior can only be set on directories");
2599         }
2600         if (enabled) {
2601             try {
2602                 Os.setxattr(path.getAbsolutePath(), name,
2603                         "1".getBytes(StandardCharsets.UTF_8), 0);
2604             } catch (ErrnoException e) {
2605                 throw e.rethrowAsIOException();
2606             }
2607         } else {
2608             try {
2609                 Os.removexattr(path.getAbsolutePath(), name);
2610             } catch (ErrnoException e) {
2611                 if (e.errno != OsConstants.ENODATA) {
2612                     throw e.rethrowAsIOException();
2613                 }
2614             }
2615         }
2616     }
2617 
2618     /** {@hide} */
isCacheBehavior(File path, String name)2619     private static boolean isCacheBehavior(File path, String name) throws IOException {
2620         try {
2621             Os.getxattr(path.getAbsolutePath(), name);
2622             return true;
2623         } catch (ErrnoException e) {
2624             if (e.errno != OsConstants.ENODATA) {
2625                 throw e.rethrowAsIOException();
2626             } else {
2627                 return false;
2628             }
2629         }
2630     }
2631 
2632     /**
2633      * Enable or disable special cache behavior that treats this directory and
2634      * its contents as an entire group.
2635      * <p>
2636      * When enabled and this directory is considered for automatic deletion by
2637      * the OS, all contained files will either be deleted together, or not at
2638      * all. This is useful when you have a directory that contains several
2639      * related metadata files that depend on each other, such as movie file and
2640      * a subtitle file.
2641      * <p>
2642      * When enabled, the <em>newest</em> {@link File#lastModified()} value of
2643      * any contained files is considered the modified time of the entire
2644      * directory.
2645      * <p>
2646      * This behavior can only be set on a directory, and it applies recursively
2647      * to all contained files and directories.
2648      */
setCacheBehaviorGroup(File path, boolean group)2649     public void setCacheBehaviorGroup(File path, boolean group) throws IOException {
2650         setCacheBehavior(path, XATTR_CACHE_GROUP, group);
2651     }
2652 
2653     /**
2654      * Read the current value set by
2655      * {@link #setCacheBehaviorGroup(File, boolean)}.
2656      */
isCacheBehaviorGroup(File path)2657     public boolean isCacheBehaviorGroup(File path) throws IOException {
2658         return isCacheBehavior(path, XATTR_CACHE_GROUP);
2659     }
2660 
2661     /**
2662      * Enable or disable special cache behavior that leaves deleted cache files
2663      * intact as tombstones.
2664      * <p>
2665      * When enabled and a file contained in this directory is automatically
2666      * deleted by the OS, the file will be truncated to have a length of 0 bytes
2667      * instead of being fully deleted. This is useful if you need to distinguish
2668      * between a file that was deleted versus one that never existed.
2669      * <p>
2670      * This behavior can only be set on a directory, and it applies recursively
2671      * to all contained files and directories.
2672      * <p class="note">
2673      * Note: this behavior is ignored completely if the user explicitly requests
2674      * that all cached data be cleared.
2675      * </p>
2676      */
setCacheBehaviorTombstone(File path, boolean tombstone)2677     public void setCacheBehaviorTombstone(File path, boolean tombstone) throws IOException {
2678         setCacheBehavior(path, XATTR_CACHE_TOMBSTONE, tombstone);
2679     }
2680 
2681     /**
2682      * Read the current value set by
2683      * {@link #setCacheBehaviorTombstone(File, boolean)}.
2684      */
isCacheBehaviorTombstone(File path)2685     public boolean isCacheBehaviorTombstone(File path) throws IOException {
2686         return isCacheBehavior(path, XATTR_CACHE_TOMBSTONE);
2687     }
2688 
2689     /**
2690      * Returns true if {@code uuid} is a FAT volume identifier. FAT Volume identifiers
2691      * are 32 randomly generated bits that are represented in string form as AAAA-AAAA.
2692      */
isFatVolumeIdentifier(String uuid)2693     private static boolean isFatVolumeIdentifier(String uuid) {
2694         return uuid.length() == 9 && uuid.charAt(4) == '-';
2695     }
2696 
2697     /** {@hide} */
2698     @TestApi
convert(@ullable String uuid)2699     public static @NonNull UUID convert(@Nullable String uuid) {
2700         // UUID_PRIVATE_INTERNAL is null, so this accepts nullable input
2701         if (Objects.equals(uuid, UUID_PRIVATE_INTERNAL)) {
2702             return UUID_DEFAULT;
2703         } else if (Objects.equals(uuid, UUID_PRIMARY_PHYSICAL)) {
2704             return UUID_PRIMARY_PHYSICAL_;
2705         } else if (Objects.equals(uuid, UUID_SYSTEM)) {
2706             return UUID_SYSTEM_;
2707         } else if (isFatVolumeIdentifier(uuid)) {
2708             // FAT volume identifiers are not UUIDs but we need to coerce them into
2709             // UUIDs in order to satisfy apis that take java.util.UUID arguments.
2710             //
2711             // We coerce a 32 bit fat volume identifier of the form XXXX-YYYY into
2712             // a UUID of form "fafafafa-fafa-5afa-8afa-fafaXXXXYYYY". This is an
2713             // RFC-422 UUID with Version 5, which is a namespaced UUID. The UUIDs we
2714             // coerce into are not true namespace UUIDs; although FAT storage volume
2715             // identifiers are unique names within a fixed namespace, this UUID is not
2716             // based on an SHA-1 hash of the name. We avoid the SHA-1 hash because
2717             // (a) we need this transform to be reversible (b) it's pointless to generate
2718             // a 128 bit hash from a 32 bit value.
2719             return UUID.fromString(FAT_UUID_PREFIX + uuid.replace("-", ""));
2720         } else {
2721             return UUID.fromString(uuid);
2722         }
2723     }
2724 
2725     /** {@hide} */
2726     @TestApi
convert(@onNull UUID storageUuid)2727     public static @NonNull String convert(@NonNull UUID storageUuid) {
2728         if (UUID_DEFAULT.equals(storageUuid)) {
2729             return UUID_PRIVATE_INTERNAL;
2730         } else if (UUID_PRIMARY_PHYSICAL_.equals(storageUuid)) {
2731             return UUID_PRIMARY_PHYSICAL;
2732         } else if (UUID_SYSTEM_.equals(storageUuid)) {
2733             return UUID_SYSTEM;
2734         } else {
2735             String uuidString = storageUuid.toString();
2736             // This prefix match will exclude fsUuids from private volumes because
2737             // (a) linux fsUuids are generally Version 4 (random) UUIDs so the prefix
2738             // will contain 4xxx instead of 5xxx and (b) we've already matched against
2739             // known namespace (Version 5) UUIDs above.
2740             if (uuidString.startsWith(FAT_UUID_PREFIX)) {
2741                 String fatStr = uuidString.substring(FAT_UUID_PREFIX.length())
2742                         .toUpperCase(Locale.US);
2743                 return fatStr.substring(0, 4) + "-" + fatStr.substring(4);
2744             }
2745 
2746             return storageUuid.toString();
2747         }
2748     }
2749 
2750     /**
2751      * Check whether the device supports filesystem checkpoint.
2752      *
2753      * @return true if the device supports filesystem checkpoint, false otherwise.
2754      */
isCheckpointSupported()2755     public boolean isCheckpointSupported() {
2756         try {
2757             return mStorageManager.supportsCheckpoint();
2758         } catch (RemoteException e) {
2759             throw e.rethrowFromSystemServer();
2760         }
2761     }
2762 
2763     /**
2764      * Reason to provide if app IO is blocked/resumed for unknown reasons
2765      *
2766      * @hide
2767      */
2768     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
2769     public static final int APP_IO_BLOCKED_REASON_UNKNOWN = 0;
2770 
2771     /**
2772      * Reason to provide if app IO is blocked/resumed because of transcoding
2773      *
2774      * @hide
2775      */
2776     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
2777     public static final int APP_IO_BLOCKED_REASON_TRANSCODING = 1;
2778 
2779     /**
2780      * Constants for use with
2781      * {@link #notifyAppIoBlocked} and {@link notifyAppIoResumed}, to specify the reason an app's
2782      * IO is blocked/resumed.
2783      *
2784      * @hide
2785      */
2786     @Retention(RetentionPolicy.SOURCE)
2787     @IntDef(prefix = { "APP_IO_BLOCKED_REASON_" }, value = {
2788                 APP_IO_BLOCKED_REASON_TRANSCODING,
2789                 APP_IO_BLOCKED_REASON_UNKNOWN,
2790     })
2791     public @interface AppIoBlockedReason {}
2792 
2793     /**
2794      * Notify the system that an app with {@code uid} and {@code tid} is blocked on an IO request on
2795      * {@code volumeUuid} for {@code reason}.
2796      *
2797      * This blocked state can be used to modify the ANR behavior for the app while it's blocked.
2798      * For example during transcoding.
2799      *
2800      * This can only be called by the {@link ExternalStorageService} holding the
2801      * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission.
2802      *
2803      * @param volumeUuid the UUID of the storage volume that the app IO is blocked on
2804      * @param uid the UID of the app blocked on IO
2805      * @param tid the tid of the app blocked on IO
2806      * @param reason the reason the app is blocked on IO
2807      *
2808      * @hide
2809      */
2810     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
notifyAppIoBlocked(@onNull UUID volumeUuid, int uid, int tid, @AppIoBlockedReason int reason)2811     public void notifyAppIoBlocked(@NonNull UUID volumeUuid, int uid, int tid,
2812             @AppIoBlockedReason int reason) {
2813         Objects.requireNonNull(volumeUuid);
2814         try {
2815             mStorageManager.notifyAppIoBlocked(convert(volumeUuid), uid, tid, reason);
2816         } catch (RemoteException e) {
2817             throw e.rethrowFromSystemServer();
2818         }
2819     }
2820 
2821     /**
2822      * Notify the system that an app with {@code uid} and {@code tid} has resmued a previously
2823      * blocked IO request on {@code volumeUuid} for {@code reason}.
2824      *
2825      * All app IO will be automatically marked as unblocked if {@code volumeUuid} is unmounted.
2826      *
2827      * This can only be called by the {@link ExternalStorageService} holding the
2828      * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission.
2829      *
2830      * @param volumeUuid the UUID of the storage volume that the app IO is resumed on
2831      * @param uid the UID of the app resuming IO
2832      * @param tid the tid of the app resuming IO
2833      * @param reason the reason the app is resuming IO
2834      *
2835      * @hide
2836      */
2837     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
notifyAppIoResumed(@onNull UUID volumeUuid, int uid, int tid, @AppIoBlockedReason int reason)2838     public void notifyAppIoResumed(@NonNull UUID volumeUuid, int uid, int tid,
2839             @AppIoBlockedReason int reason) {
2840         Objects.requireNonNull(volumeUuid);
2841         try {
2842             mStorageManager.notifyAppIoResumed(convert(volumeUuid), uid, tid, reason);
2843         } catch (RemoteException e) {
2844             throw e.rethrowFromSystemServer();
2845         }
2846     }
2847 
2848     /**
2849      * Check if {@code uid} with {@code tid} is blocked on IO for {@code reason}.
2850      *
2851      * This requires {@link ExternalStorageService} the
2852      * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission.
2853      *
2854      * @param volumeUuid the UUID of the storage volume to check IO blocked status
2855      * @param uid the UID of the app to check IO blocked status
2856      * @param tid the tid of the app to check IO blocked status
2857      * @param reason the reason to check IO blocked status for
2858      *
2859      * @hide
2860      */
2861     @TestApi
isAppIoBlocked(@onNull UUID volumeUuid, int uid, int tid, @AppIoBlockedReason int reason)2862     public boolean isAppIoBlocked(@NonNull UUID volumeUuid, int uid, int tid,
2863             @AppIoBlockedReason int reason) {
2864         Objects.requireNonNull(volumeUuid);
2865         try {
2866             return mStorageManager.isAppIoBlocked(convert(volumeUuid), uid, tid, reason);
2867         } catch (RemoteException e) {
2868             throw e.rethrowFromSystemServer();
2869         }
2870     }
2871 
2872     /**
2873      * Notify the system of the current cloud media provider.
2874      *
2875      * This can only be called by the {@link android.service.storage.ExternalStorageService}
2876      * holding the {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission.
2877      *
2878      * @param authority the authority of the content provider
2879      * @hide
2880      */
2881     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
setCloudMediaProvider(@ullable String authority)2882     public void setCloudMediaProvider(@Nullable String authority) {
2883         try {
2884             mStorageManager.setCloudMediaProvider(authority);
2885         } catch (RemoteException e) {
2886             throw e.rethrowFromSystemServer();
2887         }
2888     }
2889 
2890     /**
2891      * Returns the authority of the current cloud media provider that was set by the
2892      * {@link android.service.storage.ExternalStorageService} holding the
2893      * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission via
2894      * {@link #setCloudMediaProvider(String)}.
2895      *
2896      * @hide
2897      */
2898     @Nullable
2899     @TestApi
2900     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
getCloudMediaProvider()2901     public String getCloudMediaProvider() {
2902         try {
2903             return mStorageManager.getCloudMediaProvider();
2904         } catch (RemoteException e) {
2905             throw e.rethrowFromSystemServer();
2906         }
2907     }
2908 
2909     private final Object mFuseAppLoopLock = new Object();
2910 
2911     @GuardedBy("mFuseAppLoopLock")
2912     private @Nullable FuseAppLoop mFuseAppLoop = null;
2913 
2914     /** @hide */
2915     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2916     public static final int CRYPT_TYPE_PASSWORD = 0;
2917     /** @hide */
2918     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2919     public static final int CRYPT_TYPE_DEFAULT = 1;
2920 }
2921