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