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