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