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