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