1 /*
2  * Copyright (C) 2007 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;
18 
19 import android.Manifest;
20 import android.annotation.NonNull;
21 import android.annotation.SystemApi;
22 import android.annotation.TestApi;
23 import android.app.AppGlobals;
24 import android.app.AppOpsManager;
25 import android.app.admin.DevicePolicyManager;
26 import android.compat.Compatibility;
27 import android.compat.annotation.ChangeId;
28 import android.compat.annotation.Disabled;
29 import android.compat.annotation.UnsupportedAppUsage;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.pm.PackageManager;
33 import android.os.storage.StorageManager;
34 import android.os.storage.StorageVolume;
35 import android.provider.MediaStore;
36 import android.text.TextUtils;
37 import android.util.Log;
38 
39 import java.io.File;
40 import java.io.IOException;
41 import java.util.ArrayList;
42 import java.util.Collection;
43 import java.util.LinkedList;
44 import java.util.List;
45 import java.util.Objects;
46 
47 /**
48  * Provides access to environment variables.
49  */
50 public class Environment {
51     private static final String TAG = "Environment";
52 
53     // NOTE: keep credential-protected paths in sync with StrictMode.java
54 
55     private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
56     private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
57     private static final String ENV_ANDROID_DATA = "ANDROID_DATA";
58     private static final String ENV_ANDROID_EXPAND = "ANDROID_EXPAND";
59     private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE";
60     private static final String ENV_DOWNLOAD_CACHE = "DOWNLOAD_CACHE";
61     private static final String ENV_OEM_ROOT = "OEM_ROOT";
62     private static final String ENV_ODM_ROOT = "ODM_ROOT";
63     private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
64     private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT";
65     private static final String ENV_SYSTEM_EXT_ROOT = "SYSTEM_EXT_ROOT";
66     private static final String ENV_APEX_ROOT = "APEX_ROOT";
67 
68     /** {@hide} */
69     public static final String DIR_ANDROID = "Android";
70     private static final String DIR_DATA = "data";
71     private static final String DIR_MEDIA = "media";
72     private static final String DIR_OBB = "obb";
73     private static final String DIR_FILES = "files";
74     private static final String DIR_CACHE = "cache";
75 
76     /** {@hide} */
77     @Deprecated
78     public static final String DIRECTORY_ANDROID = DIR_ANDROID;
79 
80     private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
81     private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data");
82     private static final File DIR_ANDROID_EXPAND = getDirectory(ENV_ANDROID_EXPAND, "/mnt/expand");
83     private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage");
84     private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache");
85     private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
86     private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm");
87     private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
88     private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product");
89     private static final File DIR_SYSTEM_EXT_ROOT = getDirectory(ENV_SYSTEM_EXT_ROOT,
90             "/system_ext");
91     private static final File DIR_APEX_ROOT = getDirectory(ENV_APEX_ROOT,
92             "/apex");
93 
94     /**
95      * Scoped Storage is on by default. However, it is not strictly enforced and there are multiple
96      * ways to opt out of scoped storage:
97      * <ul>
98      * <li>Target Sdk < Q</li>
99      * <li>Target Sdk = Q and has `requestLegacyExternalStorage` set in AndroidManifest.xml</li>
100      * <li>Target Sdk > Q: Upgrading from an app that was opted out of scoped storage and has
101      * `preserveLegacyExternalStorage` set in AndroidManifest.xml</li>
102      * </ul>
103      * This flag is enabled for all apps by default as Scoped Storage is enabled by default.
104      * Developers can disable this flag to opt out of Scoped Storage and have legacy storage
105      * workflow.
106      *
107      * Note: {@code FORCE_ENABLE_SCOPED_STORAGE} should also be disabled for apps to opt out of
108      * scoped storage.
109      * Note: This flag is also used in {@code com.android.providers.media.LocalCallingIdentity}.
110      * Any modifications to this flag should be reflected there as well.
111      * See https://developer.android.com/training/data-storage#scoped-storage for more information.
112      */
113     @ChangeId
114     private static final long DEFAULT_SCOPED_STORAGE = 149924527L;
115 
116     /**
117      * Setting this flag strictly enforces Scoped Storage regardless of:
118      * <ul>
119      * <li>The value of Target Sdk</li>
120      * <li>The value of `requestLegacyExternalStorage` in AndroidManifest.xml</li>
121      * <li>The value of `preserveLegacyExternalStorage` in AndroidManifest.xml</li>
122      * </ul>
123      *
124      * Note: {@code DEFAULT_SCOPED_STORAGE} should also be enabled for apps to be enforced into
125      * scoped storage.
126      * Note: This flag is also used in {@code com.android.providers.media.LocalCallingIdentity}.
127      * Any modifications to this flag should be reflected there as well.
128      * See https://developer.android.com/training/data-storage#scoped-storage for more information.
129      */
130     @ChangeId
131     @Disabled
132     private static final long FORCE_ENABLE_SCOPED_STORAGE = 132649864L;
133 
134     @UnsupportedAppUsage
135     private static UserEnvironment sCurrentUser;
136     private static boolean sUserRequired;
137 
138     static {
initForCurrentUser()139         initForCurrentUser();
140     }
141 
142     /** {@hide} */
143     @UnsupportedAppUsage
initForCurrentUser()144     public static void initForCurrentUser() {
145         final int userId = UserHandle.myUserId();
146         sCurrentUser = new UserEnvironment(userId);
147     }
148 
149     /** {@hide} */
150     public static class UserEnvironment {
151         private final int mUserId;
152 
153         @UnsupportedAppUsage
UserEnvironment(int userId)154         public UserEnvironment(int userId) {
155             mUserId = userId;
156         }
157 
158         @UnsupportedAppUsage
getExternalDirs()159         public File[] getExternalDirs() {
160             final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId,
161                     StorageManager.FLAG_FOR_WRITE);
162             final File[] files = new File[volumes.length];
163             for (int i = 0; i < volumes.length; i++) {
164                 files[i] = volumes[i].getPathFile();
165             }
166             return files;
167         }
168 
169         @UnsupportedAppUsage
170         @Deprecated
getExternalStorageDirectory()171         public File getExternalStorageDirectory() {
172             return getExternalDirs()[0];
173         }
174 
175         @UnsupportedAppUsage
176         @Deprecated
getExternalStoragePublicDirectory(String type)177         public File getExternalStoragePublicDirectory(String type) {
178             return buildExternalStoragePublicDirs(type)[0];
179         }
180 
buildExternalStoragePublicDirs(String type)181         public File[] buildExternalStoragePublicDirs(String type) {
182             return buildPaths(getExternalDirs(), type);
183         }
184 
buildExternalStorageAndroidDataDirs()185         public File[] buildExternalStorageAndroidDataDirs() {
186             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA);
187         }
188 
buildExternalStorageAndroidObbDirs()189         public File[] buildExternalStorageAndroidObbDirs() {
190             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB);
191         }
192 
buildExternalStorageAppDataDirs(String packageName)193         public File[] buildExternalStorageAppDataDirs(String packageName) {
194             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName);
195         }
196 
buildExternalStorageAppMediaDirs(String packageName)197         public File[] buildExternalStorageAppMediaDirs(String packageName) {
198             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_MEDIA, packageName);
199         }
200 
buildExternalStorageAppObbDirs(String packageName)201         public File[] buildExternalStorageAppObbDirs(String packageName) {
202             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB, packageName);
203         }
204 
buildExternalStorageAppFilesDirs(String packageName)205         public File[] buildExternalStorageAppFilesDirs(String packageName) {
206             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_FILES);
207         }
208 
buildExternalStorageAppCacheDirs(String packageName)209         public File[] buildExternalStorageAppCacheDirs(String packageName) {
210             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE);
211         }
212     }
213 
214     /**
215      * Return root of the "system" partition holding the core Android OS.
216      * Always present and mounted read-only.
217      */
getRootDirectory()218     public static @NonNull File getRootDirectory() {
219         return DIR_ANDROID_ROOT;
220     }
221 
222     /**
223      * Return root directory where all external storage devices will be mounted.
224      * For example, {@link #getExternalStorageDirectory()} will appear under
225      * this location.
226      */
getStorageDirectory()227     public static @NonNull File getStorageDirectory() {
228         return DIR_ANDROID_STORAGE;
229     }
230 
231     /**
232      * Return root directory of the "oem" partition holding OEM customizations,
233      * if any. If present, the partition is mounted read-only.
234      *
235      * @hide
236      */
237     @SystemApi
238     @TestApi
getOemDirectory()239     public static @NonNull File getOemDirectory() {
240         return DIR_OEM_ROOT;
241     }
242 
243     /**
244      * Return root directory of the "odm" partition holding ODM customizations,
245      * if any. If present, the partition is mounted read-only.
246      *
247      * @hide
248      */
249     @SystemApi
250     @TestApi
getOdmDirectory()251     public static @NonNull File getOdmDirectory() {
252         return DIR_ODM_ROOT;
253     }
254 
255     /**
256      * Return root directory of the "vendor" partition that holds vendor-provided
257      * software that should persist across simple reflashing of the "system" partition.
258      * @hide
259      */
260     @SystemApi
261     @TestApi
getVendorDirectory()262     public static @NonNull File getVendorDirectory() {
263         return DIR_VENDOR_ROOT;
264     }
265 
266     /**
267      * Return root directory of the "product" partition holding product-specific
268      * customizations if any. If present, the partition is mounted read-only.
269      *
270      * @hide
271      */
272     @SystemApi
273     @TestApi
getProductDirectory()274     public static @NonNull File getProductDirectory() {
275         return DIR_PRODUCT_ROOT;
276     }
277 
278     /**
279      * Return root directory of the "product_services" partition holding middleware
280      * services if any. If present, the partition is mounted read-only.
281      *
282      * @deprecated This directory is not guaranteed to exist.
283      *             Its name is changed to "system_ext" because the partition's purpose is changed.
284      *             {@link #getSystemExtDirectory()}
285      * @hide
286      */
287     @SystemApi
288     @Deprecated
getProductServicesDirectory()289     public static @NonNull File getProductServicesDirectory() {
290         return getDirectory("PRODUCT_SERVICES_ROOT", "/product_services");
291     }
292 
293     /**
294      * Return root directory of the "system_ext" partition holding system partition's extension
295      * If present, the partition is mounted read-only.
296      *
297      * @hide
298      */
299     @SystemApi
300     @TestApi
getSystemExtDirectory()301     public static @NonNull File getSystemExtDirectory() {
302         return DIR_SYSTEM_EXT_ROOT;
303     }
304 
305     /**
306      * Return root directory of the apex mount point, where all the apex modules are made available
307      * to the rest of the system.
308      *
309      * @hide
310      */
getApexDirectory()311     public static @NonNull File getApexDirectory() {
312         return DIR_APEX_ROOT;
313     }
314 
315     /**
316      * Return the system directory for a user. This is for use by system
317      * services to store files relating to the user. This directory will be
318      * automatically deleted when the user is removed.
319      *
320      * @deprecated This directory is valid and still exists, but but callers
321      *             should <em>strongly</em> consider switching to using either
322      *             {@link #getDataSystemCeDirectory(int)} or
323      *             {@link #getDataSystemDeDirectory(int)}, both of which support
324      *             fast user wipe.
325      * @hide
326      */
327     @Deprecated
getUserSystemDirectory(int userId)328     public static File getUserSystemDirectory(int userId) {
329         return new File(new File(getDataSystemDirectory(), "users"), Integer.toString(userId));
330     }
331 
332     /**
333      * Returns the config directory for a user. This is for use by system
334      * services to store files relating to the user which should be readable by
335      * any app running as that user.
336      *
337      * @deprecated This directory is valid and still exists, but callers should
338      *             <em>strongly</em> consider switching to
339      *             {@link #getDataMiscCeDirectory(int)} which is protected with
340      *             user credentials or {@link #getDataMiscDeDirectory(int)}
341      *             which supports fast user wipe.
342      * @hide
343      */
344     @Deprecated
getUserConfigDirectory(int userId)345     public static File getUserConfigDirectory(int userId) {
346         return new File(new File(new File(
347                 getDataDirectory(), "misc"), "user"), Integer.toString(userId));
348     }
349 
350     /**
351      * Return the user data directory.
352      */
getDataDirectory()353     public static File getDataDirectory() {
354         return DIR_ANDROID_DATA;
355     }
356 
357     /** {@hide} */
getDataDirectory(String volumeUuid)358     public static File getDataDirectory(String volumeUuid) {
359         if (TextUtils.isEmpty(volumeUuid)) {
360             return DIR_ANDROID_DATA;
361         } else {
362             return new File("/mnt/expand/" + volumeUuid);
363         }
364     }
365 
366     /** {@hide} */
getExpandDirectory()367     public static File getExpandDirectory() {
368         return DIR_ANDROID_EXPAND;
369     }
370 
371     /** {@hide} */
372     @UnsupportedAppUsage
getDataSystemDirectory()373     public static File getDataSystemDirectory() {
374         return new File(getDataDirectory(), "system");
375     }
376 
377     /**
378      * Returns the base directory for per-user system directory, device encrypted.
379      * {@hide}
380      */
getDataSystemDeDirectory()381     public static File getDataSystemDeDirectory() {
382         return buildPath(getDataDirectory(), "system_de");
383     }
384 
385     /**
386      * Returns the base directory for per-user system directory, credential encrypted.
387      * {@hide}
388      */
getDataSystemCeDirectory()389     public static File getDataSystemCeDirectory() {
390         return buildPath(getDataDirectory(), "system_ce");
391     }
392 
393     /**
394      * Return the "credential encrypted" system directory for a user. This is
395      * for use by system services to store files relating to the user. This
396      * directory supports fast user wipe, and will be automatically deleted when
397      * the user is removed.
398      * <p>
399      * Data stored under this path is "credential encrypted", which uses an
400      * encryption key that is entangled with user credentials, such as a PIN or
401      * password. The contents will only be available once the user has been
402      * unlocked, as reported by {@code SystemService.onUnlockUser()}.
403      * <p>
404      * New code should <em>strongly</em> prefer storing sensitive data in these
405      * credential encrypted areas.
406      *
407      * @hide
408      */
getDataSystemCeDirectory(int userId)409     public static File getDataSystemCeDirectory(int userId) {
410         return buildPath(getDataDirectory(), "system_ce", String.valueOf(userId));
411     }
412 
413     /**
414      * Return the "device encrypted" system directory for a user. This is for
415      * use by system services to store files relating to the user. This
416      * directory supports fast user wipe, and will be automatically deleted when
417      * the user is removed.
418      * <p>
419      * Data stored under this path is "device encrypted", which uses an
420      * encryption key that is tied to the physical device. The contents will
421      * only be available once the device has finished a {@code dm-verity}
422      * protected boot.
423      * <p>
424      * New code should <em>strongly</em> avoid storing sensitive data in these
425      * device encrypted areas.
426      *
427      * @hide
428      */
getDataSystemDeDirectory(int userId)429     public static File getDataSystemDeDirectory(int userId) {
430         return buildPath(getDataDirectory(), "system_de", String.valueOf(userId));
431     }
432 
433     /** {@hide} */
getDataMiscDirectory()434     public static File getDataMiscDirectory() {
435         return new File(getDataDirectory(), "misc");
436     }
437 
438     /** {@hide} */
getDataMiscCeDirectory()439     public static File getDataMiscCeDirectory() {
440         return buildPath(getDataDirectory(), "misc_ce");
441     }
442 
443     /** {@hide} */
getDataMiscCeDirectory(int userId)444     public static File getDataMiscCeDirectory(int userId) {
445         return buildPath(getDataDirectory(), "misc_ce", String.valueOf(userId));
446     }
447 
448     /** {@hide} */
getDataMiscDeDirectory(int userId)449     public static File getDataMiscDeDirectory(int userId) {
450         return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId));
451     }
452 
getDataProfilesDeDirectory(int userId)453     private static File getDataProfilesDeDirectory(int userId) {
454         return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId));
455     }
456 
457     /** {@hide} */
getDataVendorCeDirectory(int userId)458     public static File getDataVendorCeDirectory(int userId) {
459         return buildPath(getDataDirectory(), "vendor_ce", String.valueOf(userId));
460     }
461 
462     /** {@hide} */
getDataVendorDeDirectory(int userId)463     public static File getDataVendorDeDirectory(int userId) {
464         return buildPath(getDataDirectory(), "vendor_de", String.valueOf(userId));
465     }
466 
467     /** {@hide} */
getDataRefProfilesDePackageDirectory(String packageName)468     public static File getDataRefProfilesDePackageDirectory(String packageName) {
469         return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName);
470     }
471 
472     /** {@hide} */
getDataProfilesDePackageDirectory(int userId, String packageName)473     public static File getDataProfilesDePackageDirectory(int userId, String packageName) {
474         return buildPath(getDataProfilesDeDirectory(userId), packageName);
475     }
476 
477     /** {@hide} */
getDataAppDirectory(String volumeUuid)478     public static File getDataAppDirectory(String volumeUuid) {
479         return new File(getDataDirectory(volumeUuid), "app");
480     }
481 
482     /** {@hide} */
getDataStagingDirectory(String volumeUuid)483     public static File getDataStagingDirectory(String volumeUuid) {
484         return new File(getDataDirectory(volumeUuid), "app-staging");
485     }
486 
487     /** {@hide} */
getDataUserCeDirectory(String volumeUuid)488     public static File getDataUserCeDirectory(String volumeUuid) {
489         return new File(getDataDirectory(volumeUuid), "user");
490     }
491 
492     /** {@hide} */
getDataUserCeDirectory(String volumeUuid, int userId)493     public static File getDataUserCeDirectory(String volumeUuid, int userId) {
494         return new File(getDataUserCeDirectory(volumeUuid), String.valueOf(userId));
495     }
496 
497     /** {@hide} */
getDataUserCePackageDirectory(String volumeUuid, int userId, String packageName)498     public static File getDataUserCePackageDirectory(String volumeUuid, int userId,
499             String packageName) {
500         // TODO: keep consistent with installd
501         return new File(getDataUserCeDirectory(volumeUuid, userId), packageName);
502     }
503 
504     /** {@hide} */
getDataUserDeDirectory(String volumeUuid)505     public static File getDataUserDeDirectory(String volumeUuid) {
506         return new File(getDataDirectory(volumeUuid), "user_de");
507     }
508 
509     /** {@hide} */
getDataUserDeDirectory(String volumeUuid, int userId)510     public static File getDataUserDeDirectory(String volumeUuid, int userId) {
511         return new File(getDataUserDeDirectory(volumeUuid), String.valueOf(userId));
512     }
513 
514     /** {@hide} */
getDataUserDePackageDirectory(String volumeUuid, int userId, String packageName)515     public static File getDataUserDePackageDirectory(String volumeUuid, int userId,
516             String packageName) {
517         // TODO: keep consistent with installd
518         return new File(getDataUserDeDirectory(volumeUuid, userId), packageName);
519     }
520 
521     /**
522      * Return preloads directory.
523      * <p>This directory may contain pre-loaded content such as
524      * {@link #getDataPreloadsDemoDirectory() demo videos} and
525      * {@link #getDataPreloadsAppsDirectory() APK files} .
526      * {@hide}
527      */
getDataPreloadsDirectory()528     public static File getDataPreloadsDirectory() {
529         return new File(getDataDirectory(), "preloads");
530     }
531 
532     /**
533      * @see #getDataPreloadsDirectory()
534      * {@hide}
535      */
getDataPreloadsDemoDirectory()536     public static File getDataPreloadsDemoDirectory() {
537         return new File(getDataPreloadsDirectory(), "demo");
538     }
539 
540     /**
541      * @see #getDataPreloadsDirectory()
542      * {@hide}
543      */
getDataPreloadsAppsDirectory()544     public static File getDataPreloadsAppsDirectory() {
545         return new File(getDataPreloadsDirectory(), "apps");
546     }
547 
548     /**
549      * @see #getDataPreloadsDirectory()
550      * {@hide}
551      */
getDataPreloadsMediaDirectory()552     public static File getDataPreloadsMediaDirectory() {
553         return new File(getDataPreloadsDirectory(), "media");
554     }
555 
556     /**
557      * Returns location of preloaded cache directory for package name
558      * @see #getDataPreloadsDirectory()
559      * {@hide}
560      */
getDataPreloadsFileCacheDirectory(String packageName)561     public static File getDataPreloadsFileCacheDirectory(String packageName) {
562         return new File(getDataPreloadsFileCacheDirectory(), packageName);
563     }
564 
565     /**
566      * Returns location of preloaded cache directory.
567      * @see #getDataPreloadsDirectory()
568      * {@hide}
569      */
getDataPreloadsFileCacheDirectory()570     public static File getDataPreloadsFileCacheDirectory() {
571         return new File(getDataPreloadsDirectory(), "file_cache");
572     }
573 
574     /**
575      * Returns location of packages cache directory.
576      * {@hide}
577      */
getPackageCacheDirectory()578     public static File getPackageCacheDirectory() {
579         return new File(getDataSystemDirectory(), "package_cache");
580     }
581 
582     /**
583      * Return locations where media files (such as ringtones, notification
584      * sounds, or alarm sounds) may be located on internal storage. These are
585      * typically indexed under {@link MediaStore#VOLUME_INTERNAL}.
586      *
587      * @hide
588      */
589     @SystemApi
getInternalMediaDirectories()590     public static @NonNull Collection<File> getInternalMediaDirectories() {
591         final ArrayList<File> res = new ArrayList<>();
592         addCanonicalFile(res, new File(Environment.getRootDirectory(), "media"));
593         addCanonicalFile(res, new File(Environment.getOemDirectory(), "media"));
594         addCanonicalFile(res, new File(Environment.getProductDirectory(), "media"));
595         return res;
596     }
597 
addCanonicalFile(List<File> list, File file)598     private static void addCanonicalFile(List<File> list, File file) {
599         try {
600             list.add(file.getCanonicalFile());
601         } catch (IOException e) {
602             Log.w(TAG, "Failed to resolve " + file + ": " + e);
603             list.add(file);
604         }
605     }
606 
607     /**
608      * Return the primary shared/external storage directory. This directory may
609      * not currently be accessible if it has been mounted by the user on their
610      * computer, has been removed from the device, or some other problem has
611      * happened. You can determine its current state with
612      * {@link #getExternalStorageState()}.
613      * <p>
614      * <em>Note: don't be confused by the word "external" here. This directory
615      * can better be thought as media/shared storage. It is a filesystem that
616      * can hold a relatively large amount of data and that is shared across all
617      * applications (does not enforce permissions). Traditionally this is an SD
618      * card, but it may also be implemented as built-in storage in a device that
619      * is distinct from the protected internal storage and can be mounted as a
620      * filesystem on a computer.</em>
621      * <p>
622      * On devices with multiple users (as described by {@link UserManager}),
623      * each user has their own isolated shared storage. Applications only have
624      * access to the shared storage for the user they're running as.
625      * <p>
626      * In devices with multiple shared/external storage directories, this
627      * directory represents the primary storage that the user will interact
628      * with. Access to secondary storage is available through
629      * {@link Context#getExternalFilesDirs(String)},
630      * {@link Context#getExternalCacheDirs()}, and
631      * {@link Context#getExternalMediaDirs()}.
632      * <p>
633      * Applications should not directly use this top-level directory, in order
634      * to avoid polluting the user's root namespace. Any files that are private
635      * to the application should be placed in a directory returned by
636      * {@link android.content.Context#getExternalFilesDir
637      * Context.getExternalFilesDir}, which the system will take care of deleting
638      * if the application is uninstalled. Other shared files should be placed in
639      * one of the directories returned by
640      * {@link #getExternalStoragePublicDirectory}.
641      * <p>
642      * Writing to this path requires the
643      * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission,
644      * and starting in {@link android.os.Build.VERSION_CODES#KITKAT}, read
645      * access requires the
646      * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission,
647      * which is automatically granted if you hold the write permission.
648      * <p>
649      * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your
650      * application only needs to store internal data, consider using
651      * {@link Context#getExternalFilesDir(String)},
652      * {@link Context#getExternalCacheDir()}, or
653      * {@link Context#getExternalMediaDirs()}, which require no permissions to
654      * read or write.
655      * <p>
656      * This path may change between platform versions, so applications should
657      * only persist relative paths.
658      * <p>
659      * Here is an example of typical code to monitor the state of external
660      * storage:
661      * <p>
662      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
663      * monitor_storage}
664      *
665      * @see #getExternalStorageState()
666      * @see #isExternalStorageRemovable()
667      * @deprecated To improve user privacy, direct access to shared/external
668      *             storage devices is deprecated. When an app targets
669      *             {@link android.os.Build.VERSION_CODES#Q}, the path returned
670      *             from this method is no longer directly accessible to apps.
671      *             Apps can continue to access content stored on shared/external
672      *             storage by migrating to alternatives such as
673      *             {@link Context#getExternalFilesDir(String)},
674      *             {@link MediaStore}, or {@link Intent#ACTION_OPEN_DOCUMENT}.
675      */
676     @Deprecated
getExternalStorageDirectory()677     public static File getExternalStorageDirectory() {
678         throwIfUserRequired();
679         return sCurrentUser.getExternalDirs()[0];
680     }
681 
682     /** {@hide} */
683     @UnsupportedAppUsage
getLegacyExternalStorageDirectory()684     public static File getLegacyExternalStorageDirectory() {
685         return new File(System.getenv(ENV_EXTERNAL_STORAGE));
686     }
687 
688     /** {@hide} */
689     @UnsupportedAppUsage
getLegacyExternalStorageObbDirectory()690     public static File getLegacyExternalStorageObbDirectory() {
691         return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB);
692     }
693 
694     /**
695      * Standard directory in which to place any audio files that should be
696      * in the regular list of music for the user.
697      * This may be combined with
698      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
699      * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
700      * of directories to categories a particular audio file as more than one
701      * type.
702      */
703     public static String DIRECTORY_MUSIC = "Music";
704 
705     /**
706      * Standard directory in which to place any audio files that should be
707      * in the list of podcasts that the user can select (not as regular
708      * music).
709      * This may be combined with {@link #DIRECTORY_MUSIC},
710      * {@link #DIRECTORY_NOTIFICATIONS},
711      * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
712      * of directories to categories a particular audio file as more than one
713      * type.
714      */
715     public static String DIRECTORY_PODCASTS = "Podcasts";
716 
717     /**
718      * Standard directory in which to place any audio files that should be
719      * in the list of ringtones that the user can select (not as regular
720      * music).
721      * This may be combined with {@link #DIRECTORY_MUSIC},
722      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and
723      * {@link #DIRECTORY_ALARMS} as a series
724      * of directories to categories a particular audio file as more than one
725      * type.
726      */
727     public static String DIRECTORY_RINGTONES = "Ringtones";
728 
729     /**
730      * Standard directory in which to place any audio files that should be
731      * in the list of alarms that the user can select (not as regular
732      * music).
733      * This may be combined with {@link #DIRECTORY_MUSIC},
734      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
735      * and {@link #DIRECTORY_RINGTONES} as a series
736      * of directories to categories a particular audio file as more than one
737      * type.
738      */
739     public static String DIRECTORY_ALARMS = "Alarms";
740 
741     /**
742      * Standard directory in which to place any audio files that should be
743      * in the list of notifications that the user can select (not as regular
744      * music).
745      * This may be combined with {@link #DIRECTORY_MUSIC},
746      * {@link #DIRECTORY_PODCASTS},
747      * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
748      * of directories to categories a particular audio file as more than one
749      * type.
750      */
751     public static String DIRECTORY_NOTIFICATIONS = "Notifications";
752 
753     /**
754      * Standard directory in which to place pictures that are available to
755      * the user.  Note that this is primarily a convention for the top-level
756      * public directory, as the media scanner will find and collect pictures
757      * in any directory.
758      */
759     public static String DIRECTORY_PICTURES = "Pictures";
760 
761     /**
762      * Standard directory in which to place movies that are available to
763      * the user.  Note that this is primarily a convention for the top-level
764      * public directory, as the media scanner will find and collect movies
765      * in any directory.
766      */
767     public static String DIRECTORY_MOVIES = "Movies";
768 
769     /**
770      * Standard directory in which to place files that have been downloaded by
771      * the user.  Note that this is primarily a convention for the top-level
772      * public directory, you are free to download files anywhere in your own
773      * private directories.  Also note that though the constant here is
774      * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for
775      * backwards compatibility reasons.
776      */
777     public static String DIRECTORY_DOWNLOADS = "Download";
778 
779     /**
780      * The traditional location for pictures and videos when mounting the
781      * device as a camera.  Note that this is primarily a convention for the
782      * top-level public directory, as this convention makes no sense elsewhere.
783      */
784     public static String DIRECTORY_DCIM = "DCIM";
785 
786     /**
787      * Standard directory in which to place documents that have been created by
788      * the user.
789      */
790     public static String DIRECTORY_DOCUMENTS = "Documents";
791 
792     /**
793      * Standard directory in which to place screenshots that have been taken by
794      * the user. Typically used as a secondary directory under
795      * {@link #DIRECTORY_PICTURES}.
796      */
797     public static String DIRECTORY_SCREENSHOTS = "Screenshots";
798 
799     /**
800      * Standard directory in which to place any audio files which are
801      * audiobooks.
802      */
803     public static String DIRECTORY_AUDIOBOOKS = "Audiobooks";
804 
805     /**
806      * List of standard storage directories.
807      * <p>
808      * Each of its values have its own constant:
809      * <ul>
810      *   <li>{@link #DIRECTORY_MUSIC}
811      *   <li>{@link #DIRECTORY_PODCASTS}
812      *   <li>{@link #DIRECTORY_ALARMS}
813      *   <li>{@link #DIRECTORY_RINGTONES}
814      *   <li>{@link #DIRECTORY_NOTIFICATIONS}
815      *   <li>{@link #DIRECTORY_PICTURES}
816      *   <li>{@link #DIRECTORY_MOVIES}
817      *   <li>{@link #DIRECTORY_DOWNLOADS}
818      *   <li>{@link #DIRECTORY_DCIM}
819      *   <li>{@link #DIRECTORY_DOCUMENTS}
820      *   <li>{@link #DIRECTORY_AUDIOBOOKS}
821      * </ul>
822      * @hide
823      */
824     public static final String[] STANDARD_DIRECTORIES = {
825             DIRECTORY_MUSIC,
826             DIRECTORY_PODCASTS,
827             DIRECTORY_RINGTONES,
828             DIRECTORY_ALARMS,
829             DIRECTORY_NOTIFICATIONS,
830             DIRECTORY_PICTURES,
831             DIRECTORY_MOVIES,
832             DIRECTORY_DOWNLOADS,
833             DIRECTORY_DCIM,
834             DIRECTORY_DOCUMENTS,
835             DIRECTORY_AUDIOBOOKS,
836     };
837 
838     /**
839      * @hide
840      */
isStandardDirectory(String dir)841     public static boolean isStandardDirectory(String dir) {
842         for (String valid : STANDARD_DIRECTORIES) {
843             if (valid.equals(dir)) {
844                 return true;
845             }
846         }
847         return false;
848     }
849 
850     /** {@hide} */ public static final int HAS_MUSIC = 1 << 0;
851     /** {@hide} */ public static final int HAS_PODCASTS = 1 << 1;
852     /** {@hide} */ public static final int HAS_RINGTONES = 1 << 2;
853     /** {@hide} */ public static final int HAS_ALARMS = 1 << 3;
854     /** {@hide} */ public static final int HAS_NOTIFICATIONS = 1 << 4;
855     /** {@hide} */ public static final int HAS_PICTURES = 1 << 5;
856     /** {@hide} */ public static final int HAS_MOVIES = 1 << 6;
857     /** {@hide} */ public static final int HAS_DOWNLOADS = 1 << 7;
858     /** {@hide} */ public static final int HAS_DCIM = 1 << 8;
859     /** {@hide} */ public static final int HAS_DOCUMENTS = 1 << 9;
860     /** {@hide} */ public static final int HAS_AUDIOBOOKS = 1 << 10;
861 
862     /** {@hide} */ public static final int HAS_ANDROID = 1 << 16;
863     /** {@hide} */ public static final int HAS_OTHER = 1 << 17;
864 
865     /**
866      * Classify the content types present on the given external storage device.
867      * <p>
868      * This is typically useful for deciding if an inserted SD card is empty, or
869      * if it contains content like photos that should be preserved.
870      *
871      * @hide
872      */
classifyExternalStorageDirectory(File dir)873     public static int classifyExternalStorageDirectory(File dir) {
874         int res = 0;
875         for (File f : FileUtils.listFilesOrEmpty(dir)) {
876             if (f.isFile() && isInterestingFile(f)) {
877                 res |= HAS_OTHER;
878             } else if (f.isDirectory() && hasInterestingFiles(f)) {
879                 final String name = f.getName();
880                 if (DIRECTORY_MUSIC.equals(name)) res |= HAS_MUSIC;
881                 else if (DIRECTORY_PODCASTS.equals(name)) res |= HAS_PODCASTS;
882                 else if (DIRECTORY_RINGTONES.equals(name)) res |= HAS_RINGTONES;
883                 else if (DIRECTORY_ALARMS.equals(name)) res |= HAS_ALARMS;
884                 else if (DIRECTORY_NOTIFICATIONS.equals(name)) res |= HAS_NOTIFICATIONS;
885                 else if (DIRECTORY_PICTURES.equals(name)) res |= HAS_PICTURES;
886                 else if (DIRECTORY_MOVIES.equals(name)) res |= HAS_MOVIES;
887                 else if (DIRECTORY_DOWNLOADS.equals(name)) res |= HAS_DOWNLOADS;
888                 else if (DIRECTORY_DCIM.equals(name)) res |= HAS_DCIM;
889                 else if (DIRECTORY_DOCUMENTS.equals(name)) res |= HAS_DOCUMENTS;
890                 else if (DIRECTORY_AUDIOBOOKS.equals(name)) res |= HAS_AUDIOBOOKS;
891                 else if (DIRECTORY_ANDROID.equals(name)) res |= HAS_ANDROID;
892                 else res |= HAS_OTHER;
893             }
894         }
895         return res;
896     }
897 
hasInterestingFiles(File dir)898     private static boolean hasInterestingFiles(File dir) {
899         final LinkedList<File> explore = new LinkedList<>();
900         explore.add(dir);
901         while (!explore.isEmpty()) {
902             dir = explore.pop();
903             for (File f : FileUtils.listFilesOrEmpty(dir)) {
904                 if (isInterestingFile(f)) return true;
905                 if (f.isDirectory()) explore.add(f);
906             }
907         }
908         return false;
909     }
910 
isInterestingFile(File file)911     private static boolean isInterestingFile(File file) {
912         if (file.isFile()) {
913             final String name = file.getName().toLowerCase();
914             if (name.endsWith(".exe") || name.equals("autorun.inf")
915                     || name.equals("launchpad.zip") || name.equals(".nomedia")) {
916                 return false;
917             } else {
918                 return true;
919             }
920         } else {
921             return false;
922         }
923     }
924 
925     /**
926      * Get a top-level shared/external storage directory for placing files of a
927      * particular type. This is where the user will typically place and manage
928      * their own files, so you should be careful about what you put here to
929      * ensure you don't erase their files or get in the way of their own
930      * organization.
931      * <p>
932      * On devices with multiple users (as described by {@link UserManager}),
933      * each user has their own isolated shared storage. Applications only have
934      * access to the shared storage for the user they're running as.
935      * </p>
936      * <p>
937      * Here is an example of typical code to manipulate a picture on the public
938      * shared storage:
939      * </p>
940      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
941      * public_picture}
942      *
943      * @param type The type of storage directory to return. Should be one of
944      *            {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
945      *            {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
946      *            {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
947      *            {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS},
948      *            {@link #DIRECTORY_DCIM}, or {@link #DIRECTORY_DOCUMENTS}. May not be null.
949      * @return Returns the File path for the directory. Note that this directory
950      *         may not yet exist, so you must make sure it exists before using
951      *         it such as with {@link File#mkdirs File.mkdirs()}.
952      * @deprecated To improve user privacy, direct access to shared/external
953      *             storage devices is deprecated. When an app targets
954      *             {@link android.os.Build.VERSION_CODES#Q}, the path returned
955      *             from this method is no longer directly accessible to apps.
956      *             Apps can continue to access content stored on shared/external
957      *             storage by migrating to alternatives such as
958      *             {@link Context#getExternalFilesDir(String)},
959      *             {@link MediaStore}, or {@link Intent#ACTION_OPEN_DOCUMENT}.
960      */
961     @Deprecated
getExternalStoragePublicDirectory(String type)962     public static File getExternalStoragePublicDirectory(String type) {
963         throwIfUserRequired();
964         return sCurrentUser.buildExternalStoragePublicDirs(type)[0];
965     }
966 
967     /**
968      * Returns the path for android-specific data on the SD card.
969      * @hide
970      */
971     @UnsupportedAppUsage
buildExternalStorageAndroidDataDirs()972     public static File[] buildExternalStorageAndroidDataDirs() {
973         throwIfUserRequired();
974         return sCurrentUser.buildExternalStorageAndroidDataDirs();
975     }
976 
977     /**
978      * Returns the path for android-specific OBB data on the SD card.
979      * @hide
980      */
buildExternalStorageAndroidObbDirs()981     public static File[] buildExternalStorageAndroidObbDirs() {
982         throwIfUserRequired();
983         return sCurrentUser.buildExternalStorageAndroidObbDirs();
984     }
985 
986     /**
987      * Generates the raw path to an application's data
988      * @hide
989      */
990     @UnsupportedAppUsage
buildExternalStorageAppDataDirs(String packageName)991     public static File[] buildExternalStorageAppDataDirs(String packageName) {
992         throwIfUserRequired();
993         return sCurrentUser.buildExternalStorageAppDataDirs(packageName);
994     }
995 
996     /**
997      * Generates the raw path to an application's media
998      * @hide
999      */
1000     @UnsupportedAppUsage
buildExternalStorageAppMediaDirs(String packageName)1001     public static File[] buildExternalStorageAppMediaDirs(String packageName) {
1002         throwIfUserRequired();
1003         return sCurrentUser.buildExternalStorageAppMediaDirs(packageName);
1004     }
1005 
1006     /**
1007      * Generates the raw path to an application's OBB files
1008      * @hide
1009      */
1010     @UnsupportedAppUsage
buildExternalStorageAppObbDirs(String packageName)1011     public static File[] buildExternalStorageAppObbDirs(String packageName) {
1012         throwIfUserRequired();
1013         return sCurrentUser.buildExternalStorageAppObbDirs(packageName);
1014     }
1015 
1016     /**
1017      * Generates the path to an application's files.
1018      * @hide
1019      */
1020     @UnsupportedAppUsage
buildExternalStorageAppFilesDirs(String packageName)1021     public static File[] buildExternalStorageAppFilesDirs(String packageName) {
1022         throwIfUserRequired();
1023         return sCurrentUser.buildExternalStorageAppFilesDirs(packageName);
1024     }
1025 
1026     /**
1027      * Generates the path to an application's cache.
1028      * @hide
1029      */
1030     @UnsupportedAppUsage
buildExternalStorageAppCacheDirs(String packageName)1031     public static File[] buildExternalStorageAppCacheDirs(String packageName) {
1032         throwIfUserRequired();
1033         return sCurrentUser.buildExternalStorageAppCacheDirs(packageName);
1034     }
1035 
1036     /** @hide */
buildExternalStoragePublicDirs(@onNull String dirType)1037     public static File[] buildExternalStoragePublicDirs(@NonNull String dirType) {
1038         throwIfUserRequired();
1039         return sCurrentUser.buildExternalStoragePublicDirs(dirType);
1040     }
1041 
1042     /**
1043      * Return the download/cache content directory.
1044      */
getDownloadCacheDirectory()1045     public static File getDownloadCacheDirectory() {
1046         return DIR_DOWNLOAD_CACHE;
1047     }
1048 
1049     /**
1050      * Unknown storage state, such as when a path isn't backed by known storage
1051      * media.
1052      *
1053      * @see #getExternalStorageState(File)
1054      */
1055     public static final String MEDIA_UNKNOWN = "unknown";
1056 
1057     /**
1058      * Storage state if the media is not present.
1059      *
1060      * @see #getExternalStorageState(File)
1061      */
1062     public static final String MEDIA_REMOVED = "removed";
1063 
1064     /**
1065      * Storage state if the media is present but not mounted.
1066      *
1067      * @see #getExternalStorageState(File)
1068      */
1069     public static final String MEDIA_UNMOUNTED = "unmounted";
1070 
1071     /**
1072      * Storage state if the media is present and being disk-checked.
1073      *
1074      * @see #getExternalStorageState(File)
1075      */
1076     public static final String MEDIA_CHECKING = "checking";
1077 
1078     /**
1079      * Storage state if the media is present but is blank or is using an
1080      * unsupported filesystem.
1081      *
1082      * @see #getExternalStorageState(File)
1083      */
1084     public static final String MEDIA_NOFS = "nofs";
1085 
1086     /**
1087      * Storage state if the media is present and mounted at its mount point with
1088      * read/write access.
1089      *
1090      * @see #getExternalStorageState(File)
1091      */
1092     public static final String MEDIA_MOUNTED = "mounted";
1093 
1094     /**
1095      * Storage state if the media is present and mounted at its mount point with
1096      * read-only access.
1097      *
1098      * @see #getExternalStorageState(File)
1099      */
1100     public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
1101 
1102     /**
1103      * Storage state if the media is present not mounted, and shared via USB
1104      * mass storage.
1105      *
1106      * @see #getExternalStorageState(File)
1107      */
1108     public static final String MEDIA_SHARED = "shared";
1109 
1110     /**
1111      * Storage state if the media was removed before it was unmounted.
1112      *
1113      * @see #getExternalStorageState(File)
1114      */
1115     public static final String MEDIA_BAD_REMOVAL = "bad_removal";
1116 
1117     /**
1118      * Storage state if the media is present but cannot be mounted. Typically
1119      * this happens if the file system on the media is corrupted.
1120      *
1121      * @see #getExternalStorageState(File)
1122      */
1123     public static final String MEDIA_UNMOUNTABLE = "unmountable";
1124 
1125     /**
1126      * Storage state if the media is in the process of being ejected.
1127      *
1128      * @see #getExternalStorageState(File)
1129      */
1130     public static final String MEDIA_EJECTING = "ejecting";
1131 
1132     /**
1133      * Returns the current state of the primary shared/external storage media.
1134      *
1135      * @see #getExternalStorageDirectory()
1136      * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
1137      *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
1138      *         {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
1139      *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
1140      *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
1141      */
getExternalStorageState()1142     public static String getExternalStorageState() {
1143         final File externalDir = sCurrentUser.getExternalDirs()[0];
1144         return getExternalStorageState(externalDir);
1145     }
1146 
1147     /**
1148      * @deprecated use {@link #getExternalStorageState(File)}
1149      */
1150     @Deprecated
getStorageState(File path)1151     public static String getStorageState(File path) {
1152         return getExternalStorageState(path);
1153     }
1154 
1155     /**
1156      * Returns the current state of the shared/external storage media at the
1157      * given path.
1158      *
1159      * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
1160      *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
1161      *         {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
1162      *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
1163      *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
1164      */
getExternalStorageState(File path)1165     public static String getExternalStorageState(File path) {
1166         final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
1167         if (volume != null) {
1168             return volume.getState();
1169         } else {
1170             return MEDIA_UNKNOWN;
1171         }
1172     }
1173 
1174     /**
1175      * Returns whether the primary shared/external storage media is physically
1176      * removable.
1177      *
1178      * @return true if the storage device can be removed (such as an SD card),
1179      *         or false if the storage device is built in and cannot be
1180      *         physically removed.
1181      */
isExternalStorageRemovable()1182     public static boolean isExternalStorageRemovable() {
1183         final File externalDir = sCurrentUser.getExternalDirs()[0];
1184         return isExternalStorageRemovable(externalDir);
1185     }
1186 
1187     /**
1188      * Returns whether the shared/external storage media at the given path is
1189      * physically removable.
1190      *
1191      * @return true if the storage device can be removed (such as an SD card),
1192      *         or false if the storage device is built in and cannot be
1193      *         physically removed.
1194      * @throws IllegalArgumentException if the path is not a valid storage
1195      *             device.
1196      */
isExternalStorageRemovable(@onNull File path)1197     public static boolean isExternalStorageRemovable(@NonNull File path) {
1198         final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
1199         if (volume != null) {
1200             return volume.isRemovable();
1201         } else {
1202             throw new IllegalArgumentException("Failed to find storage device at " + path);
1203         }
1204     }
1205 
1206     /**
1207      * Returns whether the primary shared/external storage media is emulated.
1208      * <p>
1209      * The contents of emulated storage devices are backed by a private user
1210      * data partition, which means there is little benefit to apps storing data
1211      * here instead of the private directories returned by
1212      * {@link Context#getFilesDir()}, etc.
1213      * <p>
1214      * This returns true when emulated storage is backed by either internal
1215      * storage or an adopted storage device.
1216      *
1217      * @see DevicePolicyManager#setStorageEncryption(android.content.ComponentName,
1218      *      boolean)
1219      */
isExternalStorageEmulated()1220     public static boolean isExternalStorageEmulated() {
1221         final File externalDir = sCurrentUser.getExternalDirs()[0];
1222         return isExternalStorageEmulated(externalDir);
1223     }
1224 
1225     /**
1226      * Returns whether the shared/external storage media at the given path is
1227      * emulated.
1228      * <p>
1229      * The contents of emulated storage devices are backed by a private user
1230      * data partition, which means there is little benefit to apps storing data
1231      * here instead of the private directories returned by
1232      * {@link Context#getFilesDir()}, etc.
1233      * <p>
1234      * This returns true when emulated storage is backed by either internal
1235      * storage or an adopted storage device.
1236      *
1237      * @throws IllegalArgumentException if the path is not a valid storage
1238      *             device.
1239      */
isExternalStorageEmulated(@onNull File path)1240     public static boolean isExternalStorageEmulated(@NonNull File path) {
1241         final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
1242         if (volume != null) {
1243             return volume.isEmulated();
1244         } else {
1245             throw new IllegalArgumentException("Failed to find storage device at " + path);
1246         }
1247     }
1248 
1249     /**
1250      * Returns whether the shared/external storage media is a
1251      * legacy view that includes files not owned by the app.
1252      * <p>
1253      * This value may be different from the value requested by
1254      * {@code requestLegacyExternalStorage} in the app's manifest, since an app
1255      * may inherit its legacy state based on when it was first installed, target sdk and other
1256      * factors.
1257      * <p>
1258      * Non-legacy apps can continue to discover and read media belonging to
1259      * other apps via {@link android.provider.MediaStore}.
1260      */
isExternalStorageLegacy()1261     public static boolean isExternalStorageLegacy() {
1262         final File externalDir = sCurrentUser.getExternalDirs()[0];
1263         return isExternalStorageLegacy(externalDir);
1264     }
1265 
1266     /**
1267      * Returns whether the shared/external storage media is a
1268      * legacy view that includes files not owned by the app.
1269      * <p>
1270      * This value may be different from the value requested by
1271      * {@code requestLegacyExternalStorage} in the app's manifest, since an app
1272      * may inherit its legacy state based on when it was first installed, target sdk and other
1273      * factors.
1274      * <p>
1275      * Non-legacy apps can continue to discover and read media belonging to
1276      * other apps via {@link android.provider.MediaStore}.
1277      *
1278      * @throws IllegalArgumentException if the path is not a valid storage
1279      * device.
1280      */
isExternalStorageLegacy(@onNull File path)1281     public static boolean isExternalStorageLegacy(@NonNull File path) {
1282         final Context context = AppGlobals.getInitialApplication();
1283         final int uid = context.getApplicationInfo().uid;
1284         // Isolated processes and Instant apps are never allowed to be in scoped storage
1285         if (Process.isIsolated(uid)) {
1286             return false;
1287         }
1288 
1289         final PackageManager packageManager = context.getPackageManager();
1290         if (packageManager.isInstantApp()) {
1291             return false;
1292         }
1293 
1294         boolean defaultScopedStorage = Compatibility.isChangeEnabled(DEFAULT_SCOPED_STORAGE);
1295         boolean forceEnableScopedStorage = Compatibility.isChangeEnabled(
1296                 FORCE_ENABLE_SCOPED_STORAGE);
1297         // if Scoped Storage is strictly enforced, the app does *not* have legacy storage access
1298         // Note: does not require packagename/uid as this is directly called from an app process
1299         if (isScopedStorageEnforced(defaultScopedStorage, forceEnableScopedStorage)) {
1300             return false;
1301         }
1302         // if Scoped Storage is strictly disabled, the app has legacy storage access
1303         // Note: does not require packagename/uid as this is directly called from an app process
1304         if (isScopedStorageDisabled(defaultScopedStorage, forceEnableScopedStorage)) {
1305             return true;
1306         }
1307 
1308         final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
1309         return appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
1310                 uid, context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED;
1311     }
1312 
1313     /**
1314      * Returns whether the calling app has All Files Access on the primary shared/external storage
1315      * media.
1316      * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't
1317      * enough to gain the access.
1318      * <p>To request access, use
1319      * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
1320      */
isExternalStorageManager()1321     public static boolean isExternalStorageManager() {
1322         final File externalDir = sCurrentUser.getExternalDirs()[0];
1323         return isExternalStorageManager(externalDir);
1324     }
1325 
1326     /**
1327      * Returns whether the calling app has All Files Access at the given {@code path}
1328      * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't
1329      * enough to gain the access.
1330      * <p>To request access, use
1331      * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
1332      */
isExternalStorageManager(@onNull File path)1333     public static boolean isExternalStorageManager(@NonNull File path) {
1334         final Context context = Objects.requireNonNull(AppGlobals.getInitialApplication());
1335         String packageName = Objects.requireNonNull(context.getPackageName());
1336         int uid = context.getApplicationInfo().uid;
1337 
1338         final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
1339         final int opMode =
1340                 appOps.checkOpNoThrow(AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE, uid, packageName);
1341 
1342         switch (opMode) {
1343             case AppOpsManager.MODE_DEFAULT:
1344                 return PackageManager.PERMISSION_GRANTED
1345                         == context.checkPermission(
1346                                 Manifest.permission.MANAGE_EXTERNAL_STORAGE, Process.myPid(), uid);
1347             case AppOpsManager.MODE_ALLOWED:
1348                 return true;
1349             case AppOpsManager.MODE_ERRORED:
1350             case AppOpsManager.MODE_IGNORED:
1351                 return false;
1352             default:
1353                 throw new IllegalStateException("Unknown AppOpsManager mode " + opMode);
1354         }
1355     }
1356 
isScopedStorageEnforced(boolean defaultScopedStorage, boolean forceEnableScopedStorage)1357     private static boolean isScopedStorageEnforced(boolean defaultScopedStorage,
1358             boolean forceEnableScopedStorage) {
1359         return defaultScopedStorage && forceEnableScopedStorage;
1360     }
1361 
isScopedStorageDisabled(boolean defaultScopedStorage, boolean forceEnableScopedStorage)1362     private static boolean isScopedStorageDisabled(boolean defaultScopedStorage,
1363             boolean forceEnableScopedStorage) {
1364         return !defaultScopedStorage && !forceEnableScopedStorage;
1365     }
1366 
getDirectory(String variableName, String defaultPath)1367     static File getDirectory(String variableName, String defaultPath) {
1368         String path = System.getenv(variableName);
1369         return path == null ? new File(defaultPath) : new File(path);
1370     }
1371 
1372     /** {@hide} */
setUserRequired(boolean userRequired)1373     public static void setUserRequired(boolean userRequired) {
1374         sUserRequired = userRequired;
1375     }
1376 
throwIfUserRequired()1377     private static void throwIfUserRequired() {
1378         if (sUserRequired) {
1379             Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment",
1380                     new Throwable());
1381         }
1382     }
1383 
1384     /**
1385      * Append path segments to each given base path, returning result.
1386      *
1387      * @hide
1388      */
1389     @UnsupportedAppUsage
buildPaths(File[] base, String... segments)1390     public static File[] buildPaths(File[] base, String... segments) {
1391         File[] result = new File[base.length];
1392         for (int i = 0; i < base.length; i++) {
1393             result[i] = buildPath(base[i], segments);
1394         }
1395         return result;
1396     }
1397 
1398     /**
1399      * Append path segments to given base path, returning result.
1400      *
1401      * @hide
1402      */
1403     @TestApi
buildPath(File base, String... segments)1404     public static File buildPath(File base, String... segments) {
1405         File cur = base;
1406         for (String segment : segments) {
1407             if (cur == null) {
1408                 cur = new File(segment);
1409             } else {
1410                 cur = new File(cur, segment);
1411             }
1412         }
1413         return cur;
1414     }
1415 
1416     /**
1417      * If the given path exists on emulated external storage, return the
1418      * translated backing path hosted on internal storage. This bypasses any
1419      * emulation later, improving performance. This is <em>only</em> suitable
1420      * for read-only access.
1421      * <p>
1422      * Returns original path if given path doesn't meet these criteria. Callers
1423      * must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}
1424      * permission.
1425      *
1426      * @deprecated disabled now that FUSE has been replaced by sdcardfs
1427      * @hide
1428      */
1429     @UnsupportedAppUsage
1430     @Deprecated
maybeTranslateEmulatedPathToInternal(File path)1431     public static File maybeTranslateEmulatedPathToInternal(File path) {
1432         return StorageManager.maybeTranslateEmulatedPathToInternal(path);
1433     }
1434 }
1435