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