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