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