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