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