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