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 17 package android.os; 18 19 import android.Manifest; 20 import android.annotation.NonNull; 21 import android.annotation.SuppressLint; 22 import android.annotation.SystemApi; 23 import android.annotation.TestApi; 24 import android.app.AppGlobals; 25 import android.app.AppOpsManager; 26 import android.app.admin.DevicePolicyManager; 27 import android.compat.Compatibility; 28 import android.compat.annotation.ChangeId; 29 import android.compat.annotation.Disabled; 30 import android.compat.annotation.UnsupportedAppUsage; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.pm.ApplicationInfo; 34 import android.content.pm.PackageManager; 35 import android.os.storage.StorageManager; 36 import android.os.storage.StorageVolume; 37 import android.provider.MediaStore; 38 import android.text.TextUtils; 39 import android.util.Log; 40 41 import java.io.File; 42 import java.io.IOException; 43 import java.util.ArrayList; 44 import java.util.Collection; 45 import java.util.LinkedList; 46 import java.util.List; 47 import java.util.Objects; 48 49 /** 50 * Provides access to environment variables. 51 */ 52 public class Environment { 53 private static final String TAG = "Environment"; 54 55 // NOTE: keep credential-protected paths in sync with StrictMode.java 56 57 private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE"; 58 private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT"; 59 private static final String ENV_ANDROID_DATA = "ANDROID_DATA"; 60 private static final String ENV_ANDROID_EXPAND = "ANDROID_EXPAND"; 61 private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE"; 62 private static final String ENV_DOWNLOAD_CACHE = "DOWNLOAD_CACHE"; 63 private static final String ENV_OEM_ROOT = "OEM_ROOT"; 64 private static final String ENV_ODM_ROOT = "ODM_ROOT"; 65 private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT"; 66 private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT"; 67 private static final String ENV_SYSTEM_EXT_ROOT = "SYSTEM_EXT_ROOT"; 68 private static final String ENV_APEX_ROOT = "APEX_ROOT"; 69 70 /** {@hide} */ 71 public static final String DIR_ANDROID = "Android"; 72 private static final String DIR_DATA = "data"; 73 private static final String DIR_MEDIA = "media"; 74 private static final String DIR_OBB = "obb"; 75 private static final String DIR_FILES = "files"; 76 private static final String DIR_CACHE = "cache"; 77 78 /** 79 * The folder name prefix for the user credential protected data directory. This is exposed for 80 * use in string path caching for {@link ApplicationInfo} objects, and should not be accessed 81 * directly otherwise. Prefer {@link #getDataUserCeDirectory(String, int)}. 82 * {@hide} 83 */ 84 public static final String DIR_USER_CE = "user"; 85 86 /** 87 * The folder name prefix for the user device protected data directory. This is exposed for use 88 * in string path caching for {@link ApplicationInfo} objects, and should not be accessed 89 * directly otherwise. Prefer {@link #getDataUserDeDirectory(String, int)}. 90 * {@hide} 91 */ 92 public static final String DIR_USER_DE = "user_de"; 93 94 /** {@hide} */ 95 @Deprecated 96 public static final String DIRECTORY_ANDROID = DIR_ANDROID; 97 98 private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system"); 99 private static final String DIR_ANDROID_DATA_PATH = getDirectoryPath(ENV_ANDROID_DATA, "/data"); 100 private static final File DIR_ANDROID_DATA = new File(DIR_ANDROID_DATA_PATH); 101 private static final File DIR_ANDROID_EXPAND = getDirectory(ENV_ANDROID_EXPAND, "/mnt/expand"); 102 private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage"); 103 private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache"); 104 private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem"); 105 private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm"); 106 private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor"); 107 private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product"); 108 private static final File DIR_SYSTEM_EXT_ROOT = getDirectory(ENV_SYSTEM_EXT_ROOT, 109 "/system_ext"); 110 private static final File DIR_APEX_ROOT = getDirectory(ENV_APEX_ROOT, 111 "/apex"); 112 113 /** 114 * Scoped Storage is on by default. However, it is not strictly enforced and there are multiple 115 * ways to opt out of scoped storage: 116 * <ul> 117 * <li>Target Sdk < Q</li> 118 * <li>Target Sdk = Q and has `requestLegacyExternalStorage` set in AndroidManifest.xml</li> 119 * <li>Target Sdk > Q: Upgrading from an app that was opted out of scoped storage and has 120 * `preserveLegacyExternalStorage` set in AndroidManifest.xml</li> 121 * </ul> 122 * This flag is enabled for all apps by default as Scoped Storage is enabled by default. 123 * Developers can disable this flag to opt out of Scoped Storage and have legacy storage 124 * workflow. 125 * 126 * Note: {@code FORCE_ENABLE_SCOPED_STORAGE} should also be disabled for apps to opt out of 127 * scoped storage. 128 * Note: This flag is also used in {@code com.android.providers.media.LocalCallingIdentity}. 129 * Any modifications to this flag should be reflected there as well. 130 * See https://developer.android.com/training/data-storage#scoped-storage for more information. 131 */ 132 @ChangeId 133 private static final long DEFAULT_SCOPED_STORAGE = 149924527L; 134 135 /** 136 * See definition in com.android.providers.media.LocalCallingIdentity 137 */ 138 /** 139 * Setting this flag strictly enforces Scoped Storage regardless of: 140 * <ul> 141 * <li>The value of Target Sdk</li> 142 * <li>The value of `requestLegacyExternalStorage` in AndroidManifest.xml</li> 143 * <li>The value of `preserveLegacyExternalStorage` in AndroidManifest.xml</li> 144 * </ul> 145 * 146 * Note: {@code DEFAULT_SCOPED_STORAGE} should also be enabled for apps to be enforced into 147 * scoped storage. 148 * Note: This flag is also used in {@code com.android.providers.media.LocalCallingIdentity}. 149 * Any modifications to this flag should be reflected there as well. 150 * See https://developer.android.com/training/data-storage#scoped-storage for more information. 151 */ 152 @ChangeId 153 @Disabled 154 private static final long FORCE_ENABLE_SCOPED_STORAGE = 132649864L; 155 156 @UnsupportedAppUsage 157 private static UserEnvironment sCurrentUser; 158 private static boolean sUserRequired; 159 160 static { initForCurrentUser()161 initForCurrentUser(); 162 } 163 164 /** {@hide} */ 165 @UnsupportedAppUsage initForCurrentUser()166 public static void initForCurrentUser() { 167 final int userId = UserHandle.myUserId(); 168 sCurrentUser = new UserEnvironment(userId); 169 } 170 171 /** {@hide} */ 172 public static class UserEnvironment { 173 private final int mUserId; 174 175 @UnsupportedAppUsage UserEnvironment(int userId)176 public UserEnvironment(int userId) { 177 mUserId = userId; 178 } 179 180 @UnsupportedAppUsage getExternalDirs()181 public File[] getExternalDirs() { 182 final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId, 183 StorageManager.FLAG_FOR_WRITE); 184 final File[] files = new File[volumes.length]; 185 for (int i = 0; i < volumes.length; i++) { 186 files[i] = volumes[i].getPathFile(); 187 } 188 return files; 189 } 190 191 @UnsupportedAppUsage getExternalStorageDirectory()192 public File getExternalStorageDirectory() { 193 return getExternalDirs()[0]; 194 } 195 196 @UnsupportedAppUsage getExternalStoragePublicDirectory(String type)197 public File getExternalStoragePublicDirectory(String type) { 198 return buildExternalStoragePublicDirs(type)[0]; 199 } 200 buildExternalStoragePublicDirs(String type)201 public File[] buildExternalStoragePublicDirs(String type) { 202 return buildPaths(getExternalDirs(), type); 203 } 204 buildExternalStorageAndroidDataDirs()205 public File[] buildExternalStorageAndroidDataDirs() { 206 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA); 207 } 208 buildExternalStorageAndroidObbDirs()209 public File[] buildExternalStorageAndroidObbDirs() { 210 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB); 211 } 212 buildExternalStorageAppDataDirs(String packageName)213 public File[] buildExternalStorageAppDataDirs(String packageName) { 214 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName); 215 } 216 buildExternalStorageAppMediaDirs(String packageName)217 public File[] buildExternalStorageAppMediaDirs(String packageName) { 218 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_MEDIA, packageName); 219 } 220 buildExternalStorageAppObbDirs(String packageName)221 public File[] buildExternalStorageAppObbDirs(String packageName) { 222 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB, packageName); 223 } 224 buildExternalStorageAppFilesDirs(String packageName)225 public File[] buildExternalStorageAppFilesDirs(String packageName) { 226 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_FILES); 227 } 228 buildExternalStorageAppCacheDirs(String packageName)229 public File[] buildExternalStorageAppCacheDirs(String packageName) { 230 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE); 231 } 232 } 233 234 /** 235 * Return root of the "system" partition holding the core Android OS. 236 * Always present and mounted read-only. 237 */ getRootDirectory()238 public static @NonNull File getRootDirectory() { 239 return DIR_ANDROID_ROOT; 240 } 241 242 /** 243 * Return root directory where all external storage devices will be mounted. 244 * For example, {@link #getExternalStorageDirectory()} will appear under 245 * this location. 246 */ getStorageDirectory()247 public static @NonNull File getStorageDirectory() { 248 return DIR_ANDROID_STORAGE; 249 } 250 251 /** 252 * Return root directory of the "oem" partition holding OEM customizations, 253 * if any. If present, the partition is mounted read-only. 254 * 255 * @hide 256 */ 257 @SystemApi getOemDirectory()258 public static @NonNull File getOemDirectory() { 259 return DIR_OEM_ROOT; 260 } 261 262 /** 263 * Return root directory of the "odm" partition holding ODM customizations, 264 * if any. If present, the partition is mounted read-only. 265 * 266 * @hide 267 */ 268 @SystemApi getOdmDirectory()269 public static @NonNull File getOdmDirectory() { 270 return DIR_ODM_ROOT; 271 } 272 273 /** 274 * Return root directory of the "vendor" partition that holds vendor-provided 275 * software that should persist across simple reflashing of the "system" partition. 276 * @hide 277 */ 278 @SystemApi getVendorDirectory()279 public static @NonNull File getVendorDirectory() { 280 return DIR_VENDOR_ROOT; 281 } 282 283 /** 284 * Return root directory of the "product" partition holding product-specific 285 * customizations if any. If present, the partition is mounted read-only. 286 * 287 * @hide 288 */ 289 @SystemApi getProductDirectory()290 public static @NonNull File getProductDirectory() { 291 return DIR_PRODUCT_ROOT; 292 } 293 294 /** 295 * Return root directory of the "product_services" partition holding middleware 296 * services if any. If present, the partition is mounted read-only. 297 * 298 * @deprecated This directory is not guaranteed to exist. 299 * Its name is changed to "system_ext" because the partition's purpose is changed. 300 * {@link #getSystemExtDirectory()} 301 * @hide 302 */ 303 @SystemApi 304 @Deprecated getProductServicesDirectory()305 public static @NonNull File getProductServicesDirectory() { 306 return getDirectory("PRODUCT_SERVICES_ROOT", "/product_services"); 307 } 308 309 /** 310 * Return root directory of the "system_ext" partition holding system partition's extension 311 * If present, the partition is mounted read-only. 312 * 313 * @hide 314 */ 315 @SystemApi getSystemExtDirectory()316 public static @NonNull File getSystemExtDirectory() { 317 return DIR_SYSTEM_EXT_ROOT; 318 } 319 320 /** 321 * Return root directory of the apex mount point, where all the apex modules are made available 322 * to the rest of the system. 323 * 324 * @hide 325 */ getApexDirectory()326 public static @NonNull File getApexDirectory() { 327 return DIR_APEX_ROOT; 328 } 329 330 /** 331 * Return the system directory for a user. This is for use by system 332 * services to store files relating to the user. This directory will be 333 * automatically deleted when the user is removed. 334 * 335 * @deprecated This directory is valid and still exists, but but callers 336 * should <em>strongly</em> consider switching to using either 337 * {@link #getDataSystemCeDirectory(int)} or 338 * {@link #getDataSystemDeDirectory(int)}, both of which support 339 * fast user wipe. 340 * @hide 341 */ 342 @Deprecated getUserSystemDirectory(int userId)343 public static File getUserSystemDirectory(int userId) { 344 return new File(new File(getDataSystemDirectory(), "users"), Integer.toString(userId)); 345 } 346 347 /** 348 * Returns the config directory for a user. This is for use by system 349 * services to store files relating to the user which should be readable by 350 * any app running as that user. 351 * 352 * @deprecated This directory is valid and still exists, but callers should 353 * <em>strongly</em> consider switching to 354 * {@link #getDataMiscCeDirectory(int)} which is protected with 355 * user credentials or {@link #getDataMiscDeDirectory(int)} 356 * which supports fast user wipe. 357 * @hide 358 */ 359 @Deprecated getUserConfigDirectory(int userId)360 public static File getUserConfigDirectory(int userId) { 361 return new File(new File(new File( 362 getDataDirectory(), "misc"), "user"), Integer.toString(userId)); 363 } 364 365 /** 366 * Return the user data directory. 367 */ getDataDirectory()368 public static File getDataDirectory() { 369 return DIR_ANDROID_DATA; 370 } 371 372 /** 373 * @see #getDataDirectory() 374 * @hide 375 */ getDataDirectoryPath()376 public static String getDataDirectoryPath() { 377 return DIR_ANDROID_DATA_PATH; 378 } 379 380 /** {@hide} */ getDataDirectory(String volumeUuid)381 public static File getDataDirectory(String volumeUuid) { 382 if (TextUtils.isEmpty(volumeUuid)) { 383 return DIR_ANDROID_DATA; 384 } else { 385 return new File("/mnt/expand/" + volumeUuid); 386 } 387 } 388 389 /** @hide */ getDataDirectoryPath(String volumeUuid)390 public static String getDataDirectoryPath(String volumeUuid) { 391 if (TextUtils.isEmpty(volumeUuid)) { 392 return DIR_ANDROID_DATA_PATH; 393 } else { 394 return getExpandDirectory().getAbsolutePath() + File.separator + volumeUuid; 395 } 396 } 397 398 /** {@hide} */ getExpandDirectory()399 public static File getExpandDirectory() { 400 return DIR_ANDROID_EXPAND; 401 } 402 403 /** {@hide} */ 404 @UnsupportedAppUsage getDataSystemDirectory()405 public static File getDataSystemDirectory() { 406 return new File(getDataDirectory(), "system"); 407 } 408 409 /** 410 * Returns the base directory for per-user system directory, device encrypted. 411 * {@hide} 412 */ getDataSystemDeDirectory()413 public static File getDataSystemDeDirectory() { 414 return buildPath(getDataDirectory(), "system_de"); 415 } 416 417 /** 418 * Returns the base directory for per-user system directory, credential encrypted. 419 * {@hide} 420 */ getDataSystemCeDirectory()421 public static File getDataSystemCeDirectory() { 422 return buildPath(getDataDirectory(), "system_ce"); 423 } 424 425 /** 426 * Return the "credential encrypted" system directory for a user. This is 427 * for use by system services to store files relating to the user. This 428 * directory supports fast user wipe, and will be automatically deleted when 429 * the user is removed. 430 * <p> 431 * Data stored under this path is "credential encrypted", which uses an 432 * encryption key that is entangled with user credentials, such as a PIN or 433 * password. The contents will only be available once the user has been 434 * unlocked, as reported by {@code SystemService.onUnlockUser()}. 435 * <p> 436 * New code should <em>strongly</em> prefer storing sensitive data in these 437 * credential encrypted areas. 438 * 439 * @hide 440 */ getDataSystemCeDirectory(int userId)441 public static File getDataSystemCeDirectory(int userId) { 442 return buildPath(getDataDirectory(), "system_ce", String.valueOf(userId)); 443 } 444 445 /** 446 * Return the "device encrypted" system directory for a user. This is for 447 * use by system services to store files relating to the user. This 448 * directory supports fast user wipe, and will be automatically deleted when 449 * the user is removed. 450 * <p> 451 * Data stored under this path is "device encrypted", which uses an 452 * encryption key that is tied to the physical device. The contents will 453 * only be available once the device has finished a {@code dm-verity} 454 * protected boot. 455 * <p> 456 * New code should <em>strongly</em> avoid storing sensitive data in these 457 * device encrypted areas. 458 * 459 * @hide 460 */ getDataSystemDeDirectory(int userId)461 public static File getDataSystemDeDirectory(int userId) { 462 return buildPath(getDataDirectory(), "system_de", String.valueOf(userId)); 463 } 464 465 /** {@hide} */ getDataMiscDirectory()466 public static File getDataMiscDirectory() { 467 return new File(getDataDirectory(), "misc"); 468 } 469 470 /** {@hide} */ getDataMiscCeDirectory()471 public static File getDataMiscCeDirectory() { 472 return buildPath(getDataDirectory(), "misc_ce"); 473 } 474 475 /** {@hide} */ getDataMiscCeDirectory(int userId)476 public static File getDataMiscCeDirectory(int userId) { 477 return buildPath(getDataDirectory(), "misc_ce", String.valueOf(userId)); 478 } 479 480 /** {@hide} */ getDataMiscDeDirectory(int userId)481 public static File getDataMiscDeDirectory(int userId) { 482 return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId)); 483 } 484 getDataProfilesDeDirectory(int userId)485 private static File getDataProfilesDeDirectory(int userId) { 486 return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId)); 487 } 488 489 /** {@hide} */ getDataVendorCeDirectory(int userId)490 public static File getDataVendorCeDirectory(int userId) { 491 return buildPath(getDataDirectory(), "vendor_ce", String.valueOf(userId)); 492 } 493 494 /** {@hide} */ getDataVendorDeDirectory(int userId)495 public static File getDataVendorDeDirectory(int userId) { 496 return buildPath(getDataDirectory(), "vendor_de", String.valueOf(userId)); 497 } 498 499 /** {@hide} */ getDataRefProfilesDePackageDirectory(String packageName)500 public static File getDataRefProfilesDePackageDirectory(String packageName) { 501 return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName); 502 } 503 504 /** {@hide} */ getDataProfilesDePackageDirectory(int userId, String packageName)505 public static File getDataProfilesDePackageDirectory(int userId, String packageName) { 506 return buildPath(getDataProfilesDeDirectory(userId), packageName); 507 } 508 509 /** {@hide} */ getDataAppDirectory(String volumeUuid)510 public static File getDataAppDirectory(String volumeUuid) { 511 return new File(getDataDirectory(volumeUuid), "app"); 512 } 513 514 /** {@hide} */ getDataStagingDirectory(String volumeUuid)515 public static File getDataStagingDirectory(String volumeUuid) { 516 return new File(getDataDirectory(volumeUuid), "app-staging"); 517 } 518 519 /** {@hide} */ getDataUserCeDirectory(String volumeUuid)520 public static File getDataUserCeDirectory(String volumeUuid) { 521 return new File(getDataDirectory(volumeUuid), DIR_USER_CE); 522 } 523 524 /** {@hide} */ getDataUserCeDirectory(String volumeUuid, int userId)525 public static File getDataUserCeDirectory(String volumeUuid, int userId) { 526 return new File(getDataUserCeDirectory(volumeUuid), String.valueOf(userId)); 527 } 528 529 /** {@hide} */ getDataUserCePackageDirectory(String volumeUuid, int userId, String packageName)530 public static File getDataUserCePackageDirectory(String volumeUuid, int userId, 531 String packageName) { 532 // TODO: keep consistent with installd 533 return new File(getDataUserCeDirectory(volumeUuid, userId), packageName); 534 } 535 536 /** {@hide} */ getDataUserDeDirectory(String volumeUuid)537 public static File getDataUserDeDirectory(String volumeUuid) { 538 return new File(getDataDirectory(volumeUuid), DIR_USER_DE); 539 } 540 541 /** {@hide} */ getDataUserDeDirectory(String volumeUuid, int userId)542 public static File getDataUserDeDirectory(String volumeUuid, int userId) { 543 return new File(getDataUserDeDirectory(volumeUuid), String.valueOf(userId)); 544 } 545 546 /** {@hide} */ getDataUserDePackageDirectory(String volumeUuid, int userId, String packageName)547 public static File getDataUserDePackageDirectory(String volumeUuid, int userId, 548 String packageName) { 549 // TODO: keep consistent with installd 550 return new File(getDataUserDeDirectory(volumeUuid, userId), packageName); 551 } 552 553 /** 554 * Return preloads directory. 555 * <p>This directory may contain pre-loaded content such as 556 * {@link #getDataPreloadsDemoDirectory() demo videos} and 557 * {@link #getDataPreloadsAppsDirectory() APK files} . 558 * {@hide} 559 */ getDataPreloadsDirectory()560 public static File getDataPreloadsDirectory() { 561 return new File(getDataDirectory(), "preloads"); 562 } 563 564 /** 565 * @see #getDataPreloadsDirectory() 566 * {@hide} 567 */ getDataPreloadsDemoDirectory()568 public static File getDataPreloadsDemoDirectory() { 569 return new File(getDataPreloadsDirectory(), "demo"); 570 } 571 572 /** 573 * @see #getDataPreloadsDirectory() 574 * {@hide} 575 */ getDataPreloadsAppsDirectory()576 public static File getDataPreloadsAppsDirectory() { 577 return new File(getDataPreloadsDirectory(), "apps"); 578 } 579 580 /** 581 * @see #getDataPreloadsDirectory() 582 * {@hide} 583 */ getDataPreloadsMediaDirectory()584 public static File getDataPreloadsMediaDirectory() { 585 return new File(getDataPreloadsDirectory(), "media"); 586 } 587 588 /** 589 * Returns location of preloaded cache directory for package name 590 * @see #getDataPreloadsDirectory() 591 * {@hide} 592 */ getDataPreloadsFileCacheDirectory(String packageName)593 public static File getDataPreloadsFileCacheDirectory(String packageName) { 594 return new File(getDataPreloadsFileCacheDirectory(), packageName); 595 } 596 597 /** 598 * Returns location of preloaded cache directory. 599 * @see #getDataPreloadsDirectory() 600 * {@hide} 601 */ getDataPreloadsFileCacheDirectory()602 public static File getDataPreloadsFileCacheDirectory() { 603 return new File(getDataPreloadsDirectory(), "file_cache"); 604 } 605 606 /** 607 * Returns location of packages cache directory. 608 * {@hide} 609 */ getPackageCacheDirectory()610 public static File getPackageCacheDirectory() { 611 return new File(getDataSystemDirectory(), "package_cache"); 612 } 613 614 /** 615 * Return locations where media files (such as ringtones, notification 616 * sounds, or alarm sounds) may be located on internal storage. These are 617 * typically indexed under {@link MediaStore#VOLUME_INTERNAL}. 618 * 619 * @hide 620 */ 621 @SystemApi getInternalMediaDirectories()622 public static @NonNull Collection<File> getInternalMediaDirectories() { 623 final ArrayList<File> res = new ArrayList<>(); 624 addCanonicalFile(res, new File(Environment.getRootDirectory(), "media")); 625 addCanonicalFile(res, new File(Environment.getOemDirectory(), "media")); 626 addCanonicalFile(res, new File(Environment.getProductDirectory(), "media")); 627 return res; 628 } 629 addCanonicalFile(List<File> list, File file)630 private static void addCanonicalFile(List<File> list, File file) { 631 try { 632 list.add(file.getCanonicalFile()); 633 } catch (IOException e) { 634 Log.w(TAG, "Failed to resolve " + file + ": " + e); 635 list.add(file); 636 } 637 } 638 639 /** 640 * Return the primary shared/external storage directory. This directory may 641 * not currently be accessible if it has been mounted by the user on their 642 * computer, has been removed from the device, or some other problem has 643 * happened. You can determine its current state with 644 * {@link #getExternalStorageState()}. 645 * <p> 646 * <em>Note: don't be confused by the word "external" here. This directory 647 * can better be thought as media/shared storage. It is a filesystem that 648 * can hold a relatively large amount of data and that is shared across all 649 * applications (does not enforce permissions). Traditionally this is an SD 650 * card, but it may also be implemented as built-in storage in a device that 651 * is distinct from the protected internal storage and can be mounted as a 652 * filesystem on a computer.</em> 653 * <p> 654 * On devices with multiple users (as described by {@link UserManager}), 655 * each user has their own isolated shared storage. Applications only have 656 * access to the shared storage for the user they're running as. 657 * <p> 658 * In devices with multiple shared/external storage directories, this 659 * directory represents the primary storage that the user will interact 660 * with. Access to secondary storage is available through 661 * {@link Context#getExternalFilesDirs(String)}, 662 * {@link Context#getExternalCacheDirs()}, and 663 * {@link Context#getExternalMediaDirs()}. 664 * <p> 665 * Applications should not directly use this top-level directory, in order 666 * to avoid polluting the user's root namespace. Any files that are private 667 * to the application should be placed in a directory returned by 668 * {@link android.content.Context#getExternalFilesDir 669 * Context.getExternalFilesDir}, which the system will take care of deleting 670 * if the application is uninstalled. Other shared files should be placed in 671 * one of the directories returned by 672 * {@link #getExternalStoragePublicDirectory}. 673 * <p> 674 * Writing to this path requires the 675 * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission, 676 * and starting in {@link android.os.Build.VERSION_CODES#KITKAT}, read 677 * access requires the 678 * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission, 679 * which is automatically granted if you hold the write permission. 680 * <p> 681 * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your 682 * application only needs to store internal data, consider using 683 * {@link Context#getExternalFilesDir(String)}, 684 * {@link Context#getExternalCacheDir()}, or 685 * {@link Context#getExternalMediaDirs()}, which require no permissions to 686 * read or write. 687 * <p> 688 * This path may change between platform versions, so applications should 689 * only persist relative paths. 690 * <p> 691 * Here is an example of typical code to monitor the state of external 692 * storage: 693 * <p> 694 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java 695 * monitor_storage} 696 * <p> 697 * Note that alternatives such as {@link Context#getExternalFilesDir(String)} or 698 * {@link MediaStore} offer better performance. 699 * 700 * @see #getExternalStorageState() 701 * @see #isExternalStorageRemovable() 702 */ getExternalStorageDirectory()703 public static File getExternalStorageDirectory() { 704 throwIfUserRequired(); 705 return sCurrentUser.getExternalDirs()[0]; 706 } 707 708 /** {@hide} */ 709 @UnsupportedAppUsage getLegacyExternalStorageDirectory()710 public static File getLegacyExternalStorageDirectory() { 711 return new File(System.getenv(ENV_EXTERNAL_STORAGE)); 712 } 713 714 /** {@hide} */ 715 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getLegacyExternalStorageObbDirectory()716 public static File getLegacyExternalStorageObbDirectory() { 717 return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB); 718 } 719 720 /** 721 * Standard directory in which to place any audio files that should be 722 * in the regular list of music for the user. 723 * This may be combined with {@link #DIRECTORY_AUDIOBOOKS}, 724 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, 725 * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and 726 * {@link #DIRECTORY_RECORDINGS} as a series of directories to 727 * categorize a particular audio file as more than one type. 728 */ 729 public static String DIRECTORY_MUSIC = "Music"; 730 731 /** 732 * Standard directory in which to place any audio files that should be 733 * in the list of podcasts that the user can select (not as regular 734 * music). 735 * This may be combined with {@link #DIRECTORY_MUSIC}, 736 * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_NOTIFICATIONS}, 737 * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and 738 * {@link #DIRECTORY_RECORDINGS} as a series of directories to 739 * categorize a particular audio file as more than one type. 740 */ 741 public static String DIRECTORY_PODCASTS = "Podcasts"; 742 743 /** 744 * Standard directory in which to place any audio files that should be 745 * in the list of ringtones that the user can select (not as regular 746 * music). 747 * This may be combined with {@link #DIRECTORY_MUSIC}, 748 * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS}, 749 * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_ALARMS}, 750 * and {@link #DIRECTORY_RECORDINGS} as a series of directories 751 * to categorize a particular audio file as more than one type. 752 */ 753 public static String DIRECTORY_RINGTONES = "Ringtones"; 754 755 /** 756 * Standard directory in which to place any audio files that should be 757 * in the list of alarms that the user can select (not as regular 758 * music). 759 * This may be combined with {@link #DIRECTORY_MUSIC}, 760 * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS}, 761 * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_RINGTONES}, 762 * and {@link #DIRECTORY_RECORDINGS} as a series of directories 763 * to categorize a particular audio file as more than one type. 764 */ 765 public static String DIRECTORY_ALARMS = "Alarms"; 766 767 /** 768 * Standard directory in which to place any audio files that should be 769 * in the list of notifications that the user can select (not as regular 770 * music). 771 * This may be combined with {@link #DIRECTORY_MUSIC}, 772 * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS}, 773 * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and 774 * {@link #DIRECTORY_RECORDINGS} as a series of directories to 775 * categorize a particular audio file as more than one type. 776 */ 777 public static String DIRECTORY_NOTIFICATIONS = "Notifications"; 778 779 /** 780 * Standard directory in which to place pictures that are available to 781 * the user. Note that this is primarily a convention for the top-level 782 * public directory, as the media scanner will find and collect pictures 783 * in any directory. 784 */ 785 public static String DIRECTORY_PICTURES = "Pictures"; 786 787 /** 788 * Standard directory in which to place movies that are available to 789 * the user. Note that this is primarily a convention for the top-level 790 * public directory, as the media scanner will find and collect movies 791 * in any directory. 792 */ 793 public static String DIRECTORY_MOVIES = "Movies"; 794 795 /** 796 * Standard directory in which to place files that have been downloaded by 797 * the user. Note that this is primarily a convention for the top-level 798 * public directory, you are free to download files anywhere in your own 799 * private directories. Also note that though the constant here is 800 * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for 801 * backwards compatibility reasons. 802 */ 803 public static String DIRECTORY_DOWNLOADS = "Download"; 804 805 /** 806 * The traditional location for pictures and videos when mounting the 807 * device as a camera. Note that this is primarily a convention for the 808 * top-level public directory, as this convention makes no sense elsewhere. 809 */ 810 public static String DIRECTORY_DCIM = "DCIM"; 811 812 /** 813 * Standard directory in which to place documents that have been created by 814 * the user. 815 */ 816 public static String DIRECTORY_DOCUMENTS = "Documents"; 817 818 /** 819 * Standard directory in which to place screenshots that have been taken by 820 * the user. Typically used as a secondary directory under 821 * {@link #DIRECTORY_PICTURES}. 822 */ 823 public static String DIRECTORY_SCREENSHOTS = "Screenshots"; 824 825 /** 826 * Standard directory in which to place any audio files that should be 827 * in the list of audiobooks that the user can select (not as regular 828 * music). 829 * This may be combined with {@link #DIRECTORY_MUSIC}, 830 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, 831 * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, 832 * and {@link #DIRECTORY_RECORDINGS} as a series of directories 833 * to categorize a particular audio file as more than one type. 834 */ 835 public static String DIRECTORY_AUDIOBOOKS = "Audiobooks"; 836 837 /** 838 * Standard directory in which to place any audio files that should be 839 * in the list of voice recordings recorded by voice recorder apps that 840 * the user can select (not as regular music). 841 * This may be combined with {@link #DIRECTORY_MUSIC}, 842 * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS}, 843 * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_ALARMS}, 844 * and {@link #DIRECTORY_RINGTONES} as a series of directories 845 * to categorize a particular audio file as more than one type. 846 */ 847 @NonNull 848 // The better way is that expose a static method getRecordingDirectories. 849 // But since it's an existing API surface and developers already 850 // used to DIRECTORY_* constants, we should keep using this pattern 851 // for consistency. We use SuppressLint here to avoid exposing a final 852 // field. A final field will prevent us from ever changing the value of 853 // DIRECTORY_RECORDINGS. Not that it's likely that we will ever need to 854 // change it, but it's better to have such option. 855 @SuppressLint({"MutableBareField", "AllUpper"}) 856 public static String DIRECTORY_RECORDINGS = "Recordings"; 857 858 /** 859 * List of standard storage directories. 860 * <p> 861 * Each of its values have its own constant: 862 * <ul> 863 * <li>{@link #DIRECTORY_MUSIC} 864 * <li>{@link #DIRECTORY_PODCASTS} 865 * <li>{@link #DIRECTORY_ALARMS} 866 * <li>{@link #DIRECTORY_RINGTONES} 867 * <li>{@link #DIRECTORY_NOTIFICATIONS} 868 * <li>{@link #DIRECTORY_PICTURES} 869 * <li>{@link #DIRECTORY_MOVIES} 870 * <li>{@link #DIRECTORY_DOWNLOADS} 871 * <li>{@link #DIRECTORY_DCIM} 872 * <li>{@link #DIRECTORY_DOCUMENTS} 873 * <li>{@link #DIRECTORY_AUDIOBOOKS} 874 * <li>{@link #DIRECTORY_RECORDINGS} 875 * </ul> 876 * @hide 877 */ 878 public static final String[] STANDARD_DIRECTORIES = { 879 DIRECTORY_MUSIC, 880 DIRECTORY_PODCASTS, 881 DIRECTORY_RINGTONES, 882 DIRECTORY_ALARMS, 883 DIRECTORY_NOTIFICATIONS, 884 DIRECTORY_PICTURES, 885 DIRECTORY_MOVIES, 886 DIRECTORY_DOWNLOADS, 887 DIRECTORY_DCIM, 888 DIRECTORY_DOCUMENTS, 889 DIRECTORY_AUDIOBOOKS, 890 DIRECTORY_RECORDINGS, 891 }; 892 893 /** 894 * @hide 895 */ isStandardDirectory(String dir)896 public static boolean isStandardDirectory(String dir) { 897 for (String valid : STANDARD_DIRECTORIES) { 898 if (valid.equals(dir)) { 899 return true; 900 } 901 } 902 return false; 903 } 904 905 /** {@hide} */ public static final int HAS_MUSIC = 1 << 0; 906 /** {@hide} */ public static final int HAS_PODCASTS = 1 << 1; 907 /** {@hide} */ public static final int HAS_RINGTONES = 1 << 2; 908 /** {@hide} */ public static final int HAS_ALARMS = 1 << 3; 909 /** {@hide} */ public static final int HAS_NOTIFICATIONS = 1 << 4; 910 /** {@hide} */ public static final int HAS_PICTURES = 1 << 5; 911 /** {@hide} */ public static final int HAS_MOVIES = 1 << 6; 912 /** {@hide} */ public static final int HAS_DOWNLOADS = 1 << 7; 913 /** {@hide} */ public static final int HAS_DCIM = 1 << 8; 914 /** {@hide} */ public static final int HAS_DOCUMENTS = 1 << 9; 915 /** {@hide} */ public static final int HAS_AUDIOBOOKS = 1 << 10; 916 /** {@hide} */ public static final int HAS_RECORDINGS = 1 << 11; 917 918 /** {@hide} */ public static final int HAS_ANDROID = 1 << 16; 919 /** {@hide} */ public static final int HAS_OTHER = 1 << 17; 920 921 /** 922 * Classify the content types present on the given external storage device. 923 * <p> 924 * This is typically useful for deciding if an inserted SD card is empty, or 925 * if it contains content like photos that should be preserved. 926 * 927 * @hide 928 */ classifyExternalStorageDirectory(File dir)929 public static int classifyExternalStorageDirectory(File dir) { 930 int res = 0; 931 for (File f : FileUtils.listFilesOrEmpty(dir)) { 932 if (f.isFile() && isInterestingFile(f)) { 933 res |= HAS_OTHER; 934 } else if (f.isDirectory() && hasInterestingFiles(f)) { 935 final String name = f.getName(); 936 if (DIRECTORY_MUSIC.equals(name)) res |= HAS_MUSIC; 937 else if (DIRECTORY_PODCASTS.equals(name)) res |= HAS_PODCASTS; 938 else if (DIRECTORY_RINGTONES.equals(name)) res |= HAS_RINGTONES; 939 else if (DIRECTORY_ALARMS.equals(name)) res |= HAS_ALARMS; 940 else if (DIRECTORY_NOTIFICATIONS.equals(name)) res |= HAS_NOTIFICATIONS; 941 else if (DIRECTORY_PICTURES.equals(name)) res |= HAS_PICTURES; 942 else if (DIRECTORY_MOVIES.equals(name)) res |= HAS_MOVIES; 943 else if (DIRECTORY_DOWNLOADS.equals(name)) res |= HAS_DOWNLOADS; 944 else if (DIRECTORY_DCIM.equals(name)) res |= HAS_DCIM; 945 else if (DIRECTORY_DOCUMENTS.equals(name)) res |= HAS_DOCUMENTS; 946 else if (DIRECTORY_AUDIOBOOKS.equals(name)) res |= HAS_AUDIOBOOKS; 947 else if (DIRECTORY_RECORDINGS.equals(name)) res |= HAS_RECORDINGS; 948 else if (DIRECTORY_ANDROID.equals(name)) res |= HAS_ANDROID; 949 else res |= HAS_OTHER; 950 } 951 } 952 return res; 953 } 954 hasInterestingFiles(File dir)955 private static boolean hasInterestingFiles(File dir) { 956 final LinkedList<File> explore = new LinkedList<>(); 957 explore.add(dir); 958 while (!explore.isEmpty()) { 959 dir = explore.pop(); 960 for (File f : FileUtils.listFilesOrEmpty(dir)) { 961 if (isInterestingFile(f)) return true; 962 if (f.isDirectory()) explore.add(f); 963 } 964 } 965 return false; 966 } 967 isInterestingFile(File file)968 private static boolean isInterestingFile(File file) { 969 if (file.isFile()) { 970 final String name = file.getName().toLowerCase(); 971 if (name.endsWith(".exe") || name.equals("autorun.inf") 972 || name.equals("launchpad.zip") || name.equals(".nomedia")) { 973 return false; 974 } else { 975 return true; 976 } 977 } else { 978 return false; 979 } 980 } 981 982 /** 983 * Get a top-level shared/external storage directory for placing files of a 984 * particular type. This is where the user will typically place and manage 985 * their own files, so you should be careful about what you put here to 986 * ensure you don't erase their files or get in the way of their own 987 * organization. 988 * <p> 989 * On devices with multiple users (as described by {@link UserManager}), 990 * each user has their own isolated shared storage. Applications only have 991 * access to the shared storage for the user they're running as. 992 * </p> 993 * <p> 994 * Here is an example of typical code to manipulate a picture on the public 995 * shared storage: 996 * </p> 997 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java 998 * public_picture} 999 * <p> 1000 * Note that alternatives such as {@link Context#getExternalFilesDir(String)} or 1001 * {@link MediaStore} offer better performance. 1002 * 1003 * @param type The type of storage directory to return. Should be one of 1004 * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS}, 1005 * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS}, 1006 * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES}, 1007 * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, 1008 * {@link #DIRECTORY_DCIM}, or {@link #DIRECTORY_DOCUMENTS}. May not be null. 1009 * @return Returns the File path for the directory. Note that this directory 1010 * may not yet exist, so you must make sure it exists before using 1011 * it such as with {@link File#mkdirs File.mkdirs()}. 1012 */ getExternalStoragePublicDirectory(String type)1013 public static File getExternalStoragePublicDirectory(String type) { 1014 throwIfUserRequired(); 1015 return sCurrentUser.buildExternalStoragePublicDirs(type)[0]; 1016 } 1017 1018 /** 1019 * Returns the path for android-specific data on the SD card. 1020 * @hide 1021 */ 1022 @UnsupportedAppUsage buildExternalStorageAndroidDataDirs()1023 public static File[] buildExternalStorageAndroidDataDirs() { 1024 throwIfUserRequired(); 1025 return sCurrentUser.buildExternalStorageAndroidDataDirs(); 1026 } 1027 1028 /** 1029 * Returns the path for android-specific OBB data on the SD card. 1030 * @hide 1031 */ buildExternalStorageAndroidObbDirs()1032 public static File[] buildExternalStorageAndroidObbDirs() { 1033 throwIfUserRequired(); 1034 return sCurrentUser.buildExternalStorageAndroidObbDirs(); 1035 } 1036 1037 /** 1038 * Generates the raw path to an application's data 1039 * @hide 1040 */ 1041 @UnsupportedAppUsage buildExternalStorageAppDataDirs(String packageName)1042 public static File[] buildExternalStorageAppDataDirs(String packageName) { 1043 throwIfUserRequired(); 1044 return sCurrentUser.buildExternalStorageAppDataDirs(packageName); 1045 } 1046 1047 /** 1048 * Generates the raw path to an application's media 1049 * @hide 1050 */ 1051 @UnsupportedAppUsage buildExternalStorageAppMediaDirs(String packageName)1052 public static File[] buildExternalStorageAppMediaDirs(String packageName) { 1053 throwIfUserRequired(); 1054 return sCurrentUser.buildExternalStorageAppMediaDirs(packageName); 1055 } 1056 1057 /** 1058 * Generates the raw path to an application's OBB files 1059 * @hide 1060 */ 1061 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) buildExternalStorageAppObbDirs(String packageName)1062 public static File[] buildExternalStorageAppObbDirs(String packageName) { 1063 throwIfUserRequired(); 1064 return sCurrentUser.buildExternalStorageAppObbDirs(packageName); 1065 } 1066 1067 /** 1068 * Generates the path to an application's files. 1069 * @hide 1070 */ 1071 @UnsupportedAppUsage buildExternalStorageAppFilesDirs(String packageName)1072 public static File[] buildExternalStorageAppFilesDirs(String packageName) { 1073 throwIfUserRequired(); 1074 return sCurrentUser.buildExternalStorageAppFilesDirs(packageName); 1075 } 1076 1077 /** 1078 * Generates the path to an application's cache. 1079 * @hide 1080 */ 1081 @UnsupportedAppUsage buildExternalStorageAppCacheDirs(String packageName)1082 public static File[] buildExternalStorageAppCacheDirs(String packageName) { 1083 throwIfUserRequired(); 1084 return sCurrentUser.buildExternalStorageAppCacheDirs(packageName); 1085 } 1086 1087 /** @hide */ buildExternalStoragePublicDirs(@onNull String dirType)1088 public static File[] buildExternalStoragePublicDirs(@NonNull String dirType) { 1089 throwIfUserRequired(); 1090 return sCurrentUser.buildExternalStoragePublicDirs(dirType); 1091 } 1092 1093 /** 1094 * Return the download/cache content directory. 1095 */ getDownloadCacheDirectory()1096 public static File getDownloadCacheDirectory() { 1097 return DIR_DOWNLOAD_CACHE; 1098 } 1099 1100 /** 1101 * Unknown storage state, such as when a path isn't backed by known storage 1102 * media. 1103 * 1104 * @see #getExternalStorageState(File) 1105 */ 1106 public static final String MEDIA_UNKNOWN = "unknown"; 1107 1108 /** 1109 * Storage state if the media is not present. 1110 * 1111 * @see #getExternalStorageState(File) 1112 */ 1113 public static final String MEDIA_REMOVED = "removed"; 1114 1115 /** 1116 * Storage state if the media is present but not mounted. 1117 * 1118 * @see #getExternalStorageState(File) 1119 */ 1120 public static final String MEDIA_UNMOUNTED = "unmounted"; 1121 1122 /** 1123 * Storage state if the media is present and being disk-checked. 1124 * 1125 * @see #getExternalStorageState(File) 1126 */ 1127 public static final String MEDIA_CHECKING = "checking"; 1128 1129 /** 1130 * Storage state if the media is present but is blank or is using an 1131 * unsupported filesystem. 1132 * 1133 * @see #getExternalStorageState(File) 1134 */ 1135 public static final String MEDIA_NOFS = "nofs"; 1136 1137 /** 1138 * Storage state if the media is present and mounted at its mount point with 1139 * read/write access. 1140 * 1141 * @see #getExternalStorageState(File) 1142 */ 1143 public static final String MEDIA_MOUNTED = "mounted"; 1144 1145 /** 1146 * Storage state if the media is present and mounted at its mount point with 1147 * read-only access. 1148 * 1149 * @see #getExternalStorageState(File) 1150 */ 1151 public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro"; 1152 1153 /** 1154 * Storage state if the media is present not mounted, and shared via USB 1155 * mass storage. 1156 * 1157 * @see #getExternalStorageState(File) 1158 */ 1159 public static final String MEDIA_SHARED = "shared"; 1160 1161 /** 1162 * Storage state if the media was removed before it was unmounted. 1163 * 1164 * @see #getExternalStorageState(File) 1165 */ 1166 public static final String MEDIA_BAD_REMOVAL = "bad_removal"; 1167 1168 /** 1169 * Storage state if the media is present but cannot be mounted. Typically 1170 * this happens if the file system on the media is corrupted. 1171 * 1172 * @see #getExternalStorageState(File) 1173 */ 1174 public static final String MEDIA_UNMOUNTABLE = "unmountable"; 1175 1176 /** 1177 * Storage state if the media is in the process of being ejected. 1178 * 1179 * @see #getExternalStorageState(File) 1180 */ 1181 public static final String MEDIA_EJECTING = "ejecting"; 1182 1183 /** 1184 * Returns the current state of the primary shared/external storage media. 1185 * 1186 * @see #getExternalStorageDirectory() 1187 * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED}, 1188 * {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING}, 1189 * {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED}, 1190 * {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED}, 1191 * {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}. 1192 */ getExternalStorageState()1193 public static String getExternalStorageState() { 1194 final File externalDir = sCurrentUser.getExternalDirs()[0]; 1195 return getExternalStorageState(externalDir); 1196 } 1197 1198 /** 1199 * @deprecated use {@link #getExternalStorageState(File)} 1200 */ 1201 @Deprecated getStorageState(File path)1202 public static String getStorageState(File path) { 1203 return getExternalStorageState(path); 1204 } 1205 1206 /** 1207 * Returns the current state of the shared/external storage media at the 1208 * given path. 1209 * 1210 * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED}, 1211 * {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING}, 1212 * {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED}, 1213 * {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED}, 1214 * {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}. 1215 */ getExternalStorageState(File path)1216 public static String getExternalStorageState(File path) { 1217 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId()); 1218 if (volume != null) { 1219 return volume.getState(); 1220 } else { 1221 return MEDIA_UNKNOWN; 1222 } 1223 } 1224 1225 /** 1226 * Returns whether the primary shared/external storage media is physically 1227 * removable. 1228 * 1229 * @return true if the storage device can be removed (such as an SD card), 1230 * or false if the storage device is built in and cannot be 1231 * physically removed. 1232 */ isExternalStorageRemovable()1233 public static boolean isExternalStorageRemovable() { 1234 final File externalDir = sCurrentUser.getExternalDirs()[0]; 1235 return isExternalStorageRemovable(externalDir); 1236 } 1237 1238 /** 1239 * Returns whether the shared/external storage media at the given path is 1240 * physically removable. 1241 * 1242 * @return true if the storage device can be removed (such as an SD card), 1243 * or false if the storage device is built in and cannot be 1244 * physically removed. 1245 * @throws IllegalArgumentException if the path is not a valid storage 1246 * device. 1247 */ isExternalStorageRemovable(@onNull File path)1248 public static boolean isExternalStorageRemovable(@NonNull File path) { 1249 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId()); 1250 if (volume != null) { 1251 return volume.isRemovable(); 1252 } else { 1253 throw new IllegalArgumentException("Failed to find storage device at " + path); 1254 } 1255 } 1256 1257 /** 1258 * Returns whether the primary shared/external storage media is emulated. 1259 * <p> 1260 * The contents of emulated storage devices are backed by a private user 1261 * data partition, which means there is little benefit to apps storing data 1262 * here instead of the private directories returned by 1263 * {@link Context#getFilesDir()}, etc. 1264 * <p> 1265 * This returns true when emulated storage is backed by either internal 1266 * storage or an adopted storage device. 1267 * 1268 * @see DevicePolicyManager#setStorageEncryption(android.content.ComponentName, 1269 * boolean) 1270 */ isExternalStorageEmulated()1271 public static boolean isExternalStorageEmulated() { 1272 final File externalDir = sCurrentUser.getExternalDirs()[0]; 1273 return isExternalStorageEmulated(externalDir); 1274 } 1275 1276 /** 1277 * Returns whether the shared/external storage media at the given path is 1278 * emulated. 1279 * <p> 1280 * The contents of emulated storage devices are backed by a private user 1281 * data partition, which means there is little benefit to apps storing data 1282 * here instead of the private directories returned by 1283 * {@link Context#getFilesDir()}, etc. 1284 * <p> 1285 * This returns true when emulated storage is backed by either internal 1286 * storage or an adopted storage device. 1287 * 1288 * @throws IllegalArgumentException if the path is not a valid storage 1289 * device. 1290 */ isExternalStorageEmulated(@onNull File path)1291 public static boolean isExternalStorageEmulated(@NonNull File path) { 1292 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId()); 1293 if (volume != null) { 1294 return volume.isEmulated(); 1295 } else { 1296 throw new IllegalArgumentException("Failed to find storage device at " + path); 1297 } 1298 } 1299 1300 /** 1301 * Returns whether the shared/external storage media is a 1302 * legacy view that includes files not owned by the app. 1303 * <p> 1304 * This value may be different from the value requested by 1305 * {@code requestLegacyExternalStorage} in the app's manifest, since an app 1306 * may inherit its legacy state based on when it was first installed, target sdk and other 1307 * factors. 1308 * <p> 1309 * Non-legacy apps can continue to discover and read media belonging to 1310 * other apps via {@link android.provider.MediaStore}. 1311 */ isExternalStorageLegacy()1312 public static boolean isExternalStorageLegacy() { 1313 final File externalDir = sCurrentUser.getExternalDirs()[0]; 1314 return isExternalStorageLegacy(externalDir); 1315 } 1316 1317 /** 1318 * Returns whether the shared/external storage media is a 1319 * legacy view that includes files not owned by the app. 1320 * <p> 1321 * This value may be different from the value requested by 1322 * {@code requestLegacyExternalStorage} in the app's manifest, since an app 1323 * may inherit its legacy state based on when it was first installed, target sdk and other 1324 * factors. 1325 * <p> 1326 * Non-legacy apps can continue to discover and read media belonging to 1327 * other apps via {@link android.provider.MediaStore}. 1328 * 1329 * @throws IllegalArgumentException if the path is not a valid storage 1330 * device. 1331 */ isExternalStorageLegacy(@onNull File path)1332 public static boolean isExternalStorageLegacy(@NonNull File path) { 1333 final Context context = AppGlobals.getInitialApplication(); 1334 final int uid = context.getApplicationInfo().uid; 1335 // Isolated processes and Instant apps are never allowed to be in scoped storage 1336 if (Process.isIsolated(uid)) { 1337 return false; 1338 } 1339 1340 final PackageManager packageManager = context.getPackageManager(); 1341 if (packageManager.isInstantApp()) { 1342 return false; 1343 } 1344 1345 boolean defaultScopedStorage = Compatibility.isChangeEnabled(DEFAULT_SCOPED_STORAGE); 1346 boolean forceEnableScopedStorage = Compatibility.isChangeEnabled( 1347 FORCE_ENABLE_SCOPED_STORAGE); 1348 // if Scoped Storage is strictly enforced, the app does *not* have legacy storage access 1349 // Note: does not require packagename/uid as this is directly called from an app process 1350 if (isScopedStorageEnforced(defaultScopedStorage, forceEnableScopedStorage)) { 1351 return false; 1352 } 1353 // if Scoped Storage is strictly disabled, the app has legacy storage access 1354 // Note: does not require packagename/uid as this is directly called from an app process 1355 if (isScopedStorageDisabled(defaultScopedStorage, forceEnableScopedStorage)) { 1356 return true; 1357 } 1358 1359 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); 1360 final String opPackageName = context.getOpPackageName(); 1361 1362 if (appOps.noteOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, uid, 1363 opPackageName) == AppOpsManager.MODE_ALLOWED) { 1364 return true; 1365 } 1366 1367 // Legacy external storage access is granted to instrumentations invoked with 1368 // "--no-isolated-storage" flag. 1369 return appOps.noteOpNoThrow(AppOpsManager.OP_NO_ISOLATED_STORAGE, uid, 1370 opPackageName) == AppOpsManager.MODE_ALLOWED; 1371 } 1372 isScopedStorageEnforced(boolean defaultScopedStorage, boolean forceEnableScopedStorage)1373 private static boolean isScopedStorageEnforced(boolean defaultScopedStorage, 1374 boolean forceEnableScopedStorage) { 1375 return defaultScopedStorage && forceEnableScopedStorage; 1376 } 1377 isScopedStorageDisabled(boolean defaultScopedStorage, boolean forceEnableScopedStorage)1378 private static boolean isScopedStorageDisabled(boolean defaultScopedStorage, 1379 boolean forceEnableScopedStorage) { 1380 return !defaultScopedStorage && !forceEnableScopedStorage; 1381 } 1382 1383 /** 1384 * Returns whether the calling app has All Files Access on the primary shared/external storage 1385 * media. 1386 * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't 1387 * enough to gain the access. 1388 * <p>To request access, use 1389 * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}. 1390 */ isExternalStorageManager()1391 public static boolean isExternalStorageManager() { 1392 final File externalDir = sCurrentUser.getExternalDirs()[0]; 1393 return isExternalStorageManager(externalDir); 1394 } 1395 1396 /** 1397 * Returns whether the calling app has All Files Access at the given {@code path} 1398 * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't 1399 * enough to gain the access. 1400 * <p>To request access, use 1401 * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}. 1402 */ isExternalStorageManager(@onNull File path)1403 public static boolean isExternalStorageManager(@NonNull File path) { 1404 final Context context = Objects.requireNonNull(AppGlobals.getInitialApplication()); 1405 String packageName = Objects.requireNonNull(context.getPackageName()); 1406 int uid = context.getApplicationInfo().uid; 1407 1408 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); 1409 final int opMode = 1410 appOps.checkOpNoThrow(AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE, uid, packageName); 1411 1412 switch (opMode) { 1413 case AppOpsManager.MODE_DEFAULT: 1414 return PackageManager.PERMISSION_GRANTED 1415 == context.checkPermission( 1416 Manifest.permission.MANAGE_EXTERNAL_STORAGE, Process.myPid(), uid); 1417 case AppOpsManager.MODE_ALLOWED: 1418 return true; 1419 case AppOpsManager.MODE_ERRORED: 1420 case AppOpsManager.MODE_IGNORED: 1421 return false; 1422 default: 1423 throw new IllegalStateException("Unknown AppOpsManager mode " + opMode); 1424 } 1425 } 1426 getDirectory(String variableName, String defaultPath)1427 static File getDirectory(String variableName, String defaultPath) { 1428 String path = System.getenv(variableName); 1429 return path == null ? new File(defaultPath) : new File(path); 1430 } 1431 1432 @NonNull getDirectoryPath(@onNull String variableName, @NonNull String defaultPath)1433 static String getDirectoryPath(@NonNull String variableName, @NonNull String defaultPath) { 1434 String path = System.getenv(variableName); 1435 return path == null ? defaultPath : path; 1436 } 1437 1438 /** {@hide} */ setUserRequired(boolean userRequired)1439 public static void setUserRequired(boolean userRequired) { 1440 sUserRequired = userRequired; 1441 } 1442 throwIfUserRequired()1443 private static void throwIfUserRequired() { 1444 if (sUserRequired) { 1445 Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment", 1446 new Throwable()); 1447 } 1448 } 1449 1450 /** 1451 * Append path segments to each given base path, returning result. 1452 * 1453 * @hide 1454 */ 1455 @UnsupportedAppUsage buildPaths(File[] base, String... segments)1456 public static File[] buildPaths(File[] base, String... segments) { 1457 File[] result = new File[base.length]; 1458 for (int i = 0; i < base.length; i++) { 1459 result[i] = buildPath(base[i], segments); 1460 } 1461 return result; 1462 } 1463 1464 /** 1465 * Append path segments to given base path, returning result. 1466 * 1467 * @hide 1468 */ 1469 @TestApi buildPath(File base, String... segments)1470 public static File buildPath(File base, String... segments) { 1471 File cur = base; 1472 for (String segment : segments) { 1473 if (cur == null) { 1474 cur = new File(segment); 1475 } else { 1476 cur = new File(cur, segment); 1477 } 1478 } 1479 return cur; 1480 } 1481 1482 /** 1483 * If the given path exists on emulated external storage, return the 1484 * translated backing path hosted on internal storage. This bypasses any 1485 * emulation later, improving performance. This is <em>only</em> suitable 1486 * for read-only access. 1487 * <p> 1488 * Returns original path if given path doesn't meet these criteria. Callers 1489 * must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} 1490 * permission. 1491 * 1492 * @deprecated disabled now that FUSE has been replaced by sdcardfs 1493 * @hide 1494 */ 1495 @UnsupportedAppUsage 1496 @Deprecated maybeTranslateEmulatedPathToInternal(File path)1497 public static File maybeTranslateEmulatedPathToInternal(File path) { 1498 return StorageManager.maybeTranslateEmulatedPathToInternal(path); 1499 } 1500 } 1501