StorageManager.java revision ce18c8167766f92856f94a8e88e19de4698960e6
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.MB_IN_BYTES; 20 21import android.annotation.NonNull; 22import android.annotation.Nullable; 23import android.app.ActivityThread; 24import android.content.ContentResolver; 25import android.content.Context; 26import android.content.pm.IPackageMoveObserver; 27import android.content.pm.PackageManager; 28import android.os.Binder; 29import android.os.Environment; 30import android.os.FileUtils; 31import android.os.Handler; 32import android.os.Looper; 33import android.os.Message; 34import android.os.ParcelFileDescriptor; 35import android.os.RemoteException; 36import android.os.ServiceManager; 37import android.os.SystemProperties; 38import android.os.UserHandle; 39import android.provider.Settings; 40import android.text.TextUtils; 41import android.util.Log; 42import android.util.Slog; 43import android.util.SparseArray; 44 45import com.android.internal.os.SomeArgs; 46import com.android.internal.util.Preconditions; 47 48import java.io.File; 49import java.io.IOException; 50import java.lang.ref.WeakReference; 51import java.util.ArrayList; 52import java.util.Arrays; 53import java.util.Collections; 54import java.util.Iterator; 55import java.util.List; 56import java.util.Objects; 57import java.util.concurrent.atomic.AtomicInteger; 58 59/** 60 * StorageManager is the interface to the systems storage service. The storage 61 * manager handles storage-related items such as Opaque Binary Blobs (OBBs). 62 * <p> 63 * OBBs contain a filesystem that maybe be encrypted on disk and mounted 64 * on-demand from an application. OBBs are a good way of providing large amounts 65 * of binary assets without packaging them into APKs as they may be multiple 66 * gigabytes in size. However, due to their size, they're most likely stored in 67 * a shared storage pool accessible from all programs. The system does not 68 * guarantee the security of the OBB file itself: if any program modifies the 69 * OBB, there is no guarantee that a read from that OBB will produce the 70 * expected output. 71 * <p> 72 * Get an instance of this class by calling 73 * {@link android.content.Context#getSystemService(java.lang.String)} with an 74 * argument of {@link android.content.Context#STORAGE_SERVICE}. 75 */ 76public class StorageManager { 77 private static final String TAG = "StorageManager"; 78 79 /** {@hide} */ 80 public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical"; 81 /** {@hide} */ 82 public static final String PROP_HAS_ADOPTABLE = "vold.has_adoptable"; 83 /** {@hide} */ 84 public static final String PROP_FORCE_ADOPTABLE = "persist.fw.force_adoptable"; 85 /** {@hide} */ 86 public static final String PROP_EMULATE_FBE = "persist.sys.emulate_fbe"; 87 /** {@hide} */ 88 public static final String PROP_SDCARDFS = "persist.sys.sdcardfs"; 89 90 /** {@hide} */ 91 public static final String UUID_PRIVATE_INTERNAL = null; 92 /** {@hide} */ 93 public static final String UUID_PRIMARY_PHYSICAL = "primary_physical"; 94 95 /** {@hide} */ 96 public static final int DEBUG_FORCE_ADOPTABLE = 1 << 0; 97 /** {@hide} */ 98 public static final int DEBUG_EMULATE_FBE = 1 << 1; 99 /** {@hide} */ 100 public static final int DEBUG_SDCARDFS_FORCE_ON = 1 << 2; 101 /** {@hide} */ 102 public static final int DEBUG_SDCARDFS_FORCE_OFF = 1 << 3; 103 104 // NOTE: keep in sync with installd 105 /** {@hide} */ 106 public static final int FLAG_STORAGE_DE = 1 << 0; 107 /** {@hide} */ 108 public static final int FLAG_STORAGE_CE = 1 << 1; 109 110 /** {@hide} */ 111 public static final int FLAG_FOR_WRITE = 1 << 8; 112 /** {@hide} */ 113 public static final int FLAG_REAL_STATE = 1 << 9; 114 /** {@hide} */ 115 public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10; 116 117 private final Context mContext; 118 private final ContentResolver mResolver; 119 120 private final IMountService mMountService; 121 private final Looper mLooper; 122 private final AtomicInteger mNextNonce = new AtomicInteger(0); 123 124 private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>(); 125 126 private static class StorageEventListenerDelegate extends IMountServiceListener.Stub implements 127 Handler.Callback { 128 private static final int MSG_STORAGE_STATE_CHANGED = 1; 129 private static final int MSG_VOLUME_STATE_CHANGED = 2; 130 private static final int MSG_VOLUME_RECORD_CHANGED = 3; 131 private static final int MSG_VOLUME_FORGOTTEN = 4; 132 private static final int MSG_DISK_SCANNED = 5; 133 private static final int MSG_DISK_DESTROYED = 6; 134 135 final StorageEventListener mCallback; 136 final Handler mHandler; 137 138 public StorageEventListenerDelegate(StorageEventListener callback, Looper looper) { 139 mCallback = callback; 140 mHandler = new Handler(looper, this); 141 } 142 143 @Override 144 public boolean handleMessage(Message msg) { 145 final SomeArgs args = (SomeArgs) msg.obj; 146 switch (msg.what) { 147 case MSG_STORAGE_STATE_CHANGED: 148 mCallback.onStorageStateChanged((String) args.arg1, (String) args.arg2, 149 (String) args.arg3); 150 args.recycle(); 151 return true; 152 case MSG_VOLUME_STATE_CHANGED: 153 mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3); 154 args.recycle(); 155 return true; 156 case MSG_VOLUME_RECORD_CHANGED: 157 mCallback.onVolumeRecordChanged((VolumeRecord) args.arg1); 158 args.recycle(); 159 return true; 160 case MSG_VOLUME_FORGOTTEN: 161 mCallback.onVolumeForgotten((String) args.arg1); 162 args.recycle(); 163 return true; 164 case MSG_DISK_SCANNED: 165 mCallback.onDiskScanned((DiskInfo) args.arg1, args.argi2); 166 args.recycle(); 167 return true; 168 case MSG_DISK_DESTROYED: 169 mCallback.onDiskDestroyed((DiskInfo) args.arg1); 170 args.recycle(); 171 return true; 172 } 173 args.recycle(); 174 return false; 175 } 176 177 @Override 178 public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException { 179 // Ignored 180 } 181 182 @Override 183 public void onStorageStateChanged(String path, String oldState, String newState) { 184 final SomeArgs args = SomeArgs.obtain(); 185 args.arg1 = path; 186 args.arg2 = oldState; 187 args.arg3 = newState; 188 mHandler.obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget(); 189 } 190 191 @Override 192 public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { 193 final SomeArgs args = SomeArgs.obtain(); 194 args.arg1 = vol; 195 args.argi2 = oldState; 196 args.argi3 = newState; 197 mHandler.obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget(); 198 } 199 200 @Override 201 public void onVolumeRecordChanged(VolumeRecord rec) { 202 final SomeArgs args = SomeArgs.obtain(); 203 args.arg1 = rec; 204 mHandler.obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget(); 205 } 206 207 @Override 208 public void onVolumeForgotten(String fsUuid) { 209 final SomeArgs args = SomeArgs.obtain(); 210 args.arg1 = fsUuid; 211 mHandler.obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget(); 212 } 213 214 @Override 215 public void onDiskScanned(DiskInfo disk, int volumeCount) { 216 final SomeArgs args = SomeArgs.obtain(); 217 args.arg1 = disk; 218 args.argi2 = volumeCount; 219 mHandler.obtainMessage(MSG_DISK_SCANNED, args).sendToTarget(); 220 } 221 222 @Override 223 public void onDiskDestroyed(DiskInfo disk) throws RemoteException { 224 final SomeArgs args = SomeArgs.obtain(); 225 args.arg1 = disk; 226 mHandler.obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget(); 227 } 228 } 229 230 /** 231 * Binder listener for OBB action results. 232 */ 233 private final ObbActionListener mObbActionListener = new ObbActionListener(); 234 235 private class ObbActionListener extends IObbActionListener.Stub { 236 @SuppressWarnings("hiding") 237 private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>(); 238 239 @Override 240 public void onObbResult(String filename, int nonce, int status) { 241 final ObbListenerDelegate delegate; 242 synchronized (mListeners) { 243 delegate = mListeners.get(nonce); 244 if (delegate != null) { 245 mListeners.remove(nonce); 246 } 247 } 248 249 if (delegate != null) { 250 delegate.sendObbStateChanged(filename, status); 251 } 252 } 253 254 public int addListener(OnObbStateChangeListener listener) { 255 final ObbListenerDelegate delegate = new ObbListenerDelegate(listener); 256 257 synchronized (mListeners) { 258 mListeners.put(delegate.nonce, delegate); 259 } 260 261 return delegate.nonce; 262 } 263 } 264 265 private int getNextNonce() { 266 return mNextNonce.getAndIncrement(); 267 } 268 269 /** 270 * Private class containing sender and receiver code for StorageEvents. 271 */ 272 private class ObbListenerDelegate { 273 private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef; 274 private final Handler mHandler; 275 276 private final int nonce; 277 278 ObbListenerDelegate(OnObbStateChangeListener listener) { 279 nonce = getNextNonce(); 280 mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener); 281 mHandler = new Handler(mLooper) { 282 @Override 283 public void handleMessage(Message msg) { 284 final OnObbStateChangeListener changeListener = getListener(); 285 if (changeListener == null) { 286 return; 287 } 288 289 changeListener.onObbStateChange((String) msg.obj, msg.arg1); 290 } 291 }; 292 } 293 294 OnObbStateChangeListener getListener() { 295 if (mObbEventListenerRef == null) { 296 return null; 297 } 298 return mObbEventListenerRef.get(); 299 } 300 301 void sendObbStateChanged(String path, int state) { 302 mHandler.obtainMessage(0, state, 0, path).sendToTarget(); 303 } 304 } 305 306 /** {@hide} */ 307 @Deprecated 308 public static StorageManager from(Context context) { 309 return context.getSystemService(StorageManager.class); 310 } 311 312 /** 313 * Constructs a StorageManager object through which an application can 314 * can communicate with the systems mount service. 315 * 316 * @param tgtLooper The {@link android.os.Looper} which events will be received on. 317 * 318 * <p>Applications can get instance of this class by calling 319 * {@link android.content.Context#getSystemService(java.lang.String)} with an argument 320 * of {@link android.content.Context#STORAGE_SERVICE}. 321 * 322 * @hide 323 */ 324 public StorageManager(Context context, Looper looper) { 325 mContext = context; 326 mResolver = context.getContentResolver(); 327 mLooper = looper; 328 mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount")); 329 if (mMountService == null) { 330 throw new IllegalStateException("Failed to find running mount service"); 331 } 332 } 333 334 /** 335 * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}. 336 * 337 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object. 338 * 339 * @hide 340 */ 341 public void registerListener(StorageEventListener listener) { 342 synchronized (mDelegates) { 343 final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener, 344 mLooper); 345 try { 346 mMountService.registerListener(delegate); 347 } catch (RemoteException e) { 348 throw e.rethrowFromSystemServer(); 349 } 350 mDelegates.add(delegate); 351 } 352 } 353 354 /** 355 * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}. 356 * 357 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object. 358 * 359 * @hide 360 */ 361 public void unregisterListener(StorageEventListener listener) { 362 synchronized (mDelegates) { 363 for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) { 364 final StorageEventListenerDelegate delegate = i.next(); 365 if (delegate.mCallback == listener) { 366 try { 367 mMountService.unregisterListener(delegate); 368 } catch (RemoteException e) { 369 throw e.rethrowFromSystemServer(); 370 } 371 i.remove(); 372 } 373 } 374 } 375 } 376 377 /** 378 * Enables USB Mass Storage (UMS) on the device. 379 * 380 * @hide 381 */ 382 @Deprecated 383 public void enableUsbMassStorage() { 384 } 385 386 /** 387 * Disables USB Mass Storage (UMS) on the device. 388 * 389 * @hide 390 */ 391 @Deprecated 392 public void disableUsbMassStorage() { 393 } 394 395 /** 396 * Query if a USB Mass Storage (UMS) host is connected. 397 * @return true if UMS host is connected. 398 * 399 * @hide 400 */ 401 @Deprecated 402 public boolean isUsbMassStorageConnected() { 403 return false; 404 } 405 406 /** 407 * Query if a USB Mass Storage (UMS) is enabled on the device. 408 * @return true if UMS host is enabled. 409 * 410 * @hide 411 */ 412 @Deprecated 413 public boolean isUsbMassStorageEnabled() { 414 return false; 415 } 416 417 /** 418 * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is 419 * specified, it is supplied to the mounting process to be used in any 420 * encryption used in the OBB. 421 * <p> 422 * The OBB will remain mounted for as long as the StorageManager reference 423 * is held by the application. As soon as this reference is lost, the OBBs 424 * in use will be unmounted. The {@link OnObbStateChangeListener} registered 425 * with this call will receive the success or failure of this operation. 426 * <p> 427 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the 428 * file matches a package ID that is owned by the calling program's UID. 429 * That is, shared UID applications can attempt to mount any other 430 * application's OBB that shares its UID. 431 * 432 * @param rawPath the path to the OBB file 433 * @param key secret used to encrypt the OBB; may be <code>null</code> if no 434 * encryption was used on the OBB. 435 * @param listener will receive the success or failure of the operation 436 * @return whether the mount call was successfully queued or not 437 */ 438 public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) { 439 Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 440 Preconditions.checkNotNull(listener, "listener cannot be null"); 441 442 try { 443 final String canonicalPath = new File(rawPath).getCanonicalPath(); 444 final int nonce = mObbActionListener.addListener(listener); 445 mMountService.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce); 446 return true; 447 } catch (IOException e) { 448 throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e); 449 } catch (RemoteException e) { 450 throw e.rethrowFromSystemServer(); 451 } 452 } 453 454 /** 455 * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the 456 * <code>force</code> flag is true, it will kill any application needed to 457 * unmount the given OBB (even the calling application). 458 * <p> 459 * The {@link OnObbStateChangeListener} registered with this call will 460 * receive the success or failure of this operation. 461 * <p> 462 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the 463 * file matches a package ID that is owned by the calling program's UID. 464 * That is, shared UID applications can obtain access to any other 465 * application's OBB that shares its UID. 466 * <p> 467 * 468 * @param rawPath path to the OBB file 469 * @param force whether to kill any programs using this in order to unmount 470 * it 471 * @param listener will receive the success or failure of the operation 472 * @return whether the unmount call was successfully queued or not 473 */ 474 public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) { 475 Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 476 Preconditions.checkNotNull(listener, "listener cannot be null"); 477 478 try { 479 final int nonce = mObbActionListener.addListener(listener); 480 mMountService.unmountObb(rawPath, force, mObbActionListener, nonce); 481 return true; 482 } catch (RemoteException e) { 483 throw e.rethrowFromSystemServer(); 484 } 485 } 486 487 /** 488 * Check whether an Opaque Binary Blob (OBB) is mounted or not. 489 * 490 * @param rawPath path to OBB image 491 * @return true if OBB is mounted; false if not mounted or on error 492 */ 493 public boolean isObbMounted(String rawPath) { 494 Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 495 496 try { 497 return mMountService.isObbMounted(rawPath); 498 } catch (RemoteException e) { 499 throw e.rethrowFromSystemServer(); 500 } 501 } 502 503 /** 504 * Check the mounted path of an Opaque Binary Blob (OBB) file. This will 505 * give you the path to where you can obtain access to the internals of the 506 * OBB. 507 * 508 * @param rawPath path to OBB image 509 * @return absolute path to mounted OBB image data or <code>null</code> if 510 * not mounted or exception encountered trying to read status 511 */ 512 public String getMountedObbPath(String rawPath) { 513 Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 514 515 try { 516 return mMountService.getMountedObbPath(rawPath); 517 } catch (RemoteException e) { 518 throw e.rethrowFromSystemServer(); 519 } 520 } 521 522 /** {@hide} */ 523 public @NonNull List<DiskInfo> getDisks() { 524 try { 525 return Arrays.asList(mMountService.getDisks()); 526 } catch (RemoteException e) { 527 throw e.rethrowFromSystemServer(); 528 } 529 } 530 531 /** {@hide} */ 532 public @Nullable DiskInfo findDiskById(String id) { 533 Preconditions.checkNotNull(id); 534 // TODO; go directly to service to make this faster 535 for (DiskInfo disk : getDisks()) { 536 if (Objects.equals(disk.id, id)) { 537 return disk; 538 } 539 } 540 return null; 541 } 542 543 /** {@hide} */ 544 public @Nullable VolumeInfo findVolumeById(String id) { 545 Preconditions.checkNotNull(id); 546 // TODO; go directly to service to make this faster 547 for (VolumeInfo vol : getVolumes()) { 548 if (Objects.equals(vol.id, id)) { 549 return vol; 550 } 551 } 552 return null; 553 } 554 555 /** {@hide} */ 556 public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) { 557 Preconditions.checkNotNull(fsUuid); 558 // TODO; go directly to service to make this faster 559 for (VolumeInfo vol : getVolumes()) { 560 if (Objects.equals(vol.fsUuid, fsUuid)) { 561 return vol; 562 } 563 } 564 return null; 565 } 566 567 /** {@hide} */ 568 public @Nullable VolumeRecord findRecordByUuid(String fsUuid) { 569 Preconditions.checkNotNull(fsUuid); 570 // TODO; go directly to service to make this faster 571 for (VolumeRecord rec : getVolumeRecords()) { 572 if (Objects.equals(rec.fsUuid, fsUuid)) { 573 return rec; 574 } 575 } 576 return null; 577 } 578 579 /** {@hide} */ 580 public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) { 581 if (emulatedVol != null) { 582 return findVolumeById(emulatedVol.getId().replace("emulated", "private")); 583 } else { 584 return null; 585 } 586 } 587 588 /** {@hide} */ 589 public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) { 590 if (privateVol != null) { 591 return findVolumeById(privateVol.getId().replace("private", "emulated")); 592 } else { 593 return null; 594 } 595 } 596 597 /** {@hide} */ 598 public @Nullable VolumeInfo findVolumeByQualifiedUuid(String volumeUuid) { 599 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) { 600 return findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL); 601 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) { 602 return getPrimaryPhysicalVolume(); 603 } else { 604 return findVolumeByUuid(volumeUuid); 605 } 606 } 607 608 /** {@hide} */ 609 public @NonNull List<VolumeInfo> getVolumes() { 610 try { 611 return Arrays.asList(mMountService.getVolumes(0)); 612 } catch (RemoteException e) { 613 throw e.rethrowFromSystemServer(); 614 } 615 } 616 617 /** {@hide} */ 618 public @NonNull List<VolumeInfo> getWritablePrivateVolumes() { 619 try { 620 final ArrayList<VolumeInfo> res = new ArrayList<>(); 621 for (VolumeInfo vol : mMountService.getVolumes(0)) { 622 if (vol.getType() == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) { 623 res.add(vol); 624 } 625 } 626 return res; 627 } catch (RemoteException e) { 628 throw e.rethrowFromSystemServer(); 629 } 630 } 631 632 /** {@hide} */ 633 public @NonNull List<VolumeRecord> getVolumeRecords() { 634 try { 635 return Arrays.asList(mMountService.getVolumeRecords(0)); 636 } catch (RemoteException e) { 637 throw e.rethrowFromSystemServer(); 638 } 639 } 640 641 /** {@hide} */ 642 public @Nullable String getBestVolumeDescription(VolumeInfo vol) { 643 if (vol == null) return null; 644 645 // Nickname always takes precedence when defined 646 if (!TextUtils.isEmpty(vol.fsUuid)) { 647 final VolumeRecord rec = findRecordByUuid(vol.fsUuid); 648 if (rec != null && !TextUtils.isEmpty(rec.nickname)) { 649 return rec.nickname; 650 } 651 } 652 653 if (!TextUtils.isEmpty(vol.getDescription())) { 654 return vol.getDescription(); 655 } 656 657 if (vol.disk != null) { 658 return vol.disk.getDescription(); 659 } 660 661 return null; 662 } 663 664 /** {@hide} */ 665 public @Nullable VolumeInfo getPrimaryPhysicalVolume() { 666 final List<VolumeInfo> vols = getVolumes(); 667 for (VolumeInfo vol : vols) { 668 if (vol.isPrimaryPhysical()) { 669 return vol; 670 } 671 } 672 return null; 673 } 674 675 /** {@hide} */ 676 public void mount(String volId) { 677 try { 678 mMountService.mount(volId); 679 } catch (RemoteException e) { 680 throw e.rethrowFromSystemServer(); 681 } 682 } 683 684 /** {@hide} */ 685 public void unmount(String volId) { 686 try { 687 mMountService.unmount(volId); 688 } catch (RemoteException e) { 689 throw e.rethrowFromSystemServer(); 690 } 691 } 692 693 /** {@hide} */ 694 public void format(String volId) { 695 try { 696 mMountService.format(volId); 697 } catch (RemoteException e) { 698 throw e.rethrowFromSystemServer(); 699 } 700 } 701 702 /** {@hide} */ 703 public long benchmark(String volId) { 704 try { 705 return mMountService.benchmark(volId); 706 } catch (RemoteException e) { 707 throw e.rethrowFromSystemServer(); 708 } 709 } 710 711 /** {@hide} */ 712 public void partitionPublic(String diskId) { 713 try { 714 mMountService.partitionPublic(diskId); 715 } catch (RemoteException e) { 716 throw e.rethrowFromSystemServer(); 717 } 718 } 719 720 /** {@hide} */ 721 public void partitionPrivate(String diskId) { 722 try { 723 mMountService.partitionPrivate(diskId); 724 } catch (RemoteException e) { 725 throw e.rethrowFromSystemServer(); 726 } 727 } 728 729 /** {@hide} */ 730 public void partitionMixed(String diskId, int ratio) { 731 try { 732 mMountService.partitionMixed(diskId, ratio); 733 } catch (RemoteException e) { 734 throw e.rethrowFromSystemServer(); 735 } 736 } 737 738 /** {@hide} */ 739 public void wipeAdoptableDisks() { 740 // We only wipe devices in "adoptable" locations, which are in a 741 // long-term stable slot/location on the device, where apps have a 742 // reasonable chance of storing sensitive data. (Apps need to go through 743 // SAF to write to transient volumes.) 744 final List<DiskInfo> disks = getDisks(); 745 for (DiskInfo disk : disks) { 746 final String diskId = disk.getId(); 747 if (disk.isAdoptable()) { 748 Slog.d(TAG, "Found adoptable " + diskId + "; wiping"); 749 try { 750 // TODO: switch to explicit wipe command when we have it, 751 // for now rely on the fact that vfat format does a wipe 752 mMountService.partitionPublic(diskId); 753 } catch (Exception e) { 754 Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e); 755 } 756 } else { 757 Slog.d(TAG, "Ignorning non-adoptable disk " + disk.getId()); 758 } 759 } 760 } 761 762 /** {@hide} */ 763 public void setVolumeNickname(String fsUuid, String nickname) { 764 try { 765 mMountService.setVolumeNickname(fsUuid, nickname); 766 } catch (RemoteException e) { 767 throw e.rethrowFromSystemServer(); 768 } 769 } 770 771 /** {@hide} */ 772 public void setVolumeInited(String fsUuid, boolean inited) { 773 try { 774 mMountService.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0, 775 VolumeRecord.USER_FLAG_INITED); 776 } catch (RemoteException e) { 777 throw e.rethrowFromSystemServer(); 778 } 779 } 780 781 /** {@hide} */ 782 public void setVolumeSnoozed(String fsUuid, boolean snoozed) { 783 try { 784 mMountService.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0, 785 VolumeRecord.USER_FLAG_SNOOZED); 786 } catch (RemoteException e) { 787 throw e.rethrowFromSystemServer(); 788 } 789 } 790 791 /** {@hide} */ 792 public void forgetVolume(String fsUuid) { 793 try { 794 mMountService.forgetVolume(fsUuid); 795 } catch (RemoteException e) { 796 throw e.rethrowFromSystemServer(); 797 } 798 } 799 800 /** 801 * This is not the API you're looking for. 802 * 803 * @see PackageManager#getPrimaryStorageCurrentVolume() 804 * @hide 805 */ 806 public String getPrimaryStorageUuid() { 807 try { 808 return mMountService.getPrimaryStorageUuid(); 809 } catch (RemoteException e) { 810 throw e.rethrowFromSystemServer(); 811 } 812 } 813 814 /** 815 * This is not the API you're looking for. 816 * 817 * @see PackageManager#movePrimaryStorage(VolumeInfo) 818 * @hide 819 */ 820 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) { 821 try { 822 mMountService.setPrimaryStorageUuid(volumeUuid, callback); 823 } catch (RemoteException e) { 824 throw e.rethrowFromSystemServer(); 825 } 826 } 827 828 /** 829 * Return the {@link StorageVolume} that contains the given file, or {@code null} if none. 830 */ 831 public @Nullable StorageVolume getStorageVolume(File file) { 832 return getStorageVolume(getVolumeList(), file); 833 } 834 835 /** {@hide} */ 836 public static @Nullable StorageVolume getStorageVolume(File file, int userId) { 837 return getStorageVolume(getVolumeList(userId, 0), file); 838 } 839 840 /** {@hide} */ 841 private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) { 842 if (file == null) { 843 return null; 844 } 845 try { 846 file = file.getCanonicalFile(); 847 } catch (IOException ignored) { 848 Slog.d(TAG, "Could not get canonical path for " + file); 849 return null; 850 } 851 for (StorageVolume volume : volumes) { 852 File volumeFile = volume.getPathFile(); 853 try { 854 volumeFile = volumeFile.getCanonicalFile(); 855 } catch (IOException ignored) { 856 continue; 857 } 858 if (FileUtils.contains(volumeFile, file)) { 859 return volume; 860 } 861 } 862 return null; 863 } 864 865 /** 866 * Gets the state of a volume via its mountpoint. 867 * @hide 868 */ 869 @Deprecated 870 public @NonNull String getVolumeState(String mountPoint) { 871 final StorageVolume vol = getStorageVolume(new File(mountPoint)); 872 if (vol != null) { 873 return vol.getState(); 874 } else { 875 return Environment.MEDIA_UNKNOWN; 876 } 877 } 878 879 /** 880 * Return the list of shared/external storage volumes available to the 881 * current user. This includes both the primary shared storage device and 882 * any attached external volumes including SD cards and USB drives. 883 * 884 * @see Environment#getExternalStorageDirectory() 885 * @see StorageVolume#createAccessIntent(String) 886 */ 887 public @NonNull List<StorageVolume> getStorageVolumes() { 888 final ArrayList<StorageVolume> res = new ArrayList<>(); 889 Collections.addAll(res, 890 getVolumeList(UserHandle.myUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE)); 891 return res; 892 } 893 894 /** 895 * Return the primary shared/external storage volume available to the 896 * current user. This volume is the same storage device returned by 897 * {@link Environment#getExternalStorageDirectory()} and 898 * {@link Context#getExternalFilesDir(String)}. 899 */ 900 public @NonNull StorageVolume getPrimaryStorageVolume() { 901 return getVolumeList(UserHandle.myUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE)[0]; 902 } 903 904 /** @removed */ 905 public @NonNull StorageVolume[] getVolumeList() { 906 return getVolumeList(mContext.getUserId(), 0); 907 } 908 909 /** {@hide} */ 910 public static @NonNull StorageVolume[] getVolumeList(int userId, int flags) { 911 final IMountService mountService = IMountService.Stub.asInterface( 912 ServiceManager.getService("mount")); 913 try { 914 String packageName = ActivityThread.currentOpPackageName(); 915 if (packageName == null) { 916 // Package name can be null if the activity thread is running but the app 917 // hasn't bound yet. In this case we fall back to the first package in the 918 // current UID. This works for runtime permissions as permission state is 919 // per UID and permission realted app ops are updated for all UID packages. 920 String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid( 921 android.os.Process.myUid()); 922 if (packageNames == null || packageNames.length <= 0) { 923 return new StorageVolume[0]; 924 } 925 packageName = packageNames[0]; 926 } 927 final int uid = ActivityThread.getPackageManager().getPackageUid(packageName, 928 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId); 929 if (uid <= 0) { 930 return new StorageVolume[0]; 931 } 932 return mountService.getVolumeList(uid, packageName, flags); 933 } catch (RemoteException e) { 934 throw e.rethrowFromSystemServer(); 935 } 936 } 937 938 /** 939 * Returns list of paths for all mountable volumes. 940 * @hide 941 */ 942 @Deprecated 943 public @NonNull String[] getVolumePaths() { 944 StorageVolume[] volumes = getVolumeList(); 945 int count = volumes.length; 946 String[] paths = new String[count]; 947 for (int i = 0; i < count; i++) { 948 paths[i] = volumes[i].getPath(); 949 } 950 return paths; 951 } 952 953 /** @removed */ 954 public @NonNull StorageVolume getPrimaryVolume() { 955 return getPrimaryVolume(getVolumeList()); 956 } 957 958 /** {@hide} */ 959 public static @NonNull StorageVolume getPrimaryVolume(StorageVolume[] volumes) { 960 for (StorageVolume volume : volumes) { 961 if (volume.isPrimary()) { 962 return volume; 963 } 964 } 965 throw new IllegalStateException("Missing primary storage"); 966 } 967 968 /** {@hide} */ 969 private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10; 970 private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES; 971 private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES; 972 973 /** 974 * Return the number of available bytes until the given path is considered 975 * running low on storage. 976 * 977 * @hide 978 */ 979 public long getStorageBytesUntilLow(File path) { 980 return path.getUsableSpace() - getStorageFullBytes(path); 981 } 982 983 /** 984 * Return the number of available bytes at which the given path is 985 * considered running low on storage. 986 * 987 * @hide 988 */ 989 public long getStorageLowBytes(File path) { 990 final long lowPercent = Settings.Global.getInt(mResolver, 991 Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE); 992 final long lowBytes = (path.getTotalSpace() * lowPercent) / 100; 993 994 final long maxLowBytes = Settings.Global.getLong(mResolver, 995 Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES); 996 997 return Math.min(lowBytes, maxLowBytes); 998 } 999 1000 /** 1001 * Return the number of available bytes at which the given path is 1002 * considered full. 1003 * 1004 * @hide 1005 */ 1006 public long getStorageFullBytes(File path) { 1007 return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES, 1008 DEFAULT_FULL_THRESHOLD_BYTES); 1009 } 1010 1011 /** {@hide} */ 1012 public void createUserKey(int userId, int serialNumber, boolean ephemeral) { 1013 try { 1014 mMountService.createUserKey(userId, serialNumber, ephemeral); 1015 } catch (RemoteException e) { 1016 throw e.rethrowFromSystemServer(); 1017 } 1018 } 1019 1020 /** {@hide} */ 1021 public void destroyUserKey(int userId) { 1022 try { 1023 mMountService.destroyUserKey(userId); 1024 } catch (RemoteException e) { 1025 throw e.rethrowFromSystemServer(); 1026 } 1027 } 1028 1029 /** {@hide} */ 1030 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) { 1031 try { 1032 mMountService.unlockUserKey(userId, serialNumber, token, secret); 1033 } catch (RemoteException e) { 1034 throw e.rethrowFromSystemServer(); 1035 } 1036 } 1037 1038 /** {@hide} */ 1039 public void lockUserKey(int userId) { 1040 try { 1041 mMountService.lockUserKey(userId); 1042 } catch (RemoteException e) { 1043 throw e.rethrowFromSystemServer(); 1044 } 1045 } 1046 1047 /** {@hide} */ 1048 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) { 1049 try { 1050 mMountService.prepareUserStorage(volumeUuid, userId, serialNumber, flags); 1051 } catch (RemoteException e) { 1052 throw e.rethrowFromSystemServer(); 1053 } 1054 } 1055 1056 /** {@hide} */ 1057 public void destroyUserStorage(String volumeUuid, int userId, int flags) { 1058 try { 1059 mMountService.destroyUserStorage(volumeUuid, userId, flags); 1060 } catch (RemoteException e) { 1061 throw e.rethrowFromSystemServer(); 1062 } 1063 } 1064 1065 /** {@hide} */ 1066 public static boolean isUserKeyUnlocked(int userId) { 1067 final IMountService mount = IMountService.Stub 1068 .asInterface(ServiceManager.getService("mount")); 1069 if (mount == null) { 1070 Slog.w(TAG, "Early during boot, assuming locked"); 1071 return false; 1072 } 1073 final long token = Binder.clearCallingIdentity(); 1074 try { 1075 return mount.isUserKeyUnlocked(userId); 1076 } catch (RemoteException e) { 1077 throw e.rethrowAsRuntimeException(); 1078 } finally { 1079 Binder.restoreCallingIdentity(token); 1080 } 1081 } 1082 1083 /** 1084 * Return if data stored at or under the given path will be encrypted while 1085 * at rest. This can help apps avoid the overhead of double-encrypting data. 1086 */ 1087 public boolean isEncrypted(File file) { 1088 if (FileUtils.contains(Environment.getDataDirectory(), file)) { 1089 return isEncrypted(); 1090 } else if (FileUtils.contains(Environment.getExpandDirectory(), file)) { 1091 return true; 1092 } 1093 // TODO: extend to support shared storage 1094 return false; 1095 } 1096 1097 /** {@hide} 1098 * Is this device encryptable or already encrypted? 1099 * @return true for encryptable or encrypted 1100 * false not encrypted and not encryptable 1101 */ 1102 public static boolean isEncryptable() { 1103 final String state = SystemProperties.get("ro.crypto.state", "unsupported"); 1104 return !"unsupported".equalsIgnoreCase(state); 1105 } 1106 1107 /** {@hide} 1108 * Is this device already encrypted? 1109 * @return true for encrypted. (Implies isEncryptable() == true) 1110 * false not encrypted 1111 */ 1112 public static boolean isEncrypted() { 1113 final String state = SystemProperties.get("ro.crypto.state", ""); 1114 return "encrypted".equalsIgnoreCase(state); 1115 } 1116 1117 /** {@hide} 1118 * Is this device file encrypted? 1119 * @return true for file encrypted. (Implies isEncrypted() == true) 1120 * false not encrypted or block encrypted 1121 */ 1122 public static boolean isFileEncryptedNativeOnly() { 1123 if (!isEncrypted()) { 1124 return false; 1125 } 1126 1127 final String status = SystemProperties.get("ro.crypto.type", ""); 1128 return "file".equalsIgnoreCase(status); 1129 } 1130 1131 /** {@hide} 1132 * Is this device block encrypted? 1133 * @return true for block encrypted. (Implies isEncrypted() == true) 1134 * false not encrypted or file encrypted 1135 */ 1136 public static boolean isBlockEncrypted() { 1137 if (!isEncrypted()) { 1138 return false; 1139 } 1140 final String status = SystemProperties.get("ro.crypto.type", ""); 1141 return "block".equalsIgnoreCase(status); 1142 } 1143 1144 /** {@hide} 1145 * Is this device block encrypted with credentials? 1146 * @return true for crediential block encrypted. 1147 * (Implies isBlockEncrypted() == true) 1148 * false not encrypted, file encrypted or default block encrypted 1149 */ 1150 public static boolean isNonDefaultBlockEncrypted() { 1151 if (!isBlockEncrypted()) { 1152 return false; 1153 } 1154 1155 try { 1156 IMountService mountService = IMountService.Stub.asInterface( 1157 ServiceManager.getService("mount")); 1158 return mountService.getPasswordType() != CRYPT_TYPE_DEFAULT; 1159 } catch (RemoteException e) { 1160 Log.e(TAG, "Error getting encryption type"); 1161 return false; 1162 } 1163 } 1164 1165 /** {@hide} 1166 * Is this device in the process of being block encrypted? 1167 * @return true for encrypting. 1168 * false otherwise 1169 * Whether device isEncrypted at this point is undefined 1170 * Note that only system services and CryptKeeper will ever see this return 1171 * true - no app will ever be launched in this state. 1172 * Also note that this state will not change without a teardown of the 1173 * framework, so no service needs to check for changes during their lifespan 1174 */ 1175 public static boolean isBlockEncrypting() { 1176 final String state = SystemProperties.get("vold.encrypt_progress", ""); 1177 return !"".equalsIgnoreCase(state); 1178 } 1179 1180 /** {@hide} 1181 * Is this device non default block encrypted and in the process of 1182 * prompting for credentials? 1183 * @return true for prompting for credentials. 1184 * (Implies isNonDefaultBlockEncrypted() == true) 1185 * false otherwise 1186 * Note that only system services and CryptKeeper will ever see this return 1187 * true - no app will ever be launched in this state. 1188 * Also note that this state will not change without a teardown of the 1189 * framework, so no service needs to check for changes during their lifespan 1190 */ 1191 public static boolean inCryptKeeperBounce() { 1192 final String status = SystemProperties.get("vold.decrypt"); 1193 return "trigger_restart_min_framework".equals(status); 1194 } 1195 1196 /** {@hide} */ 1197 public static boolean isFileEncryptedEmulatedOnly() { 1198 return SystemProperties.getBoolean(StorageManager.PROP_EMULATE_FBE, false); 1199 } 1200 1201 /** {@hide} 1202 * Is this device running in a file encrypted mode, either native or emulated? 1203 * @return true for file encrypted, false otherwise 1204 */ 1205 public static boolean isFileEncryptedNativeOrEmulated() { 1206 return isFileEncryptedNativeOnly() 1207 || isFileEncryptedEmulatedOnly(); 1208 } 1209 1210 /** {@hide} */ 1211 public static File maybeTranslateEmulatedPathToInternal(File path) { 1212 final IMountService mountService = IMountService.Stub.asInterface( 1213 ServiceManager.getService("mount")); 1214 try { 1215 final VolumeInfo[] vols = mountService.getVolumes(0); 1216 for (VolumeInfo vol : vols) { 1217 if ((vol.getType() == VolumeInfo.TYPE_EMULATED 1218 || vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isMountedReadable()) { 1219 final File internalPath = FileUtils.rewriteAfterRename(vol.getPath(), 1220 vol.getInternalPath(), path); 1221 if (internalPath != null && internalPath.exists()) { 1222 return internalPath; 1223 } 1224 } 1225 } 1226 } catch (RemoteException e) { 1227 throw e.rethrowFromSystemServer(); 1228 } 1229 return path; 1230 } 1231 1232 /** {@hide} */ 1233 public ParcelFileDescriptor mountAppFuse(String name) { 1234 try { 1235 return mMountService.mountAppFuse(name); 1236 } catch (RemoteException e) { 1237 throw e.rethrowFromSystemServer(); 1238 } 1239 } 1240 1241 /// Consts to match the password types in cryptfs.h 1242 /** @hide */ 1243 public static final int CRYPT_TYPE_PASSWORD = 0; 1244 /** @hide */ 1245 public static final int CRYPT_TYPE_DEFAULT = 1; 1246 /** @hide */ 1247 public static final int CRYPT_TYPE_PATTERN = 2; 1248 /** @hide */ 1249 public static final int CRYPT_TYPE_PIN = 3; 1250 1251 // Constants for the data available via MountService.getField. 1252 /** @hide */ 1253 public static final String SYSTEM_LOCALE_KEY = "SystemLocale"; 1254 /** @hide */ 1255 public static final String OWNER_INFO_KEY = "OwnerInfo"; 1256 /** @hide */ 1257 public static final String PATTERN_VISIBLE_KEY = "PatternVisible"; 1258 /** @hide */ 1259 public static final String PASSWORD_VISIBLE_KEY = "PasswordVisible"; 1260} 1261