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