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