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