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