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