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