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