Environment.java revision 4fbbda4cecb078bd3867f416b02cc75f5455284f
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
17package android.os;
18
19import android.os.storage.IMountService;
20import android.os.storage.StorageManager;
21import android.os.storage.StorageVolume;
22import android.text.TextUtils;
23import android.util.Log;
24
25import java.io.File;
26
27/**
28 * Provides access to environment variables.
29 */
30public 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>In devices with multiple "external" storage directories (such as
278     * both secure app storage and mountable shared storage), this directory
279     * represents the "primary" external storage that the user will interact
280     * with.</p>
281     *
282     * <p>Applications should not directly use this top-level directory, in
283     * order to avoid polluting the user's root namespace.  Any files that are
284     * private to the application should be placed in a directory returned
285     * by {@link android.content.Context#getExternalFilesDir
286     * Context.getExternalFilesDir}, which the system will take care of deleting
287     * if the application is uninstalled.  Other shared files should be placed
288     * in one of the directories returned by
289     * {@link #getExternalStoragePublicDirectory}.
290     *
291     * <p>Here is an example of typical code to monitor the state of
292     * external storage:</p>
293     *
294     * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
295     * monitor_storage}
296     *
297     * @see #getExternalStorageState()
298     * @see #isExternalStorageRemovable()
299     */
300    public static File getExternalStorageDirectory() {
301        throwIfSystem();
302        return sCurrentUser.getExternalStorageDirectory();
303    }
304
305    /** {@hide} */
306    public static File getLegacyExternalStorageDirectory() {
307        return new File(System.getenv(ENV_EXTERNAL_STORAGE));
308    }
309
310    /** {@hide} */
311    public static File getLegacyExternalStorageObbDirectory() {
312        return buildPath(getLegacyExternalStorageDirectory(), DIRECTORY_ANDROID, "obb");
313    }
314
315    /** {@hide} */
316    public static File getEmulatedStorageSource(int userId) {
317        // /mnt/shell/emulated/0
318        return new File(System.getenv(ENV_EMULATED_STORAGE_SOURCE), String.valueOf(userId));
319    }
320
321    /** {@hide} */
322    public static File getEmulatedStorageObbSource() {
323        // /mnt/shell/emulated/obb
324        return new File(System.getenv(ENV_EMULATED_STORAGE_SOURCE), "obb");
325    }
326
327    /**
328     * Standard directory in which to place any audio files that should be
329     * in the regular list of music for the user.
330     * This may be combined with
331     * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
332     * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
333     * of directories to categories a particular audio file as more than one
334     * type.
335     */
336    public static String DIRECTORY_MUSIC = "Music";
337
338    /**
339     * Standard directory in which to place any audio files that should be
340     * in the list of podcasts that the user can select (not as regular
341     * music).
342     * This may be combined with {@link #DIRECTORY_MUSIC},
343     * {@link #DIRECTORY_NOTIFICATIONS},
344     * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
345     * of directories to categories a particular audio file as more than one
346     * type.
347     */
348    public static String DIRECTORY_PODCASTS = "Podcasts";
349
350    /**
351     * Standard directory in which to place any audio files that should be
352     * in the list of ringtones that the user can select (not as regular
353     * music).
354     * This may be combined with {@link #DIRECTORY_MUSIC},
355     * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and
356     * {@link #DIRECTORY_ALARMS} as a series
357     * of directories to categories a particular audio file as more than one
358     * type.
359     */
360    public static String DIRECTORY_RINGTONES = "Ringtones";
361
362    /**
363     * Standard directory in which to place any audio files that should be
364     * in the list of alarms that the user can select (not as regular
365     * music).
366     * This may be combined with {@link #DIRECTORY_MUSIC},
367     * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
368     * and {@link #DIRECTORY_RINGTONES} as a series
369     * of directories to categories a particular audio file as more than one
370     * type.
371     */
372    public static String DIRECTORY_ALARMS = "Alarms";
373
374    /**
375     * Standard directory in which to place any audio files that should be
376     * in the list of notifications that the user can select (not as regular
377     * music).
378     * This may be combined with {@link #DIRECTORY_MUSIC},
379     * {@link #DIRECTORY_PODCASTS},
380     * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
381     * of directories to categories a particular audio file as more than one
382     * type.
383     */
384    public static String DIRECTORY_NOTIFICATIONS = "Notifications";
385
386    /**
387     * Standard directory in which to place pictures that are available to
388     * the user.  Note that this is primarily a convention for the top-level
389     * public directory, as the media scanner will find and collect pictures
390     * in any directory.
391     */
392    public static String DIRECTORY_PICTURES = "Pictures";
393
394    /**
395     * Standard directory in which to place movies that are available to
396     * the user.  Note that this is primarily a convention for the top-level
397     * public directory, as the media scanner will find and collect movies
398     * in any directory.
399     */
400    public static String DIRECTORY_MOVIES = "Movies";
401
402    /**
403     * Standard directory in which to place files that have been downloaded by
404     * the user.  Note that this is primarily a convention for the top-level
405     * public directory, you are free to download files anywhere in your own
406     * private directories.  Also note that though the constant here is
407     * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for
408     * backwards compatibility reasons.
409     */
410    public static String DIRECTORY_DOWNLOADS = "Download";
411
412    /**
413     * The traditional location for pictures and videos when mounting the
414     * device as a camera.  Note that this is primarily a convention for the
415     * top-level public directory, as this convention makes no sense elsewhere.
416     */
417    public static String DIRECTORY_DCIM = "DCIM";
418
419    /**
420     * Get a top-level public external storage directory for placing files of
421     * a particular type.  This is where the user will typically place and
422     * manage their own files, so you should be careful about what you put here
423     * to ensure you don't erase their files or get in the way of their own
424     * organization.
425     *
426     * <p>Here is an example of typical code to manipulate a picture on
427     * the public external storage:</p>
428     *
429     * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
430     * public_picture}
431     *
432     * @param type The type of storage directory to return.  Should be one of
433     * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
434     * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
435     * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
436     * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, or
437     * {@link #DIRECTORY_DCIM}.  May not be null.
438     *
439     * @return Returns the File path for the directory.  Note that this
440     * directory may not yet exist, so you must make sure it exists before
441     * using it such as with {@link File#mkdirs File.mkdirs()}.
442     */
443    public static File getExternalStoragePublicDirectory(String type) {
444        throwIfSystem();
445        return sCurrentUser.getExternalStoragePublicDirectory(type);
446    }
447
448    /**
449     * Returns the path for android-specific data on the SD card.
450     * @hide
451     */
452    public static File getExternalStorageAndroidDataDir() {
453        throwIfSystem();
454        return sCurrentUser.getExternalStorageAndroidDataDir();
455    }
456
457    /**
458     * Generates the raw path to an application's data
459     * @hide
460     */
461    public static File getExternalStorageAppDataDirectory(String packageName) {
462        throwIfSystem();
463        return sCurrentUser.getExternalStorageAppDataDirectory(packageName);
464    }
465
466    /**
467     * Generates the raw path to an application's media
468     * @hide
469     */
470    public static File getExternalStorageAppMediaDirectory(String packageName) {
471        throwIfSystem();
472        return sCurrentUser.getExternalStorageAppMediaDirectory(packageName);
473    }
474
475    /**
476     * Generates the raw path to an application's OBB files
477     * @hide
478     */
479    public static File getExternalStorageAppObbDirectory(String packageName) {
480        throwIfSystem();
481        return sCurrentUser.getExternalStorageAppObbDirectory(packageName);
482    }
483
484    /**
485     * Generates the path to an application's files.
486     * @hide
487     */
488    public static File getExternalStorageAppFilesDirectory(String packageName) {
489        throwIfSystem();
490        return sCurrentUser.getExternalStorageAppFilesDirectory(packageName);
491    }
492
493    /**
494     * Generates the path to an application's cache.
495     * @hide
496     */
497    public static File getExternalStorageAppCacheDirectory(String packageName) {
498        throwIfSystem();
499        return sCurrentUser.getExternalStorageAppCacheDirectory(packageName);
500    }
501
502    /**
503     * Gets the Android Download/Cache content directory.
504     */
505    public static File getDownloadCacheDirectory() {
506        return DOWNLOAD_CACHE_DIRECTORY;
507    }
508
509    /**
510     * {@link #getExternalStorageState()} returns MEDIA_REMOVED if the media is not present.
511     */
512    public static final String MEDIA_REMOVED = "removed";
513
514    /**
515     * {@link #getExternalStorageState()} returns MEDIA_UNMOUNTED if the media is present
516     * but not mounted.
517     */
518    public static final String MEDIA_UNMOUNTED = "unmounted";
519
520    /**
521     * {@link #getExternalStorageState()} returns MEDIA_CHECKING if the media is present
522     * and being disk-checked
523     */
524    public static final String MEDIA_CHECKING = "checking";
525
526    /**
527     * {@link #getExternalStorageState()} returns MEDIA_NOFS if the media is present
528     * but is blank or is using an unsupported filesystem
529     */
530    public static final String MEDIA_NOFS = "nofs";
531
532    /**
533     * {@link #getExternalStorageState()} returns MEDIA_MOUNTED if the media is present
534     * and mounted at its mount point with read/write access.
535     */
536    public static final String MEDIA_MOUNTED = "mounted";
537
538    /**
539     * {@link #getExternalStorageState()} returns MEDIA_MOUNTED_READ_ONLY if the media is present
540     * and mounted at its mount point with read only access.
541     */
542    public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
543
544    /**
545     * {@link #getExternalStorageState()} returns MEDIA_SHARED if the media is present
546     * not mounted, and shared via USB mass storage.
547     */
548    public static final String MEDIA_SHARED = "shared";
549
550    /**
551     * {@link #getExternalStorageState()} returns MEDIA_BAD_REMOVAL if the media was
552     * removed before it was unmounted.
553     */
554    public static final String MEDIA_BAD_REMOVAL = "bad_removal";
555
556    /**
557     * {@link #getExternalStorageState()} returns MEDIA_UNMOUNTABLE if the media is present
558     * but cannot be mounted.  Typically this happens if the file system on the
559     * media is corrupted.
560     */
561    public static final String MEDIA_UNMOUNTABLE = "unmountable";
562
563    /**
564     * Gets the current state of the primary "external" storage device.
565     *
566     * <p>See {@link #getExternalStorageDirectory()} for more information.
567     */
568    public static String getExternalStorageState() {
569        try {
570            IMountService mountService = IMountService.Stub.asInterface(ServiceManager
571                    .getService("mount"));
572            final StorageVolume primary = getPrimaryVolume();
573            return mountService.getVolumeState(primary.getPath());
574        } catch (RemoteException rex) {
575            Log.w(TAG, "Failed to read external storage state; assuming REMOVED: " + rex);
576            return Environment.MEDIA_REMOVED;
577        }
578    }
579
580    /**
581     * Returns whether the primary "external" storage device is removable.
582     * If true is returned, this device is for example an SD card that the
583     * user can remove.  If false is returned, the storage is built into
584     * the device and can not be physically removed.
585     *
586     * <p>See {@link #getExternalStorageDirectory()} for more information.
587     */
588    public static boolean isExternalStorageRemovable() {
589        final StorageVolume primary = getPrimaryVolume();
590        return (primary != null && primary.isRemovable());
591    }
592
593    /**
594     * Returns whether the device has an external storage device which is
595     * emulated. If true, the device does not have real external storage, and the directory
596     * returned by {@link #getExternalStorageDirectory()} will be allocated using a portion of
597     * the internal storage system.
598     *
599     * <p>Certain system services, such as the package manager, use this
600     * to determine where to install an application.
601     *
602     * <p>Emulated external storage may also be encrypted - see
603     * {@link android.app.admin.DevicePolicyManager#setStorageEncryption(
604     * android.content.ComponentName, boolean)} for additional details.
605     */
606    public static boolean isExternalStorageEmulated() {
607        final StorageVolume primary = getPrimaryVolume();
608        return (primary != null && primary.isEmulated());
609    }
610
611    static File getDirectory(String variableName, String defaultPath) {
612        String path = System.getenv(variableName);
613        return path == null ? new File(defaultPath) : new File(path);
614    }
615
616    private static void throwIfSystem() {
617        if (Process.myUid() == Process.SYSTEM_UID) {
618            Log.wtf(TAG, "Static storage paths aren't available from AID_SYSTEM", new Throwable());
619        }
620    }
621
622    private static File buildPath(File base, String... segments) {
623        File cur = base;
624        for (String segment : segments) {
625            if (cur == null) {
626                cur = new File(segment);
627            } else {
628                cur = new File(cur, segment);
629            }
630        }
631        return cur;
632    }
633}
634