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.pm.ApplicationInfo; 33 import android.content.pm.PackageManager; 34 import android.os.storage.StorageManager; 35 import android.os.storage.StorageVolume; 36 import android.provider.MediaStore; 37 import android.text.TextUtils; 38 import android.util.Log; 39 40 import java.io.File; 41 import java.io.IOException; 42 import java.util.ArrayList; 43 import java.util.Collection; 44 import java.util.LinkedList; 45 import java.util.List; 46 import java.util.Objects; 47 48 /** 49 * Provides access to environment variables. 50 */ 51 public class Environment { 52 private static final String TAG = "Environment"; 53 54 // NOTE: keep credential-protected paths in sync with StrictMode.java 55 56 private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE"; 57 private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT"; 58 private static final String ENV_ANDROID_DATA = "ANDROID_DATA"; 59 private static final String ENV_ANDROID_EXPAND = "ANDROID_EXPAND"; 60 private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE"; 61 private static final String ENV_DOWNLOAD_CACHE = "DOWNLOAD_CACHE"; 62 private static final String ENV_OEM_ROOT = "OEM_ROOT"; 63 private static final String ENV_ODM_ROOT = "ODM_ROOT"; 64 private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT"; 65 private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT"; 66 private static final String ENV_SYSTEM_EXT_ROOT = "SYSTEM_EXT_ROOT"; 67 private static final String ENV_APEX_ROOT = "APEX_ROOT"; 68 69 /** {@hide} */ 70 public static final String DIR_ANDROID = "Android"; 71 private static final String DIR_DATA = "data"; 72 private static final String DIR_MEDIA = "media"; 73 private static final String DIR_OBB = "obb"; 74 private static final String DIR_FILES = "files"; 75 private static final String DIR_CACHE = "cache"; 76 77 /** 78 * The folder name prefix for the user credential protected data directory. This is exposed for 79 * use in string path caching for {@link ApplicationInfo} objects, and should not be accessed 80 * directly otherwise. Prefer {@link #getDataUserCeDirectory(String, int)}. 81 * {@hide} 82 */ 83 public static final String DIR_USER_CE = "user"; 84 85 /** 86 * The folder name prefix for the user device protected data directory. This is exposed for use 87 * in string path caching for {@link ApplicationInfo} objects, and should not be accessed 88 * directly otherwise. Prefer {@link #getDataUserDeDirectory(String, int)}. 89 * {@hide} 90 */ 91 public static final String DIR_USER_DE = "user_de"; 92 93 /** {@hide} */ 94 @Deprecated 95 public static final String DIRECTORY_ANDROID = DIR_ANDROID; 96 97 private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system"); 98 private static final String DIR_ANDROID_DATA_PATH = getDirectoryPath(ENV_ANDROID_DATA, "/data"); 99 private static final File DIR_ANDROID_DATA = new File(DIR_ANDROID_DATA_PATH); 100 private static final File DIR_ANDROID_EXPAND = getDirectory(ENV_ANDROID_EXPAND, "/mnt/expand"); 101 private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage"); 102 private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache"); 103 private static final File DIR_METADATA = new File("/metadata"); 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} */ getDataMiscCeDirectory(String volumeUuid, int userId)481 private static File getDataMiscCeDirectory(String volumeUuid, int userId) { 482 return buildPath(getDataDirectory(volumeUuid), "misc_ce", String.valueOf(userId)); 483 } 484 485 /** {@hide} */ getDataMiscCeSharedSdkSandboxDirectory(String volumeUuid, int userId, String packageName)486 public static File getDataMiscCeSharedSdkSandboxDirectory(String volumeUuid, int userId, 487 String packageName) { 488 return buildPath(getDataMiscCeDirectory(volumeUuid, userId), "sdksandbox", 489 packageName, "shared"); 490 } 491 492 /** {@hide} */ getDataMiscDeDirectory(int userId)493 public static File getDataMiscDeDirectory(int userId) { 494 return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId)); 495 } 496 497 /** {@hide} */ getDataMiscDeDirectory(String volumeUuid, int userId)498 private static File getDataMiscDeDirectory(String volumeUuid, int userId) { 499 return buildPath(getDataDirectory(volumeUuid), "misc_de", String.valueOf(userId)); 500 } 501 502 /** {@hide} */ getDataMiscDeSharedSdkSandboxDirectory(String volumeUuid, int userId, String packageName)503 public static File getDataMiscDeSharedSdkSandboxDirectory(String volumeUuid, int userId, 504 String packageName) { 505 return buildPath(getDataMiscDeDirectory(volumeUuid, userId), "sdksandbox", 506 packageName, "shared"); 507 } 508 getDataProfilesDeDirectory(int userId)509 private static File getDataProfilesDeDirectory(int userId) { 510 return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId)); 511 } 512 513 /** {@hide} */ getDataVendorCeDirectory(int userId)514 public static File getDataVendorCeDirectory(int userId) { 515 return buildPath(getDataDirectory(), "vendor_ce", String.valueOf(userId)); 516 } 517 518 /** {@hide} */ getDataVendorDeDirectory(int userId)519 public static File getDataVendorDeDirectory(int userId) { 520 return buildPath(getDataDirectory(), "vendor_de", String.valueOf(userId)); 521 } 522 523 /** {@hide} */ getDataRefProfilesDePackageDirectory(String packageName)524 public static File getDataRefProfilesDePackageDirectory(String packageName) { 525 return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName); 526 } 527 528 /** {@hide} */ getDataProfilesDePackageDirectory(int userId, String packageName)529 public static File getDataProfilesDePackageDirectory(int userId, String packageName) { 530 return buildPath(getDataProfilesDeDirectory(userId), packageName); 531 } 532 533 /** {@hide} */ getDataAppDirectory(String volumeUuid)534 public static File getDataAppDirectory(String volumeUuid) { 535 return new File(getDataDirectory(volumeUuid), "app"); 536 } 537 538 /** {@hide} */ getDataStagingDirectory(String volumeUuid)539 public static File getDataStagingDirectory(String volumeUuid) { 540 return new File(getDataDirectory(volumeUuid), "app-staging"); 541 } 542 543 /** {@hide} */ getDataUserCeDirectory(String volumeUuid)544 public static File getDataUserCeDirectory(String volumeUuid) { 545 return new File(getDataDirectory(volumeUuid), DIR_USER_CE); 546 } 547 548 /** {@hide} */ getDataUserCeDirectory(String volumeUuid, int userId)549 public static File getDataUserCeDirectory(String volumeUuid, int userId) { 550 return new File(getDataUserCeDirectory(volumeUuid), String.valueOf(userId)); 551 } 552 553 /** {@hide} */ getDataUserCePackageDirectory(String volumeUuid, int userId, String packageName)554 public static File getDataUserCePackageDirectory(String volumeUuid, int userId, 555 String packageName) { 556 // TODO: keep consistent with installd 557 return new File(getDataUserCeDirectory(volumeUuid, userId), packageName); 558 } 559 560 /** {@hide} */ getDataUserDeDirectory(String volumeUuid)561 public static File getDataUserDeDirectory(String volumeUuid) { 562 return new File(getDataDirectory(volumeUuid), DIR_USER_DE); 563 } 564 565 /** {@hide} */ getDataUserDeDirectory(String volumeUuid, int userId)566 public static File getDataUserDeDirectory(String volumeUuid, int userId) { 567 return new File(getDataUserDeDirectory(volumeUuid), String.valueOf(userId)); 568 } 569 570 /** {@hide} */ getDataUserDePackageDirectory(String volumeUuid, int userId, String packageName)571 public static File getDataUserDePackageDirectory(String volumeUuid, int userId, 572 String packageName) { 573 // TODO: keep consistent with installd 574 return new File(getDataUserDeDirectory(volumeUuid, userId), packageName); 575 } 576 577 /** 578 * Return preloads directory. 579 * <p>This directory may contain pre-loaded content such as 580 * {@link #getDataPreloadsDemoDirectory() demo videos} and 581 * {@link #getDataPreloadsAppsDirectory() APK files} . 582 * {@hide} 583 */ getDataPreloadsDirectory()584 public static File getDataPreloadsDirectory() { 585 return new File(getDataDirectory(), "preloads"); 586 } 587 588 /** 589 * @see #getDataPreloadsDirectory() 590 * {@hide} 591 */ getDataPreloadsDemoDirectory()592 public static File getDataPreloadsDemoDirectory() { 593 return new File(getDataPreloadsDirectory(), "demo"); 594 } 595 596 /** 597 * @see #getDataPreloadsDirectory() 598 * {@hide} 599 */ getDataPreloadsAppsDirectory()600 public static File getDataPreloadsAppsDirectory() { 601 return new File(getDataPreloadsDirectory(), "apps"); 602 } 603 604 /** 605 * @see #getDataPreloadsDirectory() 606 * {@hide} 607 */ getDataPreloadsMediaDirectory()608 public static File getDataPreloadsMediaDirectory() { 609 return new File(getDataPreloadsDirectory(), "media"); 610 } 611 612 /** 613 * Returns location of preloaded cache directory for package name 614 * @see #getDataPreloadsDirectory() 615 * {@hide} 616 */ getDataPreloadsFileCacheDirectory(String packageName)617 public static File getDataPreloadsFileCacheDirectory(String packageName) { 618 return new File(getDataPreloadsFileCacheDirectory(), packageName); 619 } 620 621 /** 622 * Returns location of preloaded cache directory. 623 * @see #getDataPreloadsDirectory() 624 * {@hide} 625 */ getDataPreloadsFileCacheDirectory()626 public static File getDataPreloadsFileCacheDirectory() { 627 return new File(getDataPreloadsDirectory(), "file_cache"); 628 } 629 630 /** 631 * Returns location of packages cache directory. 632 * {@hide} 633 */ getPackageCacheDirectory()634 public static File getPackageCacheDirectory() { 635 return new File(getDataSystemDirectory(), "package_cache"); 636 } 637 638 /** 639 * Return locations where media files (such as ringtones, notification 640 * sounds, or alarm sounds) may be located on internal storage. These are 641 * typically indexed under {@link MediaStore#VOLUME_INTERNAL}. 642 * 643 * @hide 644 */ 645 @SystemApi getInternalMediaDirectories()646 public static @NonNull Collection<File> getInternalMediaDirectories() { 647 final ArrayList<File> res = new ArrayList<>(); 648 addCanonicalFile(res, new File(Environment.getRootDirectory(), "media")); 649 addCanonicalFile(res, new File(Environment.getOemDirectory(), "media")); 650 addCanonicalFile(res, new File(Environment.getProductDirectory(), "media")); 651 return res; 652 } 653 addCanonicalFile(List<File> list, File file)654 private static void addCanonicalFile(List<File> list, File file) { 655 try { 656 list.add(file.getCanonicalFile()); 657 } catch (IOException e) { 658 Log.w(TAG, "Failed to resolve " + file + ": " + e); 659 list.add(file); 660 } 661 } 662 663 /** 664 * Return the primary shared/external storage directory. This directory may 665 * not currently be accessible if it has been mounted by the user on their 666 * computer, has been removed from the device, or some other problem has 667 * happened. You can determine its current state with 668 * {@link #getExternalStorageState()}. 669 * <p> 670 * <em>Note: don't be confused by the word "external" here. This directory 671 * can better be thought as media/shared storage. It is a filesystem that 672 * can hold a relatively large amount of data and that is shared across all 673 * applications (does not enforce permissions). Traditionally this is an SD 674 * card, but it may also be implemented as built-in storage in a device that 675 * is distinct from the protected internal storage and can be mounted as a 676 * filesystem on a computer.</em> 677 * <p> 678 * On devices with multiple users (as described by {@link UserManager}), 679 * each user has their own isolated shared storage. Applications only have 680 * access to the shared storage for the user they're running as. 681 * <p> 682 * In devices with multiple shared/external storage directories, this 683 * directory represents the primary storage that the user will interact 684 * with. Access to secondary storage is available through 685 * {@link Context#getExternalFilesDirs(String)}, 686 * {@link Context#getExternalCacheDirs()}, and 687 * {@link Context#getExternalMediaDirs()}. 688 * <p> 689 * Applications should not directly use this top-level directory, in order 690 * to avoid polluting the user's root namespace. Any files that are private 691 * to the application should be placed in a directory returned by 692 * {@link android.content.Context#getExternalFilesDir 693 * Context.getExternalFilesDir}, which the system will take care of deleting 694 * if the application is uninstalled. Other shared files should be placed in 695 * one of the directories returned by 696 * {@link #getExternalStoragePublicDirectory}. 697 * <p> 698 * Writing to this path requires the 699 * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission, 700 * and starting in {@link android.os.Build.VERSION_CODES#KITKAT}, read 701 * access requires the 702 * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission, 703 * which is automatically granted if you hold the write permission. 704 * <p> 705 * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your 706 * application only needs to store internal data, consider using 707 * {@link Context#getExternalFilesDir(String)}, 708 * {@link Context#getExternalCacheDir()}, or 709 * {@link Context#getExternalMediaDirs()}, which require no permissions to 710 * read or write. 711 * <p> 712 * This path may change between platform versions, so applications should 713 * only persist relative paths. 714 * <p> 715 * Here is an example of typical code to monitor the state of external 716 * storage: 717 * <p> 718 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java 719 * monitor_storage} 720 * <p> 721 * Note that alternatives such as {@link Context#getExternalFilesDir(String)} or 722 * {@link MediaStore} offer better performance. 723 * 724 * @see #getExternalStorageState() 725 * @see #isExternalStorageRemovable() 726 */ getExternalStorageDirectory()727 public static File getExternalStorageDirectory() { 728 throwIfUserRequired(); 729 return sCurrentUser.getExternalDirs()[0]; 730 } 731 732 /** {@hide} */ 733 @UnsupportedAppUsage getLegacyExternalStorageDirectory()734 public static File getLegacyExternalStorageDirectory() { 735 return new File(System.getenv(ENV_EXTERNAL_STORAGE)); 736 } 737 738 /** {@hide} */ 739 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getLegacyExternalStorageObbDirectory()740 public static File getLegacyExternalStorageObbDirectory() { 741 return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB); 742 } 743 744 /** 745 * Standard directory in which to place any audio files that should be 746 * in the regular list of music for the user. 747 * This may be combined with {@link #DIRECTORY_AUDIOBOOKS}, 748 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, 749 * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and 750 * {@link #DIRECTORY_RECORDINGS} as a series of directories to 751 * categorize a particular audio file as more than one type. 752 */ 753 public static String DIRECTORY_MUSIC = "Music"; 754 755 /** 756 * Standard directory in which to place any audio files that should be 757 * in the list of podcasts 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_NOTIFICATIONS}, 761 * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and 762 * {@link #DIRECTORY_RECORDINGS} as a series of directories to 763 * categorize a particular audio file as more than one type. 764 */ 765 public static String DIRECTORY_PODCASTS = "Podcasts"; 766 767 /** 768 * Standard directory in which to place any audio files that should be 769 * in the list of ringtones 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_NOTIFICATIONS}, {@link #DIRECTORY_ALARMS}, 774 * and {@link #DIRECTORY_RECORDINGS} as a series of directories 775 * to categorize a particular audio file as more than one type. 776 */ 777 public static String DIRECTORY_RINGTONES = "Ringtones"; 778 779 /** 780 * Standard directory in which to place any audio files that should be 781 * in the list of alarms that the user can select (not as regular 782 * music). 783 * This may be combined with {@link #DIRECTORY_MUSIC}, 784 * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS}, 785 * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_RINGTONES}, 786 * and {@link #DIRECTORY_RECORDINGS} as a series of directories 787 * to categorize a particular audio file as more than one type. 788 */ 789 public static String DIRECTORY_ALARMS = "Alarms"; 790 791 /** 792 * Standard directory in which to place any audio files that should be 793 * in the list of notifications that the user can select (not as regular 794 * music). 795 * This may be combined with {@link #DIRECTORY_MUSIC}, 796 * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS}, 797 * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and 798 * {@link #DIRECTORY_RECORDINGS} as a series of directories to 799 * categorize a particular audio file as more than one type. 800 */ 801 public static String DIRECTORY_NOTIFICATIONS = "Notifications"; 802 803 /** 804 * Standard directory in which to place pictures that are available to 805 * the user. Note that this is primarily a convention for the top-level 806 * public directory, as the media scanner will find and collect pictures 807 * in any directory. 808 */ 809 public static String DIRECTORY_PICTURES = "Pictures"; 810 811 /** 812 * Standard directory in which to place movies that are available to 813 * the user. Note that this is primarily a convention for the top-level 814 * public directory, as the media scanner will find and collect movies 815 * in any directory. 816 */ 817 public static String DIRECTORY_MOVIES = "Movies"; 818 819 /** 820 * Standard directory in which to place files that have been downloaded by 821 * the user. Note that this is primarily a convention for the top-level 822 * public directory, you are free to download files anywhere in your own 823 * private directories. Also note that though the constant here is 824 * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for 825 * backwards compatibility reasons. 826 */ 827 public static String DIRECTORY_DOWNLOADS = "Download"; 828 829 /** 830 * The traditional location for pictures and videos when mounting the 831 * device as a camera. Note that this is primarily a convention for the 832 * top-level public directory, as this convention makes no sense elsewhere. 833 */ 834 public static String DIRECTORY_DCIM = "DCIM"; 835 836 /** 837 * Standard directory in which to place documents that have been created by 838 * the user. 839 */ 840 public static String DIRECTORY_DOCUMENTS = "Documents"; 841 842 /** 843 * Standard directory in which to place screenshots that have been taken by 844 * the user. Typically used as a secondary directory under 845 * {@link #DIRECTORY_PICTURES}. 846 */ 847 public static String DIRECTORY_SCREENSHOTS = "Screenshots"; 848 849 /** 850 * Standard directory in which to place any audio files that should be 851 * in the list of audiobooks that the user can select (not as regular 852 * music). 853 * This may be combined with {@link #DIRECTORY_MUSIC}, 854 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, 855 * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, 856 * and {@link #DIRECTORY_RECORDINGS} as a series of directories 857 * to categorize a particular audio file as more than one type. 858 */ 859 public static String DIRECTORY_AUDIOBOOKS = "Audiobooks"; 860 861 /** 862 * Standard directory in which to place any audio files that should be 863 * in the list of voice recordings recorded by voice recorder apps that 864 * the user can select (not as regular music). 865 * This may be combined with {@link #DIRECTORY_MUSIC}, 866 * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS}, 867 * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_ALARMS}, 868 * and {@link #DIRECTORY_RINGTONES} as a series of directories 869 * to categorize a particular audio file as more than one type. 870 */ 871 @NonNull 872 // The better way is that expose a static method getRecordingDirectories. 873 // But since it's an existing API surface and developers already 874 // used to DIRECTORY_* constants, we should keep using this pattern 875 // for consistency. We use SuppressLint here to avoid exposing a final 876 // field. A final field will prevent us from ever changing the value of 877 // DIRECTORY_RECORDINGS. Not that it's likely that we will ever need to 878 // change it, but it's better to have such option. 879 @SuppressLint({"MutableBareField", "AllUpper"}) 880 public static String DIRECTORY_RECORDINGS = "Recordings"; 881 882 /** 883 * List of standard storage directories. 884 * <p> 885 * Each of its values have its own constant: 886 * <ul> 887 * <li>{@link #DIRECTORY_MUSIC} 888 * <li>{@link #DIRECTORY_PODCASTS} 889 * <li>{@link #DIRECTORY_ALARMS} 890 * <li>{@link #DIRECTORY_RINGTONES} 891 * <li>{@link #DIRECTORY_NOTIFICATIONS} 892 * <li>{@link #DIRECTORY_PICTURES} 893 * <li>{@link #DIRECTORY_MOVIES} 894 * <li>{@link #DIRECTORY_DOWNLOADS} 895 * <li>{@link #DIRECTORY_DCIM} 896 * <li>{@link #DIRECTORY_DOCUMENTS} 897 * <li>{@link #DIRECTORY_AUDIOBOOKS} 898 * <li>{@link #DIRECTORY_RECORDINGS} 899 * </ul> 900 * @hide 901 */ 902 public static final String[] STANDARD_DIRECTORIES = { 903 DIRECTORY_MUSIC, 904 DIRECTORY_PODCASTS, 905 DIRECTORY_RINGTONES, 906 DIRECTORY_ALARMS, 907 DIRECTORY_NOTIFICATIONS, 908 DIRECTORY_PICTURES, 909 DIRECTORY_MOVIES, 910 DIRECTORY_DOWNLOADS, 911 DIRECTORY_DCIM, 912 DIRECTORY_DOCUMENTS, 913 DIRECTORY_AUDIOBOOKS, 914 DIRECTORY_RECORDINGS, 915 }; 916 917 /** 918 * @hide 919 */ isStandardDirectory(String dir)920 public static boolean isStandardDirectory(String dir) { 921 for (String valid : STANDARD_DIRECTORIES) { 922 if (valid.equals(dir)) { 923 return true; 924 } 925 } 926 return false; 927 } 928 929 /** {@hide} */ public static final int HAS_MUSIC = 1 << 0; 930 /** {@hide} */ public static final int HAS_PODCASTS = 1 << 1; 931 /** {@hide} */ public static final int HAS_RINGTONES = 1 << 2; 932 /** {@hide} */ public static final int HAS_ALARMS = 1 << 3; 933 /** {@hide} */ public static final int HAS_NOTIFICATIONS = 1 << 4; 934 /** {@hide} */ public static final int HAS_PICTURES = 1 << 5; 935 /** {@hide} */ public static final int HAS_MOVIES = 1 << 6; 936 /** {@hide} */ public static final int HAS_DOWNLOADS = 1 << 7; 937 /** {@hide} */ public static final int HAS_DCIM = 1 << 8; 938 /** {@hide} */ public static final int HAS_DOCUMENTS = 1 << 9; 939 /** {@hide} */ public static final int HAS_AUDIOBOOKS = 1 << 10; 940 /** {@hide} */ public static final int HAS_RECORDINGS = 1 << 11; 941 942 /** {@hide} */ public static final int HAS_ANDROID = 1 << 16; 943 /** {@hide} */ public static final int HAS_OTHER = 1 << 17; 944 945 /** 946 * Classify the content types present on the given external storage device. 947 * <p> 948 * This is typically useful for deciding if an inserted SD card is empty, or 949 * if it contains content like photos that should be preserved. 950 * 951 * @hide 952 */ classifyExternalStorageDirectory(File dir)953 public static int classifyExternalStorageDirectory(File dir) { 954 int res = 0; 955 for (File f : FileUtils.listFilesOrEmpty(dir)) { 956 if (f.isFile() && isInterestingFile(f)) { 957 res |= HAS_OTHER; 958 } else if (f.isDirectory() && hasInterestingFiles(f)) { 959 final String name = f.getName(); 960 if (DIRECTORY_MUSIC.equals(name)) res |= HAS_MUSIC; 961 else if (DIRECTORY_PODCASTS.equals(name)) res |= HAS_PODCASTS; 962 else if (DIRECTORY_RINGTONES.equals(name)) res |= HAS_RINGTONES; 963 else if (DIRECTORY_ALARMS.equals(name)) res |= HAS_ALARMS; 964 else if (DIRECTORY_NOTIFICATIONS.equals(name)) res |= HAS_NOTIFICATIONS; 965 else if (DIRECTORY_PICTURES.equals(name)) res |= HAS_PICTURES; 966 else if (DIRECTORY_MOVIES.equals(name)) res |= HAS_MOVIES; 967 else if (DIRECTORY_DOWNLOADS.equals(name)) res |= HAS_DOWNLOADS; 968 else if (DIRECTORY_DCIM.equals(name)) res |= HAS_DCIM; 969 else if (DIRECTORY_DOCUMENTS.equals(name)) res |= HAS_DOCUMENTS; 970 else if (DIRECTORY_AUDIOBOOKS.equals(name)) res |= HAS_AUDIOBOOKS; 971 else if (DIRECTORY_RECORDINGS.equals(name)) res |= HAS_RECORDINGS; 972 else if (DIRECTORY_ANDROID.equals(name)) res |= HAS_ANDROID; 973 else res |= HAS_OTHER; 974 } 975 } 976 return res; 977 } 978 hasInterestingFiles(File dir)979 private static boolean hasInterestingFiles(File dir) { 980 final LinkedList<File> explore = new LinkedList<>(); 981 explore.add(dir); 982 while (!explore.isEmpty()) { 983 dir = explore.pop(); 984 for (File f : FileUtils.listFilesOrEmpty(dir)) { 985 if (isInterestingFile(f)) return true; 986 if (f.isDirectory()) explore.add(f); 987 } 988 } 989 return false; 990 } 991 isInterestingFile(File file)992 private static boolean isInterestingFile(File file) { 993 if (file.isFile()) { 994 final String name = file.getName().toLowerCase(); 995 if (name.endsWith(".exe") || name.equals("autorun.inf") 996 || name.equals("launchpad.zip") || name.equals(".nomedia")) { 997 return false; 998 } else { 999 return true; 1000 } 1001 } else { 1002 return false; 1003 } 1004 } 1005 1006 /** 1007 * Get a top-level shared/external storage directory for placing files of a 1008 * particular type. This is where the user will typically place and manage 1009 * their own files, so you should be careful about what you put here to 1010 * ensure you don't erase their files or get in the way of their own 1011 * organization. 1012 * <p> 1013 * On devices with multiple users (as described by {@link UserManager}), 1014 * each user has their own isolated shared storage. Applications only have 1015 * access to the shared storage for the user they're running as. 1016 * </p> 1017 * <p> 1018 * Here is an example of typical code to manipulate a picture on the public 1019 * shared storage: 1020 * </p> 1021 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java 1022 * public_picture} 1023 * <p> 1024 * Note that alternatives such as {@link Context#getExternalFilesDir(String)} or 1025 * {@link MediaStore} offer better performance. 1026 * 1027 * @param type The type of storage directory to return. Should be one of 1028 * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS}, 1029 * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS}, 1030 * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES}, 1031 * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, 1032 * {@link #DIRECTORY_DCIM}, or {@link #DIRECTORY_DOCUMENTS}. May not be null. 1033 * @return Returns the File path for the directory. Note that this directory 1034 * may not yet exist, so you must make sure it exists before using 1035 * it such as with {@link File#mkdirs File.mkdirs()}. 1036 */ getExternalStoragePublicDirectory(String type)1037 public static File getExternalStoragePublicDirectory(String type) { 1038 throwIfUserRequired(); 1039 return sCurrentUser.buildExternalStoragePublicDirs(type)[0]; 1040 } 1041 1042 /** 1043 * Returns the path for android-specific data on the SD card. 1044 * @hide 1045 */ 1046 @UnsupportedAppUsage buildExternalStorageAndroidDataDirs()1047 public static File[] buildExternalStorageAndroidDataDirs() { 1048 throwIfUserRequired(); 1049 return sCurrentUser.buildExternalStorageAndroidDataDirs(); 1050 } 1051 1052 /** 1053 * Returns the path for android-specific OBB data on the SD card. 1054 * @hide 1055 */ buildExternalStorageAndroidObbDirs()1056 public static File[] buildExternalStorageAndroidObbDirs() { 1057 throwIfUserRequired(); 1058 return sCurrentUser.buildExternalStorageAndroidObbDirs(); 1059 } 1060 1061 /** 1062 * Generates the raw path to an application's data 1063 * @hide 1064 */ 1065 @UnsupportedAppUsage buildExternalStorageAppDataDirs(String packageName)1066 public static File[] buildExternalStorageAppDataDirs(String packageName) { 1067 throwIfUserRequired(); 1068 return sCurrentUser.buildExternalStorageAppDataDirs(packageName); 1069 } 1070 1071 /** 1072 * Generates the raw path to an application's media 1073 * @hide 1074 */ 1075 @UnsupportedAppUsage buildExternalStorageAppMediaDirs(String packageName)1076 public static File[] buildExternalStorageAppMediaDirs(String packageName) { 1077 throwIfUserRequired(); 1078 return sCurrentUser.buildExternalStorageAppMediaDirs(packageName); 1079 } 1080 1081 /** 1082 * Generates the raw path to an application's OBB files 1083 * @hide 1084 */ 1085 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) buildExternalStorageAppObbDirs(String packageName)1086 public static File[] buildExternalStorageAppObbDirs(String packageName) { 1087 throwIfUserRequired(); 1088 return sCurrentUser.buildExternalStorageAppObbDirs(packageName); 1089 } 1090 1091 /** 1092 * Generates the path to an application's files. 1093 * @hide 1094 */ 1095 @UnsupportedAppUsage buildExternalStorageAppFilesDirs(String packageName)1096 public static File[] buildExternalStorageAppFilesDirs(String packageName) { 1097 throwIfUserRequired(); 1098 return sCurrentUser.buildExternalStorageAppFilesDirs(packageName); 1099 } 1100 1101 /** 1102 * Generates the path to an application's cache. 1103 * @hide 1104 */ 1105 @UnsupportedAppUsage buildExternalStorageAppCacheDirs(String packageName)1106 public static File[] buildExternalStorageAppCacheDirs(String packageName) { 1107 throwIfUserRequired(); 1108 return sCurrentUser.buildExternalStorageAppCacheDirs(packageName); 1109 } 1110 1111 /** @hide */ buildExternalStoragePublicDirs(@onNull String dirType)1112 public static File[] buildExternalStoragePublicDirs(@NonNull String dirType) { 1113 throwIfUserRequired(); 1114 return sCurrentUser.buildExternalStoragePublicDirs(dirType); 1115 } 1116 1117 /** 1118 * Return the download/cache content directory. 1119 */ getDownloadCacheDirectory()1120 public static File getDownloadCacheDirectory() { 1121 return DIR_DOWNLOAD_CACHE; 1122 } 1123 1124 /** 1125 * Return the metadata directory. 1126 * 1127 * @hide 1128 */ getMetadataDirectory()1129 public static @NonNull File getMetadataDirectory() { 1130 return DIR_METADATA; 1131 } 1132 1133 /** 1134 * Unknown storage state, such as when a path isn't backed by known storage 1135 * media. 1136 * 1137 * @see #getExternalStorageState(File) 1138 */ 1139 public static final String MEDIA_UNKNOWN = "unknown"; 1140 1141 /** 1142 * Storage state if the media is not present. 1143 * 1144 * @see #getExternalStorageState(File) 1145 */ 1146 public static final String MEDIA_REMOVED = "removed"; 1147 1148 /** 1149 * Storage state if the media is present but not mounted. 1150 * 1151 * @see #getExternalStorageState(File) 1152 */ 1153 public static final String MEDIA_UNMOUNTED = "unmounted"; 1154 1155 /** 1156 * Storage state if the media is present and being disk-checked. 1157 * 1158 * @see #getExternalStorageState(File) 1159 */ 1160 public static final String MEDIA_CHECKING = "checking"; 1161 1162 /** 1163 * Storage state if the media is present but is blank or is using an 1164 * unsupported filesystem. 1165 * 1166 * @see #getExternalStorageState(File) 1167 */ 1168 public static final String MEDIA_NOFS = "nofs"; 1169 1170 /** 1171 * Storage state if the media is present and mounted at its mount point with 1172 * read/write access. 1173 * 1174 * @see #getExternalStorageState(File) 1175 */ 1176 public static final String MEDIA_MOUNTED = "mounted"; 1177 1178 /** 1179 * Storage state if the media is present and mounted at its mount point with 1180 * read-only access. 1181 * 1182 * @see #getExternalStorageState(File) 1183 */ 1184 public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro"; 1185 1186 /** 1187 * Storage state if the media is present not mounted, and shared via USB 1188 * mass storage. 1189 * 1190 * @see #getExternalStorageState(File) 1191 */ 1192 public static final String MEDIA_SHARED = "shared"; 1193 1194 /** 1195 * Storage state if the media was removed before it was unmounted. 1196 * 1197 * @see #getExternalStorageState(File) 1198 */ 1199 public static final String MEDIA_BAD_REMOVAL = "bad_removal"; 1200 1201 /** 1202 * Storage state if the media is present but cannot be mounted. Typically 1203 * this happens if the file system on the media is corrupted. 1204 * 1205 * @see #getExternalStorageState(File) 1206 */ 1207 public static final String MEDIA_UNMOUNTABLE = "unmountable"; 1208 1209 /** 1210 * Storage state if the media is in the process of being ejected. 1211 * 1212 * @see #getExternalStorageState(File) 1213 */ 1214 public static final String MEDIA_EJECTING = "ejecting"; 1215 1216 /** 1217 * Returns the current state of the primary shared/external storage media. 1218 * 1219 * @see #getExternalStorageDirectory() 1220 * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED}, 1221 * {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING}, 1222 * {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED}, 1223 * {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED}, 1224 * {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}. 1225 */ getExternalStorageState()1226 public static String getExternalStorageState() { 1227 final File externalDir = sCurrentUser.getExternalDirs()[0]; 1228 return getExternalStorageState(externalDir); 1229 } 1230 1231 /** 1232 * @deprecated use {@link #getExternalStorageState(File)} 1233 */ 1234 @Deprecated getStorageState(File path)1235 public static String getStorageState(File path) { 1236 return getExternalStorageState(path); 1237 } 1238 1239 /** 1240 * Returns the current state of the shared/external storage media at the 1241 * given path. 1242 * 1243 * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED}, 1244 * {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING}, 1245 * {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED}, 1246 * {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED}, 1247 * {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}. 1248 */ getExternalStorageState(File path)1249 public static String getExternalStorageState(File path) { 1250 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId()); 1251 if (volume != null) { 1252 return volume.getState(); 1253 } else { 1254 return MEDIA_UNKNOWN; 1255 } 1256 } 1257 1258 /** 1259 * Returns whether the primary shared/external storage media is physically 1260 * removable. 1261 * 1262 * @return true if the storage device can be removed (such as an SD card), 1263 * or false if the storage device is built in and cannot be 1264 * physically removed. 1265 */ isExternalStorageRemovable()1266 public static boolean isExternalStorageRemovable() { 1267 final File externalDir = sCurrentUser.getExternalDirs()[0]; 1268 return isExternalStorageRemovable(externalDir); 1269 } 1270 1271 /** 1272 * Returns whether the shared/external storage media at the given path is 1273 * physically removable. 1274 * 1275 * @return true if the storage device can be removed (such as an SD card), 1276 * or false if the storage device is built in and cannot be 1277 * physically removed. 1278 * @throws IllegalArgumentException if the path is not a valid storage 1279 * device. 1280 */ isExternalStorageRemovable(@onNull File path)1281 public static boolean isExternalStorageRemovable(@NonNull File path) { 1282 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId()); 1283 if (volume != null) { 1284 return volume.isRemovable(); 1285 } else { 1286 throw new IllegalArgumentException("Failed to find storage device at " + path); 1287 } 1288 } 1289 1290 /** 1291 * Returns whether the primary shared/external storage media is emulated. 1292 * <p> 1293 * The contents of emulated storage devices are backed by a private user 1294 * data partition, which means there is little benefit to apps storing data 1295 * here instead of the private directories returned by 1296 * {@link Context#getFilesDir()}, etc. 1297 * <p> 1298 * This returns true when emulated storage is backed by either internal 1299 * storage or an adopted storage device. 1300 * 1301 * @see DevicePolicyManager#setStorageEncryption(android.content.ComponentName, 1302 * boolean) 1303 */ isExternalStorageEmulated()1304 public static boolean isExternalStorageEmulated() { 1305 final File externalDir = sCurrentUser.getExternalDirs()[0]; 1306 return isExternalStorageEmulated(externalDir); 1307 } 1308 1309 /** 1310 * Returns whether the shared/external storage media at the given path is 1311 * emulated. 1312 * <p> 1313 * The contents of emulated storage devices are backed by a private user 1314 * data partition, which means there is little benefit to apps storing data 1315 * here instead of the private directories returned by 1316 * {@link Context#getFilesDir()}, etc. 1317 * <p> 1318 * This returns true when emulated storage is backed by either internal 1319 * storage or an adopted storage device. 1320 * 1321 * @throws IllegalArgumentException if the path is not a valid storage 1322 * device. 1323 */ isExternalStorageEmulated(@onNull File path)1324 public static boolean isExternalStorageEmulated(@NonNull File path) { 1325 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId()); 1326 if (volume != null) { 1327 return volume.isEmulated(); 1328 } else { 1329 throw new IllegalArgumentException("Failed to find storage device at " + path); 1330 } 1331 } 1332 1333 /** 1334 * Returns whether the shared/external storage media is a 1335 * legacy view that includes files not owned by the app. 1336 * <p> 1337 * This value may be different from the value requested by 1338 * {@code requestLegacyExternalStorage} in the app's manifest, since an app 1339 * may inherit its legacy state based on when it was first installed, target sdk and other 1340 * factors. 1341 * <p> 1342 * Non-legacy apps can continue to discover and read media belonging to 1343 * other apps via {@link android.provider.MediaStore}. 1344 */ isExternalStorageLegacy()1345 public static boolean isExternalStorageLegacy() { 1346 final File externalDir = sCurrentUser.getExternalDirs()[0]; 1347 return isExternalStorageLegacy(externalDir); 1348 } 1349 1350 /** 1351 * Returns whether the shared/external storage media is a 1352 * legacy view that includes files not owned by the app. 1353 * <p> 1354 * This value may be different from the value requested by 1355 * {@code requestLegacyExternalStorage} in the app's manifest, since an app 1356 * may inherit its legacy state based on when it was first installed, target sdk and other 1357 * factors. 1358 * <p> 1359 * Non-legacy apps can continue to discover and read media belonging to 1360 * other apps via {@link android.provider.MediaStore}. 1361 * 1362 * @throws IllegalArgumentException if the path is not a valid storage 1363 * device. 1364 */ isExternalStorageLegacy(@onNull File path)1365 public static boolean isExternalStorageLegacy(@NonNull File path) { 1366 final Context context = AppGlobals.getInitialApplication(); 1367 final int uid = context.getApplicationInfo().uid; 1368 // Isolated processes and Instant apps are never allowed to be in scoped storage 1369 if (Process.isIsolated(uid) || Process.isSdkSandboxUid(uid)) { 1370 return false; 1371 } 1372 1373 final PackageManager packageManager = context.getPackageManager(); 1374 if (packageManager.isInstantApp()) { 1375 return false; 1376 } 1377 1378 // Apps with PROPERTY_NO_APP_DATA_STORAGE should not be allowed in scoped storage 1379 final String packageName = AppGlobals.getInitialPackage(); 1380 try { 1381 final PackageManager.Property noAppStorageProp = packageManager.getProperty( 1382 PackageManager.PROPERTY_NO_APP_DATA_STORAGE, packageName); 1383 if (noAppStorageProp != null && noAppStorageProp.getBoolean()) { 1384 return false; 1385 } 1386 } catch (PackageManager.NameNotFoundException ignore) { 1387 // Property not defined for the package 1388 } 1389 1390 boolean defaultScopedStorage = Compatibility.isChangeEnabled(DEFAULT_SCOPED_STORAGE); 1391 boolean forceEnableScopedStorage = Compatibility.isChangeEnabled( 1392 FORCE_ENABLE_SCOPED_STORAGE); 1393 // if Scoped Storage is strictly enforced, the app does *not* have legacy storage access 1394 // Note: does not require packagename/uid as this is directly called from an app process 1395 if (isScopedStorageEnforced(defaultScopedStorage, forceEnableScopedStorage)) { 1396 return false; 1397 } 1398 // if Scoped Storage is strictly disabled, the app has legacy storage access 1399 // Note: does not require packagename/uid as this is directly called from an app process 1400 if (isScopedStorageDisabled(defaultScopedStorage, forceEnableScopedStorage)) { 1401 return true; 1402 } 1403 1404 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); 1405 final String opPackageName = context.getOpPackageName(); 1406 1407 if (appOps.noteOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, uid, 1408 opPackageName) == AppOpsManager.MODE_ALLOWED) { 1409 return true; 1410 } 1411 1412 // Legacy external storage access is granted to instrumentations invoked with 1413 // "--no-isolated-storage" flag. 1414 return appOps.noteOpNoThrow(AppOpsManager.OP_NO_ISOLATED_STORAGE, uid, 1415 opPackageName) == AppOpsManager.MODE_ALLOWED; 1416 } 1417 isScopedStorageEnforced(boolean defaultScopedStorage, boolean forceEnableScopedStorage)1418 private static boolean isScopedStorageEnforced(boolean defaultScopedStorage, 1419 boolean forceEnableScopedStorage) { 1420 return defaultScopedStorage && forceEnableScopedStorage; 1421 } 1422 isScopedStorageDisabled(boolean defaultScopedStorage, boolean forceEnableScopedStorage)1423 private static boolean isScopedStorageDisabled(boolean defaultScopedStorage, 1424 boolean forceEnableScopedStorage) { 1425 return !defaultScopedStorage && !forceEnableScopedStorage; 1426 } 1427 1428 /** 1429 * Returns whether the calling app has All Files Access on the primary shared/external storage 1430 * media. 1431 * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't 1432 * enough to gain the access. 1433 * <p>To request access, use 1434 * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}. 1435 */ isExternalStorageManager()1436 public static boolean isExternalStorageManager() { 1437 final File externalDir = sCurrentUser.getExternalDirs()[0]; 1438 return isExternalStorageManager(externalDir); 1439 } 1440 1441 /** 1442 * Returns whether the calling app has All Files Access at the given {@code path} 1443 * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't 1444 * enough to gain the access. 1445 * <p>To request access, use 1446 * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}. 1447 */ isExternalStorageManager(@onNull File path)1448 public static boolean isExternalStorageManager(@NonNull File path) { 1449 final Context context = Objects.requireNonNull(AppGlobals.getInitialApplication()); 1450 String packageName = Objects.requireNonNull(context.getPackageName()); 1451 int uid = context.getApplicationInfo().uid; 1452 1453 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); 1454 final int opMode = 1455 appOps.checkOpNoThrow(AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE, uid, packageName); 1456 1457 switch (opMode) { 1458 case AppOpsManager.MODE_DEFAULT: 1459 return PackageManager.PERMISSION_GRANTED 1460 == context.checkPermission( 1461 Manifest.permission.MANAGE_EXTERNAL_STORAGE, Process.myPid(), uid); 1462 case AppOpsManager.MODE_ALLOWED: 1463 return true; 1464 case AppOpsManager.MODE_ERRORED: 1465 case AppOpsManager.MODE_IGNORED: 1466 return false; 1467 default: 1468 throw new IllegalStateException("Unknown AppOpsManager mode " + opMode); 1469 } 1470 } 1471 getDirectory(String variableName, String defaultPath)1472 static File getDirectory(String variableName, String defaultPath) { 1473 String path = System.getenv(variableName); 1474 return path == null ? new File(defaultPath) : new File(path); 1475 } 1476 1477 @NonNull getDirectoryPath(@onNull String variableName, @NonNull String defaultPath)1478 static String getDirectoryPath(@NonNull String variableName, @NonNull String defaultPath) { 1479 String path = System.getenv(variableName); 1480 return path == null ? defaultPath : path; 1481 } 1482 1483 /** {@hide} */ setUserRequired(boolean userRequired)1484 public static void setUserRequired(boolean userRequired) { 1485 sUserRequired = userRequired; 1486 } 1487 throwIfUserRequired()1488 private static void throwIfUserRequired() { 1489 if (sUserRequired) { 1490 Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment", 1491 new Throwable()); 1492 } 1493 } 1494 1495 /** 1496 * Append path segments to each given base path, returning result. 1497 * 1498 * @hide 1499 */ 1500 @UnsupportedAppUsage buildPaths(File[] base, String... segments)1501 public static File[] buildPaths(File[] base, String... segments) { 1502 File[] result = new File[base.length]; 1503 for (int i = 0; i < base.length; i++) { 1504 result[i] = buildPath(base[i], segments); 1505 } 1506 return result; 1507 } 1508 1509 /** 1510 * Append path segments to given base path, returning result. 1511 * 1512 * @hide 1513 */ 1514 @TestApi buildPath(File base, String... segments)1515 public static File buildPath(File base, String... segments) { 1516 File cur = base; 1517 for (String segment : segments) { 1518 if (cur == null) { 1519 cur = new File(segment); 1520 } else { 1521 cur = new File(cur, segment); 1522 } 1523 } 1524 return cur; 1525 } 1526 1527 /** 1528 * If the given path exists on emulated external storage, return the 1529 * translated backing path hosted on internal storage. This bypasses any 1530 * emulation later, improving performance. This is <em>only</em> suitable 1531 * for read-only access. 1532 * <p> 1533 * Returns original path if given path doesn't meet these criteria. Callers 1534 * must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} 1535 * permission. 1536 * 1537 * @deprecated disabled now that FUSE has been replaced by sdcardfs 1538 * @hide 1539 */ 1540 @UnsupportedAppUsage 1541 @Deprecated maybeTranslateEmulatedPathToInternal(File path)1542 public static File maybeTranslateEmulatedPathToInternal(File path) { 1543 return StorageManager.maybeTranslateEmulatedPathToInternal(path); 1544 } 1545 } 1546