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.os.storage.IMountService;
     20 import android.os.storage.StorageManager;
     21 import android.os.storage.StorageVolume;
     22 import android.text.TextUtils;
     23 import android.util.Log;
     24 
     25 import java.io.File;
     26 
     27 /**
     28  * Provides access to environment variables.
     29  */
     30 public class Environment {
     31     private static final String TAG = "Environment";
     32 
     33     private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
     34     private static final String ENV_EMULATED_STORAGE_SOURCE = "EMULATED_STORAGE_SOURCE";
     35     private static final String ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET";
     36     private static final String ENV_MEDIA_STORAGE = "MEDIA_STORAGE";
     37 
     38     /** {@hide} */
     39     public static String DIRECTORY_ANDROID = "Android";
     40 
     41     private static final File ROOT_DIRECTORY
     42             = getDirectory("ANDROID_ROOT", "/system");
     43 
     44     private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
     45 
     46     private static UserEnvironment sCurrentUser;
     47 
     48     private static final Object sLock = new Object();
     49 
     50     // @GuardedBy("sLock")
     51     private static volatile StorageVolume sPrimaryVolume;
     52 
     53     private static StorageVolume getPrimaryVolume() {
     54         if (sPrimaryVolume == null) {
     55             synchronized (sLock) {
     56                 if (sPrimaryVolume == null) {
     57                     try {
     58                         IMountService mountService = IMountService.Stub.asInterface(ServiceManager
     59                                 .getService("mount"));
     60                         final StorageVolume[] volumes = mountService.getVolumeList();
     61                         sPrimaryVolume = StorageManager.getPrimaryVolume(volumes);
     62                     } catch (Exception e) {
     63                         Log.e(TAG, "couldn't talk to MountService", e);
     64                     }
     65                 }
     66             }
     67         }
     68         return sPrimaryVolume;
     69     }
     70 
     71     static {
     72         initForCurrentUser();
     73     }
     74 
     75     /** {@hide} */
     76     public static void initForCurrentUser() {
     77         final int userId = UserHandle.myUserId();
     78         sCurrentUser = new UserEnvironment(userId);
     79 
     80         synchronized (sLock) {
     81             sPrimaryVolume = null;
     82         }
     83     }
     84 
     85     /** {@hide} */
     86     public static class UserEnvironment {
     87         // TODO: generalize further to create package-specific environment
     88 
     89         private final File mExternalStorage;
     90         private final File mExternalStorageAndroidData;
     91         private final File mExternalStorageAndroidMedia;
     92         private final File mExternalStorageAndroidObb;
     93         private final File mMediaStorage;
     94 
     95         public UserEnvironment(int userId) {
     96             // See storage config details at http://source.android.com/tech/storage/
     97             String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE);
     98             String rawEmulatedStorageTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET);
     99             String rawMediaStorage = System.getenv(ENV_MEDIA_STORAGE);
    100             if (TextUtils.isEmpty(rawMediaStorage)) {
    101                 rawMediaStorage = "/data/media";
    102             }
    103 
    104             if (!TextUtils.isEmpty(rawEmulatedStorageTarget)) {
    105                 // Device has emulated storage; external storage paths should have
    106                 // userId burned into them.
    107                 final String rawUserId = Integer.toString(userId);
    108                 final File emulatedBase = new File(rawEmulatedStorageTarget);
    109                 final File mediaBase = new File(rawMediaStorage);
    110 
    111                 // /storage/emulated/0
    112                 mExternalStorage = buildPath(emulatedBase, rawUserId);
    113                 // /data/media/0
    114                 mMediaStorage = buildPath(mediaBase, rawUserId);
    115 
    116             } else {
    117                 // Device has physical external storage; use plain paths.
    118                 if (TextUtils.isEmpty(rawExternalStorage)) {
    119                     Log.w(TAG, "EXTERNAL_STORAGE undefined; falling back to default");
    120                     rawExternalStorage = "/storage/sdcard0";
    121                 }
    122 
    123                 // /storage/sdcard0
    124                 mExternalStorage = new File(rawExternalStorage);
    125                 // /data/media
    126                 mMediaStorage = new File(rawMediaStorage);
    127             }
    128 
    129             mExternalStorageAndroidObb = buildPath(mExternalStorage, DIRECTORY_ANDROID, "obb");
    130             mExternalStorageAndroidData = buildPath(mExternalStorage, DIRECTORY_ANDROID, "data");
    131             mExternalStorageAndroidMedia = buildPath(mExternalStorage, DIRECTORY_ANDROID, "media");
    132         }
    133 
    134         public File getExternalStorageDirectory() {
    135             return mExternalStorage;
    136         }
    137 
    138         public File getExternalStorageObbDirectory() {
    139             return mExternalStorageAndroidObb;
    140         }
    141 
    142         public File getExternalStoragePublicDirectory(String type) {
    143             return new File(mExternalStorage, type);
    144         }
    145 
    146         public File getExternalStorageAndroidDataDir() {
    147             return mExternalStorageAndroidData;
    148         }
    149 
    150         public File getExternalStorageAppDataDirectory(String packageName) {
    151             return new File(mExternalStorageAndroidData, packageName);
    152         }
    153 
    154         public File getExternalStorageAppMediaDirectory(String packageName) {
    155             return new File(mExternalStorageAndroidMedia, packageName);
    156         }
    157 
    158         public File getExternalStorageAppObbDirectory(String packageName) {
    159             return new File(mExternalStorageAndroidObb, packageName);
    160         }
    161 
    162         public File getExternalStorageAppFilesDirectory(String packageName) {
    163             return new File(new File(mExternalStorageAndroidData, packageName), "files");
    164         }
    165 
    166         public File getExternalStorageAppCacheDirectory(String packageName) {
    167             return new File(new File(mExternalStorageAndroidData, packageName), "cache");
    168         }
    169 
    170         public File getMediaStorageDirectory() {
    171             return mMediaStorage;
    172         }
    173     }
    174 
    175     /**
    176      * Gets the Android root directory.
    177      */
    178     public static File getRootDirectory() {
    179         return ROOT_DIRECTORY;
    180     }
    181 
    182     /**
    183      * Gets the system directory available for secure storage.
    184      * If Encrypted File system is enabled, it returns an encrypted directory (/data/secure/system).
    185      * Otherwise, it returns the unencrypted /data/system directory.
    186      * @return File object representing the secure storage system directory.
    187      * @hide
    188      */
    189     public static File getSystemSecureDirectory() {
    190         if (isEncryptedFilesystemEnabled()) {
    191             return new File(SECURE_DATA_DIRECTORY, "system");
    192         } else {
    193             return new File(DATA_DIRECTORY, "system");
    194         }
    195     }
    196 
    197     /**
    198      * Gets the data directory for secure storage.
    199      * If Encrypted File system is enabled, it returns an encrypted directory (/data/secure).
    200      * Otherwise, it returns the unencrypted /data directory.
    201      * @return File object representing the data directory for secure storage.
    202      * @hide
    203      */
    204     public static File getSecureDataDirectory() {
    205         if (isEncryptedFilesystemEnabled()) {
    206             return SECURE_DATA_DIRECTORY;
    207         } else {
    208             return DATA_DIRECTORY;
    209         }
    210     }
    211 
    212     /**
    213      * Return directory used for internal media storage, which is protected by
    214      * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}.
    215      *
    216      * @hide
    217      */
    218     public static File getMediaStorageDirectory() {
    219         throwIfSystem();
    220         return sCurrentUser.getMediaStorageDirectory();
    221     }
    222 
    223     /**
    224      * Return the system directory for a user. This is for use by system services to store
    225      * files relating to the user. This directory will be automatically deleted when the user
    226      * is removed.
    227      *
    228      * @hide
    229      */
    230     public static File getUserSystemDirectory(int userId) {
    231         return new File(new File(getSystemSecureDirectory(), "users"), Integer.toString(userId));
    232     }
    233 
    234     /**
    235      * Returns whether the Encrypted File System feature is enabled on the device or not.
    236      * @return <code>true</code> if Encrypted File System feature is enabled, <code>false</code>
    237      * if disabled.
    238      * @hide
    239      */
    240     public static boolean isEncryptedFilesystemEnabled() {
    241         return SystemProperties.getBoolean(SYSTEM_PROPERTY_EFS_ENABLED, false);
    242     }
    243 
    244     private static final File DATA_DIRECTORY
    245             = getDirectory("ANDROID_DATA", "/data");
    246 
    247     /**
    248      * @hide
    249      */
    250     private static final File SECURE_DATA_DIRECTORY
    251             = getDirectory("ANDROID_SECURE_DATA", "/data/secure");
    252 
    253     private static final File DOWNLOAD_CACHE_DIRECTORY = getDirectory("DOWNLOAD_CACHE", "/cache");
    254 
    255     /**
    256      * Gets the Android data directory.
    257      */
    258     public static File getDataDirectory() {
    259         return DATA_DIRECTORY;
    260     }
    261 
    262     /**
    263      * Gets the Android external storage directory.  This directory may not
    264      * currently be accessible if it has been mounted by the user on their
    265      * computer, has been removed from the device, or some other problem has
    266      * happened.  You can determine its current state with
    267      * {@link #getExternalStorageState()}.
    268      *
    269      * <p><em>Note: don't be confused by the word "external" here.  This
    270      * directory can better be thought as media/shared storage.  It is a
    271      * filesystem that can hold a relatively large amount of data and that
    272      * is shared across all applications (does not enforce permissions).
    273      * Traditionally this is an SD card, but it may also be implemented as
    274      * built-in storage in a device that is distinct from the protected
    275      * internal storage and can be mounted as a filesystem on a computer.</em></p>
    276      *
    277      * <p>On devices with multiple users (as described by {@link UserManager}),
    278      * each user has their own isolated external storage. Applications only
    279      * have access to the external storage for the user they're running as.</p>
    280      *
    281      * <p>In devices with multiple "external" storage directories (such as
    282      * both secure app storage and mountable shared storage), this directory
    283      * represents the "primary" external storage that the user will interact
    284      * with.</p>
    285      *
    286      * <p>Applications should not directly use this top-level directory, in
    287      * order to avoid polluting the user's root namespace.  Any files that are
    288      * private to the application should be placed in a directory returned
    289      * by {@link android.content.Context#getExternalFilesDir
    290      * Context.getExternalFilesDir}, which the system will take care of deleting
    291      * if the application is uninstalled.  Other shared files should be placed
    292      * in one of the directories returned by
    293      * {@link #getExternalStoragePublicDirectory}.</p>
    294      *
    295      * <p>Writing to this path requires the
    296      * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission. In
    297      * a future platform release, access to this path will require the
    298      * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission,
    299      * which is automatically granted if you hold the write permission.</p>
    300      *
    301      * <p>This path may change between platform versions, so applications
    302      * should only persist relative paths.</p>
    303      *
    304      * <p>Here is an example of typical code to monitor the state of
    305      * external storage:</p>
    306      *
    307      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
    308      * monitor_storage}
    309      *
    310      * @see #getExternalStorageState()
    311      * @see #isExternalStorageRemovable()
    312      */
    313     public static File getExternalStorageDirectory() {
    314         throwIfSystem();
    315         return sCurrentUser.getExternalStorageDirectory();
    316     }
    317 
    318     /** {@hide} */
    319     public static File getLegacyExternalStorageDirectory() {
    320         return new File(System.getenv(ENV_EXTERNAL_STORAGE));
    321     }
    322 
    323     /** {@hide} */
    324     public static File getLegacyExternalStorageObbDirectory() {
    325         return buildPath(getLegacyExternalStorageDirectory(), DIRECTORY_ANDROID, "obb");
    326     }
    327 
    328     /** {@hide} */
    329     public static File getEmulatedStorageSource(int userId) {
    330         // /mnt/shell/emulated/0
    331         return new File(System.getenv(ENV_EMULATED_STORAGE_SOURCE), String.valueOf(userId));
    332     }
    333 
    334     /** {@hide} */
    335     public static File getEmulatedStorageObbSource() {
    336         // /mnt/shell/emulated/obb
    337         return new File(System.getenv(ENV_EMULATED_STORAGE_SOURCE), "obb");
    338     }
    339 
    340     /**
    341      * Standard directory in which to place any audio files that should be
    342      * in the regular list of music for the user.
    343      * This may be combined with
    344      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
    345      * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
    346      * of directories to categories a particular audio file as more than one
    347      * type.
    348      */
    349     public static String DIRECTORY_MUSIC = "Music";
    350 
    351     /**
    352      * Standard directory in which to place any audio files that should be
    353      * in the list of podcasts that the user can select (not as regular
    354      * music).
    355      * This may be combined with {@link #DIRECTORY_MUSIC},
    356      * {@link #DIRECTORY_NOTIFICATIONS},
    357      * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
    358      * of directories to categories a particular audio file as more than one
    359      * type.
    360      */
    361     public static String DIRECTORY_PODCASTS = "Podcasts";
    362 
    363     /**
    364      * Standard directory in which to place any audio files that should be
    365      * in the list of ringtones that the user can select (not as regular
    366      * music).
    367      * This may be combined with {@link #DIRECTORY_MUSIC},
    368      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and
    369      * {@link #DIRECTORY_ALARMS} as a series
    370      * of directories to categories a particular audio file as more than one
    371      * type.
    372      */
    373     public static String DIRECTORY_RINGTONES = "Ringtones";
    374 
    375     /**
    376      * Standard directory in which to place any audio files that should be
    377      * in the list of alarms that the user can select (not as regular
    378      * music).
    379      * This may be combined with {@link #DIRECTORY_MUSIC},
    380      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
    381      * and {@link #DIRECTORY_RINGTONES} as a series
    382      * of directories to categories a particular audio file as more than one
    383      * type.
    384      */
    385     public static String DIRECTORY_ALARMS = "Alarms";
    386 
    387     /**
    388      * Standard directory in which to place any audio files that should be
    389      * in the list of notifications that the user can select (not as regular
    390      * music).
    391      * This may be combined with {@link #DIRECTORY_MUSIC},
    392      * {@link #DIRECTORY_PODCASTS},
    393      * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
    394      * of directories to categories a particular audio file as more than one
    395      * type.
    396      */
    397     public static String DIRECTORY_NOTIFICATIONS = "Notifications";
    398 
    399     /**
    400      * Standard directory in which to place pictures that are available to
    401      * the user.  Note that this is primarily a convention for the top-level
    402      * public directory, as the media scanner will find and collect pictures
    403      * in any directory.
    404      */
    405     public static String DIRECTORY_PICTURES = "Pictures";
    406 
    407     /**
    408      * Standard directory in which to place movies that are available to
    409      * the user.  Note that this is primarily a convention for the top-level
    410      * public directory, as the media scanner will find and collect movies
    411      * in any directory.
    412      */
    413     public static String DIRECTORY_MOVIES = "Movies";
    414 
    415     /**
    416      * Standard directory in which to place files that have been downloaded by
    417      * the user.  Note that this is primarily a convention for the top-level
    418      * public directory, you are free to download files anywhere in your own
    419      * private directories.  Also note that though the constant here is
    420      * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for
    421      * backwards compatibility reasons.
    422      */
    423     public static String DIRECTORY_DOWNLOADS = "Download";
    424 
    425     /**
    426      * The traditional location for pictures and videos when mounting the
    427      * device as a camera.  Note that this is primarily a convention for the
    428      * top-level public directory, as this convention makes no sense elsewhere.
    429      */
    430     public static String DIRECTORY_DCIM = "DCIM";
    431 
    432     /**
    433      * Get a top-level public external storage directory for placing files of
    434      * a particular type.  This is where the user will typically place and
    435      * manage their own files, so you should be careful about what you put here
    436      * to ensure you don't erase their files or get in the way of their own
    437      * organization.
    438      *
    439      * <p>On devices with multiple users (as described by {@link UserManager}),
    440      * each user has their own isolated external storage. Applications only
    441      * have access to the external storage for the user they're running as.</p>
    442      *
    443      * <p>Here is an example of typical code to manipulate a picture on
    444      * the public external storage:</p>
    445      *
    446      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
    447      * public_picture}
    448      *
    449      * @param type The type of storage directory to return.  Should be one of
    450      * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
    451      * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
    452      * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
    453      * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, or
    454      * {@link #DIRECTORY_DCIM}.  May not be null.
    455      *
    456      * @return Returns the File path for the directory.  Note that this
    457      * directory may not yet exist, so you must make sure it exists before
    458      * using it such as with {@link File#mkdirs File.mkdirs()}.
    459      */
    460     public static File getExternalStoragePublicDirectory(String type) {
    461         throwIfSystem();
    462         return sCurrentUser.getExternalStoragePublicDirectory(type);
    463     }
    464 
    465     /**
    466      * Returns the path for android-specific data on the SD card.
    467      * @hide
    468      */
    469     public static File getExternalStorageAndroidDataDir() {
    470         throwIfSystem();
    471         return sCurrentUser.getExternalStorageAndroidDataDir();
    472     }
    473 
    474     /**
    475      * Generates the raw path to an application's data
    476      * @hide
    477      */
    478     public static File getExternalStorageAppDataDirectory(String packageName) {
    479         throwIfSystem();
    480         return sCurrentUser.getExternalStorageAppDataDirectory(packageName);
    481     }
    482 
    483     /**
    484      * Generates the raw path to an application's media
    485      * @hide
    486      */
    487     public static File getExternalStorageAppMediaDirectory(String packageName) {
    488         throwIfSystem();
    489         return sCurrentUser.getExternalStorageAppMediaDirectory(packageName);
    490     }
    491 
    492     /**
    493      * Generates the raw path to an application's OBB files
    494      * @hide
    495      */
    496     public static File getExternalStorageAppObbDirectory(String packageName) {
    497         throwIfSystem();
    498         return sCurrentUser.getExternalStorageAppObbDirectory(packageName);
    499     }
    500 
    501     /**
    502      * Generates the path to an application's files.
    503      * @hide
    504      */
    505     public static File getExternalStorageAppFilesDirectory(String packageName) {
    506         throwIfSystem();
    507         return sCurrentUser.getExternalStorageAppFilesDirectory(packageName);
    508     }
    509 
    510     /**
    511      * Generates the path to an application's cache.
    512      * @hide
    513      */
    514     public static File getExternalStorageAppCacheDirectory(String packageName) {
    515         throwIfSystem();
    516         return sCurrentUser.getExternalStorageAppCacheDirectory(packageName);
    517     }
    518 
    519     /**
    520      * Gets the Android download/cache content directory.
    521      */
    522     public static File getDownloadCacheDirectory() {
    523         return DOWNLOAD_CACHE_DIRECTORY;
    524     }
    525 
    526     /**
    527      * {@link #getExternalStorageState()} returns MEDIA_REMOVED if the media is not present.
    528      */
    529     public static final String MEDIA_REMOVED = "removed";
    530 
    531     /**
    532      * {@link #getExternalStorageState()} returns MEDIA_UNMOUNTED if the media is present
    533      * but not mounted.
    534      */
    535     public static final String MEDIA_UNMOUNTED = "unmounted";
    536 
    537     /**
    538      * {@link #getExternalStorageState()} returns MEDIA_CHECKING if the media is present
    539      * and being disk-checked
    540      */
    541     public static final String MEDIA_CHECKING = "checking";
    542 
    543     /**
    544      * {@link #getExternalStorageState()} returns MEDIA_NOFS if the media is present
    545      * but is blank or is using an unsupported filesystem
    546      */
    547     public static final String MEDIA_NOFS = "nofs";
    548 
    549     /**
    550      * {@link #getExternalStorageState()} returns MEDIA_MOUNTED if the media is present
    551      * and mounted at its mount point with read/write access.
    552      */
    553     public static final String MEDIA_MOUNTED = "mounted";
    554 
    555     /**
    556      * {@link #getExternalStorageState()} returns MEDIA_MOUNTED_READ_ONLY if the media is present
    557      * and mounted at its mount point with read only access.
    558      */
    559     public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
    560 
    561     /**
    562      * {@link #getExternalStorageState()} returns MEDIA_SHARED if the media is present
    563      * not mounted, and shared via USB mass storage.
    564      */
    565     public static final String MEDIA_SHARED = "shared";
    566 
    567     /**
    568      * {@link #getExternalStorageState()} returns MEDIA_BAD_REMOVAL if the media was
    569      * removed before it was unmounted.
    570      */
    571     public static final String MEDIA_BAD_REMOVAL = "bad_removal";
    572 
    573     /**
    574      * {@link #getExternalStorageState()} returns MEDIA_UNMOUNTABLE if the media is present
    575      * but cannot be mounted.  Typically this happens if the file system on the
    576      * media is corrupted.
    577      */
    578     public static final String MEDIA_UNMOUNTABLE = "unmountable";
    579 
    580     /**
    581      * Gets the current state of the primary "external" storage device.
    582      *
    583      * @see #getExternalStorageDirectory()
    584      */
    585     public static String getExternalStorageState() {
    586         try {
    587             IMountService mountService = IMountService.Stub.asInterface(ServiceManager
    588                     .getService("mount"));
    589             final StorageVolume primary = getPrimaryVolume();
    590             return mountService.getVolumeState(primary.getPath());
    591         } catch (RemoteException rex) {
    592             Log.w(TAG, "Failed to read external storage state; assuming REMOVED: " + rex);
    593             return Environment.MEDIA_REMOVED;
    594         }
    595     }
    596 
    597     /**
    598      * Returns whether the primary "external" storage device is removable.
    599      * If true is returned, this device is for example an SD card that the
    600      * user can remove.  If false is returned, the storage is built into
    601      * the device and can not be physically removed.
    602      *
    603      * <p>See {@link #getExternalStorageDirectory()} for more information.
    604      */
    605     public static boolean isExternalStorageRemovable() {
    606         final StorageVolume primary = getPrimaryVolume();
    607         return (primary != null && primary.isRemovable());
    608     }
    609 
    610     /**
    611      * Returns whether the device has an external storage device which is
    612      * emulated. If true, the device does not have real external storage, and the directory
    613      * returned by {@link #getExternalStorageDirectory()} will be allocated using a portion of
    614      * the internal storage system.
    615      *
    616      * <p>Certain system services, such as the package manager, use this
    617      * to determine where to install an application.
    618      *
    619      * <p>Emulated external storage may also be encrypted - see
    620      * {@link android.app.admin.DevicePolicyManager#setStorageEncryption(
    621      * android.content.ComponentName, boolean)} for additional details.
    622      */
    623     public static boolean isExternalStorageEmulated() {
    624         final StorageVolume primary = getPrimaryVolume();
    625         return (primary != null && primary.isEmulated());
    626     }
    627 
    628     static File getDirectory(String variableName, String defaultPath) {
    629         String path = System.getenv(variableName);
    630         return path == null ? new File(defaultPath) : new File(path);
    631     }
    632 
    633     private static void throwIfSystem() {
    634         if (Process.myUid() == Process.SYSTEM_UID) {
    635             Log.wtf(TAG, "Static storage paths aren't available from AID_SYSTEM", new Throwable());
    636         }
    637     }
    638 
    639     private static File buildPath(File base, String... segments) {
    640         File cur = base;
    641         for (String segment : segments) {
    642             if (cur == null) {
    643                 cur = new File(segment);
    644             } else {
    645                 cur = new File(cur, segment);
    646             }
    647         }
    648         return cur;
    649     }
    650 }
    651