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