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