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.MB_IN_BYTES;
     20 
     21 import android.annotation.NonNull;
     22 import android.annotation.Nullable;
     23 import android.app.ActivityThread;
     24 import android.content.ContentResolver;
     25 import android.content.Context;
     26 import android.content.pm.IPackageMoveObserver;
     27 import android.content.pm.PackageManager;
     28 import android.os.Binder;
     29 import android.os.Environment;
     30 import android.os.FileUtils;
     31 import android.os.Handler;
     32 import android.os.Looper;
     33 import android.os.Message;
     34 import android.os.ParcelFileDescriptor;
     35 import android.os.RemoteException;
     36 import android.os.ServiceManager;
     37 import android.os.SystemProperties;
     38 import android.os.UserHandle;
     39 import android.provider.Settings;
     40 import android.text.TextUtils;
     41 import android.util.Log;
     42 import android.util.Slog;
     43 import android.util.SparseArray;
     44 
     45 import com.android.internal.os.SomeArgs;
     46 import com.android.internal.util.Preconditions;
     47 
     48 import java.io.File;
     49 import java.io.IOException;
     50 import java.lang.ref.WeakReference;
     51 import java.util.ArrayList;
     52 import java.util.Arrays;
     53 import java.util.Collections;
     54 import java.util.Iterator;
     55 import java.util.List;
     56 import java.util.Objects;
     57 import java.util.concurrent.atomic.AtomicInteger;
     58 
     59 /**
     60  * StorageManager is the interface to the systems storage service. The storage
     61  * manager handles storage-related items such as Opaque Binary Blobs (OBBs).
     62  * <p>
     63  * OBBs contain a filesystem that maybe be encrypted on disk and mounted
     64  * on-demand from an application. OBBs are a good way of providing large amounts
     65  * of binary assets without packaging them into APKs as they may be multiple
     66  * gigabytes in size. However, due to their size, they're most likely stored in
     67  * a shared storage pool accessible from all programs. The system does not
     68  * guarantee the security of the OBB file itself: if any program modifies the
     69  * OBB, there is no guarantee that a read from that OBB will produce the
     70  * expected output.
     71  * <p>
     72  * Get an instance of this class by calling
     73  * {@link android.content.Context#getSystemService(java.lang.String)} with an
     74  * argument of {@link android.content.Context#STORAGE_SERVICE}.
     75  */
     76 public class StorageManager {
     77     private static final String TAG = "StorageManager";
     78 
     79     /** {@hide} */
     80     public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
     81     /** {@hide} */
     82     public static final String PROP_HAS_ADOPTABLE = "vold.has_adoptable";
     83     /** {@hide} */
     84     public static final String PROP_FORCE_ADOPTABLE = "persist.fw.force_adoptable";
     85     /** {@hide} */
     86     public static final String PROP_EMULATE_FBE = "persist.sys.emulate_fbe";
     87     /** {@hide} */
     88     public static final String PROP_SDCARDFS = "persist.sys.sdcardfs";
     89 
     90     /** {@hide} */
     91     public static final String UUID_PRIVATE_INTERNAL = null;
     92     /** {@hide} */
     93     public static final String UUID_PRIMARY_PHYSICAL = "primary_physical";
     94 
     95     /** {@hide} */
     96     public static final int DEBUG_FORCE_ADOPTABLE = 1 << 0;
     97     /** {@hide} */
     98     public static final int DEBUG_EMULATE_FBE = 1 << 1;
     99     /** {@hide} */
    100     public static final int DEBUG_SDCARDFS_FORCE_ON = 1 << 2;
    101     /** {@hide} */
    102     public static final int DEBUG_SDCARDFS_FORCE_OFF = 1 << 3;
    103 
    104     // NOTE: keep in sync with installd
    105     /** {@hide} */
    106     public static final int FLAG_STORAGE_DE = 1 << 0;
    107     /** {@hide} */
    108     public static final int FLAG_STORAGE_CE = 1 << 1;
    109 
    110     /** {@hide} */
    111     public static final int FLAG_FOR_WRITE = 1 << 8;
    112     /** {@hide} */
    113     public static final int FLAG_REAL_STATE = 1 << 9;
    114     /** {@hide} */
    115     public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10;
    116 
    117     private static volatile IMountService sMountService = null;
    118 
    119     private final Context mContext;
    120     private final ContentResolver mResolver;
    121 
    122     private final IMountService mMountService;
    123     private final Looper mLooper;
    124     private final AtomicInteger mNextNonce = new AtomicInteger(0);
    125 
    126     private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>();
    127 
    128     private static class StorageEventListenerDelegate extends IMountServiceListener.Stub implements
    129             Handler.Callback {
    130         private static final int MSG_STORAGE_STATE_CHANGED = 1;
    131         private static final int MSG_VOLUME_STATE_CHANGED = 2;
    132         private static final int MSG_VOLUME_RECORD_CHANGED = 3;
    133         private static final int MSG_VOLUME_FORGOTTEN = 4;
    134         private static final int MSG_DISK_SCANNED = 5;
    135         private static final int MSG_DISK_DESTROYED = 6;
    136 
    137         final StorageEventListener mCallback;
    138         final Handler mHandler;
    139 
    140         public StorageEventListenerDelegate(StorageEventListener callback, Looper looper) {
    141             mCallback = callback;
    142             mHandler = new Handler(looper, this);
    143         }
    144 
    145         @Override
    146         public boolean handleMessage(Message msg) {
    147             final SomeArgs args = (SomeArgs) msg.obj;
    148             switch (msg.what) {
    149                 case MSG_STORAGE_STATE_CHANGED:
    150                     mCallback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
    151                             (String) args.arg3);
    152                     args.recycle();
    153                     return true;
    154                 case MSG_VOLUME_STATE_CHANGED:
    155                     mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
    156                     args.recycle();
    157                     return true;
    158                 case MSG_VOLUME_RECORD_CHANGED:
    159                     mCallback.onVolumeRecordChanged((VolumeRecord) args.arg1);
    160                     args.recycle();
    161                     return true;
    162                 case MSG_VOLUME_FORGOTTEN:
    163                     mCallback.onVolumeForgotten((String) args.arg1);
    164                     args.recycle();
    165                     return true;
    166                 case MSG_DISK_SCANNED:
    167                     mCallback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
    168                     args.recycle();
    169                     return true;
    170                 case MSG_DISK_DESTROYED:
    171                     mCallback.onDiskDestroyed((DiskInfo) args.arg1);
    172                     args.recycle();
    173                     return true;
    174             }
    175             args.recycle();
    176             return false;
    177         }
    178 
    179         @Override
    180         public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException {
    181             // Ignored
    182         }
    183 
    184         @Override
    185         public void onStorageStateChanged(String path, String oldState, String newState) {
    186             final SomeArgs args = SomeArgs.obtain();
    187             args.arg1 = path;
    188             args.arg2 = oldState;
    189             args.arg3 = newState;
    190             mHandler.obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
    191         }
    192 
    193         @Override
    194         public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
    195             final SomeArgs args = SomeArgs.obtain();
    196             args.arg1 = vol;
    197             args.argi2 = oldState;
    198             args.argi3 = newState;
    199             mHandler.obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
    200         }
    201 
    202         @Override
    203         public void onVolumeRecordChanged(VolumeRecord rec) {
    204             final SomeArgs args = SomeArgs.obtain();
    205             args.arg1 = rec;
    206             mHandler.obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
    207         }
    208 
    209         @Override
    210         public void onVolumeForgotten(String fsUuid) {
    211             final SomeArgs args = SomeArgs.obtain();
    212             args.arg1 = fsUuid;
    213             mHandler.obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
    214         }
    215 
    216         @Override
    217         public void onDiskScanned(DiskInfo disk, int volumeCount) {
    218             final SomeArgs args = SomeArgs.obtain();
    219             args.arg1 = disk;
    220             args.argi2 = volumeCount;
    221             mHandler.obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
    222         }
    223 
    224         @Override
    225         public void onDiskDestroyed(DiskInfo disk) throws RemoteException {
    226             final SomeArgs args = SomeArgs.obtain();
    227             args.arg1 = disk;
    228             mHandler.obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
    229         }
    230     }
    231 
    232     /**
    233      * Binder listener for OBB action results.
    234      */
    235     private final ObbActionListener mObbActionListener = new ObbActionListener();
    236 
    237     private class ObbActionListener extends IObbActionListener.Stub {
    238         @SuppressWarnings("hiding")
    239         private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>();
    240 
    241         @Override
    242         public void onObbResult(String filename, int nonce, int status) {
    243             final ObbListenerDelegate delegate;
    244             synchronized (mListeners) {
    245                 delegate = mListeners.get(nonce);
    246                 if (delegate != null) {
    247                     mListeners.remove(nonce);
    248                 }
    249             }
    250 
    251             if (delegate != null) {
    252                 delegate.sendObbStateChanged(filename, status);
    253             }
    254         }
    255 
    256         public int addListener(OnObbStateChangeListener listener) {
    257             final ObbListenerDelegate delegate = new ObbListenerDelegate(listener);
    258 
    259             synchronized (mListeners) {
    260                 mListeners.put(delegate.nonce, delegate);
    261             }
    262 
    263             return delegate.nonce;
    264         }
    265     }
    266 
    267     private int getNextNonce() {
    268         return mNextNonce.getAndIncrement();
    269     }
    270 
    271     /**
    272      * Private class containing sender and receiver code for StorageEvents.
    273      */
    274     private class ObbListenerDelegate {
    275         private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef;
    276         private final Handler mHandler;
    277 
    278         private final int nonce;
    279 
    280         ObbListenerDelegate(OnObbStateChangeListener listener) {
    281             nonce = getNextNonce();
    282             mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener);
    283             mHandler = new Handler(mLooper) {
    284                 @Override
    285                 public void handleMessage(Message msg) {
    286                     final OnObbStateChangeListener changeListener = getListener();
    287                     if (changeListener == null) {
    288                         return;
    289                     }
    290 
    291                     changeListener.onObbStateChange((String) msg.obj, msg.arg1);
    292                 }
    293             };
    294         }
    295 
    296         OnObbStateChangeListener getListener() {
    297             if (mObbEventListenerRef == null) {
    298                 return null;
    299             }
    300             return mObbEventListenerRef.get();
    301         }
    302 
    303         void sendObbStateChanged(String path, int state) {
    304             mHandler.obtainMessage(0, state, 0, path).sendToTarget();
    305         }
    306     }
    307 
    308     /** {@hide} */
    309     @Deprecated
    310     public static StorageManager from(Context context) {
    311         return context.getSystemService(StorageManager.class);
    312     }
    313 
    314     /**
    315      * Constructs a StorageManager object through which an application can
    316      * can communicate with the systems mount service.
    317      *
    318      * @param tgtLooper The {@link android.os.Looper} which events will be received on.
    319      *
    320      * <p>Applications can get instance of this class by calling
    321      * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
    322      * of {@link android.content.Context#STORAGE_SERVICE}.
    323      *
    324      * @hide
    325      */
    326     public StorageManager(Context context, Looper looper) {
    327         mContext = context;
    328         mResolver = context.getContentResolver();
    329         mLooper = looper;
    330         mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
    331         if (mMountService == null) {
    332             throw new IllegalStateException("Failed to find running mount service");
    333         }
    334     }
    335 
    336     /**
    337      * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
    338      *
    339      * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
    340      *
    341      * @hide
    342      */
    343     public void registerListener(StorageEventListener listener) {
    344         synchronized (mDelegates) {
    345             final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener,
    346                     mLooper);
    347             try {
    348                 mMountService.registerListener(delegate);
    349             } catch (RemoteException e) {
    350                 throw e.rethrowFromSystemServer();
    351             }
    352             mDelegates.add(delegate);
    353         }
    354     }
    355 
    356     /**
    357      * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}.
    358      *
    359      * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
    360      *
    361      * @hide
    362      */
    363     public void unregisterListener(StorageEventListener listener) {
    364         synchronized (mDelegates) {
    365             for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
    366                 final StorageEventListenerDelegate delegate = i.next();
    367                 if (delegate.mCallback == listener) {
    368                     try {
    369                         mMountService.unregisterListener(delegate);
    370                     } catch (RemoteException e) {
    371                         throw e.rethrowFromSystemServer();
    372                     }
    373                     i.remove();
    374                 }
    375             }
    376         }
    377     }
    378 
    379     /**
    380      * Enables USB Mass Storage (UMS) on the device.
    381      *
    382      * @hide
    383      */
    384     @Deprecated
    385     public void enableUsbMassStorage() {
    386     }
    387 
    388     /**
    389      * Disables USB Mass Storage (UMS) on the device.
    390      *
    391      * @hide
    392      */
    393     @Deprecated
    394     public void disableUsbMassStorage() {
    395     }
    396 
    397     /**
    398      * Query if a USB Mass Storage (UMS) host is connected.
    399      * @return true if UMS host is connected.
    400      *
    401      * @hide
    402      */
    403     @Deprecated
    404     public boolean isUsbMassStorageConnected() {
    405         return false;
    406     }
    407 
    408     /**
    409      * Query if a USB Mass Storage (UMS) is enabled on the device.
    410      * @return true if UMS host is enabled.
    411      *
    412      * @hide
    413      */
    414     @Deprecated
    415     public boolean isUsbMassStorageEnabled() {
    416         return false;
    417     }
    418 
    419     /**
    420      * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is
    421      * specified, it is supplied to the mounting process to be used in any
    422      * encryption used in the OBB.
    423      * <p>
    424      * The OBB will remain mounted for as long as the StorageManager reference
    425      * is held by the application. As soon as this reference is lost, the OBBs
    426      * in use will be unmounted. The {@link OnObbStateChangeListener} registered
    427      * with this call will receive the success or failure of this operation.
    428      * <p>
    429      * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
    430      * file matches a package ID that is owned by the calling program's UID.
    431      * That is, shared UID applications can attempt to mount any other
    432      * application's OBB that shares its UID.
    433      *
    434      * @param rawPath the path to the OBB file
    435      * @param key secret used to encrypt the OBB; may be <code>null</code> if no
    436      *            encryption was used on the OBB.
    437      * @param listener will receive the success or failure of the operation
    438      * @return whether the mount call was successfully queued or not
    439      */
    440     public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) {
    441         Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
    442         Preconditions.checkNotNull(listener, "listener cannot be null");
    443 
    444         try {
    445             final String canonicalPath = new File(rawPath).getCanonicalPath();
    446             final int nonce = mObbActionListener.addListener(listener);
    447             mMountService.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce);
    448             return true;
    449         } catch (IOException e) {
    450             throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e);
    451         } catch (RemoteException e) {
    452             throw e.rethrowFromSystemServer();
    453         }
    454     }
    455 
    456     /**
    457      * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the
    458      * <code>force</code> flag is true, it will kill any application needed to
    459      * unmount the given OBB (even the calling application).
    460      * <p>
    461      * The {@link OnObbStateChangeListener} registered with this call will
    462      * receive the success or failure of this operation.
    463      * <p>
    464      * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
    465      * file matches a package ID that is owned by the calling program's UID.
    466      * That is, shared UID applications can obtain access to any other
    467      * application's OBB that shares its UID.
    468      * <p>
    469      *
    470      * @param rawPath path to the OBB file
    471      * @param force whether to kill any programs using this in order to unmount
    472      *            it
    473      * @param listener will receive the success or failure of the operation
    474      * @return whether the unmount call was successfully queued or not
    475      */
    476     public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) {
    477         Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
    478         Preconditions.checkNotNull(listener, "listener cannot be null");
    479 
    480         try {
    481             final int nonce = mObbActionListener.addListener(listener);
    482             mMountService.unmountObb(rawPath, force, mObbActionListener, nonce);
    483             return true;
    484         } catch (RemoteException e) {
    485             throw e.rethrowFromSystemServer();
    486         }
    487     }
    488 
    489     /**
    490      * Check whether an Opaque Binary Blob (OBB) is mounted or not.
    491      *
    492      * @param rawPath path to OBB image
    493      * @return true if OBB is mounted; false if not mounted or on error
    494      */
    495     public boolean isObbMounted(String rawPath) {
    496         Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
    497 
    498         try {
    499             return mMountService.isObbMounted(rawPath);
    500         } catch (RemoteException e) {
    501             throw e.rethrowFromSystemServer();
    502         }
    503     }
    504 
    505     /**
    506      * Check the mounted path of an Opaque Binary Blob (OBB) file. This will
    507      * give you the path to where you can obtain access to the internals of the
    508      * OBB.
    509      *
    510      * @param rawPath path to OBB image
    511      * @return absolute path to mounted OBB image data or <code>null</code> if
    512      *         not mounted or exception encountered trying to read status
    513      */
    514     public String getMountedObbPath(String rawPath) {
    515         Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
    516 
    517         try {
    518             return mMountService.getMountedObbPath(rawPath);
    519         } catch (RemoteException e) {
    520             throw e.rethrowFromSystemServer();
    521         }
    522     }
    523 
    524     /** {@hide} */
    525     public @NonNull List<DiskInfo> getDisks() {
    526         try {
    527             return Arrays.asList(mMountService.getDisks());
    528         } catch (RemoteException e) {
    529             throw e.rethrowFromSystemServer();
    530         }
    531     }
    532 
    533     /** {@hide} */
    534     public @Nullable DiskInfo findDiskById(String id) {
    535         Preconditions.checkNotNull(id);
    536         // TODO; go directly to service to make this faster
    537         for (DiskInfo disk : getDisks()) {
    538             if (Objects.equals(disk.id, id)) {
    539                 return disk;
    540             }
    541         }
    542         return null;
    543     }
    544 
    545     /** {@hide} */
    546     public @Nullable VolumeInfo findVolumeById(String id) {
    547         Preconditions.checkNotNull(id);
    548         // TODO; go directly to service to make this faster
    549         for (VolumeInfo vol : getVolumes()) {
    550             if (Objects.equals(vol.id, id)) {
    551                 return vol;
    552             }
    553         }
    554         return null;
    555     }
    556 
    557     /** {@hide} */
    558     public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) {
    559         Preconditions.checkNotNull(fsUuid);
    560         // TODO; go directly to service to make this faster
    561         for (VolumeInfo vol : getVolumes()) {
    562             if (Objects.equals(vol.fsUuid, fsUuid)) {
    563                 return vol;
    564             }
    565         }
    566         return null;
    567     }
    568 
    569     /** {@hide} */
    570     public @Nullable VolumeRecord findRecordByUuid(String fsUuid) {
    571         Preconditions.checkNotNull(fsUuid);
    572         // TODO; go directly to service to make this faster
    573         for (VolumeRecord rec : getVolumeRecords()) {
    574             if (Objects.equals(rec.fsUuid, fsUuid)) {
    575                 return rec;
    576             }
    577         }
    578         return null;
    579     }
    580 
    581     /** {@hide} */
    582     public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
    583         if (emulatedVol != null) {
    584             return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
    585         } else {
    586             return null;
    587         }
    588     }
    589 
    590     /** {@hide} */
    591     public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) {
    592         if (privateVol != null) {
    593             return findVolumeById(privateVol.getId().replace("private", "emulated"));
    594         } else {
    595             return null;
    596         }
    597     }
    598 
    599     /** {@hide} */
    600     public @Nullable VolumeInfo findVolumeByQualifiedUuid(String volumeUuid) {
    601         if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
    602             return findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
    603         } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
    604             return getPrimaryPhysicalVolume();
    605         } else {
    606             return findVolumeByUuid(volumeUuid);
    607         }
    608     }
    609 
    610     /** {@hide} */
    611     public @NonNull List<VolumeInfo> getVolumes() {
    612         try {
    613             return Arrays.asList(mMountService.getVolumes(0));
    614         } catch (RemoteException e) {
    615             throw e.rethrowFromSystemServer();
    616         }
    617     }
    618 
    619     /** {@hide} */
    620     public @NonNull List<VolumeInfo> getWritablePrivateVolumes() {
    621         try {
    622             final ArrayList<VolumeInfo> res = new ArrayList<>();
    623             for (VolumeInfo vol : mMountService.getVolumes(0)) {
    624                 if (vol.getType() == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) {
    625                     res.add(vol);
    626                 }
    627             }
    628             return res;
    629         } catch (RemoteException e) {
    630             throw e.rethrowFromSystemServer();
    631         }
    632     }
    633 
    634     /** {@hide} */
    635     public @NonNull List<VolumeRecord> getVolumeRecords() {
    636         try {
    637             return Arrays.asList(mMountService.getVolumeRecords(0));
    638         } catch (RemoteException e) {
    639             throw e.rethrowFromSystemServer();
    640         }
    641     }
    642 
    643     /** {@hide} */
    644     public @Nullable String getBestVolumeDescription(VolumeInfo vol) {
    645         if (vol == null) return null;
    646 
    647         // Nickname always takes precedence when defined
    648         if (!TextUtils.isEmpty(vol.fsUuid)) {
    649             final VolumeRecord rec = findRecordByUuid(vol.fsUuid);
    650             if (rec != null && !TextUtils.isEmpty(rec.nickname)) {
    651                 return rec.nickname;
    652             }
    653         }
    654 
    655         if (!TextUtils.isEmpty(vol.getDescription())) {
    656             return vol.getDescription();
    657         }
    658 
    659         if (vol.disk != null) {
    660             return vol.disk.getDescription();
    661         }
    662 
    663         return null;
    664     }
    665 
    666     /** {@hide} */
    667     public @Nullable VolumeInfo getPrimaryPhysicalVolume() {
    668         final List<VolumeInfo> vols = getVolumes();
    669         for (VolumeInfo vol : vols) {
    670             if (vol.isPrimaryPhysical()) {
    671                 return vol;
    672             }
    673         }
    674         return null;
    675     }
    676 
    677     /** {@hide} */
    678     public void mount(String volId) {
    679         try {
    680             mMountService.mount(volId);
    681         } catch (RemoteException e) {
    682             throw e.rethrowFromSystemServer();
    683         }
    684     }
    685 
    686     /** {@hide} */
    687     public void unmount(String volId) {
    688         try {
    689             mMountService.unmount(volId);
    690         } catch (RemoteException e) {
    691             throw e.rethrowFromSystemServer();
    692         }
    693     }
    694 
    695     /** {@hide} */
    696     public void format(String volId) {
    697         try {
    698             mMountService.format(volId);
    699         } catch (RemoteException e) {
    700             throw e.rethrowFromSystemServer();
    701         }
    702     }
    703 
    704     /** {@hide} */
    705     public long benchmark(String volId) {
    706         try {
    707             return mMountService.benchmark(volId);
    708         } catch (RemoteException e) {
    709             throw e.rethrowFromSystemServer();
    710         }
    711     }
    712 
    713     /** {@hide} */
    714     public void partitionPublic(String diskId) {
    715         try {
    716             mMountService.partitionPublic(diskId);
    717         } catch (RemoteException e) {
    718             throw e.rethrowFromSystemServer();
    719         }
    720     }
    721 
    722     /** {@hide} */
    723     public void partitionPrivate(String diskId) {
    724         try {
    725             mMountService.partitionPrivate(diskId);
    726         } catch (RemoteException e) {
    727             throw e.rethrowFromSystemServer();
    728         }
    729     }
    730 
    731     /** {@hide} */
    732     public void partitionMixed(String diskId, int ratio) {
    733         try {
    734             mMountService.partitionMixed(diskId, ratio);
    735         } catch (RemoteException e) {
    736             throw e.rethrowFromSystemServer();
    737         }
    738     }
    739 
    740     /** {@hide} */
    741     public void wipeAdoptableDisks() {
    742         // We only wipe devices in "adoptable" locations, which are in a
    743         // long-term stable slot/location on the device, where apps have a
    744         // reasonable chance of storing sensitive data. (Apps need to go through
    745         // SAF to write to transient volumes.)
    746         final List<DiskInfo> disks = getDisks();
    747         for (DiskInfo disk : disks) {
    748             final String diskId = disk.getId();
    749             if (disk.isAdoptable()) {
    750                 Slog.d(TAG, "Found adoptable " + diskId + "; wiping");
    751                 try {
    752                     // TODO: switch to explicit wipe command when we have it,
    753                     // for now rely on the fact that vfat format does a wipe
    754                     mMountService.partitionPublic(diskId);
    755                 } catch (Exception e) {
    756                     Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e);
    757                 }
    758             } else {
    759                 Slog.d(TAG, "Ignorning non-adoptable disk " + disk.getId());
    760             }
    761         }
    762     }
    763 
    764     /** {@hide} */
    765     public void setVolumeNickname(String fsUuid, String nickname) {
    766         try {
    767             mMountService.setVolumeNickname(fsUuid, nickname);
    768         } catch (RemoteException e) {
    769             throw e.rethrowFromSystemServer();
    770         }
    771     }
    772 
    773     /** {@hide} */
    774     public void setVolumeInited(String fsUuid, boolean inited) {
    775         try {
    776             mMountService.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0,
    777                     VolumeRecord.USER_FLAG_INITED);
    778         } catch (RemoteException e) {
    779             throw e.rethrowFromSystemServer();
    780         }
    781     }
    782 
    783     /** {@hide} */
    784     public void setVolumeSnoozed(String fsUuid, boolean snoozed) {
    785         try {
    786             mMountService.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0,
    787                     VolumeRecord.USER_FLAG_SNOOZED);
    788         } catch (RemoteException e) {
    789             throw e.rethrowFromSystemServer();
    790         }
    791     }
    792 
    793     /** {@hide} */
    794     public void forgetVolume(String fsUuid) {
    795         try {
    796             mMountService.forgetVolume(fsUuid);
    797         } catch (RemoteException e) {
    798             throw e.rethrowFromSystemServer();
    799         }
    800     }
    801 
    802     /**
    803      * This is not the API you're looking for.
    804      *
    805      * @see PackageManager#getPrimaryStorageCurrentVolume()
    806      * @hide
    807      */
    808     public String getPrimaryStorageUuid() {
    809         try {
    810             return mMountService.getPrimaryStorageUuid();
    811         } catch (RemoteException e) {
    812             throw e.rethrowFromSystemServer();
    813         }
    814     }
    815 
    816     /**
    817      * This is not the API you're looking for.
    818      *
    819      * @see PackageManager#movePrimaryStorage(VolumeInfo)
    820      * @hide
    821      */
    822     public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
    823         try {
    824             mMountService.setPrimaryStorageUuid(volumeUuid, callback);
    825         } catch (RemoteException e) {
    826             throw e.rethrowFromSystemServer();
    827         }
    828     }
    829 
    830     /**
    831      * Return the {@link StorageVolume} that contains the given file, or {@code null} if none.
    832      */
    833     public @Nullable StorageVolume getStorageVolume(File file) {
    834         return getStorageVolume(getVolumeList(), file);
    835     }
    836 
    837     /** {@hide} */
    838     public static @Nullable StorageVolume getStorageVolume(File file, int userId) {
    839         return getStorageVolume(getVolumeList(userId, 0), file);
    840     }
    841 
    842     /** {@hide} */
    843     private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) {
    844         if (file == null) {
    845             return null;
    846         }
    847         try {
    848             file = file.getCanonicalFile();
    849         } catch (IOException ignored) {
    850             Slog.d(TAG, "Could not get canonical path for " + file);
    851             return null;
    852         }
    853         for (StorageVolume volume : volumes) {
    854             File volumeFile = volume.getPathFile();
    855             try {
    856                 volumeFile = volumeFile.getCanonicalFile();
    857             } catch (IOException ignored) {
    858                 continue;
    859             }
    860             if (FileUtils.contains(volumeFile, file)) {
    861                 return volume;
    862             }
    863         }
    864         return null;
    865     }
    866 
    867     /**
    868      * Gets the state of a volume via its mountpoint.
    869      * @hide
    870      */
    871     @Deprecated
    872     public @NonNull String getVolumeState(String mountPoint) {
    873         final StorageVolume vol = getStorageVolume(new File(mountPoint));
    874         if (vol != null) {
    875             return vol.getState();
    876         } else {
    877             return Environment.MEDIA_UNKNOWN;
    878         }
    879     }
    880 
    881     /**
    882      * Return the list of shared/external storage volumes available to the
    883      * current user. This includes both the primary shared storage device and
    884      * any attached external volumes including SD cards and USB drives.
    885      *
    886      * @see Environment#getExternalStorageDirectory()
    887      * @see StorageVolume#createAccessIntent(String)
    888      */
    889     public @NonNull List<StorageVolume> getStorageVolumes() {
    890         final ArrayList<StorageVolume> res = new ArrayList<>();
    891         Collections.addAll(res,
    892                 getVolumeList(UserHandle.myUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE));
    893         return res;
    894     }
    895 
    896     /**
    897      * Return the primary shared/external storage volume available to the
    898      * current user. This volume is the same storage device returned by
    899      * {@link Environment#getExternalStorageDirectory()} and
    900      * {@link Context#getExternalFilesDir(String)}.
    901      */
    902     public @NonNull StorageVolume getPrimaryStorageVolume() {
    903         return getVolumeList(UserHandle.myUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE)[0];
    904     }
    905 
    906     /** @removed */
    907     public @NonNull StorageVolume[] getVolumeList() {
    908         return getVolumeList(mContext.getUserId(), 0);
    909     }
    910 
    911     /** {@hide} */
    912     public static @NonNull StorageVolume[] getVolumeList(int userId, int flags) {
    913         final IMountService mountService = IMountService.Stub.asInterface(
    914                 ServiceManager.getService("mount"));
    915         try {
    916             String packageName = ActivityThread.currentOpPackageName();
    917             if (packageName == null) {
    918                 // Package name can be null if the activity thread is running but the app
    919                 // hasn't bound yet. In this case we fall back to the first package in the
    920                 // current UID. This works for runtime permissions as permission state is
    921                 // per UID and permission realted app ops are updated for all UID packages.
    922                 String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid(
    923                         android.os.Process.myUid());
    924                 if (packageNames == null || packageNames.length <= 0) {
    925                     return new StorageVolume[0];
    926                 }
    927                 packageName = packageNames[0];
    928             }
    929             final int uid = ActivityThread.getPackageManager().getPackageUid(packageName,
    930                     PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
    931             if (uid <= 0) {
    932                 return new StorageVolume[0];
    933             }
    934             return mountService.getVolumeList(uid, packageName, flags);
    935         } catch (RemoteException e) {
    936             throw e.rethrowFromSystemServer();
    937         }
    938     }
    939 
    940     /**
    941      * Returns list of paths for all mountable volumes.
    942      * @hide
    943      */
    944     @Deprecated
    945     public @NonNull String[] getVolumePaths() {
    946         StorageVolume[] volumes = getVolumeList();
    947         int count = volumes.length;
    948         String[] paths = new String[count];
    949         for (int i = 0; i < count; i++) {
    950             paths[i] = volumes[i].getPath();
    951         }
    952         return paths;
    953     }
    954 
    955     /** @removed */
    956     public @NonNull StorageVolume getPrimaryVolume() {
    957         return getPrimaryVolume(getVolumeList());
    958     }
    959 
    960     /** {@hide} */
    961     public static @NonNull StorageVolume getPrimaryVolume(StorageVolume[] volumes) {
    962         for (StorageVolume volume : volumes) {
    963             if (volume.isPrimary()) {
    964                 return volume;
    965             }
    966         }
    967         throw new IllegalStateException("Missing primary storage");
    968     }
    969 
    970     /** {@hide} */
    971     private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
    972     private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES;
    973     private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES;
    974 
    975     /**
    976      * Return the number of available bytes until the given path is considered
    977      * running low on storage.
    978      *
    979      * @hide
    980      */
    981     public long getStorageBytesUntilLow(File path) {
    982         return path.getUsableSpace() - getStorageFullBytes(path);
    983     }
    984 
    985     /**
    986      * Return the number of available bytes at which the given path is
    987      * considered running low on storage.
    988      *
    989      * @hide
    990      */
    991     public long getStorageLowBytes(File path) {
    992         final long lowPercent = Settings.Global.getInt(mResolver,
    993                 Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);
    994         final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;
    995 
    996         final long maxLowBytes = Settings.Global.getLong(mResolver,
    997                 Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES);
    998 
    999         return Math.min(lowBytes, maxLowBytes);
   1000     }
   1001 
   1002     /**
   1003      * Return the number of available bytes at which the given path is
   1004      * considered full.
   1005      *
   1006      * @hide
   1007      */
   1008     public long getStorageFullBytes(File path) {
   1009         return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
   1010                 DEFAULT_FULL_THRESHOLD_BYTES);
   1011     }
   1012 
   1013     /** {@hide} */
   1014     public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
   1015         try {
   1016             mMountService.createUserKey(userId, serialNumber, ephemeral);
   1017         } catch (RemoteException e) {
   1018             throw e.rethrowFromSystemServer();
   1019         }
   1020     }
   1021 
   1022     /** {@hide} */
   1023     public void destroyUserKey(int userId) {
   1024         try {
   1025             mMountService.destroyUserKey(userId);
   1026         } catch (RemoteException e) {
   1027             throw e.rethrowFromSystemServer();
   1028         }
   1029     }
   1030 
   1031     /** {@hide} */
   1032     public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
   1033         try {
   1034             mMountService.unlockUserKey(userId, serialNumber, token, secret);
   1035         } catch (RemoteException e) {
   1036             throw e.rethrowFromSystemServer();
   1037         }
   1038     }
   1039 
   1040     /** {@hide} */
   1041     public void lockUserKey(int userId) {
   1042         try {
   1043             mMountService.lockUserKey(userId);
   1044         } catch (RemoteException e) {
   1045             throw e.rethrowFromSystemServer();
   1046         }
   1047     }
   1048 
   1049     /** {@hide} */
   1050     public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
   1051         try {
   1052             mMountService.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
   1053         } catch (RemoteException e) {
   1054             throw e.rethrowFromSystemServer();
   1055         }
   1056     }
   1057 
   1058     /** {@hide} */
   1059     public void destroyUserStorage(String volumeUuid, int userId, int flags) {
   1060         try {
   1061             mMountService.destroyUserStorage(volumeUuid, userId, flags);
   1062         } catch (RemoteException e) {
   1063             throw e.rethrowFromSystemServer();
   1064         }
   1065     }
   1066 
   1067     /** {@hide} */
   1068     public static boolean isUserKeyUnlocked(int userId) {
   1069         if (sMountService == null) {
   1070             sMountService = IMountService.Stub
   1071                     .asInterface(ServiceManager.getService("mount"));
   1072         }
   1073         if (sMountService == null) {
   1074             Slog.w(TAG, "Early during boot, assuming locked");
   1075             return false;
   1076         }
   1077         final long token = Binder.clearCallingIdentity();
   1078         try {
   1079             return sMountService.isUserKeyUnlocked(userId);
   1080         } catch (RemoteException e) {
   1081             throw e.rethrowAsRuntimeException();
   1082         } finally {
   1083             Binder.restoreCallingIdentity(token);
   1084         }
   1085     }
   1086 
   1087     /**
   1088      * Return if data stored at or under the given path will be encrypted while
   1089      * at rest. This can help apps avoid the overhead of double-encrypting data.
   1090      */
   1091     public boolean isEncrypted(File file) {
   1092         if (FileUtils.contains(Environment.getDataDirectory(), file)) {
   1093             return isEncrypted();
   1094         } else if (FileUtils.contains(Environment.getExpandDirectory(), file)) {
   1095             return true;
   1096         }
   1097         // TODO: extend to support shared storage
   1098         return false;
   1099     }
   1100 
   1101     /** {@hide}
   1102      * Is this device encryptable or already encrypted?
   1103      * @return true for encryptable or encrypted
   1104      *         false not encrypted and not encryptable
   1105      */
   1106     public static boolean isEncryptable() {
   1107         final String state = SystemProperties.get("ro.crypto.state", "unsupported");
   1108         return !"unsupported".equalsIgnoreCase(state);
   1109     }
   1110 
   1111     /** {@hide}
   1112      * Is this device already encrypted?
   1113      * @return true for encrypted. (Implies isEncryptable() == true)
   1114      *         false not encrypted
   1115      */
   1116     public static boolean isEncrypted() {
   1117         final String state = SystemProperties.get("ro.crypto.state", "");
   1118         return "encrypted".equalsIgnoreCase(state);
   1119     }
   1120 
   1121     /** {@hide}
   1122      * Is this device file encrypted?
   1123      * @return true for file encrypted. (Implies isEncrypted() == true)
   1124      *         false not encrypted or block encrypted
   1125      */
   1126     public static boolean isFileEncryptedNativeOnly() {
   1127         if (!isEncrypted()) {
   1128             return false;
   1129         }
   1130 
   1131         final String status = SystemProperties.get("ro.crypto.type", "");
   1132         return "file".equalsIgnoreCase(status);
   1133     }
   1134 
   1135     /** {@hide}
   1136      * Is this device block encrypted?
   1137      * @return true for block encrypted. (Implies isEncrypted() == true)
   1138      *         false not encrypted or file encrypted
   1139      */
   1140     public static boolean isBlockEncrypted() {
   1141         if (!isEncrypted()) {
   1142             return false;
   1143         }
   1144         final String status = SystemProperties.get("ro.crypto.type", "");
   1145         return "block".equalsIgnoreCase(status);
   1146     }
   1147 
   1148     /** {@hide}
   1149      * Is this device block encrypted with credentials?
   1150      * @return true for crediential block encrypted.
   1151      *         (Implies isBlockEncrypted() == true)
   1152      *         false not encrypted, file encrypted or default block encrypted
   1153      */
   1154     public static boolean isNonDefaultBlockEncrypted() {
   1155         if (!isBlockEncrypted()) {
   1156             return false;
   1157         }
   1158 
   1159         try {
   1160             IMountService mountService = IMountService.Stub.asInterface(
   1161                     ServiceManager.getService("mount"));
   1162             return mountService.getPasswordType() != CRYPT_TYPE_DEFAULT;
   1163         } catch (RemoteException e) {
   1164             Log.e(TAG, "Error getting encryption type");
   1165             return false;
   1166         }
   1167     }
   1168 
   1169     /** {@hide}
   1170      * Is this device in the process of being block encrypted?
   1171      * @return true for encrypting.
   1172      *         false otherwise
   1173      * Whether device isEncrypted at this point is undefined
   1174      * Note that only system services and CryptKeeper will ever see this return
   1175      * true - no app will ever be launched in this state.
   1176      * Also note that this state will not change without a teardown of the
   1177      * framework, so no service needs to check for changes during their lifespan
   1178      */
   1179     public static boolean isBlockEncrypting() {
   1180         final String state = SystemProperties.get("vold.encrypt_progress", "");
   1181         return !"".equalsIgnoreCase(state);
   1182     }
   1183 
   1184     /** {@hide}
   1185      * Is this device non default block encrypted and in the process of
   1186      * prompting for credentials?
   1187      * @return true for prompting for credentials.
   1188      *         (Implies isNonDefaultBlockEncrypted() == true)
   1189      *         false otherwise
   1190      * Note that only system services and CryptKeeper will ever see this return
   1191      * true - no app will ever be launched in this state.
   1192      * Also note that this state will not change without a teardown of the
   1193      * framework, so no service needs to check for changes during their lifespan
   1194      */
   1195     public static boolean inCryptKeeperBounce() {
   1196         final String status = SystemProperties.get("vold.decrypt");
   1197         return "trigger_restart_min_framework".equals(status);
   1198     }
   1199 
   1200     /** {@hide} */
   1201     public static boolean isFileEncryptedEmulatedOnly() {
   1202         return SystemProperties.getBoolean(StorageManager.PROP_EMULATE_FBE, false);
   1203     }
   1204 
   1205     /** {@hide}
   1206      * Is this device running in a file encrypted mode, either native or emulated?
   1207      * @return true for file encrypted, false otherwise
   1208      */
   1209     public static boolean isFileEncryptedNativeOrEmulated() {
   1210         return isFileEncryptedNativeOnly()
   1211                || isFileEncryptedEmulatedOnly();
   1212     }
   1213 
   1214     /** {@hide} */
   1215     public static File maybeTranslateEmulatedPathToInternal(File path) {
   1216         final IMountService mountService = IMountService.Stub.asInterface(
   1217                 ServiceManager.getService("mount"));
   1218         try {
   1219             final VolumeInfo[] vols = mountService.getVolumes(0);
   1220             for (VolumeInfo vol : vols) {
   1221                 if ((vol.getType() == VolumeInfo.TYPE_EMULATED
   1222                         || vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isMountedReadable()) {
   1223                     final File internalPath = FileUtils.rewriteAfterRename(vol.getPath(),
   1224                             vol.getInternalPath(), path);
   1225                     if (internalPath != null && internalPath.exists()) {
   1226                         return internalPath;
   1227                     }
   1228                 }
   1229             }
   1230         } catch (RemoteException e) {
   1231             throw e.rethrowFromSystemServer();
   1232         }
   1233         return path;
   1234     }
   1235 
   1236     /** {@hide} */
   1237     public ParcelFileDescriptor mountAppFuse(String name) {
   1238         try {
   1239             return mMountService.mountAppFuse(name);
   1240         } catch (RemoteException e) {
   1241             throw e.rethrowFromSystemServer();
   1242         }
   1243     }
   1244 
   1245     /// Consts to match the password types in cryptfs.h
   1246     /** @hide */
   1247     public static final int CRYPT_TYPE_PASSWORD = 0;
   1248     /** @hide */
   1249     public static final int CRYPT_TYPE_DEFAULT = 1;
   1250     /** @hide */
   1251     public static final int CRYPT_TYPE_PATTERN = 2;
   1252     /** @hide */
   1253     public static final int CRYPT_TYPE_PIN = 3;
   1254 
   1255     // Constants for the data available via MountService.getField.
   1256     /** @hide */
   1257     public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
   1258     /** @hide */
   1259     public static final String OWNER_INFO_KEY = "OwnerInfo";
   1260     /** @hide */
   1261     public static final String PATTERN_VISIBLE_KEY = "PatternVisible";
   1262     /** @hide */
   1263     public static final String PASSWORD_VISIBLE_KEY = "PasswordVisible";
   1264 }
   1265