Home | History | Annotate | Download | only in os
      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.app.admin.DevicePolicyManager;
     20 import android.content.Context;
     21 import android.os.storage.IMountService;
     22 import android.os.storage.StorageVolume;
     23 import android.text.TextUtils;
     24 import android.util.Log;
     25 
     26 import com.google.android.collect.Lists;
     27 
     28 import java.io.File;
     29 import java.io.IOException;
     30 import java.util.ArrayList;
     31 
     32 /**
     33  * Provides access to environment variables.
     34  */
     35 public class Environment {
     36     private static final String TAG = "Environment";
     37 
     38     private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
     39     private static final String ENV_EMULATED_STORAGE_SOURCE = "EMULATED_STORAGE_SOURCE";
     40     private static final String ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET";
     41     private static final String ENV_MEDIA_STORAGE = "MEDIA_STORAGE";
     42     private static final String ENV_SECONDARY_STORAGE = "SECONDARY_STORAGE";
     43     private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
     44     private static final String ENV_OEM_ROOT = "OEM_ROOT";
     45     private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
     46 
     47     /** {@hide} */
     48     public static final String DIR_ANDROID = "Android";
     49     private static final String DIR_DATA = "data";
     50     private static final String DIR_MEDIA = "media";
     51     private static final String DIR_OBB = "obb";
     52     private static final String DIR_FILES = "files";
     53     private static final String DIR_CACHE = "cache";
     54 
     55     /** {@hide} */
     56     @Deprecated
     57     public static final String DIRECTORY_ANDROID = DIR_ANDROID;
     58 
     59     private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
     60     private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
     61     private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
     62     private static final File DIR_MEDIA_STORAGE = getDirectory(ENV_MEDIA_STORAGE, "/data/media");
     63 
     64     private static final String CANONCIAL_EMULATED_STORAGE_TARGET = getCanonicalPathOrNull(
     65             ENV_EMULATED_STORAGE_TARGET);
     66 
     67     private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
     68 
     69     private static UserEnvironment sCurrentUser;
     70     private static boolean sUserRequired;
     71 
     72     static {
     73         initForCurrentUser();
     74     }
     75 
     76     /** {@hide} */
     77     public static void initForCurrentUser() {
     78         final int userId = UserHandle.myUserId();
     79         sCurrentUser = new UserEnvironment(userId);
     80     }
     81 
     82     /** {@hide} */
     83     public static class UserEnvironment {
     84         // TODO: generalize further to create package-specific environment
     85 
     86         /** External storage dirs, as visible to vold */
     87         private final File[] mExternalDirsForVold;
     88         /** External storage dirs, as visible to apps */
     89         private final File[] mExternalDirsForApp;
     90         /** Primary emulated storage dir for direct access */
     91         private final File mEmulatedDirForDirect;
     92 
     93         public UserEnvironment(int userId) {
     94             // See storage config details at http://source.android.com/tech/storage/
     95             String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE);
     96             String rawEmulatedSource = System.getenv(ENV_EMULATED_STORAGE_SOURCE);
     97             String rawEmulatedTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET);
     98 
     99             String rawMediaStorage = System.getenv(ENV_MEDIA_STORAGE);
    100             if (TextUtils.isEmpty(rawMediaStorage)) {
    101                 rawMediaStorage = "/data/media";
    102             }
    103 
    104             ArrayList<File> externalForVold = Lists.newArrayList();
    105             ArrayList<File> externalForApp = Lists.newArrayList();
    106 
    107             if (!TextUtils.isEmpty(rawEmulatedTarget)) {
    108                 // Device has emulated storage; external storage paths should have
    109                 // userId burned into them.
    110                 final String rawUserId = Integer.toString(userId);
    111                 final File emulatedSourceBase = new File(rawEmulatedSource);
    112                 final File emulatedTargetBase = new File(rawEmulatedTarget);
    113                 final File mediaBase = new File(rawMediaStorage);
    114 
    115                 // /storage/emulated/0
    116                 externalForVold.add(buildPath(emulatedSourceBase, rawUserId));
    117                 externalForApp.add(buildPath(emulatedTargetBase, rawUserId));
    118                 // /data/media/0
    119                 mEmulatedDirForDirect = buildPath(mediaBase, rawUserId);
    120 
    121             } else {
    122                 // Device has physical external storage; use plain paths.
    123                 if (TextUtils.isEmpty(rawExternalStorage)) {
    124                     Log.w(TAG, "EXTERNAL_STORAGE undefined; falling back to default");
    125                     rawExternalStorage = "/storage/sdcard0";
    126                 }
    127 
    128                 // /storage/sdcard0
    129                 externalForVold.add(new File(rawExternalStorage));
    130                 externalForApp.add(new File(rawExternalStorage));
    131                 // /data/media
    132                 mEmulatedDirForDirect = new File(rawMediaStorage);
    133             }
    134 
    135             // Splice in any secondary storage paths, but only for owner
    136             final String rawSecondaryStorage = System.getenv(ENV_SECONDARY_STORAGE);
    137             if (!TextUtils.isEmpty(rawSecondaryStorage) && userId == UserHandle.USER_OWNER) {
    138                 for (String secondaryPath : rawSecondaryStorage.split(":")) {
    139                     externalForVold.add(new File(secondaryPath));
    140                     externalForApp.add(new File(secondaryPath));
    141                 }
    142             }
    143 
    144             mExternalDirsForVold = externalForVold.toArray(new File[externalForVold.size()]);
    145             mExternalDirsForApp = externalForApp.toArray(new File[externalForApp.size()]);
    146         }
    147 
    148         @Deprecated
    149         public File getExternalStorageDirectory() {
    150             return mExternalDirsForApp[0];
    151         }
    152 
    153         @Deprecated
    154         public File getExternalStoragePublicDirectory(String type) {
    155             return buildExternalStoragePublicDirs(type)[0];
    156         }
    157 
    158         public File[] getExternalDirsForVold() {
    159             return mExternalDirsForVold;
    160         }
    161 
    162         public File[] getExternalDirsForApp() {
    163             return mExternalDirsForApp;
    164         }
    165 
    166         public File getMediaDir() {
    167             return mEmulatedDirForDirect;
    168         }
    169 
    170         public File[] buildExternalStoragePublicDirs(String type) {
    171             return buildPaths(mExternalDirsForApp, type);
    172         }
    173 
    174         public File[] buildExternalStorageAndroidDataDirs() {
    175             return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA);
    176         }
    177 
    178         public File[] buildExternalStorageAndroidObbDirs() {
    179             return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_OBB);
    180         }
    181 
    182         public File[] buildExternalStorageAppDataDirs(String packageName) {
    183             return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName);
    184         }
    185 
    186         public File[] buildExternalStorageAppDataDirsForVold(String packageName) {
    187             return buildPaths(mExternalDirsForVold, DIR_ANDROID, DIR_DATA, packageName);
    188         }
    189 
    190         public File[] buildExternalStorageAppMediaDirs(String packageName) {
    191             return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_MEDIA, packageName);
    192         }
    193 
    194         public File[] buildExternalStorageAppMediaDirsForVold(String packageName) {
    195             return buildPaths(mExternalDirsForVold, DIR_ANDROID, DIR_MEDIA, packageName);
    196         }
    197 
    198         public File[] buildExternalStorageAppObbDirs(String packageName) {
    199             return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_OBB, packageName);
    200         }
    201 
    202         public File[] buildExternalStorageAppObbDirsForVold(String packageName) {
    203             return buildPaths(mExternalDirsForVold, DIR_ANDROID, DIR_OBB, packageName);
    204         }
    205 
    206         public File[] buildExternalStorageAppFilesDirs(String packageName) {
    207             return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName, DIR_FILES);
    208         }
    209 
    210         public File[] buildExternalStorageAppCacheDirs(String packageName) {
    211             return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE);
    212         }
    213     }
    214 
    215     /**
    216      * Return root of the "system" partition holding the core Android OS.
    217      * Always present and mounted read-only.
    218      */
    219     public static File getRootDirectory() {
    220         return DIR_ANDROID_ROOT;
    221     }
    222 
    223     /**
    224      * Return root directory of the "oem" partition holding OEM customizations,
    225      * if any. If present, the partition is mounted read-only.
    226      *
    227      * @hide
    228      */
    229     public static File getOemDirectory() {
    230         return DIR_OEM_ROOT;
    231     }
    232 
    233     /**
    234      * Return root directory of the "vendor" partition that holds vendor-provided
    235      * software that should persist across simple reflashing of the "system" partition.
    236      * @hide
    237      */
    238     public static File getVendorDirectory() {
    239         return DIR_VENDOR_ROOT;
    240     }
    241 
    242     /**
    243      * Gets the system directory available for secure storage.
    244      * If Encrypted File system is enabled, it returns an encrypted directory (/data/secure/system).
    245      * Otherwise, it returns the unencrypted /data/system directory.
    246      * @return File object representing the secure storage system directory.
    247      * @hide
    248      */
    249     public static File getSystemSecureDirectory() {
    250         if (isEncryptedFilesystemEnabled()) {
    251             return new File(SECURE_DATA_DIRECTORY, "system");
    252         } else {
    253             return new File(DATA_DIRECTORY, "system");
    254         }
    255     }
    256 
    257     /**
    258      * Gets the data directory for secure storage.
    259      * If Encrypted File system is enabled, it returns an encrypted directory (/data/secure).
    260      * Otherwise, it returns the unencrypted /data directory.
    261      * @return File object representing the data directory for secure storage.
    262      * @hide
    263      */
    264     public static File getSecureDataDirectory() {
    265         if (isEncryptedFilesystemEnabled()) {
    266             return SECURE_DATA_DIRECTORY;
    267         } else {
    268             return DATA_DIRECTORY;
    269         }
    270     }
    271 
    272     /**
    273      * Return directory used for internal media storage, which is protected by
    274      * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}.
    275      *
    276      * @hide
    277      */
    278     public static File getMediaStorageDirectory() {
    279         throwIfUserRequired();
    280         return sCurrentUser.getMediaDir();
    281     }
    282 
    283     /**
    284      * Return the system directory for a user. This is for use by system services to store
    285      * files relating to the user. This directory will be automatically deleted when the user
    286      * is removed.
    287      *
    288      * @hide
    289      */
    290     public static File getUserSystemDirectory(int userId) {
    291         return new File(new File(getSystemSecureDirectory(), "users"), Integer.toString(userId));
    292     }
    293 
    294     /**
    295      * Returns the config directory for a user. This is for use by system services to store files
    296      * relating to the user which should be readable by any app running as that user.
    297      *
    298      * @hide
    299      */
    300     public static File getUserConfigDirectory(int userId) {
    301         return new File(new File(new File(
    302                 getDataDirectory(), "misc"), "user"), Integer.toString(userId));
    303     }
    304 
    305     /**
    306      * Returns whether the Encrypted File System feature is enabled on the device or not.
    307      * @return <code>true</code> if Encrypted File System feature is enabled, <code>false</code>
    308      * if disabled.
    309      * @hide
    310      */
    311     public static boolean isEncryptedFilesystemEnabled() {
    312         return SystemProperties.getBoolean(SYSTEM_PROPERTY_EFS_ENABLED, false);
    313     }
    314 
    315     private static final File DATA_DIRECTORY
    316             = getDirectory("ANDROID_DATA", "/data");
    317 
    318     /**
    319      * @hide
    320      */
    321     private static final File SECURE_DATA_DIRECTORY
    322             = getDirectory("ANDROID_SECURE_DATA", "/data/secure");
    323 
    324     private static final File DOWNLOAD_CACHE_DIRECTORY = getDirectory("DOWNLOAD_CACHE", "/cache");
    325 
    326     /**
    327      * Return the user data directory.
    328      */
    329     public static File getDataDirectory() {
    330         return DATA_DIRECTORY;
    331     }
    332 
    333     /**
    334      * Return the primary external storage directory. This directory may not
    335      * currently be accessible if it has been mounted by the user on their
    336      * computer, has been removed from the device, or some other problem has
    337      * happened. You can determine its current state with
    338      * {@link #getExternalStorageState()}.
    339      * <p>
    340      * <em>Note: don't be confused by the word "external" here. This directory
    341      * can better be thought as media/shared storage. It is a filesystem that
    342      * can hold a relatively large amount of data and that is shared across all
    343      * applications (does not enforce permissions). Traditionally this is an SD
    344      * card, but it may also be implemented as built-in storage in a device that
    345      * is distinct from the protected internal storage and can be mounted as a
    346      * filesystem on a computer.</em>
    347      * <p>
    348      * On devices with multiple users (as described by {@link UserManager}),
    349      * each user has their own isolated external storage. Applications only have
    350      * access to the external storage for the user they're running as.
    351      * <p>
    352      * In devices with multiple "external" storage directories, this directory
    353      * represents the "primary" external storage that the user will interact
    354      * with. Access to secondary storage is available through
    355      * <p>
    356      * Applications should not directly use this top-level directory, in order
    357      * to avoid polluting the user's root namespace. Any files that are private
    358      * to the application should be placed in a directory returned by
    359      * {@link android.content.Context#getExternalFilesDir
    360      * Context.getExternalFilesDir}, which the system will take care of deleting
    361      * if the application is uninstalled. Other shared files should be placed in
    362      * one of the directories returned by
    363      * {@link #getExternalStoragePublicDirectory}.
    364      * <p>
    365      * Writing to this path requires the
    366      * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission,
    367      * and starting in read access requires the
    368      * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission,
    369      * which is automatically granted if you hold the write permission.
    370      * <p>
    371      * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your
    372      * application only needs to store internal data, consider using
    373      * {@link Context#getExternalFilesDir(String)} or
    374      * {@link Context#getExternalCacheDir()}, which require no permissions to
    375      * read or write.
    376      * <p>
    377      * This path may change between platform versions, so applications should
    378      * only persist relative paths.
    379      * <p>
    380      * Here is an example of typical code to monitor the state of external
    381      * storage:
    382      * <p>
    383      * {@sample
    384      * development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
    385      * monitor_storage}
    386      *
    387      * @see #getExternalStorageState()
    388      * @see #isExternalStorageRemovable()
    389      */
    390     public static File getExternalStorageDirectory() {
    391         throwIfUserRequired();
    392         return sCurrentUser.getExternalDirsForApp()[0];
    393     }
    394 
    395     /** {@hide} */
    396     public static File getLegacyExternalStorageDirectory() {
    397         return new File(System.getenv(ENV_EXTERNAL_STORAGE));
    398     }
    399 
    400     /** {@hide} */
    401     public static File getLegacyExternalStorageObbDirectory() {
    402         return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB);
    403     }
    404 
    405     /** {@hide} */
    406     public static File getEmulatedStorageSource(int userId) {
    407         // /mnt/shell/emulated/0
    408         return new File(System.getenv(ENV_EMULATED_STORAGE_SOURCE), String.valueOf(userId));
    409     }
    410 
    411     /** {@hide} */
    412     public static File getEmulatedStorageObbSource() {
    413         // /mnt/shell/emulated/obb
    414         return new File(System.getenv(ENV_EMULATED_STORAGE_SOURCE), DIR_OBB);
    415     }
    416 
    417     /**
    418      * Standard directory in which to place any audio files that should be
    419      * in the regular list of music for the user.
    420      * This may be combined with
    421      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
    422      * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
    423      * of directories to categories a particular audio file as more than one
    424      * type.
    425      */
    426     public static String DIRECTORY_MUSIC = "Music";
    427 
    428     /**
    429      * Standard directory in which to place any audio files that should be
    430      * in the list of podcasts that the user can select (not as regular
    431      * music).
    432      * This may be combined with {@link #DIRECTORY_MUSIC},
    433      * {@link #DIRECTORY_NOTIFICATIONS},
    434      * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
    435      * of directories to categories a particular audio file as more than one
    436      * type.
    437      */
    438     public static String DIRECTORY_PODCASTS = "Podcasts";
    439 
    440     /**
    441      * Standard directory in which to place any audio files that should be
    442      * in the list of ringtones that the user can select (not as regular
    443      * music).
    444      * This may be combined with {@link #DIRECTORY_MUSIC},
    445      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and
    446      * {@link #DIRECTORY_ALARMS} as a series
    447      * of directories to categories a particular audio file as more than one
    448      * type.
    449      */
    450     public static String DIRECTORY_RINGTONES = "Ringtones";
    451 
    452     /**
    453      * Standard directory in which to place any audio files that should be
    454      * in the list of alarms that the user can select (not as regular
    455      * music).
    456      * This may be combined with {@link #DIRECTORY_MUSIC},
    457      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
    458      * and {@link #DIRECTORY_RINGTONES} as a series
    459      * of directories to categories a particular audio file as more than one
    460      * type.
    461      */
    462     public static String DIRECTORY_ALARMS = "Alarms";
    463 
    464     /**
    465      * Standard directory in which to place any audio files that should be
    466      * in the list of notifications that the user can select (not as regular
    467      * music).
    468      * This may be combined with {@link #DIRECTORY_MUSIC},
    469      * {@link #DIRECTORY_PODCASTS},
    470      * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
    471      * of directories to categories a particular audio file as more than one
    472      * type.
    473      */
    474     public static String DIRECTORY_NOTIFICATIONS = "Notifications";
    475 
    476     /**
    477      * Standard directory in which to place pictures that are available to
    478      * the user.  Note that this is primarily a convention for the top-level
    479      * public directory, as the media scanner will find and collect pictures
    480      * in any directory.
    481      */
    482     public static String DIRECTORY_PICTURES = "Pictures";
    483 
    484     /**
    485      * Standard directory in which to place movies that are available to
    486      * the user.  Note that this is primarily a convention for the top-level
    487      * public directory, as the media scanner will find and collect movies
    488      * in any directory.
    489      */
    490     public static String DIRECTORY_MOVIES = "Movies";
    491 
    492     /**
    493      * Standard directory in which to place files that have been downloaded by
    494      * the user.  Note that this is primarily a convention for the top-level
    495      * public directory, you are free to download files anywhere in your own
    496      * private directories.  Also note that though the constant here is
    497      * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for
    498      * backwards compatibility reasons.
    499      */
    500     public static String DIRECTORY_DOWNLOADS = "Download";
    501 
    502     /**
    503      * The traditional location for pictures and videos when mounting the
    504      * device as a camera.  Note that this is primarily a convention for the
    505      * top-level public directory, as this convention makes no sense elsewhere.
    506      */
    507     public static String DIRECTORY_DCIM = "DCIM";
    508 
    509     /**
    510      * Standard directory in which to place documents that have been created by
    511      * the user.
    512      */
    513     public static String DIRECTORY_DOCUMENTS = "Documents";
    514 
    515     /**
    516      * Get a top-level public external storage directory for placing files of
    517      * a particular type.  This is where the user will typically place and
    518      * manage their own files, so you should be careful about what you put here
    519      * to ensure you don't erase their files or get in the way of their own
    520      * organization.
    521      *
    522      * <p>On devices with multiple users (as described by {@link UserManager}),
    523      * each user has their own isolated external storage. Applications only
    524      * have access to the external storage for the user they're running as.</p>
    525      *
    526      * <p>Here is an example of typical code to manipulate a picture on
    527      * the public external storage:</p>
    528      *
    529      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
    530      * public_picture}
    531      *
    532      * @param type The type of storage directory to return.  Should be one of
    533      * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
    534      * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
    535      * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
    536      * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, or
    537      * {@link #DIRECTORY_DCIM}.  May not be null.
    538      *
    539      * @return Returns the File path for the directory.  Note that this
    540      * directory may not yet exist, so you must make sure it exists before
    541      * using it such as with {@link File#mkdirs File.mkdirs()}.
    542      */
    543     public static File getExternalStoragePublicDirectory(String type) {
    544         throwIfUserRequired();
    545         return sCurrentUser.buildExternalStoragePublicDirs(type)[0];
    546     }
    547 
    548     /**
    549      * Returns the path for android-specific data on the SD card.
    550      * @hide
    551      */
    552     public static File[] buildExternalStorageAndroidDataDirs() {
    553         throwIfUserRequired();
    554         return sCurrentUser.buildExternalStorageAndroidDataDirs();
    555     }
    556 
    557     /**
    558      * Generates the raw path to an application's data
    559      * @hide
    560      */
    561     public static File[] buildExternalStorageAppDataDirs(String packageName) {
    562         throwIfUserRequired();
    563         return sCurrentUser.buildExternalStorageAppDataDirs(packageName);
    564     }
    565 
    566     /**
    567      * Generates the raw path to an application's media
    568      * @hide
    569      */
    570     public static File[] buildExternalStorageAppMediaDirs(String packageName) {
    571         throwIfUserRequired();
    572         return sCurrentUser.buildExternalStorageAppMediaDirs(packageName);
    573     }
    574 
    575     /**
    576      * Generates the raw path to an application's OBB files
    577      * @hide
    578      */
    579     public static File[] buildExternalStorageAppObbDirs(String packageName) {
    580         throwIfUserRequired();
    581         return sCurrentUser.buildExternalStorageAppObbDirs(packageName);
    582     }
    583 
    584     /**
    585      * Generates the path to an application's files.
    586      * @hide
    587      */
    588     public static File[] buildExternalStorageAppFilesDirs(String packageName) {
    589         throwIfUserRequired();
    590         return sCurrentUser.buildExternalStorageAppFilesDirs(packageName);
    591     }
    592 
    593     /**
    594      * Generates the path to an application's cache.
    595      * @hide
    596      */
    597     public static File[] buildExternalStorageAppCacheDirs(String packageName) {
    598         throwIfUserRequired();
    599         return sCurrentUser.buildExternalStorageAppCacheDirs(packageName);
    600     }
    601 
    602     /**
    603      * Return the download/cache content directory.
    604      */
    605     public static File getDownloadCacheDirectory() {
    606         return DOWNLOAD_CACHE_DIRECTORY;
    607     }
    608 
    609     /**
    610      * Unknown storage state, such as when a path isn't backed by known storage
    611      * media.
    612      *
    613      * @see #getExternalStorageState(File)
    614      */
    615     public static final String MEDIA_UNKNOWN = "unknown";
    616 
    617     /**
    618      * Storage state if the media is not present.
    619      *
    620      * @see #getExternalStorageState(File)
    621      */
    622     public static final String MEDIA_REMOVED = "removed";
    623 
    624     /**
    625      * Storage state if the media is present but not mounted.
    626      *
    627      * @see #getExternalStorageState(File)
    628      */
    629     public static final String MEDIA_UNMOUNTED = "unmounted";
    630 
    631     /**
    632      * Storage state if the media is present and being disk-checked.
    633      *
    634      * @see #getExternalStorageState(File)
    635      */
    636     public static final String MEDIA_CHECKING = "checking";
    637 
    638     /**
    639      * Storage state if the media is present but is blank or is using an
    640      * unsupported filesystem.
    641      *
    642      * @see #getExternalStorageState(File)
    643      */
    644     public static final String MEDIA_NOFS = "nofs";
    645 
    646     /**
    647      * Storage state if the media is present and mounted at its mount point with
    648      * read/write access.
    649      *
    650      * @see #getExternalStorageState(File)
    651      */
    652     public static final String MEDIA_MOUNTED = "mounted";
    653 
    654     /**
    655      * Storage state if the media is present and mounted at its mount point with
    656      * read-only access.
    657      *
    658      * @see #getExternalStorageState(File)
    659      */
    660     public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
    661 
    662     /**
    663      * Storage state if the media is present not mounted, and shared via USB
    664      * mass storage.
    665      *
    666      * @see #getExternalStorageState(File)
    667      */
    668     public static final String MEDIA_SHARED = "shared";
    669 
    670     /**
    671      * Storage state if the media was removed before it was unmounted.
    672      *
    673      * @see #getExternalStorageState(File)
    674      */
    675     public static final String MEDIA_BAD_REMOVAL = "bad_removal";
    676 
    677     /**
    678      * Storage state if the media is present but cannot be mounted. Typically
    679      * this happens if the file system on the media is corrupted.
    680      *
    681      * @see #getExternalStorageState(File)
    682      */
    683     public static final String MEDIA_UNMOUNTABLE = "unmountable";
    684 
    685     /**
    686      * Returns the current state of the primary "external" storage device.
    687      *
    688      * @see #getExternalStorageDirectory()
    689      * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
    690      *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
    691      *         {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
    692      *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
    693      *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
    694      */
    695     public static String getExternalStorageState() {
    696         final File externalDir = sCurrentUser.getExternalDirsForApp()[0];
    697         return getExternalStorageState(externalDir);
    698     }
    699 
    700     /**
    701      * @deprecated use {@link #getExternalStorageState(File)}
    702      */
    703     @Deprecated
    704     public static String getStorageState(File path) {
    705         return getExternalStorageState(path);
    706     }
    707 
    708     /**
    709      * Returns the current state of the storage device that provides the given
    710      * path.
    711      *
    712      * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
    713      *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
    714      *         {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
    715      *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
    716      *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
    717      */
    718     public static String getExternalStorageState(File path) {
    719         final StorageVolume volume = getStorageVolume(path);
    720         if (volume != null) {
    721             final IMountService mountService = IMountService.Stub.asInterface(
    722                     ServiceManager.getService("mount"));
    723             try {
    724                 return mountService.getVolumeState(volume.getPath());
    725             } catch (RemoteException e) {
    726             }
    727         }
    728 
    729         return Environment.MEDIA_UNKNOWN;
    730     }
    731 
    732     /**
    733      * Returns whether the primary "external" storage device is removable.
    734      *
    735      * @return true if the storage device can be removed (such as an SD card),
    736      *         or false if the storage device is built in and cannot be
    737      *         physically removed.
    738      */
    739     public static boolean isExternalStorageRemovable() {
    740         if (isStorageDisabled()) return false;
    741         final File externalDir = sCurrentUser.getExternalDirsForApp()[0];
    742         return isExternalStorageRemovable(externalDir);
    743     }
    744 
    745     /**
    746      * Returns whether the storage device that provides the given path is
    747      * removable.
    748      *
    749      * @return true if the storage device can be removed (such as an SD card),
    750      *         or false if the storage device is built in and cannot be
    751      *         physically removed.
    752      * @throws IllegalArgumentException if the path is not a valid storage
    753      *             device.
    754      */
    755     public static boolean isExternalStorageRemovable(File path) {
    756         final StorageVolume volume = getStorageVolume(path);
    757         if (volume != null) {
    758             return volume.isRemovable();
    759         } else {
    760             throw new IllegalArgumentException("Failed to find storage device at " + path);
    761         }
    762     }
    763 
    764     /**
    765      * Returns whether the primary "external" storage device is emulated. If
    766      * true, data stored on this device will be stored on a portion of the
    767      * internal storage system.
    768      *
    769      * @see DevicePolicyManager#setStorageEncryption(android.content.ComponentName,
    770      *      boolean)
    771      */
    772     public static boolean isExternalStorageEmulated() {
    773         if (isStorageDisabled()) return false;
    774         final File externalDir = sCurrentUser.getExternalDirsForApp()[0];
    775         return isExternalStorageEmulated(externalDir);
    776     }
    777 
    778     /**
    779      * Returns whether the storage device that provides the given path is
    780      * emulated. If true, data stored on this device will be stored on a portion
    781      * of the internal storage system.
    782      *
    783      * @throws IllegalArgumentException if the path is not a valid storage
    784      *             device.
    785      */
    786     public static boolean isExternalStorageEmulated(File path) {
    787         final StorageVolume volume = getStorageVolume(path);
    788         if (volume != null) {
    789             return volume.isEmulated();
    790         } else {
    791             throw new IllegalArgumentException("Failed to find storage device at " + path);
    792         }
    793     }
    794 
    795     static File getDirectory(String variableName, String defaultPath) {
    796         String path = System.getenv(variableName);
    797         return path == null ? new File(defaultPath) : new File(path);
    798     }
    799 
    800     private static String getCanonicalPathOrNull(String variableName) {
    801         String path = System.getenv(variableName);
    802         if (path == null) {
    803             return null;
    804         }
    805         try {
    806             return new File(path).getCanonicalPath();
    807         } catch (IOException e) {
    808             Log.w(TAG, "Unable to resolve canonical path for " + path);
    809             return null;
    810         }
    811     }
    812 
    813     /** {@hide} */
    814     public static void setUserRequired(boolean userRequired) {
    815         sUserRequired = userRequired;
    816     }
    817 
    818     private static void throwIfUserRequired() {
    819         if (sUserRequired) {
    820             Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment",
    821                     new Throwable());
    822         }
    823     }
    824 
    825     /**
    826      * Append path segments to each given base path, returning result.
    827      *
    828      * @hide
    829      */
    830     public static File[] buildPaths(File[] base, String... segments) {
    831         File[] result = new File[base.length];
    832         for (int i = 0; i < base.length; i++) {
    833             result[i] = buildPath(base[i], segments);
    834         }
    835         return result;
    836     }
    837 
    838     /**
    839      * Append path segments to given base path, returning result.
    840      *
    841      * @hide
    842      */
    843     public static File buildPath(File base, String... segments) {
    844         File cur = base;
    845         for (String segment : segments) {
    846             if (cur == null) {
    847                 cur = new File(segment);
    848             } else {
    849                 cur = new File(cur, segment);
    850             }
    851         }
    852         return cur;
    853     }
    854 
    855     private static boolean isStorageDisabled() {
    856         return SystemProperties.getBoolean("config.disable_storage", false);
    857     }
    858 
    859     private static StorageVolume getStorageVolume(File path) {
    860         try {
    861             path = path.getCanonicalFile();
    862         } catch (IOException e) {
    863             return null;
    864         }
    865 
    866         try {
    867             final IMountService mountService = IMountService.Stub.asInterface(
    868                     ServiceManager.getService("mount"));
    869             final StorageVolume[] volumes = mountService.getVolumeList();
    870             for (StorageVolume volume : volumes) {
    871                 if (FileUtils.contains(volume.getPathFile(), path)) {
    872                     return volume;
    873                 }
    874             }
    875         } catch (RemoteException e) {
    876         }
    877 
    878         return null;
    879     }
    880 
    881     /**
    882      * If the given path exists on emulated external storage, return the
    883      * translated backing path hosted on internal storage. This bypasses any
    884      * emulation later, improving performance. This is <em>only</em> suitable
    885      * for read-only access.
    886      * <p>
    887      * Returns original path if given path doesn't meet these criteria. Callers
    888      * must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}
    889      * permission.
    890      *
    891      * @hide
    892      */
    893     public static File maybeTranslateEmulatedPathToInternal(File path) {
    894         // Fast return if not emulated, or missing variables
    895         if (!Environment.isExternalStorageEmulated()
    896                 || CANONCIAL_EMULATED_STORAGE_TARGET == null) {
    897             return path;
    898         }
    899 
    900         try {
    901             final String rawPath = path.getCanonicalPath();
    902             if (rawPath.startsWith(CANONCIAL_EMULATED_STORAGE_TARGET)) {
    903                 final File internalPath = new File(DIR_MEDIA_STORAGE,
    904                         rawPath.substring(CANONCIAL_EMULATED_STORAGE_TARGET.length()));
    905                 if (internalPath.exists()) {
    906                     return internalPath;
    907                 }
    908             }
    909         } catch (IOException e) {
    910             Log.w(TAG, "Failed to resolve canonical path for " + path);
    911         }
    912 
    913         // Unable to translate to internal path; use original
    914         return path;
    915     }
    916 }
    917