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