OSDN Git Service

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