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