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