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