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