1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.os; 18 19 import android.Manifest; 20 import android.annotation.NonNull; 21 import android.annotation.SystemApi; 22 import android.annotation.TestApi; 23 import android.app.AppGlobals; 24 import android.app.AppOpsManager; 25 import android.app.admin.DevicePolicyManager; 26 import android.compat.annotation.UnsupportedAppUsage; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.pm.PackageManager; 30 import android.os.storage.StorageManager; 31 import android.os.storage.StorageVolume; 32 import android.provider.MediaStore; 33 import android.text.TextUtils; 34 import android.util.Log; 35 36 import java.io.File; 37 import java.util.LinkedList; 38 39 /** 40 * Provides access to environment variables. 41 */ 42 public class Environment { 43 private static final String TAG = "Environment"; 44 45 // NOTE: keep credential-protected paths in sync with StrictMode.java 46 47 private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE"; 48 private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT"; 49 private static final String ENV_ANDROID_DATA = "ANDROID_DATA"; 50 private static final String ENV_ANDROID_EXPAND = "ANDROID_EXPAND"; 51 private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE"; 52 private static final String ENV_DOWNLOAD_CACHE = "DOWNLOAD_CACHE"; 53 private static final String ENV_OEM_ROOT = "OEM_ROOT"; 54 private static final String ENV_ODM_ROOT = "ODM_ROOT"; 55 private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT"; 56 private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT"; 57 private static final String ENV_SYSTEM_EXT_ROOT = "SYSTEM_EXT_ROOT"; 58 private static final String ENV_APEX_ROOT = "APEX_ROOT"; 59 60 /** {@hide} */ 61 public static final String DIR_ANDROID = "Android"; 62 private static final String DIR_DATA = "data"; 63 private static final String DIR_MEDIA = "media"; 64 private static final String DIR_OBB = "obb"; 65 private static final String DIR_FILES = "files"; 66 private static final String DIR_CACHE = "cache"; 67 68 /** {@hide} */ 69 @Deprecated 70 public static final String DIRECTORY_ANDROID = DIR_ANDROID; 71 72 private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system"); 73 private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data"); 74 private static final File DIR_ANDROID_EXPAND = getDirectory(ENV_ANDROID_EXPAND, "/mnt/expand"); 75 private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage"); 76 private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache"); 77 private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem"); 78 private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm"); 79 private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor"); 80 private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product"); 81 private static final File DIR_SYSTEM_EXT_ROOT = getDirectory(ENV_SYSTEM_EXT_ROOT, 82 "/system_ext"); 83 private static final File DIR_APEX_ROOT = getDirectory(ENV_APEX_ROOT, 84 "/apex"); 85 86 @UnsupportedAppUsage 87 private static UserEnvironment sCurrentUser; 88 private static boolean sUserRequired; 89 90 static { initForCurrentUser()91 initForCurrentUser(); 92 } 93 94 /** {@hide} */ 95 @UnsupportedAppUsage initForCurrentUser()96 public static void initForCurrentUser() { 97 final int userId = UserHandle.myUserId(); 98 sCurrentUser = new UserEnvironment(userId); 99 } 100 101 /** {@hide} */ 102 public static class UserEnvironment { 103 private final int mUserId; 104 105 @UnsupportedAppUsage UserEnvironment(int userId)106 public UserEnvironment(int userId) { 107 mUserId = userId; 108 } 109 110 @UnsupportedAppUsage getExternalDirs()111 public File[] getExternalDirs() { 112 final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId, 113 StorageManager.FLAG_FOR_WRITE); 114 final File[] files = new File[volumes.length]; 115 for (int i = 0; i < volumes.length; i++) { 116 files[i] = volumes[i].getPathFile(); 117 } 118 return files; 119 } 120 121 @UnsupportedAppUsage 122 @Deprecated getExternalStorageDirectory()123 public File getExternalStorageDirectory() { 124 return getExternalDirs()[0]; 125 } 126 127 @UnsupportedAppUsage 128 @Deprecated getExternalStoragePublicDirectory(String type)129 public File getExternalStoragePublicDirectory(String type) { 130 return buildExternalStoragePublicDirs(type)[0]; 131 } 132 buildExternalStoragePublicDirs(String type)133 public File[] buildExternalStoragePublicDirs(String type) { 134 return buildPaths(getExternalDirs(), type); 135 } 136 buildExternalStorageAndroidDataDirs()137 public File[] buildExternalStorageAndroidDataDirs() { 138 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA); 139 } 140 buildExternalStorageAndroidObbDirs()141 public File[] buildExternalStorageAndroidObbDirs() { 142 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB); 143 } 144 buildExternalStorageAppDataDirs(String packageName)145 public File[] buildExternalStorageAppDataDirs(String packageName) { 146 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName); 147 } 148 buildExternalStorageAppMediaDirs(String packageName)149 public File[] buildExternalStorageAppMediaDirs(String packageName) { 150 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_MEDIA, packageName); 151 } 152 buildExternalStorageAppObbDirs(String packageName)153 public File[] buildExternalStorageAppObbDirs(String packageName) { 154 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB, packageName); 155 } 156 buildExternalStorageAppFilesDirs(String packageName)157 public File[] buildExternalStorageAppFilesDirs(String packageName) { 158 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_FILES); 159 } 160 buildExternalStorageAppCacheDirs(String packageName)161 public File[] buildExternalStorageAppCacheDirs(String packageName) { 162 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE); 163 } 164 } 165 166 /** 167 * Return root of the "system" partition holding the core Android OS. 168 * Always present and mounted read-only. 169 */ getRootDirectory()170 public static @NonNull File getRootDirectory() { 171 return DIR_ANDROID_ROOT; 172 } 173 174 /** {@hide} */ 175 @UnsupportedAppUsage 176 @TestApi getStorageDirectory()177 public static @NonNull File getStorageDirectory() { 178 return DIR_ANDROID_STORAGE; 179 } 180 181 /** 182 * Return root directory of the "oem" partition holding OEM customizations, 183 * if any. If present, the partition is mounted read-only. 184 * 185 * @hide 186 */ 187 @SystemApi getOemDirectory()188 public static @NonNull File getOemDirectory() { 189 return DIR_OEM_ROOT; 190 } 191 192 /** 193 * Return root directory of the "odm" partition holding ODM customizations, 194 * if any. If present, the partition is mounted read-only. 195 * 196 * @hide 197 */ 198 @SystemApi getOdmDirectory()199 public static @NonNull File getOdmDirectory() { 200 return DIR_ODM_ROOT; 201 } 202 203 /** 204 * Return root directory of the "vendor" partition that holds vendor-provided 205 * software that should persist across simple reflashing of the "system" partition. 206 * @hide 207 */ 208 @SystemApi getVendorDirectory()209 public static @NonNull File getVendorDirectory() { 210 return DIR_VENDOR_ROOT; 211 } 212 213 /** 214 * Return root directory of the "product" partition holding product-specific 215 * customizations if any. If present, the partition is mounted read-only. 216 * 217 * @hide 218 */ 219 @SystemApi 220 @TestApi getProductDirectory()221 public static @NonNull File getProductDirectory() { 222 return DIR_PRODUCT_ROOT; 223 } 224 225 /** 226 * Return root directory of the "product_services" partition holding middleware 227 * services if any. If present, the partition is mounted read-only. 228 * 229 * @deprecated This directory is not guaranteed to exist. 230 * Its name is changed to "system_ext" because the partition's purpose is changed. 231 * {@link #getSystemExtDirectory()} 232 * @hide 233 */ 234 @SystemApi 235 @Deprecated getProductServicesDirectory()236 public static @NonNull File getProductServicesDirectory() { 237 return getDirectory("PRODUCT_SERVICES_ROOT", "/product_services"); 238 } 239 240 /** 241 * Return root directory of the "system_ext" partition holding system partition's extension 242 * If present, the partition is mounted read-only. 243 * 244 * @hide 245 */ 246 @SystemApi getSystemExtDirectory()247 public static @NonNull File getSystemExtDirectory() { 248 return DIR_SYSTEM_EXT_ROOT; 249 } 250 251 /** 252 * Return root directory of the apex mount point, where all the apex modules are made available 253 * to the rest of the system. 254 * 255 * @hide 256 */ getApexDirectory()257 public static @NonNull File getApexDirectory() { 258 return DIR_APEX_ROOT; 259 } 260 261 /** 262 * Return the system directory for a user. This is for use by system 263 * services to store files relating to the user. This directory will be 264 * automatically deleted when the user is removed. 265 * 266 * @deprecated This directory is valid and still exists, but but callers 267 * should <em>strongly</em> consider switching to using either 268 * {@link #getDataSystemCeDirectory(int)} or 269 * {@link #getDataSystemDeDirectory(int)}, both of which support 270 * fast user wipe. 271 * @hide 272 */ 273 @Deprecated getUserSystemDirectory(int userId)274 public static File getUserSystemDirectory(int userId) { 275 return new File(new File(getDataSystemDirectory(), "users"), Integer.toString(userId)); 276 } 277 278 /** 279 * Returns the config directory for a user. This is for use by system 280 * services to store files relating to the user which should be readable by 281 * any app running as that user. 282 * 283 * @deprecated This directory is valid and still exists, but callers should 284 * <em>strongly</em> consider switching to 285 * {@link #getDataMiscCeDirectory(int)} which is protected with 286 * user credentials or {@link #getDataMiscDeDirectory(int)} 287 * which supports fast user wipe. 288 * @hide 289 */ 290 @Deprecated getUserConfigDirectory(int userId)291 public static File getUserConfigDirectory(int userId) { 292 return new File(new File(new File( 293 getDataDirectory(), "misc"), "user"), Integer.toString(userId)); 294 } 295 296 /** 297 * Return the user data directory. 298 */ getDataDirectory()299 public static File getDataDirectory() { 300 return DIR_ANDROID_DATA; 301 } 302 303 /** {@hide} */ getDataDirectory(String volumeUuid)304 public static File getDataDirectory(String volumeUuid) { 305 if (TextUtils.isEmpty(volumeUuid)) { 306 return DIR_ANDROID_DATA; 307 } else { 308 return new File("/mnt/expand/" + volumeUuid); 309 } 310 } 311 312 /** {@hide} */ getExpandDirectory()313 public static File getExpandDirectory() { 314 return DIR_ANDROID_EXPAND; 315 } 316 317 /** {@hide} */ 318 @UnsupportedAppUsage getDataSystemDirectory()319 public static File getDataSystemDirectory() { 320 return new File(getDataDirectory(), "system"); 321 } 322 323 /** 324 * Returns the base directory for per-user system directory, device encrypted. 325 * {@hide} 326 */ getDataSystemDeDirectory()327 public static File getDataSystemDeDirectory() { 328 return buildPath(getDataDirectory(), "system_de"); 329 } 330 331 /** 332 * Returns the base directory for per-user system directory, credential encrypted. 333 * {@hide} 334 */ getDataSystemCeDirectory()335 public static File getDataSystemCeDirectory() { 336 return buildPath(getDataDirectory(), "system_ce"); 337 } 338 339 /** 340 * Return the "credential encrypted" system directory for a user. This is 341 * for use by system services to store files relating to the user. This 342 * directory supports fast user wipe, and will be automatically deleted when 343 * the user is removed. 344 * <p> 345 * Data stored under this path is "credential encrypted", which uses an 346 * encryption key that is entangled with user credentials, such as a PIN or 347 * password. The contents will only be available once the user has been 348 * unlocked, as reported by {@code SystemService.onUnlockUser()}. 349 * <p> 350 * New code should <em>strongly</em> prefer storing sensitive data in these 351 * credential encrypted areas. 352 * 353 * @hide 354 */ getDataSystemCeDirectory(int userId)355 public static File getDataSystemCeDirectory(int userId) { 356 return buildPath(getDataDirectory(), "system_ce", String.valueOf(userId)); 357 } 358 359 /** 360 * Return the "device encrypted" system directory for a user. This is for 361 * use by system services to store files relating to the user. This 362 * directory supports fast user wipe, and will be automatically deleted when 363 * the user is removed. 364 * <p> 365 * Data stored under this path is "device encrypted", which uses an 366 * encryption key that is tied to the physical device. The contents will 367 * only be available once the device has finished a {@code dm-verity} 368 * protected boot. 369 * <p> 370 * New code should <em>strongly</em> avoid storing sensitive data in these 371 * device encrypted areas. 372 * 373 * @hide 374 */ getDataSystemDeDirectory(int userId)375 public static File getDataSystemDeDirectory(int userId) { 376 return buildPath(getDataDirectory(), "system_de", String.valueOf(userId)); 377 } 378 379 /** {@hide} */ getDataMiscDirectory()380 public static File getDataMiscDirectory() { 381 return new File(getDataDirectory(), "misc"); 382 } 383 384 /** {@hide} */ getDataMiscCeDirectory()385 public static File getDataMiscCeDirectory() { 386 return buildPath(getDataDirectory(), "misc_ce"); 387 } 388 389 /** {@hide} */ getDataMiscCeDirectory(int userId)390 public static File getDataMiscCeDirectory(int userId) { 391 return buildPath(getDataDirectory(), "misc_ce", String.valueOf(userId)); 392 } 393 394 /** {@hide} */ getDataMiscDeDirectory(int userId)395 public static File getDataMiscDeDirectory(int userId) { 396 return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId)); 397 } 398 getDataProfilesDeDirectory(int userId)399 private static File getDataProfilesDeDirectory(int userId) { 400 return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId)); 401 } 402 403 /** {@hide} */ getDataVendorCeDirectory(int userId)404 public static File getDataVendorCeDirectory(int userId) { 405 return buildPath(getDataDirectory(), "vendor_ce", String.valueOf(userId)); 406 } 407 408 /** {@hide} */ getDataVendorDeDirectory(int userId)409 public static File getDataVendorDeDirectory(int userId) { 410 return buildPath(getDataDirectory(), "vendor_de", String.valueOf(userId)); 411 } 412 413 /** {@hide} */ getDataRefProfilesDePackageDirectory(String packageName)414 public static File getDataRefProfilesDePackageDirectory(String packageName) { 415 return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName); 416 } 417 418 /** {@hide} */ getDataProfilesDePackageDirectory(int userId, String packageName)419 public static File getDataProfilesDePackageDirectory(int userId, String packageName) { 420 return buildPath(getDataProfilesDeDirectory(userId), packageName); 421 } 422 423 /** {@hide} */ getDataAppDirectory(String volumeUuid)424 public static File getDataAppDirectory(String volumeUuid) { 425 return new File(getDataDirectory(volumeUuid), "app"); 426 } 427 428 /** {@hide} */ getDataStagingDirectory(String volumeUuid)429 public static File getDataStagingDirectory(String volumeUuid) { 430 return new File(getDataDirectory(volumeUuid), "app-staging"); 431 } 432 433 /** {@hide} */ getDataUserCeDirectory(String volumeUuid)434 public static File getDataUserCeDirectory(String volumeUuid) { 435 return new File(getDataDirectory(volumeUuid), "user"); 436 } 437 438 /** {@hide} */ getDataUserCeDirectory(String volumeUuid, int userId)439 public static File getDataUserCeDirectory(String volumeUuid, int userId) { 440 return new File(getDataUserCeDirectory(volumeUuid), String.valueOf(userId)); 441 } 442 443 /** {@hide} */ getDataUserCePackageDirectory(String volumeUuid, int userId, String packageName)444 public static File getDataUserCePackageDirectory(String volumeUuid, int userId, 445 String packageName) { 446 // TODO: keep consistent with installd 447 return new File(getDataUserCeDirectory(volumeUuid, userId), packageName); 448 } 449 450 /** {@hide} */ getDataUserDeDirectory(String volumeUuid)451 public static File getDataUserDeDirectory(String volumeUuid) { 452 return new File(getDataDirectory(volumeUuid), "user_de"); 453 } 454 455 /** {@hide} */ getDataUserDeDirectory(String volumeUuid, int userId)456 public static File getDataUserDeDirectory(String volumeUuid, int userId) { 457 return new File(getDataUserDeDirectory(volumeUuid), String.valueOf(userId)); 458 } 459 460 /** {@hide} */ getDataUserDePackageDirectory(String volumeUuid, int userId, String packageName)461 public static File getDataUserDePackageDirectory(String volumeUuid, int userId, 462 String packageName) { 463 // TODO: keep consistent with installd 464 return new File(getDataUserDeDirectory(volumeUuid, userId), packageName); 465 } 466 467 /** 468 * Return preloads directory. 469 * <p>This directory may contain pre-loaded content such as 470 * {@link #getDataPreloadsDemoDirectory() demo videos} and 471 * {@link #getDataPreloadsAppsDirectory() APK files} . 472 * {@hide} 473 */ getDataPreloadsDirectory()474 public static File getDataPreloadsDirectory() { 475 return new File(getDataDirectory(), "preloads"); 476 } 477 478 /** 479 * @see #getDataPreloadsDirectory() 480 * {@hide} 481 */ getDataPreloadsDemoDirectory()482 public static File getDataPreloadsDemoDirectory() { 483 return new File(getDataPreloadsDirectory(), "demo"); 484 } 485 486 /** 487 * @see #getDataPreloadsDirectory() 488 * {@hide} 489 */ getDataPreloadsAppsDirectory()490 public static File getDataPreloadsAppsDirectory() { 491 return new File(getDataPreloadsDirectory(), "apps"); 492 } 493 494 /** 495 * @see #getDataPreloadsDirectory() 496 * {@hide} 497 */ getDataPreloadsMediaDirectory()498 public static File getDataPreloadsMediaDirectory() { 499 return new File(getDataPreloadsDirectory(), "media"); 500 } 501 502 /** 503 * Returns location of preloaded cache directory for package name 504 * @see #getDataPreloadsDirectory() 505 * {@hide} 506 */ getDataPreloadsFileCacheDirectory(String packageName)507 public static File getDataPreloadsFileCacheDirectory(String packageName) { 508 return new File(getDataPreloadsFileCacheDirectory(), packageName); 509 } 510 511 /** 512 * Returns location of preloaded cache directory. 513 * @see #getDataPreloadsDirectory() 514 * {@hide} 515 */ getDataPreloadsFileCacheDirectory()516 public static File getDataPreloadsFileCacheDirectory() { 517 return new File(getDataPreloadsDirectory(), "file_cache"); 518 } 519 520 /** 521 * Returns location of packages cache directory. 522 * {@hide} 523 */ getPackageCacheDirectory()524 public static File getPackageCacheDirectory() { 525 return new File(getDataSystemDirectory(), "package_cache"); 526 } 527 528 /** 529 * Return the primary shared/external storage directory. This directory may 530 * not currently be accessible if it has been mounted by the user on their 531 * computer, has been removed from the device, or some other problem has 532 * happened. You can determine its current state with 533 * {@link #getExternalStorageState()}. 534 * <p> 535 * <em>Note: don't be confused by the word "external" here. This directory 536 * can better be thought as media/shared storage. It is a filesystem that 537 * can hold a relatively large amount of data and that is shared across all 538 * applications (does not enforce permissions). Traditionally this is an SD 539 * card, but it may also be implemented as built-in storage in a device that 540 * is distinct from the protected internal storage and can be mounted as a 541 * filesystem on a computer.</em> 542 * <p> 543 * On devices with multiple users (as described by {@link UserManager}), 544 * each user has their own isolated shared storage. Applications only have 545 * access to the shared storage for the user they're running as. 546 * <p> 547 * In devices with multiple shared/external storage directories, this 548 * directory represents the primary storage that the user will interact 549 * with. Access to secondary storage is available through 550 * {@link Context#getExternalFilesDirs(String)}, 551 * {@link Context#getExternalCacheDirs()}, and 552 * {@link Context#getExternalMediaDirs()}. 553 * <p> 554 * Applications should not directly use this top-level directory, in order 555 * to avoid polluting the user's root namespace. Any files that are private 556 * to the application should be placed in a directory returned by 557 * {@link android.content.Context#getExternalFilesDir 558 * Context.getExternalFilesDir}, which the system will take care of deleting 559 * if the application is uninstalled. Other shared files should be placed in 560 * one of the directories returned by 561 * {@link #getExternalStoragePublicDirectory}. 562 * <p> 563 * Writing to this path requires the 564 * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission, 565 * and starting in {@link android.os.Build.VERSION_CODES#KITKAT}, read 566 * access requires the 567 * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission, 568 * which is automatically granted if you hold the write permission. 569 * <p> 570 * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your 571 * application only needs to store internal data, consider using 572 * {@link Context#getExternalFilesDir(String)}, 573 * {@link Context#getExternalCacheDir()}, or 574 * {@link Context#getExternalMediaDirs()}, which require no permissions to 575 * read or write. 576 * <p> 577 * This path may change between platform versions, so applications should 578 * only persist relative paths. 579 * <p> 580 * Here is an example of typical code to monitor the state of external 581 * storage: 582 * <p> 583 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java 584 * monitor_storage} 585 * 586 * @see #getExternalStorageState() 587 * @see #isExternalStorageRemovable() 588 * @deprecated To improve user privacy, direct access to shared/external 589 * storage devices is deprecated. When an app targets 590 * {@link android.os.Build.VERSION_CODES#Q}, the path returned 591 * from this method is no longer directly accessible to apps. 592 * Apps can continue to access content stored on shared/external 593 * storage by migrating to alternatives such as 594 * {@link Context#getExternalFilesDir(String)}, 595 * {@link MediaStore}, or {@link Intent#ACTION_OPEN_DOCUMENT}. 596 */ 597 @Deprecated getExternalStorageDirectory()598 public static File getExternalStorageDirectory() { 599 throwIfUserRequired(); 600 return sCurrentUser.getExternalDirs()[0]; 601 } 602 603 /** {@hide} */ 604 @UnsupportedAppUsage getLegacyExternalStorageDirectory()605 public static File getLegacyExternalStorageDirectory() { 606 return new File(System.getenv(ENV_EXTERNAL_STORAGE)); 607 } 608 609 /** {@hide} */ 610 @UnsupportedAppUsage getLegacyExternalStorageObbDirectory()611 public static File getLegacyExternalStorageObbDirectory() { 612 return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB); 613 } 614 615 /** 616 * Standard directory in which to place any audio files that should be 617 * in the regular list of music for the user. 618 * This may be combined with 619 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, 620 * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series 621 * of directories to categories a particular audio file as more than one 622 * type. 623 */ 624 public static String DIRECTORY_MUSIC = "Music"; 625 626 /** 627 * Standard directory in which to place any audio files that should be 628 * in the list of podcasts that the user can select (not as regular 629 * music). 630 * This may be combined with {@link #DIRECTORY_MUSIC}, 631 * {@link #DIRECTORY_NOTIFICATIONS}, 632 * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series 633 * of directories to categories a particular audio file as more than one 634 * type. 635 */ 636 public static String DIRECTORY_PODCASTS = "Podcasts"; 637 638 /** 639 * Standard directory in which to place any audio files that should be 640 * in the list of ringtones that the user can select (not as regular 641 * music). 642 * This may be combined with {@link #DIRECTORY_MUSIC}, 643 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and 644 * {@link #DIRECTORY_ALARMS} as a series 645 * of directories to categories a particular audio file as more than one 646 * type. 647 */ 648 public static String DIRECTORY_RINGTONES = "Ringtones"; 649 650 /** 651 * Standard directory in which to place any audio files that should be 652 * in the list of alarms that the user can select (not as regular 653 * music). 654 * This may be combined with {@link #DIRECTORY_MUSIC}, 655 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, 656 * and {@link #DIRECTORY_RINGTONES} as a series 657 * of directories to categories a particular audio file as more than one 658 * type. 659 */ 660 public static String DIRECTORY_ALARMS = "Alarms"; 661 662 /** 663 * Standard directory in which to place any audio files that should be 664 * in the list of notifications that the user can select (not as regular 665 * music). 666 * This may be combined with {@link #DIRECTORY_MUSIC}, 667 * {@link #DIRECTORY_PODCASTS}, 668 * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series 669 * of directories to categories a particular audio file as more than one 670 * type. 671 */ 672 public static String DIRECTORY_NOTIFICATIONS = "Notifications"; 673 674 /** 675 * Standard directory in which to place pictures that are available to 676 * the user. Note that this is primarily a convention for the top-level 677 * public directory, as the media scanner will find and collect pictures 678 * in any directory. 679 */ 680 public static String DIRECTORY_PICTURES = "Pictures"; 681 682 /** 683 * Standard directory in which to place movies that are available to 684 * the user. Note that this is primarily a convention for the top-level 685 * public directory, as the media scanner will find and collect movies 686 * in any directory. 687 */ 688 public static String DIRECTORY_MOVIES = "Movies"; 689 690 /** 691 * Standard directory in which to place files that have been downloaded by 692 * the user. Note that this is primarily a convention for the top-level 693 * public directory, you are free to download files anywhere in your own 694 * private directories. Also note that though the constant here is 695 * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for 696 * backwards compatibility reasons. 697 */ 698 public static String DIRECTORY_DOWNLOADS = "Download"; 699 700 /** 701 * The traditional location for pictures and videos when mounting the 702 * device as a camera. Note that this is primarily a convention for the 703 * top-level public directory, as this convention makes no sense elsewhere. 704 */ 705 public static String DIRECTORY_DCIM = "DCIM"; 706 707 /** 708 * Standard directory in which to place documents that have been created by 709 * the user. 710 */ 711 public static String DIRECTORY_DOCUMENTS = "Documents"; 712 713 /** 714 * Standard directory in which to place screenshots that have been taken by 715 * the user. Typically used as a secondary directory under 716 * {@link #DIRECTORY_PICTURES}. 717 */ 718 public static String DIRECTORY_SCREENSHOTS = "Screenshots"; 719 720 /** 721 * Standard directory in which to place any audio files which are 722 * audiobooks. 723 */ 724 public static String DIRECTORY_AUDIOBOOKS = "Audiobooks"; 725 726 /** 727 * List of standard storage directories. 728 * <p> 729 * Each of its values have its own constant: 730 * <ul> 731 * <li>{@link #DIRECTORY_MUSIC} 732 * <li>{@link #DIRECTORY_PODCASTS} 733 * <li>{@link #DIRECTORY_ALARMS} 734 * <li>{@link #DIRECTORY_RINGTONES} 735 * <li>{@link #DIRECTORY_NOTIFICATIONS} 736 * <li>{@link #DIRECTORY_PICTURES} 737 * <li>{@link #DIRECTORY_MOVIES} 738 * <li>{@link #DIRECTORY_DOWNLOADS} 739 * <li>{@link #DIRECTORY_DCIM} 740 * <li>{@link #DIRECTORY_DOCUMENTS} 741 * <li>{@link #DIRECTORY_AUDIOBOOKS} 742 * </ul> 743 * @hide 744 */ 745 public static final String[] STANDARD_DIRECTORIES = { 746 DIRECTORY_MUSIC, 747 DIRECTORY_PODCASTS, 748 DIRECTORY_RINGTONES, 749 DIRECTORY_ALARMS, 750 DIRECTORY_NOTIFICATIONS, 751 DIRECTORY_PICTURES, 752 DIRECTORY_MOVIES, 753 DIRECTORY_DOWNLOADS, 754 DIRECTORY_DCIM, 755 DIRECTORY_DOCUMENTS, 756 DIRECTORY_AUDIOBOOKS, 757 }; 758 759 /** 760 * @hide 761 */ isStandardDirectory(String dir)762 public static boolean isStandardDirectory(String dir) { 763 for (String valid : STANDARD_DIRECTORIES) { 764 if (valid.equals(dir)) { 765 return true; 766 } 767 } 768 return false; 769 } 770 771 /** {@hide} */ public static final int HAS_MUSIC = 1 << 0; 772 /** {@hide} */ public static final int HAS_PODCASTS = 1 << 1; 773 /** {@hide} */ public static final int HAS_RINGTONES = 1 << 2; 774 /** {@hide} */ public static final int HAS_ALARMS = 1 << 3; 775 /** {@hide} */ public static final int HAS_NOTIFICATIONS = 1 << 4; 776 /** {@hide} */ public static final int HAS_PICTURES = 1 << 5; 777 /** {@hide} */ public static final int HAS_MOVIES = 1 << 6; 778 /** {@hide} */ public static final int HAS_DOWNLOADS = 1 << 7; 779 /** {@hide} */ public static final int HAS_DCIM = 1 << 8; 780 /** {@hide} */ public static final int HAS_DOCUMENTS = 1 << 9; 781 /** {@hide} */ public static final int HAS_AUDIOBOOKS = 1 << 10; 782 783 /** {@hide} */ public static final int HAS_ANDROID = 1 << 16; 784 /** {@hide} */ public static final int HAS_OTHER = 1 << 17; 785 786 /** 787 * Classify the content types present on the given external storage device. 788 * <p> 789 * This is typically useful for deciding if an inserted SD card is empty, or 790 * if it contains content like photos that should be preserved. 791 * 792 * @hide 793 */ classifyExternalStorageDirectory(File dir)794 public static int classifyExternalStorageDirectory(File dir) { 795 int res = 0; 796 for (File f : FileUtils.listFilesOrEmpty(dir)) { 797 if (f.isFile() && isInterestingFile(f)) { 798 res |= HAS_OTHER; 799 } else if (f.isDirectory() && hasInterestingFiles(f)) { 800 final String name = f.getName(); 801 if (DIRECTORY_MUSIC.equals(name)) res |= HAS_MUSIC; 802 else if (DIRECTORY_PODCASTS.equals(name)) res |= HAS_PODCASTS; 803 else if (DIRECTORY_RINGTONES.equals(name)) res |= HAS_RINGTONES; 804 else if (DIRECTORY_ALARMS.equals(name)) res |= HAS_ALARMS; 805 else if (DIRECTORY_NOTIFICATIONS.equals(name)) res |= HAS_NOTIFICATIONS; 806 else if (DIRECTORY_PICTURES.equals(name)) res |= HAS_PICTURES; 807 else if (DIRECTORY_MOVIES.equals(name)) res |= HAS_MOVIES; 808 else if (DIRECTORY_DOWNLOADS.equals(name)) res |= HAS_DOWNLOADS; 809 else if (DIRECTORY_DCIM.equals(name)) res |= HAS_DCIM; 810 else if (DIRECTORY_DOCUMENTS.equals(name)) res |= HAS_DOCUMENTS; 811 else if (DIRECTORY_AUDIOBOOKS.equals(name)) res |= HAS_AUDIOBOOKS; 812 else if (DIRECTORY_ANDROID.equals(name)) res |= HAS_ANDROID; 813 else res |= HAS_OTHER; 814 } 815 } 816 return res; 817 } 818 hasInterestingFiles(File dir)819 private static boolean hasInterestingFiles(File dir) { 820 final LinkedList<File> explore = new LinkedList<>(); 821 explore.add(dir); 822 while (!explore.isEmpty()) { 823 dir = explore.pop(); 824 for (File f : FileUtils.listFilesOrEmpty(dir)) { 825 if (isInterestingFile(f)) return true; 826 if (f.isDirectory()) explore.add(f); 827 } 828 } 829 return false; 830 } 831 isInterestingFile(File file)832 private static boolean isInterestingFile(File file) { 833 if (file.isFile()) { 834 final String name = file.getName().toLowerCase(); 835 if (name.endsWith(".exe") || name.equals("autorun.inf") 836 || name.equals("launchpad.zip") || name.equals(".nomedia")) { 837 return false; 838 } else { 839 return true; 840 } 841 } else { 842 return false; 843 } 844 } 845 846 /** 847 * Get a top-level shared/external storage directory for placing files of a 848 * particular type. This is where the user will typically place and manage 849 * their own files, so you should be careful about what you put here to 850 * ensure you don't erase their files or get in the way of their own 851 * organization. 852 * <p> 853 * On devices with multiple users (as described by {@link UserManager}), 854 * each user has their own isolated shared storage. Applications only have 855 * access to the shared storage for the user they're running as. 856 * </p> 857 * <p> 858 * Here is an example of typical code to manipulate a picture on the public 859 * shared storage: 860 * </p> 861 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java 862 * public_picture} 863 * 864 * @param type The type of storage directory to return. Should be one of 865 * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS}, 866 * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS}, 867 * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES}, 868 * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, 869 * {@link #DIRECTORY_DCIM}, or {@link #DIRECTORY_DOCUMENTS}. May not be null. 870 * @return Returns the File path for the directory. Note that this directory 871 * may not yet exist, so you must make sure it exists before using 872 * it such as with {@link File#mkdirs File.mkdirs()}. 873 * @deprecated To improve user privacy, direct access to shared/external 874 * storage devices is deprecated. When an app targets 875 * {@link android.os.Build.VERSION_CODES#Q}, the path returned 876 * from this method is no longer directly accessible to apps. 877 * Apps can continue to access content stored on shared/external 878 * storage by migrating to alternatives such as 879 * {@link Context#getExternalFilesDir(String)}, 880 * {@link MediaStore}, or {@link Intent#ACTION_OPEN_DOCUMENT}. 881 */ 882 @Deprecated getExternalStoragePublicDirectory(String type)883 public static File getExternalStoragePublicDirectory(String type) { 884 throwIfUserRequired(); 885 return sCurrentUser.buildExternalStoragePublicDirs(type)[0]; 886 } 887 888 /** 889 * Returns the path for android-specific data on the SD card. 890 * @hide 891 */ 892 @UnsupportedAppUsage buildExternalStorageAndroidDataDirs()893 public static File[] buildExternalStorageAndroidDataDirs() { 894 throwIfUserRequired(); 895 return sCurrentUser.buildExternalStorageAndroidDataDirs(); 896 } 897 898 /** 899 * Generates the raw path to an application's data 900 * @hide 901 */ 902 @UnsupportedAppUsage buildExternalStorageAppDataDirs(String packageName)903 public static File[] buildExternalStorageAppDataDirs(String packageName) { 904 throwIfUserRequired(); 905 return sCurrentUser.buildExternalStorageAppDataDirs(packageName); 906 } 907 908 /** 909 * Generates the raw path to an application's media 910 * @hide 911 */ 912 @UnsupportedAppUsage buildExternalStorageAppMediaDirs(String packageName)913 public static File[] buildExternalStorageAppMediaDirs(String packageName) { 914 throwIfUserRequired(); 915 return sCurrentUser.buildExternalStorageAppMediaDirs(packageName); 916 } 917 918 /** 919 * Generates the raw path to an application's OBB files 920 * @hide 921 */ 922 @UnsupportedAppUsage buildExternalStorageAppObbDirs(String packageName)923 public static File[] buildExternalStorageAppObbDirs(String packageName) { 924 throwIfUserRequired(); 925 return sCurrentUser.buildExternalStorageAppObbDirs(packageName); 926 } 927 928 /** 929 * Generates the path to an application's files. 930 * @hide 931 */ 932 @UnsupportedAppUsage buildExternalStorageAppFilesDirs(String packageName)933 public static File[] buildExternalStorageAppFilesDirs(String packageName) { 934 throwIfUserRequired(); 935 return sCurrentUser.buildExternalStorageAppFilesDirs(packageName); 936 } 937 938 /** 939 * Generates the path to an application's cache. 940 * @hide 941 */ 942 @UnsupportedAppUsage buildExternalStorageAppCacheDirs(String packageName)943 public static File[] buildExternalStorageAppCacheDirs(String packageName) { 944 throwIfUserRequired(); 945 return sCurrentUser.buildExternalStorageAppCacheDirs(packageName); 946 } 947 948 /** @hide */ buildExternalStoragePublicDirs(@onNull String dirType)949 public static File[] buildExternalStoragePublicDirs(@NonNull String dirType) { 950 throwIfUserRequired(); 951 return sCurrentUser.buildExternalStoragePublicDirs(dirType); 952 } 953 954 /** 955 * Return the download/cache content directory. 956 */ getDownloadCacheDirectory()957 public static File getDownloadCacheDirectory() { 958 return DIR_DOWNLOAD_CACHE; 959 } 960 961 /** 962 * Unknown storage state, such as when a path isn't backed by known storage 963 * media. 964 * 965 * @see #getExternalStorageState(File) 966 */ 967 public static final String MEDIA_UNKNOWN = "unknown"; 968 969 /** 970 * Storage state if the media is not present. 971 * 972 * @see #getExternalStorageState(File) 973 */ 974 public static final String MEDIA_REMOVED = "removed"; 975 976 /** 977 * Storage state if the media is present but not mounted. 978 * 979 * @see #getExternalStorageState(File) 980 */ 981 public static final String MEDIA_UNMOUNTED = "unmounted"; 982 983 /** 984 * Storage state if the media is present and being disk-checked. 985 * 986 * @see #getExternalStorageState(File) 987 */ 988 public static final String MEDIA_CHECKING = "checking"; 989 990 /** 991 * Storage state if the media is present but is blank or is using an 992 * unsupported filesystem. 993 * 994 * @see #getExternalStorageState(File) 995 */ 996 public static final String MEDIA_NOFS = "nofs"; 997 998 /** 999 * Storage state if the media is present and mounted at its mount point with 1000 * read/write access. 1001 * 1002 * @see #getExternalStorageState(File) 1003 */ 1004 public static final String MEDIA_MOUNTED = "mounted"; 1005 1006 /** 1007 * Storage state if the media is present and mounted at its mount point with 1008 * read-only access. 1009 * 1010 * @see #getExternalStorageState(File) 1011 */ 1012 public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro"; 1013 1014 /** 1015 * Storage state if the media is present not mounted, and shared via USB 1016 * mass storage. 1017 * 1018 * @see #getExternalStorageState(File) 1019 */ 1020 public static final String MEDIA_SHARED = "shared"; 1021 1022 /** 1023 * Storage state if the media was removed before it was unmounted. 1024 * 1025 * @see #getExternalStorageState(File) 1026 */ 1027 public static final String MEDIA_BAD_REMOVAL = "bad_removal"; 1028 1029 /** 1030 * Storage state if the media is present but cannot be mounted. Typically 1031 * this happens if the file system on the media is corrupted. 1032 * 1033 * @see #getExternalStorageState(File) 1034 */ 1035 public static final String MEDIA_UNMOUNTABLE = "unmountable"; 1036 1037 /** 1038 * Storage state if the media is in the process of being ejected. 1039 * 1040 * @see #getExternalStorageState(File) 1041 */ 1042 public static final String MEDIA_EJECTING = "ejecting"; 1043 1044 /** 1045 * Returns the current state of the primary shared/external storage media. 1046 * 1047 * @see #getExternalStorageDirectory() 1048 * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED}, 1049 * {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING}, 1050 * {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED}, 1051 * {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED}, 1052 * {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}. 1053 */ getExternalStorageState()1054 public static String getExternalStorageState() { 1055 final File externalDir = sCurrentUser.getExternalDirs()[0]; 1056 return getExternalStorageState(externalDir); 1057 } 1058 1059 /** 1060 * @deprecated use {@link #getExternalStorageState(File)} 1061 */ 1062 @Deprecated getStorageState(File path)1063 public static String getStorageState(File path) { 1064 return getExternalStorageState(path); 1065 } 1066 1067 /** 1068 * Returns the current state of the shared/external storage media at the 1069 * given path. 1070 * 1071 * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED}, 1072 * {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING}, 1073 * {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED}, 1074 * {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED}, 1075 * {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}. 1076 */ getExternalStorageState(File path)1077 public static String getExternalStorageState(File path) { 1078 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId()); 1079 if (volume != null) { 1080 return volume.getState(); 1081 } else { 1082 return MEDIA_UNKNOWN; 1083 } 1084 } 1085 1086 /** 1087 * Returns whether the primary shared/external storage media is physically 1088 * removable. 1089 * 1090 * @return true if the storage device can be removed (such as an SD card), 1091 * or false if the storage device is built in and cannot be 1092 * physically removed. 1093 */ isExternalStorageRemovable()1094 public static boolean isExternalStorageRemovable() { 1095 final File externalDir = sCurrentUser.getExternalDirs()[0]; 1096 return isExternalStorageRemovable(externalDir); 1097 } 1098 1099 /** 1100 * Returns whether the shared/external storage media at the given path is 1101 * physically removable. 1102 * 1103 * @return true if the storage device can be removed (such as an SD card), 1104 * or false if the storage device is built in and cannot be 1105 * physically removed. 1106 * @throws IllegalArgumentException if the path is not a valid storage 1107 * device. 1108 */ isExternalStorageRemovable(@onNull File path)1109 public static boolean isExternalStorageRemovable(@NonNull File path) { 1110 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId()); 1111 if (volume != null) { 1112 return volume.isRemovable(); 1113 } else { 1114 throw new IllegalArgumentException("Failed to find storage device at " + path); 1115 } 1116 } 1117 1118 /** 1119 * Returns whether the primary shared/external storage media is emulated. 1120 * <p> 1121 * The contents of emulated storage devices are backed by a private user 1122 * data partition, which means there is little benefit to apps storing data 1123 * here instead of the private directories returned by 1124 * {@link Context#getFilesDir()}, etc. 1125 * <p> 1126 * This returns true when emulated storage is backed by either internal 1127 * storage or an adopted storage device. 1128 * 1129 * @see DevicePolicyManager#setStorageEncryption(android.content.ComponentName, 1130 * boolean) 1131 */ isExternalStorageEmulated()1132 public static boolean isExternalStorageEmulated() { 1133 final File externalDir = sCurrentUser.getExternalDirs()[0]; 1134 return isExternalStorageEmulated(externalDir); 1135 } 1136 1137 /** 1138 * Returns whether the shared/external storage media at the given path is 1139 * emulated. 1140 * <p> 1141 * The contents of emulated storage devices are backed by a private user 1142 * data partition, which means there is little benefit to apps storing data 1143 * here instead of the private directories returned by 1144 * {@link Context#getFilesDir()}, etc. 1145 * <p> 1146 * This returns true when emulated storage is backed by either internal 1147 * storage or an adopted storage device. 1148 * 1149 * @throws IllegalArgumentException if the path is not a valid storage 1150 * device. 1151 */ isExternalStorageEmulated(@onNull File path)1152 public static boolean isExternalStorageEmulated(@NonNull File path) { 1153 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId()); 1154 if (volume != null) { 1155 return volume.isEmulated(); 1156 } else { 1157 throw new IllegalArgumentException("Failed to find storage device at " + path); 1158 } 1159 } 1160 1161 /** 1162 * Returns whether the primary shared/external storage media is a legacy 1163 * view that includes files not owned by the app. 1164 * <p> 1165 * This value may be different from the value requested by 1166 * {@code requestLegacyExternalStorage} in the app's manifest, since an app 1167 * may inherit its legacy state based on when it was first installed. 1168 * <p> 1169 * Non-legacy apps can continue to discover and read media belonging to 1170 * other apps via {@link android.provider.MediaStore}. 1171 */ isExternalStorageLegacy()1172 public static boolean isExternalStorageLegacy() { 1173 final File externalDir = sCurrentUser.getExternalDirs()[0]; 1174 return isExternalStorageLegacy(externalDir); 1175 } 1176 1177 /** 1178 * Returns whether the shared/external storage media at the given path is a 1179 * legacy view that includes files not owned by the app. 1180 * <p> 1181 * This value may be different from the value requested by 1182 * {@code requestLegacyExternalStorage} in the app's manifest, since an app 1183 * may inherit its legacy state based on when it was first installed. 1184 * <p> 1185 * Non-legacy apps can continue to discover and read media belonging to 1186 * other apps via {@link android.provider.MediaStore}. 1187 * 1188 * @throws IllegalArgumentException if the path is not a valid storage 1189 * device. 1190 */ isExternalStorageLegacy(@onNull File path)1191 public static boolean isExternalStorageLegacy(@NonNull File path) { 1192 final Context context = AppGlobals.getInitialApplication(); 1193 final int uid = context.getApplicationInfo().uid; 1194 if (Process.isIsolated(uid)) { 1195 return false; 1196 } 1197 1198 final PackageManager packageManager = context.getPackageManager(); 1199 if (packageManager.isInstantApp()) { 1200 return false; 1201 } 1202 1203 if (packageManager.checkPermission(Manifest.permission.WRITE_MEDIA_STORAGE, 1204 context.getPackageName()) == PackageManager.PERMISSION_GRANTED) { 1205 return true; 1206 } 1207 1208 if (packageManager.checkPermission(Manifest.permission.INSTALL_PACKAGES, 1209 context.getPackageName()) == PackageManager.PERMISSION_GRANTED) { 1210 return true; 1211 } 1212 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); 1213 final String[] packagesForUid = packageManager.getPackagesForUid(uid); 1214 for (String packageName : packagesForUid) { 1215 if (appOps.checkOpNoThrow(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, 1216 uid, packageName) == AppOpsManager.MODE_ALLOWED) { 1217 return true; 1218 } 1219 } 1220 1221 return appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, 1222 uid, context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED; 1223 } 1224 getDirectory(String variableName, String defaultPath)1225 static File getDirectory(String variableName, String defaultPath) { 1226 String path = System.getenv(variableName); 1227 return path == null ? new File(defaultPath) : new File(path); 1228 } 1229 1230 /** {@hide} */ setUserRequired(boolean userRequired)1231 public static void setUserRequired(boolean userRequired) { 1232 sUserRequired = userRequired; 1233 } 1234 throwIfUserRequired()1235 private static void throwIfUserRequired() { 1236 if (sUserRequired) { 1237 Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment", 1238 new Throwable()); 1239 } 1240 } 1241 1242 /** 1243 * Append path segments to each given base path, returning result. 1244 * 1245 * @hide 1246 */ 1247 @UnsupportedAppUsage buildPaths(File[] base, String... segments)1248 public static File[] buildPaths(File[] base, String... segments) { 1249 File[] result = new File[base.length]; 1250 for (int i = 0; i < base.length; i++) { 1251 result[i] = buildPath(base[i], segments); 1252 } 1253 return result; 1254 } 1255 1256 /** 1257 * Append path segments to given base path, returning result. 1258 * 1259 * @hide 1260 */ 1261 @TestApi buildPath(File base, String... segments)1262 public static File buildPath(File base, String... segments) { 1263 File cur = base; 1264 for (String segment : segments) { 1265 if (cur == null) { 1266 cur = new File(segment); 1267 } else { 1268 cur = new File(cur, segment); 1269 } 1270 } 1271 return cur; 1272 } 1273 1274 /** 1275 * If the given path exists on emulated external storage, return the 1276 * translated backing path hosted on internal storage. This bypasses any 1277 * emulation later, improving performance. This is <em>only</em> suitable 1278 * for read-only access. 1279 * <p> 1280 * Returns original path if given path doesn't meet these criteria. Callers 1281 * must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} 1282 * permission. 1283 * 1284 * @deprecated disabled now that FUSE has been replaced by sdcardfs 1285 * @hide 1286 */ 1287 @UnsupportedAppUsage 1288 @Deprecated maybeTranslateEmulatedPathToInternal(File path)1289 public static File maybeTranslateEmulatedPathToInternal(File path) { 1290 return StorageManager.maybeTranslateEmulatedPathToInternal(path); 1291 } 1292 } 1293