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