1 /* 2 * Copyright (C) 2008 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.storage; 18 19 import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE; 20 import static android.Manifest.permission.READ_EXTERNAL_STORAGE; 21 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; 22 import static android.app.AppOpsManager.OP_LEGACY_STORAGE; 23 import static android.app.AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE; 24 import static android.app.AppOpsManager.OP_READ_EXTERNAL_STORAGE; 25 import static android.app.AppOpsManager.OP_READ_MEDIA_AUDIO; 26 import static android.app.AppOpsManager.OP_READ_MEDIA_IMAGES; 27 import static android.app.AppOpsManager.OP_READ_MEDIA_VIDEO; 28 import static android.app.AppOpsManager.OP_WRITE_EXTERNAL_STORAGE; 29 import static android.app.AppOpsManager.OP_WRITE_MEDIA_AUDIO; 30 import static android.app.AppOpsManager.OP_WRITE_MEDIA_IMAGES; 31 import static android.app.AppOpsManager.OP_WRITE_MEDIA_VIDEO; 32 import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX; 33 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 34 import static android.os.UserHandle.PER_USER_RANGE; 35 36 import android.annotation.BytesLong; 37 import android.annotation.CallbackExecutor; 38 import android.annotation.IntDef; 39 import android.annotation.NonNull; 40 import android.annotation.Nullable; 41 import android.annotation.RequiresPermission; 42 import android.annotation.SdkConstant; 43 import android.annotation.SuppressLint; 44 import android.annotation.SystemApi; 45 import android.annotation.SystemService; 46 import android.annotation.TestApi; 47 import android.annotation.WorkerThread; 48 import android.app.Activity; 49 import android.app.ActivityThread; 50 import android.app.AppGlobals; 51 import android.app.AppOpsManager; 52 import android.app.PendingIntent; 53 import android.compat.annotation.UnsupportedAppUsage; 54 import android.content.ContentResolver; 55 import android.content.Context; 56 import android.content.Intent; 57 import android.content.pm.ApplicationInfo; 58 import android.content.pm.IPackageMoveObserver; 59 import android.content.pm.PackageManager; 60 import android.content.res.ObbInfo; 61 import android.content.res.ObbScanner; 62 import android.database.Cursor; 63 import android.net.Uri; 64 import android.os.Binder; 65 import android.os.Build; 66 import android.os.Environment; 67 import android.os.FileUtils; 68 import android.os.Handler; 69 import android.os.IInstalld; 70 import android.os.IVold; 71 import android.os.IVoldTaskListener; 72 import android.os.Looper; 73 import android.os.Message; 74 import android.os.ParcelFileDescriptor; 75 import android.os.ParcelableException; 76 import android.os.PersistableBundle; 77 import android.os.ProxyFileDescriptorCallback; 78 import android.os.RemoteException; 79 import android.os.ServiceManager; 80 import android.os.ServiceManager.ServiceNotFoundException; 81 import android.os.SystemProperties; 82 import android.os.UserHandle; 83 import android.provider.DeviceConfig; 84 import android.provider.MediaStore; 85 import android.provider.Settings; 86 import android.system.ErrnoException; 87 import android.system.Os; 88 import android.system.OsConstants; 89 import android.text.TextUtils; 90 import android.util.DataUnit; 91 import android.util.Log; 92 import android.util.Pair; 93 import android.util.Slog; 94 import android.util.SparseArray; 95 96 import com.android.internal.annotations.GuardedBy; 97 import com.android.internal.annotations.VisibleForTesting; 98 import com.android.internal.logging.MetricsLogger; 99 import com.android.internal.os.AppFuseMount; 100 import com.android.internal.os.FuseAppLoop; 101 import com.android.internal.os.FuseUnavailableMountException; 102 import com.android.internal.os.RoSystemProperties; 103 import com.android.internal.util.Preconditions; 104 105 import dalvik.system.BlockGuard; 106 107 import java.io.File; 108 import java.io.FileDescriptor; 109 import java.io.FileNotFoundException; 110 import java.io.IOException; 111 import java.lang.annotation.Retention; 112 import java.lang.annotation.RetentionPolicy; 113 import java.lang.ref.WeakReference; 114 import java.nio.charset.StandardCharsets; 115 import java.util.ArrayList; 116 import java.util.Arrays; 117 import java.util.Collections; 118 import java.util.Iterator; 119 import java.util.List; 120 import java.util.Locale; 121 import java.util.Objects; 122 import java.util.UUID; 123 import java.util.concurrent.CompletableFuture; 124 import java.util.concurrent.Executor; 125 import java.util.concurrent.ThreadFactory; 126 import java.util.concurrent.TimeUnit; 127 import java.util.concurrent.atomic.AtomicInteger; 128 129 /** 130 * StorageManager is the interface to the systems storage service. The storage 131 * manager handles storage-related items such as Opaque Binary Blobs (OBBs). 132 * <p> 133 * OBBs contain a filesystem that maybe be encrypted on disk and mounted 134 * on-demand from an application. OBBs are a good way of providing large amounts 135 * of binary assets without packaging them into APKs as they may be multiple 136 * gigabytes in size. However, due to their size, they're most likely stored in 137 * a shared storage pool accessible from all programs. The system does not 138 * guarantee the security of the OBB file itself: if any program modifies the 139 * OBB, there is no guarantee that a read from that OBB will produce the 140 * expected output. 141 */ 142 @SystemService(Context.STORAGE_SERVICE) 143 public class StorageManager { 144 private static final String TAG = "StorageManager"; 145 private static final boolean LOCAL_LOGV = Log.isLoggable(TAG, Log.VERBOSE); 146 147 /** {@hide} */ 148 public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical"; 149 /** {@hide} */ 150 public static final String PROP_HAS_ADOPTABLE = "vold.has_adoptable"; 151 /** {@hide} */ 152 public static final String PROP_HAS_RESERVED = "vold.has_reserved"; 153 /** {@hide} */ 154 public static final String PROP_ADOPTABLE = "persist.sys.adoptable"; 155 /** {@hide} */ 156 public static final String PROP_EMULATE_FBE = "persist.sys.emulate_fbe"; 157 /** {@hide} */ 158 public static final String PROP_SDCARDFS = "persist.sys.sdcardfs"; 159 /** {@hide} */ 160 public static final String PROP_VIRTUAL_DISK = "persist.sys.virtual_disk"; 161 /** {@hide} */ 162 public static final String PROP_FORCED_SCOPED_STORAGE_WHITELIST = 163 "forced_scoped_storage_whitelist"; 164 165 /** {@hide} */ 166 public static final String UUID_PRIVATE_INTERNAL = null; 167 /** {@hide} */ 168 public static final String UUID_PRIMARY_PHYSICAL = "primary_physical"; 169 /** {@hide} */ 170 public static final String UUID_SYSTEM = "system"; 171 172 // NOTE: See comments around #convert for more details. 173 private static final String FAT_UUID_PREFIX = "fafafafa-fafa-5afa-8afa-fafa"; 174 175 // NOTE: UUID constants below are namespaced 176 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad default 177 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad primary_physical 178 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad system 179 180 /** 181 * UUID representing the default internal storage of this device which 182 * provides {@link Environment#getDataDirectory()}. 183 * <p> 184 * This value is constant across all devices and it will never change, and 185 * thus it cannot be used to uniquely identify a particular physical device. 186 * 187 * @see #getUuidForPath(File) 188 * @see ApplicationInfo#storageUuid 189 */ 190 public static final UUID UUID_DEFAULT = UUID 191 .fromString("41217664-9172-527a-b3d5-edabb50a7d69"); 192 193 /** {@hide} */ 194 public static final UUID UUID_PRIMARY_PHYSICAL_ = UUID 195 .fromString("0f95a519-dae7-5abf-9519-fbd6209e05fd"); 196 197 /** {@hide} */ 198 public static final UUID UUID_SYSTEM_ = UUID 199 .fromString("5d258386-e60d-59e3-826d-0089cdd42cc0"); 200 201 /** 202 * Activity Action: Allows the user to manage their storage. This activity 203 * provides the ability to free up space on the device by deleting data such 204 * as apps. 205 * <p> 206 * If the sending application has a specific storage device or allocation 207 * size in mind, they can optionally define {@link #EXTRA_UUID} or 208 * {@link #EXTRA_REQUESTED_BYTES}, respectively. 209 * <p> 210 * This intent should be launched using 211 * {@link Activity#startActivityForResult(Intent, int)} so that the user 212 * knows which app is requesting the storage space. The returned result will 213 * be {@link Activity#RESULT_OK} if the requested space was made available, 214 * or {@link Activity#RESULT_CANCELED} otherwise. 215 */ 216 @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) 217 public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE"; 218 219 /** 220 * Activity Action: Allows the user to free up space by clearing app external cache directories. 221 * The intent doesn't automatically clear cache, but shows a dialog and lets the user decide. 222 * <p> 223 * This intent should be launched using 224 * {@link Activity#startActivityForResult(Intent, int)} so that the user 225 * knows which app is requesting to clear cache. The returned result will be: 226 * {@link Activity#RESULT_OK} if the activity was launched and all cache was cleared, 227 * {@link OsConstants#EIO} if an error occurred while clearing the cache or 228 * {@link Activity#RESULT_CANCELED} otherwise. 229 */ 230 @RequiresPermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE) 231 @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) 232 public static final String ACTION_CLEAR_APP_CACHE = "android.os.storage.action.CLEAR_APP_CACHE"; 233 234 /** 235 * Extra {@link UUID} used to indicate the storage volume where an 236 * application is interested in allocating or managing disk space. 237 * 238 * @see #ACTION_MANAGE_STORAGE 239 * @see #UUID_DEFAULT 240 * @see #getUuidForPath(File) 241 * @see Intent#putExtra(String, java.io.Serializable) 242 */ 243 public static final String EXTRA_UUID = "android.os.storage.extra.UUID"; 244 245 /** 246 * Extra used to indicate the total size (in bytes) that an application is 247 * interested in allocating. 248 * <p> 249 * When defined, the management UI will help guide the user to free up 250 * enough disk space to reach this requested value. 251 * 252 * @see #ACTION_MANAGE_STORAGE 253 */ 254 public static final String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES"; 255 256 /** {@hide} */ 257 public static final int DEBUG_ADOPTABLE_FORCE_ON = 1 << 0; 258 /** {@hide} */ 259 public static final int DEBUG_ADOPTABLE_FORCE_OFF = 1 << 1; 260 /** {@hide} */ 261 public static final int DEBUG_EMULATE_FBE = 1 << 2; 262 /** {@hide} */ 263 public static final int DEBUG_SDCARDFS_FORCE_ON = 1 << 3; 264 /** {@hide} */ 265 public static final int DEBUG_SDCARDFS_FORCE_OFF = 1 << 4; 266 /** {@hide} */ 267 public static final int DEBUG_VIRTUAL_DISK = 1 << 5; 268 269 /** {@hide} */ 270 public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE; 271 /** {@hide} */ 272 public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE; 273 /** {@hide} */ 274 public static final int FLAG_STORAGE_EXTERNAL = IInstalld.FLAG_STORAGE_EXTERNAL; 275 /** @hide */ 276 public static final int FLAG_STORAGE_SDK = IInstalld.FLAG_STORAGE_SDK; 277 278 /** {@hide} */ 279 @IntDef(prefix = "FLAG_STORAGE_", value = { 280 FLAG_STORAGE_DE, 281 FLAG_STORAGE_CE, 282 FLAG_STORAGE_EXTERNAL, 283 FLAG_STORAGE_SDK, 284 }) 285 @Retention(RetentionPolicy.SOURCE) 286 public @interface StorageFlags {} 287 288 /** {@hide} */ 289 public static final int FLAG_FOR_WRITE = 1 << 8; 290 /** {@hide} */ 291 public static final int FLAG_REAL_STATE = 1 << 9; 292 /** {@hide} */ 293 public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10; 294 /** {@hide} */ 295 public static final int FLAG_INCLUDE_RECENT = 1 << 11; 296 /** {@hide} */ 297 public static final int FLAG_INCLUDE_SHARED_PROFILE = 1 << 12; 298 299 /** {@hide} */ 300 public static final int FSTRIM_FLAG_DEEP = IVold.FSTRIM_FLAG_DEEP_TRIM; 301 302 /** @hide The volume is not encrypted. */ 303 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 304 public static final int ENCRYPTION_STATE_NONE = 1; 305 306 private static volatile IStorageManager sStorageManager = null; 307 308 private final Context mContext; 309 private final ContentResolver mResolver; 310 311 private final IStorageManager mStorageManager; 312 private final AppOpsManager mAppOps; 313 private final Looper mLooper; 314 private final AtomicInteger mNextNonce = new AtomicInteger(0); 315 316 @GuardedBy("mDelegates") 317 private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>(); 318 319 private class StorageEventListenerDelegate extends IStorageEventListener.Stub { 320 final Executor mExecutor; 321 final StorageEventListener mListener; 322 final StorageVolumeCallback mCallback; 323 StorageEventListenerDelegate(@onNull Executor executor, @NonNull StorageEventListener listener, @NonNull StorageVolumeCallback callback)324 public StorageEventListenerDelegate(@NonNull Executor executor, 325 @NonNull StorageEventListener listener, @NonNull StorageVolumeCallback callback) { 326 mExecutor = executor; 327 mListener = listener; 328 mCallback = callback; 329 } 330 331 @Override onUsbMassStorageConnectionChanged(boolean connected)332 public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException { 333 mExecutor.execute(() -> { 334 mListener.onUsbMassStorageConnectionChanged(connected); 335 }); 336 } 337 338 @Override onStorageStateChanged(String path, String oldState, String newState)339 public void onStorageStateChanged(String path, String oldState, String newState) { 340 mExecutor.execute(() -> { 341 mListener.onStorageStateChanged(path, oldState, newState); 342 343 if (path != null) { 344 for (StorageVolume sv : getStorageVolumes()) { 345 if (Objects.equals(path, sv.getPath())) { 346 mCallback.onStateChanged(sv); 347 } 348 } 349 } 350 }); 351 } 352 353 @Override onVolumeStateChanged(VolumeInfo vol, int oldState, int newState)354 public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { 355 mExecutor.execute(() -> { 356 mListener.onVolumeStateChanged(vol, oldState, newState); 357 358 final File path = vol.getPathForUser(UserHandle.myUserId()); 359 if (path != null) { 360 for (StorageVolume sv : getStorageVolumes()) { 361 if (Objects.equals(path.getAbsolutePath(), sv.getPath())) { 362 mCallback.onStateChanged(sv); 363 } 364 } 365 } 366 }); 367 } 368 369 @Override onVolumeRecordChanged(VolumeRecord rec)370 public void onVolumeRecordChanged(VolumeRecord rec) { 371 mExecutor.execute(() -> { 372 mListener.onVolumeRecordChanged(rec); 373 }); 374 } 375 376 @Override onVolumeForgotten(String fsUuid)377 public void onVolumeForgotten(String fsUuid) { 378 mExecutor.execute(() -> { 379 mListener.onVolumeForgotten(fsUuid); 380 }); 381 } 382 383 @Override onDiskScanned(DiskInfo disk, int volumeCount)384 public void onDiskScanned(DiskInfo disk, int volumeCount) { 385 mExecutor.execute(() -> { 386 mListener.onDiskScanned(disk, volumeCount); 387 }); 388 } 389 390 @Override onDiskDestroyed(DiskInfo disk)391 public void onDiskDestroyed(DiskInfo disk) throws RemoteException { 392 mExecutor.execute(() -> { 393 mListener.onDiskDestroyed(disk); 394 }); 395 } 396 } 397 398 /** 399 * Binder listener for OBB action results. 400 */ 401 private final ObbActionListener mObbActionListener = new ObbActionListener(); 402 403 private class ObbActionListener extends IObbActionListener.Stub { 404 @SuppressWarnings("hiding") 405 private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>(); 406 407 @Override onObbResult(String filename, int nonce, int status)408 public void onObbResult(String filename, int nonce, int status) { 409 final ObbListenerDelegate delegate; 410 synchronized (mListeners) { 411 delegate = mListeners.get(nonce); 412 if (delegate != null) { 413 mListeners.remove(nonce); 414 } 415 } 416 417 if (delegate != null) { 418 delegate.sendObbStateChanged(filename, status); 419 } 420 } 421 addListener(OnObbStateChangeListener listener)422 public int addListener(OnObbStateChangeListener listener) { 423 final ObbListenerDelegate delegate = new ObbListenerDelegate(listener); 424 425 synchronized (mListeners) { 426 mListeners.put(delegate.nonce, delegate); 427 } 428 429 return delegate.nonce; 430 } 431 } 432 getNextNonce()433 private int getNextNonce() { 434 return mNextNonce.getAndIncrement(); 435 } 436 437 /** 438 * Private class containing sender and receiver code for StorageEvents. 439 */ 440 private class ObbListenerDelegate { 441 private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef; 442 private final Handler mHandler; 443 444 private final int nonce; 445 ObbListenerDelegate(OnObbStateChangeListener listener)446 ObbListenerDelegate(OnObbStateChangeListener listener) { 447 nonce = getNextNonce(); 448 mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener); 449 mHandler = new Handler(mLooper) { 450 @Override 451 public void handleMessage(Message msg) { 452 final OnObbStateChangeListener changeListener = getListener(); 453 if (changeListener == null) { 454 return; 455 } 456 457 changeListener.onObbStateChange((String) msg.obj, msg.arg1); 458 } 459 }; 460 } 461 getListener()462 OnObbStateChangeListener getListener() { 463 if (mObbEventListenerRef == null) { 464 return null; 465 } 466 return mObbEventListenerRef.get(); 467 } 468 sendObbStateChanged(String path, int state)469 void sendObbStateChanged(String path, int state) { 470 mHandler.obtainMessage(0, state, 0, path).sendToTarget(); 471 } 472 } 473 474 /** {@hide} */ 475 @Deprecated 476 @UnsupportedAppUsage from(Context context)477 public static StorageManager from(Context context) { 478 return context.getSystemService(StorageManager.class); 479 } 480 481 /** 482 * Constructs a StorageManager object through which an application can 483 * can communicate with the systems mount service. 484 * 485 * @param looper The {@link android.os.Looper} which events will be received on. 486 * 487 * <p>Applications can get instance of this class by calling 488 * {@link android.content.Context#getSystemService(java.lang.String)} with an argument 489 * of {@link android.content.Context#STORAGE_SERVICE}. 490 * 491 * @hide 492 */ 493 @UnsupportedAppUsage StorageManager(Context context, Looper looper)494 public StorageManager(Context context, Looper looper) throws ServiceNotFoundException { 495 mContext = context; 496 mResolver = context.getContentResolver(); 497 mLooper = looper; 498 mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getServiceOrThrow("mount")); 499 mAppOps = mContext.getSystemService(AppOpsManager.class); 500 } 501 502 /** 503 * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}. 504 * 505 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object. 506 * 507 * @hide 508 */ 509 @UnsupportedAppUsage registerListener(StorageEventListener listener)510 public void registerListener(StorageEventListener listener) { 511 synchronized (mDelegates) { 512 final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate( 513 mContext.getMainExecutor(), listener, new StorageVolumeCallback()); 514 try { 515 mStorageManager.registerListener(delegate); 516 } catch (RemoteException e) { 517 throw e.rethrowFromSystemServer(); 518 } 519 mDelegates.add(delegate); 520 } 521 } 522 523 /** 524 * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}. 525 * 526 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object. 527 * 528 * @hide 529 */ 530 @UnsupportedAppUsage unregisterListener(StorageEventListener listener)531 public void unregisterListener(StorageEventListener listener) { 532 synchronized (mDelegates) { 533 for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) { 534 final StorageEventListenerDelegate delegate = i.next(); 535 if (delegate.mListener == listener) { 536 try { 537 mStorageManager.unregisterListener(delegate); 538 } catch (RemoteException e) { 539 throw e.rethrowFromSystemServer(); 540 } 541 i.remove(); 542 } 543 } 544 } 545 } 546 547 /** 548 * Callback that delivers {@link StorageVolume} related events. 549 * <p> 550 * For example, this can be used to detect when a volume changes to the 551 * {@link Environment#MEDIA_MOUNTED} or {@link Environment#MEDIA_UNMOUNTED} 552 * states. 553 * 554 * @see StorageManager#registerStorageVolumeCallback 555 * @see StorageManager#unregisterStorageVolumeCallback 556 */ 557 public static class StorageVolumeCallback { 558 /** 559 * Called when {@link StorageVolume#getState()} changes, such as 560 * changing to the {@link Environment#MEDIA_MOUNTED} or 561 * {@link Environment#MEDIA_UNMOUNTED} states. 562 * <p> 563 * The given argument is a snapshot in time and can be used to process 564 * events in the order they occurred, or you can call 565 * {@link StorageManager#getStorageVolumes()} to observe the latest 566 * value. 567 */ onStateChanged(@onNull StorageVolume volume)568 public void onStateChanged(@NonNull StorageVolume volume) { } 569 } 570 571 /** 572 * Registers the given callback to listen for {@link StorageVolume} changes. 573 * <p> 574 * For example, this can be used to detect when a volume changes to the 575 * {@link Environment#MEDIA_MOUNTED} or {@link Environment#MEDIA_UNMOUNTED} 576 * states. 577 * 578 * @see StorageManager#unregisterStorageVolumeCallback 579 */ registerStorageVolumeCallback(@allbackExecutor @onNull Executor executor, @NonNull StorageVolumeCallback callback)580 public void registerStorageVolumeCallback(@CallbackExecutor @NonNull Executor executor, 581 @NonNull StorageVolumeCallback callback) { 582 synchronized (mDelegates) { 583 final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate( 584 executor, new StorageEventListener(), callback); 585 try { 586 mStorageManager.registerListener(delegate); 587 } catch (RemoteException e) { 588 throw e.rethrowFromSystemServer(); 589 } 590 mDelegates.add(delegate); 591 } 592 } 593 594 /** 595 * Unregisters the given callback from listening for {@link StorageVolume} 596 * changes. 597 * 598 * @see StorageManager#registerStorageVolumeCallback 599 */ unregisterStorageVolumeCallback(@onNull StorageVolumeCallback callback)600 public void unregisterStorageVolumeCallback(@NonNull StorageVolumeCallback callback) { 601 synchronized (mDelegates) { 602 for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) { 603 final StorageEventListenerDelegate delegate = i.next(); 604 if (delegate.mCallback == callback) { 605 try { 606 mStorageManager.unregisterListener(delegate); 607 } catch (RemoteException e) { 608 throw e.rethrowFromSystemServer(); 609 } 610 i.remove(); 611 } 612 } 613 } 614 } 615 616 /** 617 * Enables USB Mass Storage (UMS) on the device. 618 * 619 * @hide 620 */ 621 @Deprecated 622 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) enableUsbMassStorage()623 public void enableUsbMassStorage() { 624 } 625 626 /** 627 * Disables USB Mass Storage (UMS) on the device. 628 * 629 * @hide 630 */ 631 @Deprecated 632 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) disableUsbMassStorage()633 public void disableUsbMassStorage() { 634 } 635 636 /** 637 * Query if a USB Mass Storage (UMS) host is connected. 638 * @return true if UMS host is connected. 639 * 640 * @hide 641 */ 642 @Deprecated 643 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isUsbMassStorageConnected()644 public boolean isUsbMassStorageConnected() { 645 return false; 646 } 647 648 /** 649 * Query if a USB Mass Storage (UMS) is enabled on the device. 650 * @return true if UMS host is enabled. 651 * 652 * @hide 653 */ 654 @Deprecated 655 @UnsupportedAppUsage isUsbMassStorageEnabled()656 public boolean isUsbMassStorageEnabled() { 657 return false; 658 } 659 660 /** 661 * Mount an Opaque Binary Blob (OBB) file. 662 * <p> 663 * The OBB will remain mounted for as long as the StorageManager reference 664 * is held by the application. As soon as this reference is lost, the OBBs 665 * in use will be unmounted. The {@link OnObbStateChangeListener} registered 666 * with this call will receive the success or failure of this operation. 667 * <p> 668 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the 669 * file matches a package ID that is owned by the calling program's UID. 670 * That is, shared UID applications can attempt to mount any other 671 * application's OBB that shares its UID. 672 * 673 * @param rawPath the path to the OBB file 674 * @param key must be <code>null</code>. Previously, some Android device 675 * implementations accepted a non-<code>null</code> key to mount 676 * an encrypted OBB file. However, this never worked reliably and 677 * is no longer supported. 678 * @param listener will receive the success or failure of the operation 679 * @return whether the mount call was successfully queued or not 680 */ mountObb(String rawPath, String key, OnObbStateChangeListener listener)681 public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) { 682 Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 683 Preconditions.checkArgument(key == null, "mounting encrypted OBBs is no longer supported"); 684 Preconditions.checkNotNull(listener, "listener cannot be null"); 685 686 try { 687 final String canonicalPath = new File(rawPath).getCanonicalPath(); 688 final int nonce = mObbActionListener.addListener(listener); 689 mStorageManager.mountObb(rawPath, canonicalPath, mObbActionListener, nonce, 690 getObbInfo(canonicalPath)); 691 return true; 692 } catch (IOException e) { 693 throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e); 694 } catch (RemoteException e) { 695 throw e.rethrowFromSystemServer(); 696 } 697 } 698 699 /** 700 * Returns a {@link PendingIntent} that can be used by Apps with 701 * {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} permission 702 * to launch the manageSpaceActivity for any App that implements it, irrespective of its 703 * exported status. 704 * <p> 705 * Caller has the responsibility of supplying a valid packageName which has 706 * manageSpaceActivity implemented. 707 * 708 * @param packageName package name for the App for which manageSpaceActivity is to be launched 709 * @param requestCode for launching the activity 710 * @return PendingIntent to launch the manageSpaceActivity if successful, null if the 711 * packageName doesn't have a manageSpaceActivity. 712 * @throws IllegalArgumentException an invalid packageName is supplied. 713 */ 714 @RequiresPermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE) 715 @Nullable getManageSpaceActivityIntent( @onNull String packageName, int requestCode)716 public PendingIntent getManageSpaceActivityIntent( 717 @NonNull String packageName, int requestCode) { 718 try { 719 return mStorageManager.getManageSpaceActivityIntent(packageName, 720 requestCode); 721 } catch (RemoteException e) { 722 throw e.rethrowFromSystemServer(); 723 } 724 } 725 getObbInfo(String canonicalPath)726 private ObbInfo getObbInfo(String canonicalPath) { 727 try { 728 final ObbInfo obbInfo = ObbScanner.getObbInfo(canonicalPath); 729 return obbInfo; 730 } catch (IOException e) { 731 throw new IllegalArgumentException("Couldn't get OBB info for " + canonicalPath, e); 732 } 733 } 734 735 /** 736 * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the 737 * <code>force</code> flag is true, it will kill any application needed to 738 * unmount the given OBB (even the calling application). 739 * <p> 740 * The {@link OnObbStateChangeListener} registered with this call will 741 * receive the success or failure of this operation. 742 * <p> 743 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the 744 * file matches a package ID that is owned by the calling program's UID. 745 * That is, shared UID applications can obtain access to any other 746 * application's OBB that shares its UID. 747 * <p> 748 * 749 * @param rawPath path to the OBB file 750 * @param force whether to kill any programs using this in order to unmount 751 * it 752 * @param listener will receive the success or failure of the operation 753 * @return whether the unmount call was successfully queued or not 754 */ unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener)755 public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) { 756 Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 757 Preconditions.checkNotNull(listener, "listener cannot be null"); 758 759 try { 760 final int nonce = mObbActionListener.addListener(listener); 761 mStorageManager.unmountObb(rawPath, force, mObbActionListener, nonce); 762 return true; 763 } catch (RemoteException e) { 764 throw e.rethrowFromSystemServer(); 765 } 766 } 767 768 /** 769 * Check whether an Opaque Binary Blob (OBB) is mounted or not. 770 * 771 * @param rawPath path to OBB image 772 * @return true if OBB is mounted; false if not mounted or on error 773 */ isObbMounted(String rawPath)774 public boolean isObbMounted(String rawPath) { 775 Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 776 777 try { 778 return mStorageManager.isObbMounted(rawPath); 779 } catch (RemoteException e) { 780 throw e.rethrowFromSystemServer(); 781 } 782 } 783 784 /** 785 * Check the mounted path of an Opaque Binary Blob (OBB) file. This will 786 * give you the path to where you can obtain access to the internals of the 787 * OBB. 788 * 789 * @param rawPath path to OBB image 790 * @return absolute path to mounted OBB image data or <code>null</code> if 791 * not mounted or exception encountered trying to read status 792 */ getMountedObbPath(String rawPath)793 public String getMountedObbPath(String rawPath) { 794 Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 795 796 try { 797 return mStorageManager.getMountedObbPath(rawPath); 798 } catch (RemoteException e) { 799 throw e.rethrowFromSystemServer(); 800 } 801 } 802 803 /** {@hide} */ 804 @UnsupportedAppUsage getDisks()805 public @NonNull List<DiskInfo> getDisks() { 806 try { 807 return Arrays.asList(mStorageManager.getDisks()); 808 } catch (RemoteException e) { 809 throw e.rethrowFromSystemServer(); 810 } 811 } 812 813 /** {@hide} */ 814 @UnsupportedAppUsage findDiskById(String id)815 public @Nullable DiskInfo findDiskById(String id) { 816 Preconditions.checkNotNull(id); 817 // TODO; go directly to service to make this faster 818 for (DiskInfo disk : getDisks()) { 819 if (Objects.equals(disk.id, id)) { 820 return disk; 821 } 822 } 823 return null; 824 } 825 826 /** {@hide} */ 827 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) findVolumeById(String id)828 public @Nullable VolumeInfo findVolumeById(String id) { 829 Preconditions.checkNotNull(id); 830 // TODO; go directly to service to make this faster 831 for (VolumeInfo vol : getVolumes()) { 832 if (Objects.equals(vol.id, id)) { 833 return vol; 834 } 835 } 836 return null; 837 } 838 839 /** {@hide} */ 840 @UnsupportedAppUsage findVolumeByUuid(String fsUuid)841 public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) { 842 Preconditions.checkNotNull(fsUuid); 843 // TODO; go directly to service to make this faster 844 for (VolumeInfo vol : getVolumes()) { 845 if (Objects.equals(vol.fsUuid, fsUuid)) { 846 return vol; 847 } 848 } 849 return null; 850 } 851 852 /** {@hide} */ findRecordByUuid(String fsUuid)853 public @Nullable VolumeRecord findRecordByUuid(String fsUuid) { 854 Preconditions.checkNotNull(fsUuid); 855 // TODO; go directly to service to make this faster 856 for (VolumeRecord rec : getVolumeRecords()) { 857 if (Objects.equals(rec.fsUuid, fsUuid)) { 858 return rec; 859 } 860 } 861 return null; 862 } 863 864 /** {@hide} */ findPrivateForEmulated(VolumeInfo emulatedVol)865 public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) { 866 if (emulatedVol != null) { 867 String id = emulatedVol.getId(); 868 int idx = id.indexOf(";"); 869 if (idx != -1) { 870 id = id.substring(0, idx); 871 } 872 return findVolumeById(id.replace("emulated", "private")); 873 } else { 874 return null; 875 } 876 } 877 878 /** {@hide} */ 879 @UnsupportedAppUsage findEmulatedForPrivate(VolumeInfo privateVol)880 public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) { 881 if (privateVol != null) { 882 return findVolumeById(privateVol.getId().replace("private", "emulated") + ";" 883 + mContext.getUserId()); 884 } else { 885 return null; 886 } 887 } 888 889 /** {@hide} */ findVolumeByQualifiedUuid(String volumeUuid)890 public @Nullable VolumeInfo findVolumeByQualifiedUuid(String volumeUuid) { 891 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) { 892 return findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL); 893 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) { 894 return getPrimaryPhysicalVolume(); 895 } else { 896 return findVolumeByUuid(volumeUuid); 897 } 898 } 899 900 /** 901 * Return a UUID identifying the storage volume that hosts the given 902 * filesystem path. 903 * <p> 904 * If this path is hosted by the default internal storage of the device at 905 * {@link Environment#getDataDirectory()}, the returned value will be 906 * {@link #UUID_DEFAULT}. 907 * 908 * @throws IOException when the storage device hosting the given path isn't 909 * present, or when it doesn't have a valid UUID. 910 */ getUuidForPath(@onNull File path)911 public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException { 912 Preconditions.checkNotNull(path); 913 final String pathString = path.getCanonicalPath(); 914 if (FileUtils.contains(Environment.getDataDirectory().getAbsolutePath(), pathString)) { 915 return UUID_DEFAULT; 916 } 917 try { 918 for (VolumeInfo vol : mStorageManager.getVolumes(0)) { 919 if (vol.path != null && FileUtils.contains(vol.path, pathString) 920 && vol.type != VolumeInfo.TYPE_PUBLIC && vol.type != VolumeInfo.TYPE_STUB) { 921 // TODO: verify that emulated adopted devices have UUID of 922 // underlying volume 923 try { 924 return convert(vol.fsUuid); 925 } catch (IllegalArgumentException e) { 926 continue; 927 } 928 } 929 } 930 } catch (RemoteException e) { 931 throw e.rethrowFromSystemServer(); 932 } 933 throw new FileNotFoundException("Failed to find a storage device for " + path); 934 } 935 936 /** {@hide} */ findPathForUuid(String volumeUuid)937 public @NonNull File findPathForUuid(String volumeUuid) throws FileNotFoundException { 938 final VolumeInfo vol = findVolumeByQualifiedUuid(volumeUuid); 939 if (vol != null) { 940 return vol.getPath(); 941 } 942 throw new FileNotFoundException("Failed to find a storage device for " + volumeUuid); 943 } 944 945 /** 946 * Test if the given file descriptor supports allocation of disk space using 947 * {@link #allocateBytes(FileDescriptor, long)}. 948 */ isAllocationSupported(@onNull FileDescriptor fd)949 public boolean isAllocationSupported(@NonNull FileDescriptor fd) { 950 try { 951 getUuidForPath(ParcelFileDescriptor.getFile(fd)); 952 return true; 953 } catch (IOException e) { 954 return false; 955 } 956 } 957 958 /** {@hide} */ 959 @UnsupportedAppUsage getVolumes()960 public @NonNull List<VolumeInfo> getVolumes() { 961 try { 962 return Arrays.asList(mStorageManager.getVolumes(0)); 963 } catch (RemoteException e) { 964 throw e.rethrowFromSystemServer(); 965 } 966 } 967 968 /** {@hide} */ getWritablePrivateVolumes()969 public @NonNull List<VolumeInfo> getWritablePrivateVolumes() { 970 try { 971 final ArrayList<VolumeInfo> res = new ArrayList<>(); 972 for (VolumeInfo vol : mStorageManager.getVolumes(0)) { 973 if (vol.getType() == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) { 974 res.add(vol); 975 } 976 } 977 return res; 978 } catch (RemoteException e) { 979 throw e.rethrowFromSystemServer(); 980 } 981 } 982 983 /** {@hide} */ getVolumeRecords()984 public @NonNull List<VolumeRecord> getVolumeRecords() { 985 try { 986 return Arrays.asList(mStorageManager.getVolumeRecords(0)); 987 } catch (RemoteException e) { 988 throw e.rethrowFromSystemServer(); 989 } 990 } 991 992 /** {@hide} */ 993 @UnsupportedAppUsage getBestVolumeDescription(VolumeInfo vol)994 public @Nullable String getBestVolumeDescription(VolumeInfo vol) { 995 if (vol == null) return null; 996 997 // Nickname always takes precedence when defined 998 if (!TextUtils.isEmpty(vol.fsUuid)) { 999 final VolumeRecord rec = findRecordByUuid(vol.fsUuid); 1000 if (rec != null && !TextUtils.isEmpty(rec.nickname)) { 1001 return rec.nickname; 1002 } 1003 } 1004 1005 if (!TextUtils.isEmpty(vol.getDescription())) { 1006 return vol.getDescription(); 1007 } 1008 1009 if (vol.disk != null) { 1010 return vol.disk.getDescription(); 1011 } 1012 1013 return null; 1014 } 1015 1016 /** {@hide} */ 1017 @UnsupportedAppUsage getPrimaryPhysicalVolume()1018 public @Nullable VolumeInfo getPrimaryPhysicalVolume() { 1019 final List<VolumeInfo> vols = getVolumes(); 1020 for (VolumeInfo vol : vols) { 1021 if (vol.isPrimaryPhysical()) { 1022 return vol; 1023 } 1024 } 1025 return null; 1026 } 1027 1028 /** {@hide} */ mount(String volId)1029 public void mount(String volId) { 1030 try { 1031 mStorageManager.mount(volId); 1032 } catch (RemoteException e) { 1033 throw e.rethrowFromSystemServer(); 1034 } 1035 } 1036 1037 /** {@hide} */ 1038 @UnsupportedAppUsage unmount(String volId)1039 public void unmount(String volId) { 1040 try { 1041 mStorageManager.unmount(volId); 1042 } catch (RemoteException e) { 1043 throw e.rethrowFromSystemServer(); 1044 } 1045 } 1046 1047 /** {@hide} */ 1048 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) format(String volId)1049 public void format(String volId) { 1050 try { 1051 mStorageManager.format(volId); 1052 } catch (RemoteException e) { 1053 throw e.rethrowFromSystemServer(); 1054 } 1055 } 1056 1057 /** {@hide} */ 1058 @Deprecated benchmark(String volId)1059 public long benchmark(String volId) { 1060 final CompletableFuture<PersistableBundle> result = new CompletableFuture<>(); 1061 benchmark(volId, new IVoldTaskListener.Stub() { 1062 @Override 1063 public void onStatus(int status, PersistableBundle extras) { 1064 // Ignored 1065 } 1066 1067 @Override 1068 public void onFinished(int status, PersistableBundle extras) { 1069 result.complete(extras); 1070 } 1071 }); 1072 try { 1073 // Convert ms to ns 1074 return result.get(3, TimeUnit.MINUTES).getLong("run", Long.MAX_VALUE) * 1000000; 1075 } catch (Exception e) { 1076 return Long.MAX_VALUE; 1077 } 1078 } 1079 1080 /** {@hide} */ benchmark(String volId, IVoldTaskListener listener)1081 public void benchmark(String volId, IVoldTaskListener listener) { 1082 try { 1083 mStorageManager.benchmark(volId, listener); 1084 } catch (RemoteException e) { 1085 throw e.rethrowFromSystemServer(); 1086 } 1087 } 1088 1089 /** {@hide} */ 1090 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) partitionPublic(String diskId)1091 public void partitionPublic(String diskId) { 1092 try { 1093 mStorageManager.partitionPublic(diskId); 1094 } catch (RemoteException e) { 1095 throw e.rethrowFromSystemServer(); 1096 } 1097 } 1098 1099 /** {@hide} */ partitionPrivate(String diskId)1100 public void partitionPrivate(String diskId) { 1101 try { 1102 mStorageManager.partitionPrivate(diskId); 1103 } catch (RemoteException e) { 1104 throw e.rethrowFromSystemServer(); 1105 } 1106 } 1107 1108 /** {@hide} */ partitionMixed(String diskId, int ratio)1109 public void partitionMixed(String diskId, int ratio) { 1110 try { 1111 mStorageManager.partitionMixed(diskId, ratio); 1112 } catch (RemoteException e) { 1113 throw e.rethrowFromSystemServer(); 1114 } 1115 } 1116 1117 /** {@hide} */ wipeAdoptableDisks()1118 public void wipeAdoptableDisks() { 1119 // We only wipe devices in "adoptable" locations, which are in a 1120 // long-term stable slot/location on the device, where apps have a 1121 // reasonable chance of storing sensitive data. (Apps need to go through 1122 // SAF to write to transient volumes.) 1123 final List<DiskInfo> disks = getDisks(); 1124 for (DiskInfo disk : disks) { 1125 final String diskId = disk.getId(); 1126 if (disk.isAdoptable()) { 1127 Slog.d(TAG, "Found adoptable " + diskId + "; wiping"); 1128 try { 1129 // TODO: switch to explicit wipe command when we have it, 1130 // for now rely on the fact that vfat format does a wipe 1131 mStorageManager.partitionPublic(diskId); 1132 } catch (Exception e) { 1133 Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e); 1134 } 1135 } else { 1136 Slog.d(TAG, "Ignorning non-adoptable disk " + disk.getId()); 1137 } 1138 } 1139 } 1140 1141 /** {@hide} */ setVolumeNickname(String fsUuid, String nickname)1142 public void setVolumeNickname(String fsUuid, String nickname) { 1143 try { 1144 mStorageManager.setVolumeNickname(fsUuid, nickname); 1145 } catch (RemoteException e) { 1146 throw e.rethrowFromSystemServer(); 1147 } 1148 } 1149 1150 /** {@hide} */ setVolumeInited(String fsUuid, boolean inited)1151 public void setVolumeInited(String fsUuid, boolean inited) { 1152 try { 1153 mStorageManager.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0, 1154 VolumeRecord.USER_FLAG_INITED); 1155 } catch (RemoteException e) { 1156 throw e.rethrowFromSystemServer(); 1157 } 1158 } 1159 1160 /** {@hide} */ setVolumeSnoozed(String fsUuid, boolean snoozed)1161 public void setVolumeSnoozed(String fsUuid, boolean snoozed) { 1162 try { 1163 mStorageManager.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0, 1164 VolumeRecord.USER_FLAG_SNOOZED); 1165 } catch (RemoteException e) { 1166 throw e.rethrowFromSystemServer(); 1167 } 1168 } 1169 1170 /** {@hide} */ forgetVolume(String fsUuid)1171 public void forgetVolume(String fsUuid) { 1172 try { 1173 mStorageManager.forgetVolume(fsUuid); 1174 } catch (RemoteException e) { 1175 throw e.rethrowFromSystemServer(); 1176 } 1177 } 1178 1179 /** 1180 * This is not the API you're looking for. 1181 * 1182 * @see PackageManager#getPrimaryStorageCurrentVolume() 1183 * @hide 1184 */ getPrimaryStorageUuid()1185 public String getPrimaryStorageUuid() { 1186 try { 1187 return mStorageManager.getPrimaryStorageUuid(); 1188 } catch (RemoteException e) { 1189 throw e.rethrowFromSystemServer(); 1190 } 1191 } 1192 1193 /** 1194 * This is not the API you're looking for. 1195 * 1196 * @see PackageManager#movePrimaryStorage(VolumeInfo) 1197 * @hide 1198 */ setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)1199 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) { 1200 try { 1201 mStorageManager.setPrimaryStorageUuid(volumeUuid, callback); 1202 } catch (RemoteException e) { 1203 throw e.rethrowFromSystemServer(); 1204 } 1205 } 1206 1207 /** 1208 * Return the {@link StorageVolume} that contains the given file, or 1209 * {@code null} if none. 1210 */ getStorageVolume(@onNull File file)1211 public @Nullable StorageVolume getStorageVolume(@NonNull File file) { 1212 return getStorageVolume(getVolumeList(), file); 1213 } 1214 1215 /** 1216 * Return the {@link StorageVolume} that contains the given 1217 * {@link MediaStore} item. 1218 */ getStorageVolume(@onNull Uri uri)1219 public @NonNull StorageVolume getStorageVolume(@NonNull Uri uri) { 1220 String volumeName = MediaStore.getVolumeName(uri); 1221 1222 // When Uri is pointing at a synthetic volume, we're willing to query to 1223 // resolve the actual volume name 1224 if (Objects.equals(volumeName, MediaStore.VOLUME_EXTERNAL)) { 1225 try (Cursor c = mContext.getContentResolver().query(uri, 1226 new String[] { MediaStore.MediaColumns.VOLUME_NAME }, null, null)) { 1227 if (c.moveToFirst()) { 1228 volumeName = c.getString(0); 1229 } 1230 } 1231 } 1232 1233 switch (volumeName) { 1234 case MediaStore.VOLUME_EXTERNAL_PRIMARY: 1235 return getPrimaryStorageVolume(); 1236 default: 1237 for (StorageVolume vol : getStorageVolumes()) { 1238 if (Objects.equals(vol.getMediaStoreVolumeName(), volumeName)) { 1239 return vol; 1240 } 1241 } 1242 } 1243 throw new IllegalStateException("Unknown volume for " + uri); 1244 } 1245 1246 /** {@hide} */ getStorageVolume(File file, int userId)1247 public static @Nullable StorageVolume getStorageVolume(File file, int userId) { 1248 return getStorageVolume(getVolumeList(userId, 0), file); 1249 } 1250 1251 /** {@hide} */ 1252 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getStorageVolume(StorageVolume[] volumes, File file)1253 private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) { 1254 if (file == null) { 1255 return null; 1256 } 1257 final String path = file.getAbsolutePath(); 1258 if (path.startsWith(DEPRECATE_DATA_PREFIX)) { 1259 final Uri uri = ContentResolver.translateDeprecatedDataPath(path); 1260 return AppGlobals.getInitialApplication().getSystemService(StorageManager.class) 1261 .getStorageVolume(uri); 1262 } 1263 try { 1264 file = file.getCanonicalFile(); 1265 } catch (IOException ignored) { 1266 Slog.d(TAG, "Could not get canonical path for " + file); 1267 return null; 1268 } 1269 for (StorageVolume volume : volumes) { 1270 File volumeFile = volume.getPathFile(); 1271 try { 1272 volumeFile = volumeFile.getCanonicalFile(); 1273 } catch (IOException ignored) { 1274 continue; 1275 } 1276 if (FileUtils.contains(volumeFile, file)) { 1277 return volume; 1278 } 1279 } 1280 return null; 1281 } 1282 1283 /** 1284 * Gets the state of a volume via its mountpoint. 1285 * @hide 1286 */ 1287 @Deprecated 1288 @UnsupportedAppUsage getVolumeState(String mountPoint)1289 public @NonNull String getVolumeState(String mountPoint) { 1290 final StorageVolume vol = getStorageVolume(new File(mountPoint)); 1291 if (vol != null) { 1292 return vol.getState(); 1293 } else { 1294 return Environment.MEDIA_UNKNOWN; 1295 } 1296 } 1297 1298 /** 1299 * Return the list of shared/external storage volumes currently available to 1300 * the calling user. 1301 * <p> 1302 * These storage volumes are actively attached to the device, but may be in 1303 * any mount state, as returned by {@link StorageVolume#getState()}. Returns 1304 * both the primary shared storage device and any attached external volumes, 1305 * including SD cards and USB drives. 1306 */ getStorageVolumes()1307 public @NonNull List<StorageVolume> getStorageVolumes() { 1308 final ArrayList<StorageVolume> res = new ArrayList<>(); 1309 Collections.addAll(res, 1310 getVolumeList(mContext.getUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE)); 1311 return res; 1312 } 1313 1314 /** 1315 * Return the list of shared/external storage volumes currently available to 1316 * the calling user and the user it shares media with. Please refer to 1317 * <a href="https://source.android.com/compatibility/12/android-12-cdd#95_multi-user_support"> 1318 * multi-user support</a> for more details. 1319 * 1320 * <p> 1321 * This is similar to {@link StorageManager#getStorageVolumes()} except that the result also 1322 * includes the volumes belonging to any user it shares media with 1323 */ 1324 @RequiresPermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE) getStorageVolumesIncludingSharedProfiles()1325 public @NonNull List<StorageVolume> getStorageVolumesIncludingSharedProfiles() { 1326 final ArrayList<StorageVolume> res = new ArrayList<>(); 1327 Collections.addAll(res, 1328 getVolumeList(mContext.getUserId(), 1329 FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE | FLAG_INCLUDE_SHARED_PROFILE)); 1330 return res; 1331 } 1332 1333 /** 1334 * Return the list of shared/external storage volumes both currently and 1335 * recently available to the calling user. 1336 * <p> 1337 * Recently available storage volumes are likely to reappear in the future, 1338 * so apps are encouraged to preserve any indexed metadata related to these 1339 * volumes to optimize user experiences. 1340 */ getRecentStorageVolumes()1341 public @NonNull List<StorageVolume> getRecentStorageVolumes() { 1342 final ArrayList<StorageVolume> res = new ArrayList<>(); 1343 Collections.addAll(res, 1344 getVolumeList(mContext.getUserId(), 1345 FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE | FLAG_INCLUDE_RECENT)); 1346 return res; 1347 } 1348 1349 /** 1350 * Return the primary shared/external storage volume available to the 1351 * current user. This volume is the same storage device returned by 1352 * {@link Environment#getExternalStorageDirectory()} and 1353 * {@link Context#getExternalFilesDir(String)}. 1354 */ getPrimaryStorageVolume()1355 public @NonNull StorageVolume getPrimaryStorageVolume() { 1356 return getVolumeList(mContext.getUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE)[0]; 1357 } 1358 1359 /** {@hide} */ getPrimaryStoragePathAndSize()1360 public static Pair<String, Long> getPrimaryStoragePathAndSize() { 1361 return Pair.create(null, 1362 FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace() 1363 + Environment.getRootDirectory().getTotalSpace())); 1364 } 1365 1366 /** {@hide} */ getPrimaryStorageSize()1367 public long getPrimaryStorageSize() { 1368 return FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace() 1369 + Environment.getRootDirectory().getTotalSpace()); 1370 } 1371 1372 /** {@hide} */ mkdirs(File file)1373 public void mkdirs(File file) { 1374 BlockGuard.getVmPolicy().onPathAccess(file.getAbsolutePath()); 1375 try { 1376 mStorageManager.mkdirs(mContext.getOpPackageName(), file.getAbsolutePath()); 1377 } catch (RemoteException e) { 1378 throw e.rethrowFromSystemServer(); 1379 } 1380 } 1381 1382 /** @removed */ getVolumeList()1383 public @NonNull StorageVolume[] getVolumeList() { 1384 return getVolumeList(mContext.getUserId(), 0); 1385 } 1386 1387 /** {@hide} */ 1388 @UnsupportedAppUsage getVolumeList(int userId, int flags)1389 public static @NonNull StorageVolume[] getVolumeList(int userId, int flags) { 1390 final IStorageManager storageManager = IStorageManager.Stub.asInterface( 1391 ServiceManager.getService("mount")); 1392 try { 1393 String packageName = ActivityThread.currentOpPackageName(); 1394 if (packageName == null) { 1395 // Package name can be null if the activity thread is running but the app 1396 // hasn't bound yet. In this case we fall back to the first package in the 1397 // current UID. This works for runtime permissions as permission state is 1398 // per UID and permission realted app ops are updated for all UID packages. 1399 String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid( 1400 android.os.Process.myUid()); 1401 if (packageNames == null || packageNames.length <= 0) { 1402 Log.w(TAG, "Missing package names; no storage volumes available"); 1403 return new StorageVolume[0]; 1404 } 1405 packageName = packageNames[0]; 1406 } 1407 return storageManager.getVolumeList(userId, packageName, flags); 1408 } catch (RemoteException e) { 1409 throw e.rethrowFromSystemServer(); 1410 } 1411 } 1412 1413 /** 1414 * Returns list of paths for all mountable volumes. 1415 * @hide 1416 */ 1417 @Deprecated 1418 @UnsupportedAppUsage getVolumePaths()1419 public @NonNull String[] getVolumePaths() { 1420 StorageVolume[] volumes = getVolumeList(); 1421 int count = volumes.length; 1422 String[] paths = new String[count]; 1423 for (int i = 0; i < count; i++) { 1424 paths[i] = volumes[i].getPath(); 1425 } 1426 return paths; 1427 } 1428 1429 /** @removed */ getPrimaryVolume()1430 public @NonNull StorageVolume getPrimaryVolume() { 1431 return getPrimaryVolume(getVolumeList()); 1432 } 1433 1434 /** {@hide} */ getPrimaryVolume(StorageVolume[] volumes)1435 public static @NonNull StorageVolume getPrimaryVolume(StorageVolume[] volumes) { 1436 for (StorageVolume volume : volumes) { 1437 if (volume.isPrimary()) { 1438 return volume; 1439 } 1440 } 1441 throw new IllegalStateException("Missing primary storage"); 1442 } 1443 1444 /** 1445 * Devices having above STORAGE_THRESHOLD_PERCENT_HIGH of total space free are considered to be 1446 * in high free space category. 1447 * 1448 * @hide 1449 */ 1450 public static final int DEFAULT_STORAGE_THRESHOLD_PERCENT_HIGH = 20; 1451 /** {@hide} */ 1452 @TestApi 1453 public static final String 1454 STORAGE_THRESHOLD_PERCENT_HIGH_KEY = "storage_threshold_percent_high"; 1455 /** 1456 * Devices having below STORAGE_THRESHOLD_PERCENT_LOW of total space free are considered to be 1457 * in low free space category and can be configured via 1458 * Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE. 1459 * 1460 * @hide 1461 */ 1462 public static final int DEFAULT_STORAGE_THRESHOLD_PERCENT_LOW = 5; 1463 /** 1464 * For devices in high free space category, CACHE_RESERVE_PERCENT_HIGH percent of total space is 1465 * allocated for cache. 1466 * 1467 * @hide 1468 */ 1469 public static final int DEFAULT_CACHE_RESERVE_PERCENT_HIGH = 10; 1470 /** {@hide} */ 1471 @TestApi 1472 public static final String CACHE_RESERVE_PERCENT_HIGH_KEY = "cache_reserve_percent_high"; 1473 /** 1474 * For devices in low free space category, CACHE_RESERVE_PERCENT_LOW percent of total space is 1475 * allocated for cache. 1476 * 1477 * @hide 1478 */ 1479 public static final int DEFAULT_CACHE_RESERVE_PERCENT_LOW = 2; 1480 /** {@hide} */ 1481 @TestApi 1482 public static final String CACHE_RESERVE_PERCENT_LOW_KEY = "cache_reserve_percent_low"; 1483 1484 private static final long DEFAULT_THRESHOLD_MAX_BYTES = DataUnit.MEBIBYTES.toBytes(500); 1485 1486 private static final long DEFAULT_FULL_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(1); 1487 1488 /** 1489 * Return the number of available bytes until the given path is considered 1490 * running low on storage. 1491 * 1492 * @hide 1493 */ 1494 @UnsupportedAppUsage getStorageBytesUntilLow(File path)1495 public long getStorageBytesUntilLow(File path) { 1496 return path.getUsableSpace() - getStorageFullBytes(path); 1497 } 1498 1499 /** 1500 * Return the number of available bytes at which the given path is 1501 * considered running low on storage. 1502 * 1503 * @hide 1504 */ 1505 @UnsupportedAppUsage getStorageLowBytes(File path)1506 public long getStorageLowBytes(File path) { 1507 final long lowPercent = Settings.Global.getInt(mResolver, 1508 Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, 1509 DEFAULT_STORAGE_THRESHOLD_PERCENT_LOW); 1510 final long lowBytes = (path.getTotalSpace() * lowPercent) / 100; 1511 1512 final long maxLowBytes = Settings.Global.getLong(mResolver, 1513 Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES); 1514 1515 return Math.min(lowBytes, maxLowBytes); 1516 } 1517 1518 /** 1519 * Compute the minimum number of bytes of storage on the device that could 1520 * be reserved for cached data depending on the device state which is then passed on 1521 * to getStorageCacheBytes. 1522 * 1523 * Input File path must point to a storage volume. 1524 * 1525 * @hide 1526 */ 1527 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 1528 @TestApi 1529 @SuppressLint("StreamFiles") computeStorageCacheBytes(@onNull File path)1530 public long computeStorageCacheBytes(@NonNull File path) { 1531 final int storageThresholdPercentHigh = DeviceConfig.getInt( 1532 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 1533 STORAGE_THRESHOLD_PERCENT_HIGH_KEY, DEFAULT_STORAGE_THRESHOLD_PERCENT_HIGH); 1534 final int cacheReservePercentHigh = DeviceConfig.getInt( 1535 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 1536 CACHE_RESERVE_PERCENT_HIGH_KEY, DEFAULT_CACHE_RESERVE_PERCENT_HIGH); 1537 final int cacheReservePercentLow = DeviceConfig.getInt( 1538 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, 1539 CACHE_RESERVE_PERCENT_LOW_KEY, DEFAULT_CACHE_RESERVE_PERCENT_LOW); 1540 final long totalBytes = path.getTotalSpace(); 1541 final long usableBytes = path.getUsableSpace(); 1542 final long storageThresholdHighBytes = totalBytes * storageThresholdPercentHigh / 100; 1543 final long storageThresholdLowBytes = getStorageLowBytes(path); 1544 long result; 1545 if (usableBytes > storageThresholdHighBytes) { 1546 // If free space is >storageThresholdPercentHigh of total space, 1547 // reserve cacheReservePercentHigh of total space 1548 result = totalBytes * cacheReservePercentHigh / 100; 1549 } else if (usableBytes < storageThresholdLowBytes) { 1550 // If free space is <min(storageThresholdPercentLow of total space, 500MB), 1551 // reserve cacheReservePercentLow of total space 1552 result = totalBytes * cacheReservePercentLow / 100; 1553 } else { 1554 // Else, linearly interpolate the amount of space to reserve 1555 double slope = (cacheReservePercentHigh - cacheReservePercentLow) * totalBytes 1556 / (100.0 * (storageThresholdHighBytes - storageThresholdLowBytes)); 1557 double intercept = totalBytes * cacheReservePercentLow / 100.0 1558 - storageThresholdLowBytes * slope; 1559 result = Math.round(slope * usableBytes + intercept); 1560 } 1561 return result; 1562 } 1563 1564 /** 1565 * Return the minimum number of bytes of storage on the device that should 1566 * be reserved for cached data. 1567 * 1568 * @hide 1569 */ getStorageCacheBytes(@onNull File path, @AllocateFlags int flags)1570 public long getStorageCacheBytes(@NonNull File path, @AllocateFlags int flags) { 1571 if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) { 1572 return 0; 1573 } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED) != 0) { 1574 return 0; 1575 } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED) != 0) { 1576 return computeStorageCacheBytes(path) / 2; 1577 } else { 1578 return computeStorageCacheBytes(path); 1579 } 1580 } 1581 1582 /** 1583 * Return the number of available bytes at which the given path is 1584 * considered full. 1585 * 1586 * @hide 1587 */ 1588 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getStorageFullBytes(File path)1589 public long getStorageFullBytes(File path) { 1590 return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES, 1591 DEFAULT_FULL_THRESHOLD_BYTES); 1592 } 1593 1594 /** {@hide} */ createUserKey(int userId, int serialNumber, boolean ephemeral)1595 public void createUserKey(int userId, int serialNumber, boolean ephemeral) { 1596 try { 1597 mStorageManager.createUserKey(userId, serialNumber, ephemeral); 1598 } catch (RemoteException e) { 1599 throw e.rethrowFromSystemServer(); 1600 } 1601 } 1602 1603 /** {@hide} */ destroyUserKey(int userId)1604 public void destroyUserKey(int userId) { 1605 try { 1606 mStorageManager.destroyUserKey(userId); 1607 } catch (RemoteException e) { 1608 throw e.rethrowFromSystemServer(); 1609 } 1610 } 1611 1612 /** {@hide} */ unlockUserKey(int userId, int serialNumber, byte[] secret)1613 public void unlockUserKey(int userId, int serialNumber, byte[] secret) { 1614 try { 1615 mStorageManager.unlockUserKey(userId, serialNumber, secret); 1616 } catch (RemoteException e) { 1617 throw e.rethrowFromSystemServer(); 1618 } 1619 } 1620 1621 /** {@hide} */ lockUserKey(int userId)1622 public void lockUserKey(int userId) { 1623 try { 1624 mStorageManager.lockUserKey(userId); 1625 } catch (RemoteException e) { 1626 throw e.rethrowFromSystemServer(); 1627 } 1628 } 1629 1630 /** {@hide} */ prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags)1631 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) { 1632 try { 1633 mStorageManager.prepareUserStorage(volumeUuid, userId, serialNumber, flags); 1634 } catch (RemoteException e) { 1635 throw e.rethrowFromSystemServer(); 1636 } 1637 } 1638 1639 /** {@hide} */ destroyUserStorage(String volumeUuid, int userId, int flags)1640 public void destroyUserStorage(String volumeUuid, int userId, int flags) { 1641 try { 1642 mStorageManager.destroyUserStorage(volumeUuid, userId, flags); 1643 } catch (RemoteException e) { 1644 throw e.rethrowFromSystemServer(); 1645 } 1646 } 1647 1648 /** {@hide} */ 1649 @TestApi isUserKeyUnlocked(int userId)1650 public static boolean isUserKeyUnlocked(int userId) { 1651 if (sStorageManager == null) { 1652 sStorageManager = IStorageManager.Stub 1653 .asInterface(ServiceManager.getService("mount")); 1654 } 1655 if (sStorageManager == null) { 1656 Slog.w(TAG, "Early during boot, assuming locked"); 1657 return false; 1658 } 1659 final long token = Binder.clearCallingIdentity(); 1660 try { 1661 return sStorageManager.isUserKeyUnlocked(userId); 1662 } catch (RemoteException e) { 1663 throw e.rethrowAsRuntimeException(); 1664 } finally { 1665 Binder.restoreCallingIdentity(token); 1666 } 1667 } 1668 1669 /** 1670 * Return if data stored at or under the given path will be encrypted while 1671 * at rest. This can help apps avoid the overhead of double-encrypting data. 1672 */ isEncrypted(File file)1673 public boolean isEncrypted(File file) { 1674 if (FileUtils.contains(Environment.getDataDirectory(), file)) { 1675 return isEncrypted(); 1676 } else if (FileUtils.contains(Environment.getExpandDirectory(), file)) { 1677 return true; 1678 } 1679 // TODO: extend to support shared storage 1680 return false; 1681 } 1682 1683 /** {@hide} 1684 * Is this device encrypted? 1685 * <p> 1686 * Note: all devices launching with Android 10 (API level 29) or later are 1687 * required to be encrypted. This should only ever return false for 1688 * in-development devices on which encryption has not yet been configured. 1689 * 1690 * @return true if encrypted, false if not encrypted 1691 */ isEncrypted()1692 public static boolean isEncrypted() { 1693 return RoSystemProperties.CRYPTO_ENCRYPTED; 1694 } 1695 1696 /** {@hide} 1697 * Is this device file encrypted? 1698 * @return true for file encrypted. (Implies isEncrypted() == true) 1699 * false not encrypted or using "managed" encryption 1700 */ 1701 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isFileEncryptedNativeOnly()1702 public static boolean isFileEncryptedNativeOnly() { 1703 if (!isEncrypted()) { 1704 return false; 1705 } 1706 return RoSystemProperties.CRYPTO_FILE_ENCRYPTED; 1707 } 1708 1709 /** {@hide} */ isFileEncryptedEmulatedOnly()1710 public static boolean isFileEncryptedEmulatedOnly() { 1711 return SystemProperties.getBoolean(StorageManager.PROP_EMULATE_FBE, false); 1712 } 1713 1714 /** {@hide} 1715 * Is this device running in a file encrypted mode, either native or emulated? 1716 * @return true for file encrypted, false otherwise 1717 */ isFileEncryptedNativeOrEmulated()1718 public static boolean isFileEncryptedNativeOrEmulated() { 1719 return isFileEncryptedNativeOnly() 1720 || isFileEncryptedEmulatedOnly(); 1721 } 1722 1723 /** {@hide} */ hasAdoptable()1724 public static boolean hasAdoptable() { 1725 switch (SystemProperties.get(PROP_ADOPTABLE)) { 1726 case "force_on": 1727 return true; 1728 case "force_off": 1729 return false; 1730 default: 1731 return SystemProperties.getBoolean(PROP_HAS_ADOPTABLE, false); 1732 } 1733 } 1734 1735 /** 1736 * Return if the currently booted device has the "isolated storage" feature 1737 * flag enabled. 1738 * 1739 * @hide 1740 */ 1741 @SystemApi hasIsolatedStorage()1742 public static boolean hasIsolatedStorage() { 1743 return false; 1744 } 1745 1746 /** 1747 * @deprecated disabled now that FUSE has been replaced by sdcardfs 1748 * @hide 1749 */ 1750 @Deprecated maybeTranslateEmulatedPathToInternal(File path)1751 public static File maybeTranslateEmulatedPathToInternal(File path) { 1752 // Disabled now that FUSE has been replaced by sdcardfs 1753 return path; 1754 } 1755 1756 /** 1757 * Translate given shared storage path from a path in an app sandbox 1758 * namespace to a path in the system namespace. 1759 * 1760 * @hide 1761 */ translateAppToSystem(File file, int pid, int uid)1762 public File translateAppToSystem(File file, int pid, int uid) { 1763 return file; 1764 } 1765 1766 /** 1767 * Translate given shared storage path from a path in the system namespace 1768 * to a path in an app sandbox namespace. 1769 * 1770 * @hide 1771 */ translateSystemToApp(File file, int pid, int uid)1772 public File translateSystemToApp(File file, int pid, int uid) { 1773 return file; 1774 } 1775 1776 /** 1777 * Check that given app holds both permission and appop. 1778 * @hide 1779 */ checkPermissionAndAppOp(Context context, boolean enforce, int pid, int uid, String packageName, @NonNull String featureId, String permission, int op)1780 public static boolean checkPermissionAndAppOp(Context context, boolean enforce, int pid, 1781 int uid, String packageName, @NonNull String featureId, String permission, int op) { 1782 return checkPermissionAndAppOp(context, enforce, pid, uid, packageName, featureId, 1783 permission, op, true); 1784 } 1785 1786 /** 1787 * Check that given app holds both permission and appop but do not noteOp. 1788 * @hide 1789 */ checkPermissionAndCheckOp(Context context, boolean enforce, int pid, int uid, String packageName, String permission, int op)1790 public static boolean checkPermissionAndCheckOp(Context context, boolean enforce, 1791 int pid, int uid, String packageName, String permission, int op) { 1792 return checkPermissionAndAppOp(context, enforce, pid, uid, packageName, 1793 null /* featureId is not needed when not noting */, permission, op, false); 1794 } 1795 1796 /** 1797 * Check that given app holds both permission and appop. 1798 * @hide 1799 */ checkPermissionAndAppOp(Context context, boolean enforce, int pid, int uid, String packageName, @Nullable String featureId, String permission, int op, boolean note)1800 private static boolean checkPermissionAndAppOp(Context context, boolean enforce, int pid, 1801 int uid, String packageName, @Nullable String featureId, String permission, int op, 1802 boolean note) { 1803 if (context.checkPermission(permission, pid, uid) != PERMISSION_GRANTED) { 1804 if (enforce) { 1805 throw new SecurityException( 1806 "Permission " + permission + " denied for package " + packageName); 1807 } else { 1808 return false; 1809 } 1810 } 1811 1812 AppOpsManager appOps = context.getSystemService(AppOpsManager.class); 1813 final int mode; 1814 if (note) { 1815 mode = appOps.noteOpNoThrow(op, uid, packageName, featureId, null); 1816 } else { 1817 try { 1818 appOps.checkPackage(uid, packageName); 1819 } catch (SecurityException e) { 1820 if (enforce) { 1821 throw e; 1822 } else { 1823 return false; 1824 } 1825 } 1826 mode = appOps.checkOpNoThrow(op, uid, packageName); 1827 } 1828 switch (mode) { 1829 case AppOpsManager.MODE_ALLOWED: 1830 return true; 1831 case AppOpsManager.MODE_DEFAULT: 1832 case AppOpsManager.MODE_IGNORED: 1833 case AppOpsManager.MODE_ERRORED: 1834 if (enforce) { 1835 throw new SecurityException("Op " + AppOpsManager.opToName(op) + " " 1836 + AppOpsManager.modeToName(mode) + " for package " + packageName); 1837 } else { 1838 return false; 1839 } 1840 default: 1841 throw new IllegalStateException( 1842 AppOpsManager.opToName(op) + " has unknown mode " 1843 + AppOpsManager.modeToName(mode)); 1844 } 1845 } 1846 checkPermissionAndAppOp(boolean enforce, int pid, int uid, String packageName, @Nullable String featureId, String permission, int op)1847 private boolean checkPermissionAndAppOp(boolean enforce, int pid, int uid, String packageName, 1848 @Nullable String featureId, String permission, int op) { 1849 return checkPermissionAndAppOp(mContext, enforce, pid, uid, packageName, featureId, 1850 permission, op); 1851 } 1852 noteAppOpAllowingLegacy(boolean enforce, int pid, int uid, String packageName, @Nullable String featureId, int op)1853 private boolean noteAppOpAllowingLegacy(boolean enforce, 1854 int pid, int uid, String packageName, @Nullable String featureId, int op) { 1855 final int mode = mAppOps.noteOpNoThrow(op, uid, packageName, featureId, null); 1856 switch (mode) { 1857 case AppOpsManager.MODE_ALLOWED: 1858 return true; 1859 case AppOpsManager.MODE_DEFAULT: 1860 case AppOpsManager.MODE_IGNORED: 1861 case AppOpsManager.MODE_ERRORED: 1862 // Legacy apps technically have the access granted by this op, 1863 // even when the op is denied 1864 if ((mAppOps.checkOpNoThrow(OP_LEGACY_STORAGE, uid, 1865 packageName) == AppOpsManager.MODE_ALLOWED)) return true; 1866 1867 if (enforce) { 1868 throw new SecurityException("Op " + AppOpsManager.opToName(op) + " " 1869 + AppOpsManager.modeToName(mode) + " for package " + packageName); 1870 } else { 1871 return false; 1872 } 1873 default: 1874 throw new IllegalStateException( 1875 AppOpsManager.opToName(op) + " has unknown mode " 1876 + AppOpsManager.modeToName(mode)); 1877 } 1878 } 1879 1880 // Callers must hold both the old and new permissions, so that we can 1881 // handle obscure cases like when an app targets Q but was installed on 1882 // a device that was originally running on P before being upgraded to Q. 1883 1884 /** {@hide} */ checkPermissionReadAudio(boolean enforce, int pid, int uid, String packageName, @Nullable String featureId)1885 public boolean checkPermissionReadAudio(boolean enforce, 1886 int pid, int uid, String packageName, @Nullable String featureId) { 1887 if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId, 1888 READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE)) { 1889 return false; 1890 } 1891 return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId, 1892 OP_READ_MEDIA_AUDIO); 1893 } 1894 1895 /** {@hide} */ checkPermissionWriteAudio(boolean enforce, int pid, int uid, String packageName, @Nullable String featureId)1896 public boolean checkPermissionWriteAudio(boolean enforce, 1897 int pid, int uid, String packageName, @Nullable String featureId) { 1898 if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId, 1899 WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE)) { 1900 return false; 1901 } 1902 return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId, 1903 OP_WRITE_MEDIA_AUDIO); 1904 } 1905 1906 /** {@hide} */ checkPermissionReadVideo(boolean enforce, int pid, int uid, String packageName, @Nullable String featureId)1907 public boolean checkPermissionReadVideo(boolean enforce, 1908 int pid, int uid, String packageName, @Nullable String featureId) { 1909 if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId, 1910 READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE)) { 1911 return false; 1912 } 1913 return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId, 1914 OP_READ_MEDIA_VIDEO); 1915 } 1916 1917 /** {@hide} */ checkPermissionWriteVideo(boolean enforce, int pid, int uid, String packageName, @Nullable String featureId)1918 public boolean checkPermissionWriteVideo(boolean enforce, 1919 int pid, int uid, String packageName, @Nullable String featureId) { 1920 if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId, 1921 WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE)) { 1922 return false; 1923 } 1924 return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId, 1925 OP_WRITE_MEDIA_VIDEO); 1926 } 1927 1928 /** {@hide} */ checkPermissionReadImages(boolean enforce, int pid, int uid, String packageName, @Nullable String featureId)1929 public boolean checkPermissionReadImages(boolean enforce, 1930 int pid, int uid, String packageName, @Nullable String featureId) { 1931 if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId, 1932 READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE)) { 1933 return false; 1934 } 1935 return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId, 1936 OP_READ_MEDIA_IMAGES); 1937 } 1938 1939 /** {@hide} */ checkPermissionWriteImages(boolean enforce, int pid, int uid, String packageName, @Nullable String featureId)1940 public boolean checkPermissionWriteImages(boolean enforce, 1941 int pid, int uid, String packageName, @Nullable String featureId) { 1942 if (!checkExternalStoragePermissionAndAppOp(enforce, pid, uid, packageName, featureId, 1943 WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE)) { 1944 return false; 1945 } 1946 return noteAppOpAllowingLegacy(enforce, pid, uid, packageName, featureId, 1947 OP_WRITE_MEDIA_IMAGES); 1948 } 1949 checkExternalStoragePermissionAndAppOp(boolean enforce, int pid, int uid, String packageName, @Nullable String featureId, String permission, int op)1950 private boolean checkExternalStoragePermissionAndAppOp(boolean enforce, 1951 int pid, int uid, String packageName, @Nullable String featureId, String permission, 1952 int op) { 1953 // First check if app has MANAGE_EXTERNAL_STORAGE. 1954 final int mode = mAppOps.noteOpNoThrow(OP_MANAGE_EXTERNAL_STORAGE, uid, packageName, 1955 featureId, null); 1956 if (mode == AppOpsManager.MODE_ALLOWED) { 1957 return true; 1958 } 1959 if (mode == AppOpsManager.MODE_DEFAULT && mContext.checkPermission( 1960 MANAGE_EXTERNAL_STORAGE, pid, uid) == PERMISSION_GRANTED) { 1961 return true; 1962 } 1963 // If app doesn't have MANAGE_EXTERNAL_STORAGE, then check if it has requested granular 1964 // permission. 1965 return checkPermissionAndAppOp(enforce, pid, uid, packageName, featureId, permission, op); 1966 } 1967 1968 /** {@hide} */ 1969 @VisibleForTesting openProxyFileDescriptor( int mode, ProxyFileDescriptorCallback callback, Handler handler, ThreadFactory factory)1970 public @NonNull ParcelFileDescriptor openProxyFileDescriptor( 1971 int mode, ProxyFileDescriptorCallback callback, Handler handler, ThreadFactory factory) 1972 throws IOException { 1973 Preconditions.checkNotNull(callback); 1974 MetricsLogger.count(mContext, "storage_open_proxy_file_descriptor", 1); 1975 // Retry is needed because the mount point mFuseAppLoop is using may be unmounted before 1976 // invoking StorageManagerService#openProxyFileDescriptor. In this case, we need to re-mount 1977 // the bridge by calling mountProxyFileDescriptorBridge. 1978 while (true) { 1979 try { 1980 synchronized (mFuseAppLoopLock) { 1981 boolean newlyCreated = false; 1982 if (mFuseAppLoop == null) { 1983 final AppFuseMount mount = mStorageManager.mountProxyFileDescriptorBridge(); 1984 if (mount == null) { 1985 throw new IOException("Failed to mount proxy bridge"); 1986 } 1987 mFuseAppLoop = new FuseAppLoop(mount.mountPointId, mount.fd, factory); 1988 newlyCreated = true; 1989 } 1990 if (handler == null) { 1991 handler = new Handler(Looper.getMainLooper()); 1992 } 1993 try { 1994 final int fileId = mFuseAppLoop.registerCallback(callback, handler); 1995 final ParcelFileDescriptor pfd = mStorageManager.openProxyFileDescriptor( 1996 mFuseAppLoop.getMountPointId(), fileId, mode); 1997 if (pfd == null) { 1998 mFuseAppLoop.unregisterCallback(fileId); 1999 throw new FuseUnavailableMountException( 2000 mFuseAppLoop.getMountPointId()); 2001 } 2002 return pfd; 2003 } catch (FuseUnavailableMountException exception) { 2004 // The bridge is being unmounted. Tried to recreate it unless the bridge was 2005 // just created. 2006 if (newlyCreated) { 2007 throw new IOException(exception); 2008 } 2009 mFuseAppLoop = null; 2010 continue; 2011 } 2012 } 2013 } catch (RemoteException e) { 2014 // Cannot recover from remote exception. 2015 throw new IOException(e); 2016 } 2017 } 2018 } 2019 2020 /** {@hide} */ openProxyFileDescriptor( int mode, ProxyFileDescriptorCallback callback)2021 public @NonNull ParcelFileDescriptor openProxyFileDescriptor( 2022 int mode, ProxyFileDescriptorCallback callback) 2023 throws IOException { 2024 return openProxyFileDescriptor(mode, callback, null, null); 2025 } 2026 2027 /** 2028 * Opens a seekable {@link ParcelFileDescriptor} that proxies all low-level 2029 * I/O requests back to the given {@link ProxyFileDescriptorCallback}. 2030 * <p> 2031 * This can be useful when you want to provide quick access to a large file 2032 * that isn't backed by a real file on disk, such as a file on a network 2033 * share, cloud storage service, etc. As an example, you could respond to a 2034 * {@link ContentResolver#openFileDescriptor(android.net.Uri, String)} 2035 * request by returning a {@link ParcelFileDescriptor} created with this 2036 * method, and then stream the content on-demand as requested. 2037 * <p> 2038 * Another useful example might be where you have an encrypted file that 2039 * you're willing to decrypt on-demand, but where you want to avoid 2040 * persisting the cleartext version. 2041 * 2042 * @param mode The desired access mode, must be one of 2043 * {@link ParcelFileDescriptor#MODE_READ_ONLY}, 2044 * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or 2045 * {@link ParcelFileDescriptor#MODE_READ_WRITE} 2046 * @param callback Callback to process file operation requests issued on 2047 * returned file descriptor. 2048 * @param handler Handler that invokes callback methods. 2049 * @return Seekable ParcelFileDescriptor. 2050 * @throws IOException 2051 */ openProxyFileDescriptor( int mode, ProxyFileDescriptorCallback callback, Handler handler)2052 public @NonNull ParcelFileDescriptor openProxyFileDescriptor( 2053 int mode, ProxyFileDescriptorCallback callback, Handler handler) 2054 throws IOException { 2055 Preconditions.checkNotNull(handler); 2056 return openProxyFileDescriptor(mode, callback, handler, null); 2057 } 2058 2059 /** {@hide} */ 2060 @VisibleForTesting getProxyFileDescriptorMountPointId()2061 public int getProxyFileDescriptorMountPointId() { 2062 synchronized (mFuseAppLoopLock) { 2063 return mFuseAppLoop != null ? mFuseAppLoop.getMountPointId() : -1; 2064 } 2065 } 2066 2067 /** 2068 * Return quota size in bytes for all cached data belonging to the calling 2069 * app on the given storage volume. 2070 * <p> 2071 * If your app goes above this quota, your cached files will be some of the 2072 * first to be deleted when additional disk space is needed. Conversely, if 2073 * your app stays under this quota, your cached files will be some of the 2074 * last to be deleted when additional disk space is needed. 2075 * <p> 2076 * This quota will change over time depending on how frequently the user 2077 * interacts with your app, and depending on how much system-wide disk space 2078 * is used. 2079 * <p class="note"> 2080 * Note: if your app uses the {@code android:sharedUserId} manifest feature, 2081 * then cached data for all packages in your shared UID is tracked together 2082 * as a single unit. 2083 * </p> 2084 * 2085 * @param storageUuid the UUID of the storage volume that you're interested 2086 * in. The UUID for a specific path can be obtained using 2087 * {@link #getUuidForPath(File)}. 2088 * @throws IOException when the storage device isn't present, or when it 2089 * doesn't support cache quotas. 2090 * @see #getCacheSizeBytes(UUID) 2091 */ 2092 @WorkerThread getCacheQuotaBytes(@onNull UUID storageUuid)2093 public @BytesLong long getCacheQuotaBytes(@NonNull UUID storageUuid) throws IOException { 2094 try { 2095 final ApplicationInfo app = mContext.getApplicationInfo(); 2096 return mStorageManager.getCacheQuotaBytes(convert(storageUuid), app.uid); 2097 } catch (ParcelableException e) { 2098 e.maybeRethrow(IOException.class); 2099 throw new RuntimeException(e); 2100 } catch (RemoteException e) { 2101 throw e.rethrowFromSystemServer(); 2102 } 2103 } 2104 2105 /** 2106 * Return total size in bytes of all cached data belonging to the calling 2107 * app on the given storage volume. 2108 * <p> 2109 * Cached data tracked by this method always includes 2110 * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}, and 2111 * it also includes {@link Context#getExternalCacheDir()} if the primary 2112 * shared/external storage is hosted on the same storage device as your 2113 * private data. 2114 * <p class="note"> 2115 * Note: if your app uses the {@code android:sharedUserId} manifest feature, 2116 * then cached data for all packages in your shared UID is tracked together 2117 * as a single unit. 2118 * </p> 2119 * 2120 * @param storageUuid the UUID of the storage volume that you're interested 2121 * in. The UUID for a specific path can be obtained using 2122 * {@link #getUuidForPath(File)}. 2123 * @throws IOException when the storage device isn't present, or when it 2124 * doesn't support cache quotas. 2125 * @see #getCacheQuotaBytes(UUID) 2126 */ 2127 @WorkerThread getCacheSizeBytes(@onNull UUID storageUuid)2128 public @BytesLong long getCacheSizeBytes(@NonNull UUID storageUuid) throws IOException { 2129 try { 2130 final ApplicationInfo app = mContext.getApplicationInfo(); 2131 return mStorageManager.getCacheSizeBytes(convert(storageUuid), app.uid); 2132 } catch (ParcelableException e) { 2133 e.maybeRethrow(IOException.class); 2134 throw new RuntimeException(e); 2135 } catch (RemoteException e) { 2136 throw e.rethrowFromSystemServer(); 2137 } 2138 } 2139 2140 2141 /** @hide */ 2142 @IntDef(prefix = { "MOUNT_MODE_" }, value = { 2143 MOUNT_MODE_EXTERNAL_NONE, 2144 MOUNT_MODE_EXTERNAL_DEFAULT, 2145 MOUNT_MODE_EXTERNAL_INSTALLER, 2146 MOUNT_MODE_EXTERNAL_PASS_THROUGH, 2147 MOUNT_MODE_EXTERNAL_ANDROID_WRITABLE 2148 }) 2149 /** @hide */ 2150 public @interface MountMode {} 2151 2152 /** 2153 * No external storage should be mounted. 2154 * @hide 2155 */ 2156 @SystemApi 2157 public static final int MOUNT_MODE_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE; 2158 /** 2159 * Default external storage should be mounted. 2160 * @hide 2161 */ 2162 @SystemApi 2163 public static final int MOUNT_MODE_EXTERNAL_DEFAULT = IVold.REMOUNT_MODE_DEFAULT; 2164 /** 2165 * Mount mode for package installers which should give them access to 2166 * all obb dirs in addition to their package sandboxes 2167 * @hide 2168 */ 2169 @SystemApi 2170 public static final int MOUNT_MODE_EXTERNAL_INSTALLER = IVold.REMOUNT_MODE_INSTALLER; 2171 /** 2172 * The lower file system should be bind mounted directly on external storage 2173 * @hide 2174 */ 2175 @SystemApi 2176 public static final int MOUNT_MODE_EXTERNAL_PASS_THROUGH = IVold.REMOUNT_MODE_PASS_THROUGH; 2177 2178 /** 2179 * Use the regular scoped storage filesystem, but Android/ should be writable. 2180 * Used to support the applications hosting DownloadManager and the MTP server. 2181 * @hide 2182 */ 2183 @SystemApi 2184 public static final int MOUNT_MODE_EXTERNAL_ANDROID_WRITABLE = 2185 IVold.REMOUNT_MODE_ANDROID_WRITABLE; 2186 /** 2187 * Flag indicating that a disk space allocation request should operate in an 2188 * aggressive mode. This flag should only be rarely used in situations that 2189 * are critical to system health or security. 2190 * <p> 2191 * When set, the system is more aggressive about the data that it considers 2192 * for possible deletion when allocating disk space. 2193 * <p class="note"> 2194 * Note: your app must hold the 2195 * {@link android.Manifest.permission#ALLOCATE_AGGRESSIVE} permission for 2196 * this flag to take effect. 2197 * </p> 2198 * 2199 * @see #getAllocatableBytes(UUID, int) 2200 * @see #allocateBytes(UUID, long, int) 2201 * @see #allocateBytes(FileDescriptor, long, int) 2202 * @hide 2203 */ 2204 @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) 2205 @SystemApi 2206 public static final int FLAG_ALLOCATE_AGGRESSIVE = 1 << 0; 2207 2208 /** 2209 * Flag indicating that a disk space allocation request should be allowed to 2210 * clear up to all reserved disk space. 2211 * 2212 * @hide 2213 */ 2214 public static final int FLAG_ALLOCATE_DEFY_ALL_RESERVED = 1 << 1; 2215 2216 /** 2217 * Flag indicating that a disk space allocation request should be allowed to 2218 * clear up to half of all reserved disk space. 2219 * 2220 * @hide 2221 */ 2222 public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2; 2223 2224 /** 2225 * Flag indicating that a disk space check should not take into account 2226 * freeable cached space when determining allocatable space. 2227 * 2228 * Intended for use with {@link #getAllocatableBytes()}. 2229 * @hide 2230 */ 2231 public static final int FLAG_ALLOCATE_NON_CACHE_ONLY = 1 << 3; 2232 2233 /** 2234 * Flag indicating that a disk space check should only return freeable 2235 * cached space when determining allocatable space. 2236 * 2237 * Intended for use with {@link #getAllocatableBytes()}. 2238 * @hide 2239 */ 2240 public static final int FLAG_ALLOCATE_CACHE_ONLY = 1 << 4; 2241 2242 /** @hide */ 2243 @IntDef(flag = true, prefix = { "FLAG_ALLOCATE_" }, value = { 2244 FLAG_ALLOCATE_AGGRESSIVE, 2245 FLAG_ALLOCATE_DEFY_ALL_RESERVED, 2246 FLAG_ALLOCATE_DEFY_HALF_RESERVED, 2247 FLAG_ALLOCATE_NON_CACHE_ONLY, 2248 FLAG_ALLOCATE_CACHE_ONLY, 2249 }) 2250 @Retention(RetentionPolicy.SOURCE) 2251 public @interface AllocateFlags {} 2252 2253 /** 2254 * Return the maximum number of new bytes that your app can allocate for 2255 * itself on the given storage volume. This value is typically larger than 2256 * {@link File#getUsableSpace()}, since the system may be willing to delete 2257 * cached files to satisfy an allocation request. You can then allocate 2258 * space for yourself using {@link #allocateBytes(UUID, long)} or 2259 * {@link #allocateBytes(FileDescriptor, long)}. 2260 * <p> 2261 * This method is best used as a pre-flight check, such as deciding if there 2262 * is enough space to store an entire music album before you allocate space 2263 * for each audio file in the album. Attempts to allocate disk space beyond 2264 * the returned value will fail. 2265 * <p> 2266 * If the returned value is not large enough for the data you'd like to 2267 * persist, you can launch {@link #ACTION_MANAGE_STORAGE} with the 2268 * {@link #EXTRA_UUID} and {@link #EXTRA_REQUESTED_BYTES} options to help 2269 * involve the user in freeing up disk space. 2270 * <p> 2271 * If you're progressively allocating an unbounded amount of storage space 2272 * (such as when recording a video) you should avoid calling this method 2273 * more than once every 30 seconds. 2274 * <p class="note"> 2275 * Note: if your app uses the {@code android:sharedUserId} manifest feature, 2276 * then allocatable space for all packages in your shared UID is tracked 2277 * together as a single unit. 2278 * </p> 2279 * 2280 * @param storageUuid the UUID of the storage volume where you're 2281 * considering allocating disk space, since allocatable space can 2282 * vary widely depending on the underlying storage device. The 2283 * UUID for a specific path can be obtained using 2284 * {@link #getUuidForPath(File)}. 2285 * @return the maximum number of new bytes that the calling app can allocate 2286 * using {@link #allocateBytes(UUID, long)} or 2287 * {@link #allocateBytes(FileDescriptor, long)}. 2288 * @throws IOException when the storage device isn't present, or when it 2289 * doesn't support allocating space. 2290 */ 2291 @WorkerThread getAllocatableBytes(@onNull UUID storageUuid)2292 public @BytesLong long getAllocatableBytes(@NonNull UUID storageUuid) 2293 throws IOException { 2294 return getAllocatableBytes(storageUuid, 0); 2295 } 2296 2297 /** @hide */ 2298 @SystemApi 2299 @WorkerThread 2300 @SuppressLint("RequiresPermission") getAllocatableBytes(@onNull UUID storageUuid, @RequiresPermission @AllocateFlags int flags)2301 public long getAllocatableBytes(@NonNull UUID storageUuid, 2302 @RequiresPermission @AllocateFlags int flags) throws IOException { 2303 try { 2304 return mStorageManager.getAllocatableBytes(convert(storageUuid), flags, 2305 mContext.getOpPackageName()); 2306 } catch (ParcelableException e) { 2307 e.maybeRethrow(IOException.class); 2308 throw new RuntimeException(e); 2309 } catch (RemoteException e) { 2310 throw e.rethrowFromSystemServer(); 2311 } 2312 } 2313 2314 /** 2315 * Allocate the requested number of bytes for your application to use on the 2316 * given storage volume. This will cause the system to delete any cached 2317 * files necessary to satisfy your request. 2318 * <p> 2319 * Attempts to allocate disk space beyond the value returned by 2320 * {@link #getAllocatableBytes(UUID)} will fail. 2321 * <p> 2322 * Since multiple apps can be running simultaneously, this method may be 2323 * subject to race conditions. If possible, consider using 2324 * {@link #allocateBytes(FileDescriptor, long)} which will guarantee 2325 * that bytes are allocated to an opened file. 2326 * <p> 2327 * If you're progressively allocating an unbounded amount of storage space 2328 * (such as when recording a video) you should avoid calling this method 2329 * more than once every 60 seconds. 2330 * 2331 * @param storageUuid the UUID of the storage volume where you'd like to 2332 * allocate disk space. The UUID for a specific path can be 2333 * obtained using {@link #getUuidForPath(File)}. 2334 * @param bytes the number of bytes to allocate. 2335 * @throws IOException when the storage device isn't present, or when it 2336 * doesn't support allocating space, or if the device had 2337 * trouble allocating the requested space. 2338 * @see #getAllocatableBytes(UUID) 2339 */ 2340 @WorkerThread allocateBytes(@onNull UUID storageUuid, @BytesLong long bytes)2341 public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes) 2342 throws IOException { 2343 allocateBytes(storageUuid, bytes, 0); 2344 } 2345 2346 /** @hide */ 2347 @SystemApi 2348 @WorkerThread 2349 @SuppressLint("RequiresPermission") allocateBytes(@onNull UUID storageUuid, @BytesLong long bytes, @RequiresPermission @AllocateFlags int flags)2350 public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes, 2351 @RequiresPermission @AllocateFlags int flags) throws IOException { 2352 try { 2353 mStorageManager.allocateBytes(convert(storageUuid), bytes, flags, 2354 mContext.getOpPackageName()); 2355 } catch (ParcelableException e) { 2356 e.maybeRethrow(IOException.class); 2357 } catch (RemoteException e) { 2358 throw e.rethrowFromSystemServer(); 2359 } 2360 } 2361 2362 /** 2363 * Returns the External Storage mount mode corresponding to the given uid and packageName. 2364 * These mount modes specify different views and access levels for 2365 * different apps on external storage. 2366 * 2367 * @params uid UID of the application 2368 * @params packageName name of the package 2369 * @return {@code MountMode} for the given uid and packageName. 2370 * 2371 * @hide 2372 */ 2373 @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) 2374 @SystemApi 2375 @MountMode getExternalStorageMountMode(int uid, @NonNull String packageName)2376 public int getExternalStorageMountMode(int uid, @NonNull String packageName) { 2377 try { 2378 return mStorageManager.getExternalStorageMountMode(uid, packageName); 2379 } catch (RemoteException e) { 2380 throw e.rethrowFromSystemServer(); 2381 } 2382 } 2383 2384 /** 2385 * Allocate the requested number of bytes for your application to use in the 2386 * given open file. This will cause the system to delete any cached files 2387 * necessary to satisfy your request. 2388 * <p> 2389 * Attempts to allocate disk space beyond the value returned by 2390 * {@link #getAllocatableBytes(UUID)} will fail. 2391 * <p> 2392 * This method guarantees that bytes have been allocated to the opened file, 2393 * otherwise it will throw if fast allocation is not possible. Fast 2394 * allocation is typically only supported in private app data directories, 2395 * and on shared/external storage devices which are emulated. 2396 * <p> 2397 * If you're progressively allocating an unbounded amount of storage space 2398 * (such as when recording a video) you should avoid calling this method 2399 * more than once every 60 seconds. 2400 * 2401 * @param fd the open file that you'd like to allocate disk space for. 2402 * @param bytes the number of bytes to allocate. This is the desired final 2403 * size of the open file. If the open file is smaller than this 2404 * requested size, it will be extended without modifying any 2405 * existing contents. If the open file is larger than this 2406 * requested size, it will be truncated. 2407 * @throws IOException when the storage device isn't present, or when it 2408 * doesn't support allocating space, or if the device had 2409 * trouble allocating the requested space. 2410 * @see #isAllocationSupported(FileDescriptor) 2411 * @see Environment#isExternalStorageEmulated(File) 2412 */ 2413 @WorkerThread allocateBytes(FileDescriptor fd, @BytesLong long bytes)2414 public void allocateBytes(FileDescriptor fd, @BytesLong long bytes) throws IOException { 2415 allocateBytes(fd, bytes, 0); 2416 } 2417 2418 /** @hide */ 2419 @SystemApi 2420 @WorkerThread 2421 @SuppressLint("RequiresPermission") allocateBytes(FileDescriptor fd, @BytesLong long bytes, @RequiresPermission @AllocateFlags int flags)2422 public void allocateBytes(FileDescriptor fd, @BytesLong long bytes, 2423 @RequiresPermission @AllocateFlags int flags) throws IOException { 2424 final File file = ParcelFileDescriptor.getFile(fd); 2425 final UUID uuid = getUuidForPath(file); 2426 for (int i = 0; i < 3; i++) { 2427 try { 2428 final long haveBytes = Os.fstat(fd).st_blocks * 512; 2429 final long needBytes = bytes - haveBytes; 2430 2431 if (needBytes > 0) { 2432 allocateBytes(uuid, needBytes, flags); 2433 } 2434 2435 try { 2436 Os.posix_fallocate(fd, 0, bytes); 2437 return; 2438 } catch (ErrnoException e) { 2439 if (e.errno == OsConstants.ENOSYS || e.errno == OsConstants.ENOTSUP) { 2440 Log.w(TAG, "fallocate() not supported; falling back to ftruncate()"); 2441 Os.ftruncate(fd, bytes); 2442 return; 2443 } else { 2444 throw e; 2445 } 2446 } 2447 } catch (ErrnoException e) { 2448 if (e.errno == OsConstants.ENOSPC) { 2449 Log.w(TAG, "Odd, not enough space; let's try again?"); 2450 continue; 2451 } 2452 throw e.rethrowAsIOException(); 2453 } 2454 } 2455 throw new IOException( 2456 "Well this is embarassing; we can't allocate " + bytes + " for " + file); 2457 } 2458 2459 private static final String XATTR_CACHE_GROUP = "user.cache_group"; 2460 private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone"; 2461 2462 2463 // Project IDs below must match android_projectid_config.h 2464 /** 2465 * Default project ID for files on external storage 2466 * 2467 * {@hide} 2468 */ 2469 public static final int PROJECT_ID_EXT_DEFAULT = 1000; 2470 2471 /** 2472 * project ID for audio files on external storage 2473 * 2474 * {@hide} 2475 */ 2476 public static final int PROJECT_ID_EXT_MEDIA_AUDIO = 1001; 2477 2478 /** 2479 * project ID for video files on external storage 2480 * 2481 * {@hide} 2482 */ 2483 public static final int PROJECT_ID_EXT_MEDIA_VIDEO = 1002; 2484 2485 /** 2486 * project ID for image files on external storage 2487 * 2488 * {@hide} 2489 */ 2490 public static final int PROJECT_ID_EXT_MEDIA_IMAGE = 1003; 2491 2492 /** 2493 * Constant for use with 2494 * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file 2495 * is not a media file. 2496 * 2497 * @hide 2498 */ 2499 @SystemApi 2500 public static final int QUOTA_TYPE_MEDIA_NONE = 0; 2501 2502 /** 2503 * Constant for use with 2504 * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file 2505 * is an image file. 2506 * 2507 * @hide 2508 */ 2509 @SystemApi 2510 public static final int QUOTA_TYPE_MEDIA_IMAGE = 1; 2511 2512 /** 2513 * Constant for use with 2514 * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file 2515 * is an audio file. 2516 * 2517 * @hide 2518 */ 2519 @SystemApi 2520 public static final int QUOTA_TYPE_MEDIA_AUDIO = 2; 2521 2522 /** 2523 * Constant for use with 2524 * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file 2525 * is a video file. 2526 * 2527 * @hide 2528 */ 2529 @SystemApi 2530 public static final int QUOTA_TYPE_MEDIA_VIDEO = 3; 2531 2532 /** @hide */ 2533 @Retention(RetentionPolicy.SOURCE) 2534 @IntDef(prefix = { "QUOTA_TYPE_" }, value = { 2535 QUOTA_TYPE_MEDIA_NONE, 2536 QUOTA_TYPE_MEDIA_AUDIO, 2537 QUOTA_TYPE_MEDIA_VIDEO, 2538 QUOTA_TYPE_MEDIA_IMAGE, 2539 }) 2540 public @interface QuotaType {} 2541 setQuotaProjectId(String path, long projectId)2542 private static native boolean setQuotaProjectId(String path, long projectId); 2543 getProjectIdForUser(int userId, int projectId)2544 private static long getProjectIdForUser(int userId, int projectId) { 2545 // Much like UserHandle.getUid(), store the user ID in the upper bits 2546 return userId * PER_USER_RANGE + projectId; 2547 } 2548 2549 /** 2550 * Let StorageManager know that the quota type for a file on external storage should 2551 * be updated. Android tracks quotas for various media types. Consequently, this should be 2552 * called on first creation of a new file on external storage, and whenever the 2553 * media type of the file is updated later. 2554 * 2555 * This API doesn't require any special permissions, though typical implementations 2556 * will require being called from an SELinux domain that allows setting file attributes 2557 * related to quota (eg the GID or project ID). 2558 * If the calling user has MANAGE_EXTERNAL_STORAGE permissions, quota for shared profile's 2559 * volumes is also updated. 2560 * 2561 * The default platform user of this API is the MediaProvider process, which is 2562 * responsible for managing all of external storage. 2563 * 2564 * @param path the path to the file for which we should update the quota type 2565 * @param quotaType the quota type of the file; this is based on the 2566 * {@code QuotaType} constants, eg 2567 * {@code StorageManager.QUOTA_TYPE_MEDIA_AUDIO} 2568 * 2569 * @throws IllegalArgumentException if {@code quotaType} does not correspond to a valid 2570 * quota type. 2571 * @throws IOException if the quota type could not be updated. 2572 * 2573 * @hide 2574 */ 2575 @SystemApi updateExternalStorageFileQuotaType(@onNull File path, @QuotaType int quotaType)2576 public void updateExternalStorageFileQuotaType(@NonNull File path, 2577 @QuotaType int quotaType) throws IOException { 2578 long projectId; 2579 final String filePath = path.getCanonicalPath(); 2580 int volFlags = FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE; 2581 // If caller has MANAGE_EXTERNAL_STORAGE permission, results from User Profile(s) are also 2582 // returned by enabling FLAG_INCLUDE_SHARED_PROFILE. 2583 if (mContext.checkSelfPermission(MANAGE_EXTERNAL_STORAGE) == PERMISSION_GRANTED) { 2584 volFlags |= FLAG_INCLUDE_SHARED_PROFILE; 2585 } 2586 final StorageVolume[] availableVolumes = getVolumeList(mContext.getUserId(), volFlags); 2587 final StorageVolume volume = getStorageVolume(availableVolumes, path); 2588 if (volume == null) { 2589 Log.w(TAG, "Failed to update quota type for " + filePath); 2590 return; 2591 } 2592 if (!volume.isEmulated()) { 2593 // We only support quota tracking on emulated filesystems 2594 return; 2595 } 2596 2597 final int userId = volume.getOwner().getIdentifier(); 2598 if (userId < 0) { 2599 throw new IllegalStateException("Failed to update quota type for " + filePath); 2600 } 2601 switch (quotaType) { 2602 case QUOTA_TYPE_MEDIA_NONE: 2603 projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_DEFAULT); 2604 break; 2605 case QUOTA_TYPE_MEDIA_AUDIO: 2606 projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_AUDIO); 2607 break; 2608 case QUOTA_TYPE_MEDIA_VIDEO: 2609 projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_VIDEO); 2610 break; 2611 case QUOTA_TYPE_MEDIA_IMAGE: 2612 projectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_IMAGE); 2613 break; 2614 default: 2615 throw new IllegalArgumentException("Invalid quota type: " + quotaType); 2616 } 2617 if (!setQuotaProjectId(filePath, projectId)) { 2618 throw new IOException("Failed to update quota type for " + filePath); 2619 } 2620 } 2621 2622 /** 2623 * Asks StorageManager to fixup the permissions of an application-private directory. 2624 * 2625 * On devices without sdcardfs, filesystem permissions aren't magically fixed up. This 2626 * is problematic mostly in application-private directories, which are owned by the 2627 * application itself; if another process with elevated permissions creates a file 2628 * in these directories, the UID will be wrong, and the owning package won't be able 2629 * to access the files. 2630 * 2631 * This API can be used to recursively fix up the permissions on the passed in path. 2632 * The default platform user of this API is the DownloadProvider, which can download 2633 * things in application-private directories on their behalf. 2634 * 2635 * This API doesn't require any special permissions, because it merely changes the 2636 * permissions of a directory to what they should anyway be. 2637 * 2638 * @param path the path for which we should fix up the permissions 2639 * 2640 * @hide 2641 */ fixupAppDir(@onNull File path)2642 public void fixupAppDir(@NonNull File path) { 2643 try { 2644 mStorageManager.fixupAppDir(path.getCanonicalPath()); 2645 } catch (IOException e) { 2646 Log.e(TAG, "Failed to get canonical path for " + path.getPath(), e); 2647 } catch (RemoteException e) { 2648 throw e.rethrowFromSystemServer(); 2649 } 2650 } 2651 2652 /** {@hide} */ setCacheBehavior(File path, String name, boolean enabled)2653 private static void setCacheBehavior(File path, String name, boolean enabled) 2654 throws IOException { 2655 if (!path.isDirectory()) { 2656 throw new IOException("Cache behavior can only be set on directories"); 2657 } 2658 if (enabled) { 2659 try { 2660 Os.setxattr(path.getAbsolutePath(), name, 2661 "1".getBytes(StandardCharsets.UTF_8), 0); 2662 } catch (ErrnoException e) { 2663 throw e.rethrowAsIOException(); 2664 } 2665 } else { 2666 try { 2667 Os.removexattr(path.getAbsolutePath(), name); 2668 } catch (ErrnoException e) { 2669 if (e.errno != OsConstants.ENODATA) { 2670 throw e.rethrowAsIOException(); 2671 } 2672 } 2673 } 2674 } 2675 2676 /** {@hide} */ isCacheBehavior(File path, String name)2677 private static boolean isCacheBehavior(File path, String name) throws IOException { 2678 try { 2679 Os.getxattr(path.getAbsolutePath(), name); 2680 return true; 2681 } catch (ErrnoException e) { 2682 if (e.errno != OsConstants.ENODATA) { 2683 throw e.rethrowAsIOException(); 2684 } else { 2685 return false; 2686 } 2687 } 2688 } 2689 2690 /** 2691 * Enable or disable special cache behavior that treats this directory and 2692 * its contents as an entire group. 2693 * <p> 2694 * When enabled and this directory is considered for automatic deletion by 2695 * the OS, all contained files will either be deleted together, or not at 2696 * all. This is useful when you have a directory that contains several 2697 * related metadata files that depend on each other, such as movie file and 2698 * a subtitle file. 2699 * <p> 2700 * When enabled, the <em>newest</em> {@link File#lastModified()} value of 2701 * any contained files is considered the modified time of the entire 2702 * directory. 2703 * <p> 2704 * This behavior can only be set on a directory, and it applies recursively 2705 * to all contained files and directories. 2706 */ setCacheBehaviorGroup(File path, boolean group)2707 public void setCacheBehaviorGroup(File path, boolean group) throws IOException { 2708 setCacheBehavior(path, XATTR_CACHE_GROUP, group); 2709 } 2710 2711 /** 2712 * Read the current value set by 2713 * {@link #setCacheBehaviorGroup(File, boolean)}. 2714 */ isCacheBehaviorGroup(File path)2715 public boolean isCacheBehaviorGroup(File path) throws IOException { 2716 return isCacheBehavior(path, XATTR_CACHE_GROUP); 2717 } 2718 2719 /** 2720 * Enable or disable special cache behavior that leaves deleted cache files 2721 * intact as tombstones. 2722 * <p> 2723 * When enabled and a file contained in this directory is automatically 2724 * deleted by the OS, the file will be truncated to have a length of 0 bytes 2725 * instead of being fully deleted. This is useful if you need to distinguish 2726 * between a file that was deleted versus one that never existed. 2727 * <p> 2728 * This behavior can only be set on a directory, and it applies recursively 2729 * to all contained files and directories. 2730 * <p class="note"> 2731 * Note: this behavior is ignored completely if the user explicitly requests 2732 * that all cached data be cleared. 2733 * </p> 2734 */ setCacheBehaviorTombstone(File path, boolean tombstone)2735 public void setCacheBehaviorTombstone(File path, boolean tombstone) throws IOException { 2736 setCacheBehavior(path, XATTR_CACHE_TOMBSTONE, tombstone); 2737 } 2738 2739 /** 2740 * Read the current value set by 2741 * {@link #setCacheBehaviorTombstone(File, boolean)}. 2742 */ isCacheBehaviorTombstone(File path)2743 public boolean isCacheBehaviorTombstone(File path) throws IOException { 2744 return isCacheBehavior(path, XATTR_CACHE_TOMBSTONE); 2745 } 2746 2747 /** 2748 * Returns true if {@code uuid} is a FAT volume identifier. FAT Volume identifiers 2749 * are 32 randomly generated bits that are represented in string form as AAAA-AAAA. 2750 */ isFatVolumeIdentifier(String uuid)2751 private static boolean isFatVolumeIdentifier(String uuid) { 2752 return uuid.length() == 9 && uuid.charAt(4) == '-'; 2753 } 2754 2755 /** {@hide} */ 2756 @TestApi convert(@onNull String uuid)2757 public static @NonNull UUID convert(@NonNull String uuid) { 2758 if (Objects.equals(uuid, UUID_PRIVATE_INTERNAL)) { 2759 return UUID_DEFAULT; 2760 } else if (Objects.equals(uuid, UUID_PRIMARY_PHYSICAL)) { 2761 return UUID_PRIMARY_PHYSICAL_; 2762 } else if (Objects.equals(uuid, UUID_SYSTEM)) { 2763 return UUID_SYSTEM_; 2764 } else if (isFatVolumeIdentifier(uuid)) { 2765 // FAT volume identifiers are not UUIDs but we need to coerce them into 2766 // UUIDs in order to satisfy apis that take java.util.UUID arguments. 2767 // 2768 // We coerce a 32 bit fat volume identifier of the form XXXX-YYYY into 2769 // a UUID of form "fafafafa-fafa-5afa-8afa-fafaXXXXYYYY". This is an 2770 // RFC-422 UUID with Version 5, which is a namespaced UUID. The UUIDs we 2771 // coerce into are not true namespace UUIDs; although FAT storage volume 2772 // identifiers are unique names within a fixed namespace, this UUID is not 2773 // based on an SHA-1 hash of the name. We avoid the SHA-1 hash because 2774 // (a) we need this transform to be reversible (b) it's pointless to generate 2775 // a 128 bit hash from a 32 bit value. 2776 return UUID.fromString(FAT_UUID_PREFIX + uuid.replace("-", "")); 2777 } else { 2778 return UUID.fromString(uuid); 2779 } 2780 } 2781 2782 /** {@hide} */ 2783 @TestApi convert(@onNull UUID storageUuid)2784 public static @NonNull String convert(@NonNull UUID storageUuid) { 2785 if (UUID_DEFAULT.equals(storageUuid)) { 2786 return UUID_PRIVATE_INTERNAL; 2787 } else if (UUID_PRIMARY_PHYSICAL_.equals(storageUuid)) { 2788 return UUID_PRIMARY_PHYSICAL; 2789 } else if (UUID_SYSTEM_.equals(storageUuid)) { 2790 return UUID_SYSTEM; 2791 } else { 2792 String uuidString = storageUuid.toString(); 2793 // This prefix match will exclude fsUuids from private volumes because 2794 // (a) linux fsUuids are generally Version 4 (random) UUIDs so the prefix 2795 // will contain 4xxx instead of 5xxx and (b) we've already matched against 2796 // known namespace (Version 5) UUIDs above. 2797 if (uuidString.startsWith(FAT_UUID_PREFIX)) { 2798 String fatStr = uuidString.substring(FAT_UUID_PREFIX.length()) 2799 .toUpperCase(Locale.US); 2800 return fatStr.substring(0, 4) + "-" + fatStr.substring(4); 2801 } 2802 2803 return storageUuid.toString(); 2804 } 2805 } 2806 2807 /** 2808 * Check whether the device supports filesystem checkpoint. 2809 * 2810 * @return true if the device supports filesystem checkpoint, false otherwise. 2811 */ isCheckpointSupported()2812 public boolean isCheckpointSupported() { 2813 try { 2814 return mStorageManager.supportsCheckpoint(); 2815 } catch (RemoteException e) { 2816 throw e.rethrowFromSystemServer(); 2817 } 2818 } 2819 2820 /** 2821 * Reason to provide if app IO is blocked/resumed for unknown reasons 2822 * 2823 * @hide 2824 */ 2825 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 2826 public static final int APP_IO_BLOCKED_REASON_UNKNOWN = 0; 2827 2828 /** 2829 * Reason to provide if app IO is blocked/resumed because of transcoding 2830 * 2831 * @hide 2832 */ 2833 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 2834 public static final int APP_IO_BLOCKED_REASON_TRANSCODING = 1; 2835 2836 /** 2837 * Constants for use with 2838 * {@link #notifyAppIoBlocked} and {@link notifyAppIoResumed}, to specify the reason an app's 2839 * IO is blocked/resumed. 2840 * 2841 * @hide 2842 */ 2843 @Retention(RetentionPolicy.SOURCE) 2844 @IntDef(prefix = { "APP_IO_BLOCKED_REASON_" }, value = { 2845 APP_IO_BLOCKED_REASON_TRANSCODING, 2846 APP_IO_BLOCKED_REASON_UNKNOWN, 2847 }) 2848 public @interface AppIoBlockedReason {} 2849 2850 /** 2851 * Notify the system that an app with {@code uid} and {@code tid} is blocked on an IO request on 2852 * {@code volumeUuid} for {@code reason}. 2853 * 2854 * This blocked state can be used to modify the ANR behavior for the app while it's blocked. 2855 * For example during transcoding. 2856 * 2857 * This can only be called by the {@link ExternalStorageService} holding the 2858 * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission. 2859 * 2860 * @param volumeUuid the UUID of the storage volume that the app IO is blocked on 2861 * @param uid the UID of the app blocked on IO 2862 * @param tid the tid of the app blocked on IO 2863 * @param reason the reason the app is blocked on IO 2864 * 2865 * @hide 2866 */ 2867 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) notifyAppIoBlocked(@onNull UUID volumeUuid, int uid, int tid, @AppIoBlockedReason int reason)2868 public void notifyAppIoBlocked(@NonNull UUID volumeUuid, int uid, int tid, 2869 @AppIoBlockedReason int reason) { 2870 Objects.requireNonNull(volumeUuid); 2871 try { 2872 mStorageManager.notifyAppIoBlocked(convert(volumeUuid), uid, tid, reason); 2873 } catch (RemoteException e) { 2874 throw e.rethrowFromSystemServer(); 2875 } 2876 } 2877 2878 /** 2879 * Notify the system that an app with {@code uid} and {@code tid} has resmued a previously 2880 * blocked IO request on {@code volumeUuid} for {@code reason}. 2881 * 2882 * All app IO will be automatically marked as unblocked if {@code volumeUuid} is unmounted. 2883 * 2884 * This can only be called by the {@link ExternalStorageService} holding the 2885 * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission. 2886 * 2887 * @param volumeUuid the UUID of the storage volume that the app IO is resumed on 2888 * @param uid the UID of the app resuming IO 2889 * @param tid the tid of the app resuming IO 2890 * @param reason the reason the app is resuming IO 2891 * 2892 * @hide 2893 */ 2894 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) notifyAppIoResumed(@onNull UUID volumeUuid, int uid, int tid, @AppIoBlockedReason int reason)2895 public void notifyAppIoResumed(@NonNull UUID volumeUuid, int uid, int tid, 2896 @AppIoBlockedReason int reason) { 2897 Objects.requireNonNull(volumeUuid); 2898 try { 2899 mStorageManager.notifyAppIoResumed(convert(volumeUuid), uid, tid, reason); 2900 } catch (RemoteException e) { 2901 throw e.rethrowFromSystemServer(); 2902 } 2903 } 2904 2905 /** 2906 * Check if {@code uid} with {@code tid} is blocked on IO for {@code reason}. 2907 * 2908 * This requires {@link ExternalStorageService} the 2909 * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission. 2910 * 2911 * @param volumeUuid the UUID of the storage volume to check IO blocked status 2912 * @param uid the UID of the app to check IO blocked status 2913 * @param tid the tid of the app to check IO blocked status 2914 * @param reason the reason to check IO blocked status for 2915 * 2916 * @hide 2917 */ 2918 @TestApi isAppIoBlocked(@onNull UUID volumeUuid, int uid, int tid, @AppIoBlockedReason int reason)2919 public boolean isAppIoBlocked(@NonNull UUID volumeUuid, int uid, int tid, 2920 @AppIoBlockedReason int reason) { 2921 Objects.requireNonNull(volumeUuid); 2922 try { 2923 return mStorageManager.isAppIoBlocked(convert(volumeUuid), uid, tid, reason); 2924 } catch (RemoteException e) { 2925 throw e.rethrowFromSystemServer(); 2926 } 2927 } 2928 2929 /** 2930 * Notify the system of the current cloud media provider. 2931 * 2932 * This can only be called by the {@link android.service.storage.ExternalStorageService} 2933 * holding the {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission. 2934 * 2935 * @param authority the authority of the content provider 2936 * @hide 2937 */ 2938 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) setCloudMediaProvider(@ullable String authority)2939 public void setCloudMediaProvider(@Nullable String authority) { 2940 try { 2941 mStorageManager.setCloudMediaProvider(authority); 2942 } catch (RemoteException e) { 2943 throw e.rethrowFromSystemServer(); 2944 } 2945 } 2946 2947 /** 2948 * Returns the authority of the current cloud media provider that was set by the 2949 * {@link android.service.storage.ExternalStorageService} holding the 2950 * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission via 2951 * {@link #setCloudMediaProvider(String)}. 2952 * 2953 * @hide 2954 */ 2955 @Nullable 2956 @TestApi 2957 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) getCloudMediaProvider()2958 public String getCloudMediaProvider() { 2959 try { 2960 return mStorageManager.getCloudMediaProvider(); 2961 } catch (RemoteException e) { 2962 throw e.rethrowFromSystemServer(); 2963 } 2964 } 2965 2966 private final Object mFuseAppLoopLock = new Object(); 2967 2968 @GuardedBy("mFuseAppLoopLock") 2969 private @Nullable FuseAppLoop mFuseAppLoop = null; 2970 2971 /** @hide */ 2972 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2973 public static final int CRYPT_TYPE_PASSWORD = 0; 2974 /** @hide */ 2975 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2976 public static final int CRYPT_TYPE_DEFAULT = 1; 2977 } 2978