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