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