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