• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.pm.ApplicationInfo;
33 import android.content.pm.PackageManager;
34 import android.os.storage.StorageManager;
35 import android.os.storage.StorageVolume;
36 import android.provider.MediaStore;
37 import android.text.TextUtils;
38 import android.util.Log;
39 
40 import java.io.File;
41 import java.io.IOException;
42 import java.util.ArrayList;
43 import java.util.Collection;
44 import java.util.LinkedList;
45 import java.util.List;
46 import java.util.Objects;
47 
48 /**
49  * Provides access to environment variables.
50  */
51 public class Environment {
52     private static final String TAG = "Environment";
53 
54     // NOTE: keep credential-protected paths in sync with StrictMode.java
55 
56     private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
57     private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
58     private static final String ENV_ANDROID_DATA = "ANDROID_DATA";
59     private static final String ENV_ANDROID_EXPAND = "ANDROID_EXPAND";
60     private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE";
61     private static final String ENV_DOWNLOAD_CACHE = "DOWNLOAD_CACHE";
62     private static final String ENV_OEM_ROOT = "OEM_ROOT";
63     private static final String ENV_ODM_ROOT = "ODM_ROOT";
64     private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
65     private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT";
66     private static final String ENV_SYSTEM_EXT_ROOT = "SYSTEM_EXT_ROOT";
67     private static final String ENV_APEX_ROOT = "APEX_ROOT";
68 
69     /** {@hide} */
70     public static final String DIR_ANDROID = "Android";
71     private static final String DIR_DATA = "data";
72     private static final String DIR_MEDIA = "media";
73     private static final String DIR_OBB = "obb";
74     private static final String DIR_FILES = "files";
75     private static final String DIR_CACHE = "cache";
76 
77     /**
78      * The folder name prefix for the user credential protected data directory. This is exposed for
79      * use in string path caching for {@link ApplicationInfo} objects, and should not be accessed
80      * directly otherwise. Prefer {@link #getDataUserCeDirectory(String, int)}.
81      * {@hide}
82      */
83     public static final String DIR_USER_CE = "user";
84 
85     /**
86      * The folder name prefix for the user device protected data directory. This is exposed for use
87      * in string path caching for {@link ApplicationInfo} objects, and should not be accessed
88      * directly otherwise. Prefer {@link #getDataUserDeDirectory(String, int)}.
89      * {@hide}
90      */
91     public static final String DIR_USER_DE = "user_de";
92 
93     /** {@hide} */
94     @Deprecated
95     public static final String DIRECTORY_ANDROID = DIR_ANDROID;
96 
97     private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
98     private static final String DIR_ANDROID_DATA_PATH = getDirectoryPath(ENV_ANDROID_DATA, "/data");
99     private static final File DIR_ANDROID_DATA = new File(DIR_ANDROID_DATA_PATH);
100     private static final File DIR_ANDROID_EXPAND = getDirectory(ENV_ANDROID_EXPAND, "/mnt/expand");
101     private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage");
102     private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache");
103     private static final File DIR_METADATA = new File("/metadata");
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} */
getDataMiscCeDirectory(String volumeUuid, int userId)481     private static File getDataMiscCeDirectory(String volumeUuid, int userId) {
482         return buildPath(getDataDirectory(volumeUuid), "misc_ce", String.valueOf(userId));
483     }
484 
485     /** {@hide} */
getDataMiscCeSharedSdkSandboxDirectory(String volumeUuid, int userId, String packageName)486     public static File getDataMiscCeSharedSdkSandboxDirectory(String volumeUuid, int userId,
487             String packageName) {
488         return buildPath(getDataMiscCeDirectory(volumeUuid, userId), "sdksandbox",
489                 packageName, "shared");
490     }
491 
492     /** {@hide} */
getDataMiscDeDirectory(int userId)493     public static File getDataMiscDeDirectory(int userId) {
494         return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId));
495     }
496 
497     /** {@hide} */
getDataMiscDeDirectory(String volumeUuid, int userId)498     private static File getDataMiscDeDirectory(String volumeUuid, int userId) {
499         return buildPath(getDataDirectory(volumeUuid), "misc_de", String.valueOf(userId));
500     }
501 
502     /** {@hide} */
getDataMiscDeSharedSdkSandboxDirectory(String volumeUuid, int userId, String packageName)503     public static File getDataMiscDeSharedSdkSandboxDirectory(String volumeUuid, int userId,
504             String packageName) {
505         return buildPath(getDataMiscDeDirectory(volumeUuid, userId), "sdksandbox",
506                 packageName, "shared");
507     }
508 
getDataProfilesDeDirectory(int userId)509     private static File getDataProfilesDeDirectory(int userId) {
510         return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId));
511     }
512 
513     /** {@hide} */
getDataVendorCeDirectory(int userId)514     public static File getDataVendorCeDirectory(int userId) {
515         return buildPath(getDataDirectory(), "vendor_ce", String.valueOf(userId));
516     }
517 
518     /** {@hide} */
getDataVendorDeDirectory(int userId)519     public static File getDataVendorDeDirectory(int userId) {
520         return buildPath(getDataDirectory(), "vendor_de", String.valueOf(userId));
521     }
522 
523     /** {@hide} */
getDataRefProfilesDePackageDirectory(String packageName)524     public static File getDataRefProfilesDePackageDirectory(String packageName) {
525         return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName);
526     }
527 
528     /** {@hide} */
getDataProfilesDePackageDirectory(int userId, String packageName)529     public static File getDataProfilesDePackageDirectory(int userId, String packageName) {
530         return buildPath(getDataProfilesDeDirectory(userId), packageName);
531     }
532 
533     /** {@hide} */
getDataAppDirectory(String volumeUuid)534     public static File getDataAppDirectory(String volumeUuid) {
535         return new File(getDataDirectory(volumeUuid), "app");
536     }
537 
538     /** {@hide} */
getDataStagingDirectory(String volumeUuid)539     public static File getDataStagingDirectory(String volumeUuid) {
540         return new File(getDataDirectory(volumeUuid), "app-staging");
541     }
542 
543     /** {@hide} */
getDataUserCeDirectory(String volumeUuid)544     public static File getDataUserCeDirectory(String volumeUuid) {
545         return new File(getDataDirectory(volumeUuid), DIR_USER_CE);
546     }
547 
548     /** {@hide} */
getDataUserCeDirectory(String volumeUuid, int userId)549     public static File getDataUserCeDirectory(String volumeUuid, int userId) {
550         return new File(getDataUserCeDirectory(volumeUuid), String.valueOf(userId));
551     }
552 
553     /** {@hide} */
getDataUserCePackageDirectory(String volumeUuid, int userId, String packageName)554     public static File getDataUserCePackageDirectory(String volumeUuid, int userId,
555             String packageName) {
556         // TODO: keep consistent with installd
557         return new File(getDataUserCeDirectory(volumeUuid, userId), packageName);
558     }
559 
560     /** {@hide} */
getDataUserDeDirectory(String volumeUuid)561     public static File getDataUserDeDirectory(String volumeUuid) {
562         return new File(getDataDirectory(volumeUuid), DIR_USER_DE);
563     }
564 
565     /** {@hide} */
getDataUserDeDirectory(String volumeUuid, int userId)566     public static File getDataUserDeDirectory(String volumeUuid, int userId) {
567         return new File(getDataUserDeDirectory(volumeUuid), String.valueOf(userId));
568     }
569 
570     /** {@hide} */
getDataUserDePackageDirectory(String volumeUuid, int userId, String packageName)571     public static File getDataUserDePackageDirectory(String volumeUuid, int userId,
572             String packageName) {
573         // TODO: keep consistent with installd
574         return new File(getDataUserDeDirectory(volumeUuid, userId), packageName);
575     }
576 
577     /**
578      * Return preloads directory.
579      * <p>This directory may contain pre-loaded content such as
580      * {@link #getDataPreloadsDemoDirectory() demo videos} and
581      * {@link #getDataPreloadsAppsDirectory() APK files} .
582      * {@hide}
583      */
getDataPreloadsDirectory()584     public static File getDataPreloadsDirectory() {
585         return new File(getDataDirectory(), "preloads");
586     }
587 
588     /**
589      * @see #getDataPreloadsDirectory()
590      * {@hide}
591      */
getDataPreloadsDemoDirectory()592     public static File getDataPreloadsDemoDirectory() {
593         return new File(getDataPreloadsDirectory(), "demo");
594     }
595 
596     /**
597      * @see #getDataPreloadsDirectory()
598      * {@hide}
599      */
getDataPreloadsAppsDirectory()600     public static File getDataPreloadsAppsDirectory() {
601         return new File(getDataPreloadsDirectory(), "apps");
602     }
603 
604     /**
605      * @see #getDataPreloadsDirectory()
606      * {@hide}
607      */
getDataPreloadsMediaDirectory()608     public static File getDataPreloadsMediaDirectory() {
609         return new File(getDataPreloadsDirectory(), "media");
610     }
611 
612     /**
613      * Returns location of preloaded cache directory for package name
614      * @see #getDataPreloadsDirectory()
615      * {@hide}
616      */
getDataPreloadsFileCacheDirectory(String packageName)617     public static File getDataPreloadsFileCacheDirectory(String packageName) {
618         return new File(getDataPreloadsFileCacheDirectory(), packageName);
619     }
620 
621     /**
622      * Returns location of preloaded cache directory.
623      * @see #getDataPreloadsDirectory()
624      * {@hide}
625      */
getDataPreloadsFileCacheDirectory()626     public static File getDataPreloadsFileCacheDirectory() {
627         return new File(getDataPreloadsDirectory(), "file_cache");
628     }
629 
630     /**
631      * Returns location of packages cache directory.
632      * {@hide}
633      */
getPackageCacheDirectory()634     public static File getPackageCacheDirectory() {
635         return new File(getDataSystemDirectory(), "package_cache");
636     }
637 
638     /**
639      * Return locations where media files (such as ringtones, notification
640      * sounds, or alarm sounds) may be located on internal storage. These are
641      * typically indexed under {@link MediaStore#VOLUME_INTERNAL}.
642      *
643      * @hide
644      */
645     @SystemApi
getInternalMediaDirectories()646     public static @NonNull Collection<File> getInternalMediaDirectories() {
647         final ArrayList<File> res = new ArrayList<>();
648         addCanonicalFile(res, new File(Environment.getRootDirectory(), "media"));
649         addCanonicalFile(res, new File(Environment.getOemDirectory(), "media"));
650         addCanonicalFile(res, new File(Environment.getProductDirectory(), "media"));
651         return res;
652     }
653 
addCanonicalFile(List<File> list, File file)654     private static void addCanonicalFile(List<File> list, File file) {
655         try {
656             list.add(file.getCanonicalFile());
657         } catch (IOException e) {
658             Log.w(TAG, "Failed to resolve " + file + ": " + e);
659             list.add(file);
660         }
661     }
662 
663     /**
664      * Return the primary shared/external storage directory. This directory may
665      * not currently be accessible if it has been mounted by the user on their
666      * computer, has been removed from the device, or some other problem has
667      * happened. You can determine its current state with
668      * {@link #getExternalStorageState()}.
669      * <p>
670      * <em>Note: don't be confused by the word "external" here. This directory
671      * can better be thought as media/shared storage. It is a filesystem that
672      * can hold a relatively large amount of data and that is shared across all
673      * applications (does not enforce permissions). Traditionally this is an SD
674      * card, but it may also be implemented as built-in storage in a device that
675      * is distinct from the protected internal storage and can be mounted as a
676      * filesystem on a computer.</em>
677      * <p>
678      * On devices with multiple users (as described by {@link UserManager}),
679      * each user has their own isolated shared storage. Applications only have
680      * access to the shared storage for the user they're running as.
681      * <p>
682      * In devices with multiple shared/external storage directories, this
683      * directory represents the primary storage that the user will interact
684      * with. Access to secondary storage is available through
685      * {@link Context#getExternalFilesDirs(String)},
686      * {@link Context#getExternalCacheDirs()}, and
687      * {@link Context#getExternalMediaDirs()}.
688      * <p>
689      * Applications should not directly use this top-level directory, in order
690      * to avoid polluting the user's root namespace. Any files that are private
691      * to the application should be placed in a directory returned by
692      * {@link android.content.Context#getExternalFilesDir
693      * Context.getExternalFilesDir}, which the system will take care of deleting
694      * if the application is uninstalled. Other shared files should be placed in
695      * one of the directories returned by
696      * {@link #getExternalStoragePublicDirectory}.
697      * <p>
698      * Writing to this path requires the
699      * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission,
700      * and starting in {@link android.os.Build.VERSION_CODES#KITKAT}, read
701      * access requires the
702      * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission,
703      * which is automatically granted if you hold the write permission.
704      * <p>
705      * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your
706      * application only needs to store internal data, consider using
707      * {@link Context#getExternalFilesDir(String)},
708      * {@link Context#getExternalCacheDir()}, or
709      * {@link Context#getExternalMediaDirs()}, which require no permissions to
710      * read or write.
711      * <p>
712      * This path may change between platform versions, so applications should
713      * only persist relative paths.
714      * <p>
715      * Here is an example of typical code to monitor the state of external
716      * storage:
717      * <p>
718      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
719      * monitor_storage}
720      * <p>
721      * Note that alternatives such as {@link Context#getExternalFilesDir(String)} or
722      * {@link MediaStore} offer better performance.
723      *
724      * @see #getExternalStorageState()
725      * @see #isExternalStorageRemovable()
726      */
getExternalStorageDirectory()727     public static File getExternalStorageDirectory() {
728         throwIfUserRequired();
729         return sCurrentUser.getExternalDirs()[0];
730     }
731 
732     /** {@hide} */
733     @UnsupportedAppUsage
getLegacyExternalStorageDirectory()734     public static File getLegacyExternalStorageDirectory() {
735         return new File(System.getenv(ENV_EXTERNAL_STORAGE));
736     }
737 
738     /** {@hide} */
739     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getLegacyExternalStorageObbDirectory()740     public static File getLegacyExternalStorageObbDirectory() {
741         return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB);
742     }
743 
744     /**
745      * Standard directory in which to place any audio files that should be
746      * in the regular list of music for the user.
747      * This may be combined with {@link #DIRECTORY_AUDIOBOOKS},
748      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
749      * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and
750      * {@link #DIRECTORY_RECORDINGS} as a series of directories to
751      * categorize a particular audio file as more than one type.
752      */
753     public static String DIRECTORY_MUSIC = "Music";
754 
755     /**
756      * Standard directory in which to place any audio files that should be
757      * in the list of podcasts 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_NOTIFICATIONS},
761      * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and
762      * {@link #DIRECTORY_RECORDINGS} as a series of directories to
763      * categorize a particular audio file as more than one type.
764      */
765     public static String DIRECTORY_PODCASTS = "Podcasts";
766 
767     /**
768      * Standard directory in which to place any audio files that should be
769      * in the list of ringtones 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_NOTIFICATIONS}, {@link #DIRECTORY_ALARMS},
774      * and {@link #DIRECTORY_RECORDINGS} as a series of directories
775      * to categorize a particular audio file as more than one type.
776      */
777     public static String DIRECTORY_RINGTONES = "Ringtones";
778 
779     /**
780      * Standard directory in which to place any audio files that should be
781      * in the list of alarms that the user can select (not as regular
782      * music).
783      * This may be combined with {@link #DIRECTORY_MUSIC},
784      * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
785      * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_RINGTONES},
786      * and {@link #DIRECTORY_RECORDINGS} as a series of directories
787      * to categorize a particular audio file as more than one type.
788      */
789     public static String DIRECTORY_ALARMS = "Alarms";
790 
791     /**
792      * Standard directory in which to place any audio files that should be
793      * in the list of notifications that the user can select (not as regular
794      * music).
795      * This may be combined with {@link #DIRECTORY_MUSIC},
796      * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
797      * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and
798      * {@link #DIRECTORY_RECORDINGS} as a series of directories to
799      * categorize a particular audio file as more than one type.
800      */
801     public static String DIRECTORY_NOTIFICATIONS = "Notifications";
802 
803     /**
804      * Standard directory in which to place pictures that are available to
805      * the user.  Note that this is primarily a convention for the top-level
806      * public directory, as the media scanner will find and collect pictures
807      * in any directory.
808      */
809     public static String DIRECTORY_PICTURES = "Pictures";
810 
811     /**
812      * Standard directory in which to place movies that are available to
813      * the user.  Note that this is primarily a convention for the top-level
814      * public directory, as the media scanner will find and collect movies
815      * in any directory.
816      */
817     public static String DIRECTORY_MOVIES = "Movies";
818 
819     /**
820      * Standard directory in which to place files that have been downloaded by
821      * the user.  Note that this is primarily a convention for the top-level
822      * public directory, you are free to download files anywhere in your own
823      * private directories.  Also note that though the constant here is
824      * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for
825      * backwards compatibility reasons.
826      */
827     public static String DIRECTORY_DOWNLOADS = "Download";
828 
829     /**
830      * The traditional location for pictures and videos when mounting the
831      * device as a camera.  Note that this is primarily a convention for the
832      * top-level public directory, as this convention makes no sense elsewhere.
833      */
834     public static String DIRECTORY_DCIM = "DCIM";
835 
836     /**
837      * Standard directory in which to place documents that have been created by
838      * the user.
839      */
840     public static String DIRECTORY_DOCUMENTS = "Documents";
841 
842     /**
843      * Standard directory in which to place screenshots that have been taken by
844      * the user. Typically used as a secondary directory under
845      * {@link #DIRECTORY_PICTURES}.
846      */
847     public static String DIRECTORY_SCREENSHOTS = "Screenshots";
848 
849     /**
850      * Standard directory in which to place any audio files that should be
851      * in the list of audiobooks that the user can select (not as regular
852      * music).
853      * This may be combined with {@link #DIRECTORY_MUSIC},
854      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
855      * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES},
856      * and {@link #DIRECTORY_RECORDINGS} as a series of directories
857      * to categorize a particular audio file as more than one type.
858      */
859     public static String DIRECTORY_AUDIOBOOKS = "Audiobooks";
860 
861     /**
862      * Standard directory in which to place any audio files that should be
863      * in the list of voice recordings recorded by voice recorder apps that
864      * the user can select (not as regular music).
865      * This may be combined with {@link #DIRECTORY_MUSIC},
866      * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
867      * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_ALARMS},
868      * and {@link #DIRECTORY_RINGTONES} as a series of directories
869      * to categorize a particular audio file as more than one type.
870      */
871     @NonNull
872     // The better way is that expose a static method getRecordingDirectories.
873     // But since it's an existing API surface and developers already
874     // used to DIRECTORY_* constants, we should keep using this pattern
875     // for consistency. We use SuppressLint here to avoid exposing a final
876     // field. A final field will prevent us from ever changing the value of
877     // DIRECTORY_RECORDINGS. Not that it's likely that we will ever need to
878     // change it, but it's better to have such option.
879     @SuppressLint({"MutableBareField", "AllUpper"})
880     public static String DIRECTORY_RECORDINGS = "Recordings";
881 
882     /**
883      * List of standard storage directories.
884      * <p>
885      * Each of its values have its own constant:
886      * <ul>
887      *   <li>{@link #DIRECTORY_MUSIC}
888      *   <li>{@link #DIRECTORY_PODCASTS}
889      *   <li>{@link #DIRECTORY_ALARMS}
890      *   <li>{@link #DIRECTORY_RINGTONES}
891      *   <li>{@link #DIRECTORY_NOTIFICATIONS}
892      *   <li>{@link #DIRECTORY_PICTURES}
893      *   <li>{@link #DIRECTORY_MOVIES}
894      *   <li>{@link #DIRECTORY_DOWNLOADS}
895      *   <li>{@link #DIRECTORY_DCIM}
896      *   <li>{@link #DIRECTORY_DOCUMENTS}
897      *   <li>{@link #DIRECTORY_AUDIOBOOKS}
898      *   <li>{@link #DIRECTORY_RECORDINGS}
899      * </ul>
900      * @hide
901      */
902     public static final String[] STANDARD_DIRECTORIES = {
903             DIRECTORY_MUSIC,
904             DIRECTORY_PODCASTS,
905             DIRECTORY_RINGTONES,
906             DIRECTORY_ALARMS,
907             DIRECTORY_NOTIFICATIONS,
908             DIRECTORY_PICTURES,
909             DIRECTORY_MOVIES,
910             DIRECTORY_DOWNLOADS,
911             DIRECTORY_DCIM,
912             DIRECTORY_DOCUMENTS,
913             DIRECTORY_AUDIOBOOKS,
914             DIRECTORY_RECORDINGS,
915     };
916 
917     /**
918      * @hide
919      */
isStandardDirectory(String dir)920     public static boolean isStandardDirectory(String dir) {
921         for (String valid : STANDARD_DIRECTORIES) {
922             if (valid.equals(dir)) {
923                 return true;
924             }
925         }
926         return false;
927     }
928 
929     /** {@hide} */ public static final int HAS_MUSIC = 1 << 0;
930     /** {@hide} */ public static final int HAS_PODCASTS = 1 << 1;
931     /** {@hide} */ public static final int HAS_RINGTONES = 1 << 2;
932     /** {@hide} */ public static final int HAS_ALARMS = 1 << 3;
933     /** {@hide} */ public static final int HAS_NOTIFICATIONS = 1 << 4;
934     /** {@hide} */ public static final int HAS_PICTURES = 1 << 5;
935     /** {@hide} */ public static final int HAS_MOVIES = 1 << 6;
936     /** {@hide} */ public static final int HAS_DOWNLOADS = 1 << 7;
937     /** {@hide} */ public static final int HAS_DCIM = 1 << 8;
938     /** {@hide} */ public static final int HAS_DOCUMENTS = 1 << 9;
939     /** {@hide} */ public static final int HAS_AUDIOBOOKS = 1 << 10;
940     /** {@hide} */ public static final int HAS_RECORDINGS = 1 << 11;
941 
942     /** {@hide} */ public static final int HAS_ANDROID = 1 << 16;
943     /** {@hide} */ public static final int HAS_OTHER = 1 << 17;
944 
945     /**
946      * Classify the content types present on the given external storage device.
947      * <p>
948      * This is typically useful for deciding if an inserted SD card is empty, or
949      * if it contains content like photos that should be preserved.
950      *
951      * @hide
952      */
classifyExternalStorageDirectory(File dir)953     public static int classifyExternalStorageDirectory(File dir) {
954         int res = 0;
955         for (File f : FileUtils.listFilesOrEmpty(dir)) {
956             if (f.isFile() && isInterestingFile(f)) {
957                 res |= HAS_OTHER;
958             } else if (f.isDirectory() && hasInterestingFiles(f)) {
959                 final String name = f.getName();
960                 if (DIRECTORY_MUSIC.equals(name)) res |= HAS_MUSIC;
961                 else if (DIRECTORY_PODCASTS.equals(name)) res |= HAS_PODCASTS;
962                 else if (DIRECTORY_RINGTONES.equals(name)) res |= HAS_RINGTONES;
963                 else if (DIRECTORY_ALARMS.equals(name)) res |= HAS_ALARMS;
964                 else if (DIRECTORY_NOTIFICATIONS.equals(name)) res |= HAS_NOTIFICATIONS;
965                 else if (DIRECTORY_PICTURES.equals(name)) res |= HAS_PICTURES;
966                 else if (DIRECTORY_MOVIES.equals(name)) res |= HAS_MOVIES;
967                 else if (DIRECTORY_DOWNLOADS.equals(name)) res |= HAS_DOWNLOADS;
968                 else if (DIRECTORY_DCIM.equals(name)) res |= HAS_DCIM;
969                 else if (DIRECTORY_DOCUMENTS.equals(name)) res |= HAS_DOCUMENTS;
970                 else if (DIRECTORY_AUDIOBOOKS.equals(name)) res |= HAS_AUDIOBOOKS;
971                 else if (DIRECTORY_RECORDINGS.equals(name)) res |= HAS_RECORDINGS;
972                 else if (DIRECTORY_ANDROID.equals(name)) res |= HAS_ANDROID;
973                 else res |= HAS_OTHER;
974             }
975         }
976         return res;
977     }
978 
hasInterestingFiles(File dir)979     private static boolean hasInterestingFiles(File dir) {
980         final LinkedList<File> explore = new LinkedList<>();
981         explore.add(dir);
982         while (!explore.isEmpty()) {
983             dir = explore.pop();
984             for (File f : FileUtils.listFilesOrEmpty(dir)) {
985                 if (isInterestingFile(f)) return true;
986                 if (f.isDirectory()) explore.add(f);
987             }
988         }
989         return false;
990     }
991 
isInterestingFile(File file)992     private static boolean isInterestingFile(File file) {
993         if (file.isFile()) {
994             final String name = file.getName().toLowerCase();
995             if (name.endsWith(".exe") || name.equals("autorun.inf")
996                     || name.equals("launchpad.zip") || name.equals(".nomedia")) {
997                 return false;
998             } else {
999                 return true;
1000             }
1001         } else {
1002             return false;
1003         }
1004     }
1005 
1006     /**
1007      * Get a top-level shared/external storage directory for placing files of a
1008      * particular type. This is where the user will typically place and manage
1009      * their own files, so you should be careful about what you put here to
1010      * ensure you don't erase their files or get in the way of their own
1011      * organization.
1012      * <p>
1013      * On devices with multiple users (as described by {@link UserManager}),
1014      * each user has their own isolated shared storage. Applications only have
1015      * access to the shared storage for the user they're running as.
1016      * </p>
1017      * <p>
1018      * Here is an example of typical code to manipulate a picture on the public
1019      * shared storage:
1020      * </p>
1021      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
1022      * public_picture}
1023      * <p>
1024      * Note that alternatives such as {@link Context#getExternalFilesDir(String)} or
1025      * {@link MediaStore} offer better performance.
1026      *
1027      * @param type The type of storage directory to return. Should be one of
1028      *            {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
1029      *            {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
1030      *            {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
1031      *            {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS},
1032      *            {@link #DIRECTORY_DCIM}, or {@link #DIRECTORY_DOCUMENTS}. May not be null.
1033      * @return Returns the File path for the directory. Note that this directory
1034      *         may not yet exist, so you must make sure it exists before using
1035      *         it such as with {@link File#mkdirs File.mkdirs()}.
1036      */
getExternalStoragePublicDirectory(String type)1037     public static File getExternalStoragePublicDirectory(String type) {
1038         throwIfUserRequired();
1039         return sCurrentUser.buildExternalStoragePublicDirs(type)[0];
1040     }
1041 
1042     /**
1043      * Returns the path for android-specific data on the SD card.
1044      * @hide
1045      */
1046     @UnsupportedAppUsage
buildExternalStorageAndroidDataDirs()1047     public static File[] buildExternalStorageAndroidDataDirs() {
1048         throwIfUserRequired();
1049         return sCurrentUser.buildExternalStorageAndroidDataDirs();
1050     }
1051 
1052     /**
1053      * Returns the path for android-specific OBB data on the SD card.
1054      * @hide
1055      */
buildExternalStorageAndroidObbDirs()1056     public static File[] buildExternalStorageAndroidObbDirs() {
1057         throwIfUserRequired();
1058         return sCurrentUser.buildExternalStorageAndroidObbDirs();
1059     }
1060 
1061     /**
1062      * Generates the raw path to an application's data
1063      * @hide
1064      */
1065     @UnsupportedAppUsage
buildExternalStorageAppDataDirs(String packageName)1066     public static File[] buildExternalStorageAppDataDirs(String packageName) {
1067         throwIfUserRequired();
1068         return sCurrentUser.buildExternalStorageAppDataDirs(packageName);
1069     }
1070 
1071     /**
1072      * Generates the raw path to an application's media
1073      * @hide
1074      */
1075     @UnsupportedAppUsage
buildExternalStorageAppMediaDirs(String packageName)1076     public static File[] buildExternalStorageAppMediaDirs(String packageName) {
1077         throwIfUserRequired();
1078         return sCurrentUser.buildExternalStorageAppMediaDirs(packageName);
1079     }
1080 
1081     /**
1082      * Generates the raw path to an application's OBB files
1083      * @hide
1084      */
1085     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
buildExternalStorageAppObbDirs(String packageName)1086     public static File[] buildExternalStorageAppObbDirs(String packageName) {
1087         throwIfUserRequired();
1088         return sCurrentUser.buildExternalStorageAppObbDirs(packageName);
1089     }
1090 
1091     /**
1092      * Generates the path to an application's files.
1093      * @hide
1094      */
1095     @UnsupportedAppUsage
buildExternalStorageAppFilesDirs(String packageName)1096     public static File[] buildExternalStorageAppFilesDirs(String packageName) {
1097         throwIfUserRequired();
1098         return sCurrentUser.buildExternalStorageAppFilesDirs(packageName);
1099     }
1100 
1101     /**
1102      * Generates the path to an application's cache.
1103      * @hide
1104      */
1105     @UnsupportedAppUsage
buildExternalStorageAppCacheDirs(String packageName)1106     public static File[] buildExternalStorageAppCacheDirs(String packageName) {
1107         throwIfUserRequired();
1108         return sCurrentUser.buildExternalStorageAppCacheDirs(packageName);
1109     }
1110 
1111     /** @hide */
buildExternalStoragePublicDirs(@onNull String dirType)1112     public static File[] buildExternalStoragePublicDirs(@NonNull String dirType) {
1113         throwIfUserRequired();
1114         return sCurrentUser.buildExternalStoragePublicDirs(dirType);
1115     }
1116 
1117     /**
1118      * Return the download/cache content directory.
1119      */
getDownloadCacheDirectory()1120     public static File getDownloadCacheDirectory() {
1121         return DIR_DOWNLOAD_CACHE;
1122     }
1123 
1124     /**
1125      * Return the metadata directory.
1126      *
1127      * @hide
1128      */
getMetadataDirectory()1129     public static @NonNull File getMetadataDirectory() {
1130         return DIR_METADATA;
1131     }
1132 
1133     /**
1134      * Unknown storage state, such as when a path isn't backed by known storage
1135      * media.
1136      *
1137      * @see #getExternalStorageState(File)
1138      */
1139     public static final String MEDIA_UNKNOWN = "unknown";
1140 
1141     /**
1142      * Storage state if the media is not present.
1143      *
1144      * @see #getExternalStorageState(File)
1145      */
1146     public static final String MEDIA_REMOVED = "removed";
1147 
1148     /**
1149      * Storage state if the media is present but not mounted.
1150      *
1151      * @see #getExternalStorageState(File)
1152      */
1153     public static final String MEDIA_UNMOUNTED = "unmounted";
1154 
1155     /**
1156      * Storage state if the media is present and being disk-checked.
1157      *
1158      * @see #getExternalStorageState(File)
1159      */
1160     public static final String MEDIA_CHECKING = "checking";
1161 
1162     /**
1163      * Storage state if the media is present but is blank or is using an
1164      * unsupported filesystem.
1165      *
1166      * @see #getExternalStorageState(File)
1167      */
1168     public static final String MEDIA_NOFS = "nofs";
1169 
1170     /**
1171      * Storage state if the media is present and mounted at its mount point with
1172      * read/write access.
1173      *
1174      * @see #getExternalStorageState(File)
1175      */
1176     public static final String MEDIA_MOUNTED = "mounted";
1177 
1178     /**
1179      * Storage state if the media is present and mounted at its mount point with
1180      * read-only access.
1181      *
1182      * @see #getExternalStorageState(File)
1183      */
1184     public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
1185 
1186     /**
1187      * Storage state if the media is present not mounted, and shared via USB
1188      * mass storage.
1189      *
1190      * @see #getExternalStorageState(File)
1191      */
1192     public static final String MEDIA_SHARED = "shared";
1193 
1194     /**
1195      * Storage state if the media was removed before it was unmounted.
1196      *
1197      * @see #getExternalStorageState(File)
1198      */
1199     public static final String MEDIA_BAD_REMOVAL = "bad_removal";
1200 
1201     /**
1202      * Storage state if the media is present but cannot be mounted. Typically
1203      * this happens if the file system on the media is corrupted.
1204      *
1205      * @see #getExternalStorageState(File)
1206      */
1207     public static final String MEDIA_UNMOUNTABLE = "unmountable";
1208 
1209     /**
1210      * Storage state if the media is in the process of being ejected.
1211      *
1212      * @see #getExternalStorageState(File)
1213      */
1214     public static final String MEDIA_EJECTING = "ejecting";
1215 
1216     /**
1217      * Returns the current state of the primary shared/external storage media.
1218      *
1219      * @see #getExternalStorageDirectory()
1220      * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
1221      *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
1222      *         {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
1223      *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
1224      *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
1225      */
getExternalStorageState()1226     public static String getExternalStorageState() {
1227         final File externalDir = sCurrentUser.getExternalDirs()[0];
1228         return getExternalStorageState(externalDir);
1229     }
1230 
1231     /**
1232      * @deprecated use {@link #getExternalStorageState(File)}
1233      */
1234     @Deprecated
getStorageState(File path)1235     public static String getStorageState(File path) {
1236         return getExternalStorageState(path);
1237     }
1238 
1239     /**
1240      * Returns the current state of the shared/external storage media at the
1241      * given path.
1242      *
1243      * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
1244      *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
1245      *         {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
1246      *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
1247      *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
1248      */
getExternalStorageState(File path)1249     public static String getExternalStorageState(File path) {
1250         final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
1251         if (volume != null) {
1252             return volume.getState();
1253         } else {
1254             return MEDIA_UNKNOWN;
1255         }
1256     }
1257 
1258     /**
1259      * Returns whether the primary shared/external storage media is physically
1260      * removable.
1261      *
1262      * @return true if the storage device can be removed (such as an SD card),
1263      *         or false if the storage device is built in and cannot be
1264      *         physically removed.
1265      */
isExternalStorageRemovable()1266     public static boolean isExternalStorageRemovable() {
1267         final File externalDir = sCurrentUser.getExternalDirs()[0];
1268         return isExternalStorageRemovable(externalDir);
1269     }
1270 
1271     /**
1272      * Returns whether the shared/external storage media at the given path is
1273      * physically removable.
1274      *
1275      * @return true if the storage device can be removed (such as an SD card),
1276      *         or false if the storage device is built in and cannot be
1277      *         physically removed.
1278      * @throws IllegalArgumentException if the path is not a valid storage
1279      *             device.
1280      */
isExternalStorageRemovable(@onNull File path)1281     public static boolean isExternalStorageRemovable(@NonNull File path) {
1282         final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
1283         if (volume != null) {
1284             return volume.isRemovable();
1285         } else {
1286             throw new IllegalArgumentException("Failed to find storage device at " + path);
1287         }
1288     }
1289 
1290     /**
1291      * Returns whether the primary shared/external storage media is emulated.
1292      * <p>
1293      * The contents of emulated storage devices are backed by a private user
1294      * data partition, which means there is little benefit to apps storing data
1295      * here instead of the private directories returned by
1296      * {@link Context#getFilesDir()}, etc.
1297      * <p>
1298      * This returns true when emulated storage is backed by either internal
1299      * storage or an adopted storage device.
1300      *
1301      * @see DevicePolicyManager#setStorageEncryption(android.content.ComponentName,
1302      *      boolean)
1303      */
isExternalStorageEmulated()1304     public static boolean isExternalStorageEmulated() {
1305         final File externalDir = sCurrentUser.getExternalDirs()[0];
1306         return isExternalStorageEmulated(externalDir);
1307     }
1308 
1309     /**
1310      * Returns whether the shared/external storage media at the given path is
1311      * emulated.
1312      * <p>
1313      * The contents of emulated storage devices are backed by a private user
1314      * data partition, which means there is little benefit to apps storing data
1315      * here instead of the private directories returned by
1316      * {@link Context#getFilesDir()}, etc.
1317      * <p>
1318      * This returns true when emulated storage is backed by either internal
1319      * storage or an adopted storage device.
1320      *
1321      * @throws IllegalArgumentException if the path is not a valid storage
1322      *             device.
1323      */
isExternalStorageEmulated(@onNull File path)1324     public static boolean isExternalStorageEmulated(@NonNull File path) {
1325         final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
1326         if (volume != null) {
1327             return volume.isEmulated();
1328         } else {
1329             throw new IllegalArgumentException("Failed to find storage device at " + path);
1330         }
1331     }
1332 
1333     /**
1334      * Returns whether the shared/external storage media is a
1335      * legacy view that includes files not owned by the app.
1336      * <p>
1337      * This value may be different from the value requested by
1338      * {@code requestLegacyExternalStorage} in the app's manifest, since an app
1339      * may inherit its legacy state based on when it was first installed, target sdk and other
1340      * factors.
1341      * <p>
1342      * Non-legacy apps can continue to discover and read media belonging to
1343      * other apps via {@link android.provider.MediaStore}.
1344      */
isExternalStorageLegacy()1345     public static boolean isExternalStorageLegacy() {
1346         final File externalDir = sCurrentUser.getExternalDirs()[0];
1347         return isExternalStorageLegacy(externalDir);
1348     }
1349 
1350     /**
1351      * Returns whether the shared/external storage media is a
1352      * legacy view that includes files not owned by the app.
1353      * <p>
1354      * This value may be different from the value requested by
1355      * {@code requestLegacyExternalStorage} in the app's manifest, since an app
1356      * may inherit its legacy state based on when it was first installed, target sdk and other
1357      * factors.
1358      * <p>
1359      * Non-legacy apps can continue to discover and read media belonging to
1360      * other apps via {@link android.provider.MediaStore}.
1361      *
1362      * @throws IllegalArgumentException if the path is not a valid storage
1363      * device.
1364      */
isExternalStorageLegacy(@onNull File path)1365     public static boolean isExternalStorageLegacy(@NonNull File path) {
1366         final Context context = AppGlobals.getInitialApplication();
1367         final int uid = context.getApplicationInfo().uid;
1368         // Isolated processes and Instant apps are never allowed to be in scoped storage
1369         if (Process.isIsolated(uid) || Process.isSdkSandboxUid(uid)) {
1370             return false;
1371         }
1372 
1373         final PackageManager packageManager = context.getPackageManager();
1374         if (packageManager.isInstantApp()) {
1375             return false;
1376         }
1377 
1378         // Apps with PROPERTY_NO_APP_DATA_STORAGE should not be allowed in scoped storage
1379         final String packageName = AppGlobals.getInitialPackage();
1380         try {
1381             final PackageManager.Property noAppStorageProp = packageManager.getProperty(
1382                     PackageManager.PROPERTY_NO_APP_DATA_STORAGE, packageName);
1383             if (noAppStorageProp != null && noAppStorageProp.getBoolean()) {
1384                 return false;
1385             }
1386         } catch (PackageManager.NameNotFoundException ignore) {
1387             // Property not defined for the package
1388         }
1389 
1390         boolean defaultScopedStorage = Compatibility.isChangeEnabled(DEFAULT_SCOPED_STORAGE);
1391         boolean forceEnableScopedStorage = Compatibility.isChangeEnabled(
1392                 FORCE_ENABLE_SCOPED_STORAGE);
1393         // if Scoped Storage is strictly enforced, the app does *not* have legacy storage access
1394         // Note: does not require packagename/uid as this is directly called from an app process
1395         if (isScopedStorageEnforced(defaultScopedStorage, forceEnableScopedStorage)) {
1396             return false;
1397         }
1398         // if Scoped Storage is strictly disabled, the app has legacy storage access
1399         // Note: does not require packagename/uid as this is directly called from an app process
1400         if (isScopedStorageDisabled(defaultScopedStorage, forceEnableScopedStorage)) {
1401             return true;
1402         }
1403 
1404         final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
1405         final String opPackageName = context.getOpPackageName();
1406 
1407         if (appOps.noteOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, uid,
1408                 opPackageName) == AppOpsManager.MODE_ALLOWED) {
1409             return true;
1410         }
1411 
1412         // Legacy external storage access is granted to instrumentations invoked with
1413         // "--no-isolated-storage" flag.
1414         return appOps.noteOpNoThrow(AppOpsManager.OP_NO_ISOLATED_STORAGE, uid,
1415                 opPackageName) == AppOpsManager.MODE_ALLOWED;
1416     }
1417 
isScopedStorageEnforced(boolean defaultScopedStorage, boolean forceEnableScopedStorage)1418     private static boolean isScopedStorageEnforced(boolean defaultScopedStorage,
1419             boolean forceEnableScopedStorage) {
1420         return defaultScopedStorage && forceEnableScopedStorage;
1421     }
1422 
isScopedStorageDisabled(boolean defaultScopedStorage, boolean forceEnableScopedStorage)1423     private static boolean isScopedStorageDisabled(boolean defaultScopedStorage,
1424             boolean forceEnableScopedStorage) {
1425         return !defaultScopedStorage && !forceEnableScopedStorage;
1426     }
1427 
1428     /**
1429      * Returns whether the calling app has All Files Access on the primary shared/external storage
1430      * media.
1431      * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't
1432      * enough to gain the access.
1433      * <p>To request access, use
1434      * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
1435      */
isExternalStorageManager()1436     public static boolean isExternalStorageManager() {
1437         final File externalDir = sCurrentUser.getExternalDirs()[0];
1438         return isExternalStorageManager(externalDir);
1439     }
1440 
1441     /**
1442      * Returns whether the calling app has All Files Access at the given {@code path}
1443      * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't
1444      * enough to gain the access.
1445      * <p>To request access, use
1446      * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
1447      */
isExternalStorageManager(@onNull File path)1448     public static boolean isExternalStorageManager(@NonNull File path) {
1449         final Context context = Objects.requireNonNull(AppGlobals.getInitialApplication());
1450         String packageName = Objects.requireNonNull(context.getPackageName());
1451         int uid = context.getApplicationInfo().uid;
1452 
1453         final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
1454         final int opMode =
1455                 appOps.checkOpNoThrow(AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE, uid, packageName);
1456 
1457         switch (opMode) {
1458             case AppOpsManager.MODE_DEFAULT:
1459                 return PackageManager.PERMISSION_GRANTED
1460                         == context.checkPermission(
1461                                 Manifest.permission.MANAGE_EXTERNAL_STORAGE, Process.myPid(), uid);
1462             case AppOpsManager.MODE_ALLOWED:
1463                 return true;
1464             case AppOpsManager.MODE_ERRORED:
1465             case AppOpsManager.MODE_IGNORED:
1466                 return false;
1467             default:
1468                 throw new IllegalStateException("Unknown AppOpsManager mode " + opMode);
1469         }
1470     }
1471 
getDirectory(String variableName, String defaultPath)1472     static File getDirectory(String variableName, String defaultPath) {
1473         String path = System.getenv(variableName);
1474         return path == null ? new File(defaultPath) : new File(path);
1475     }
1476 
1477     @NonNull
getDirectoryPath(@onNull String variableName, @NonNull String defaultPath)1478     static String getDirectoryPath(@NonNull String variableName, @NonNull String defaultPath) {
1479         String path = System.getenv(variableName);
1480         return path == null ? defaultPath : path;
1481     }
1482 
1483     /** {@hide} */
setUserRequired(boolean userRequired)1484     public static void setUserRequired(boolean userRequired) {
1485         sUserRequired = userRequired;
1486     }
1487 
throwIfUserRequired()1488     private static void throwIfUserRequired() {
1489         if (sUserRequired) {
1490             Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment",
1491                     new Throwable());
1492         }
1493     }
1494 
1495     /**
1496      * Append path segments to each given base path, returning result.
1497      *
1498      * @hide
1499      */
1500     @UnsupportedAppUsage
buildPaths(File[] base, String... segments)1501     public static File[] buildPaths(File[] base, String... segments) {
1502         File[] result = new File[base.length];
1503         for (int i = 0; i < base.length; i++) {
1504             result[i] = buildPath(base[i], segments);
1505         }
1506         return result;
1507     }
1508 
1509     /**
1510      * Append path segments to given base path, returning result.
1511      *
1512      * @hide
1513      */
1514     @TestApi
buildPath(File base, String... segments)1515     public static File buildPath(File base, String... segments) {
1516         File cur = base;
1517         for (String segment : segments) {
1518             if (cur == null) {
1519                 cur = new File(segment);
1520             } else {
1521                 cur = new File(cur, segment);
1522             }
1523         }
1524         return cur;
1525     }
1526 
1527     /**
1528      * If the given path exists on emulated external storage, return the
1529      * translated backing path hosted on internal storage. This bypasses any
1530      * emulation later, improving performance. This is <em>only</em> suitable
1531      * for read-only access.
1532      * <p>
1533      * Returns original path if given path doesn't meet these criteria. Callers
1534      * must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}
1535      * permission.
1536      *
1537      * @deprecated disabled now that FUSE has been replaced by sdcardfs
1538      * @hide
1539      */
1540     @UnsupportedAppUsage
1541     @Deprecated
maybeTranslateEmulatedPathToInternal(File path)1542     public static File maybeTranslateEmulatedPathToInternal(File path) {
1543         return StorageManager.maybeTranslateEmulatedPathToInternal(path);
1544     }
1545 }
1546