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