1 /* 2 * Copyright (C) 2007 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 17 package com.android.server; 18 19 import static com.android.internal.util.XmlUtils.readBooleanAttribute; 20 import static com.android.internal.util.XmlUtils.readIntAttribute; 21 import static com.android.internal.util.XmlUtils.readLongAttribute; 22 import static com.android.internal.util.XmlUtils.readStringAttribute; 23 import static com.android.internal.util.XmlUtils.writeBooleanAttribute; 24 import static com.android.internal.util.XmlUtils.writeIntAttribute; 25 import static com.android.internal.util.XmlUtils.writeLongAttribute; 26 import static com.android.internal.util.XmlUtils.writeStringAttribute; 27 28 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 29 import static org.xmlpull.v1.XmlPullParser.START_TAG; 30 31 import android.Manifest; 32 import android.annotation.Nullable; 33 import android.app.ActivityManager; 34 import android.app.AppOpsManager; 35 import android.app.IActivityManager; 36 import android.app.usage.StorageStatsManager; 37 import android.content.BroadcastReceiver; 38 import android.content.ComponentName; 39 import android.content.Context; 40 import android.content.Intent; 41 import android.content.IntentFilter; 42 import android.content.ServiceConnection; 43 import android.content.pm.IPackageMoveObserver; 44 import android.content.pm.PackageManager; 45 import android.content.pm.ProviderInfo; 46 import android.content.pm.UserInfo; 47 import android.content.res.Configuration; 48 import android.content.res.ObbInfo; 49 import android.net.TrafficStats; 50 import android.net.Uri; 51 import android.os.Binder; 52 import android.os.DropBoxManager; 53 import android.os.Environment; 54 import android.os.Environment.UserEnvironment; 55 import android.os.FileUtils; 56 import android.os.Handler; 57 import android.os.HandlerThread; 58 import android.os.IBinder; 59 import android.os.Looper; 60 import android.os.Message; 61 import android.os.ParcelFileDescriptor; 62 import android.os.ParcelableException; 63 import android.os.PowerManager; 64 import android.os.Process; 65 import android.os.RemoteCallbackList; 66 import android.os.RemoteException; 67 import android.os.ServiceManager; 68 import android.os.SystemClock; 69 import android.os.SystemProperties; 70 import android.os.UserHandle; 71 import android.os.UserManager; 72 import android.os.storage.DiskInfo; 73 import android.os.storage.IObbActionListener; 74 import android.os.storage.IStorageEventListener; 75 import android.os.storage.IStorageManager; 76 import android.os.storage.IStorageShutdownObserver; 77 import android.os.storage.OnObbStateChangeListener; 78 import android.os.storage.StorageManager; 79 import android.os.storage.StorageManagerInternal; 80 import android.os.storage.StorageResultCode; 81 import android.os.storage.StorageVolume; 82 import android.os.storage.VolumeInfo; 83 import android.os.storage.VolumeRecord; 84 import android.provider.MediaStore; 85 import android.provider.Settings; 86 import android.text.TextUtils; 87 import android.text.format.DateUtils; 88 import android.util.ArrayMap; 89 import android.util.AtomicFile; 90 import android.util.Log; 91 import android.util.Pair; 92 import android.util.Slog; 93 import android.util.SparseArray; 94 import android.util.TimeUtils; 95 import android.util.Xml; 96 97 import com.android.internal.annotations.GuardedBy; 98 import com.android.internal.app.IMediaContainerService; 99 import com.android.internal.os.AppFuseMount; 100 import com.android.internal.os.FuseAppLoop; 101 import com.android.internal.os.FuseUnavailableMountException; 102 import com.android.internal.os.SomeArgs; 103 import com.android.internal.os.Zygote; 104 import com.android.internal.util.ArrayUtils; 105 import com.android.internal.util.DumpUtils; 106 import com.android.internal.util.FastXmlSerializer; 107 import com.android.internal.util.HexDump; 108 import com.android.internal.util.IndentingPrintWriter; 109 import com.android.internal.util.Preconditions; 110 import com.android.internal.widget.LockPatternUtils; 111 import com.android.server.NativeDaemonConnector.Command; 112 import com.android.server.NativeDaemonConnector.SensitiveArg; 113 import com.android.server.pm.PackageManagerService; 114 import com.android.server.storage.AppFuseBridge; 115 116 import libcore.io.IoUtils; 117 import libcore.util.EmptyArray; 118 119 import org.xmlpull.v1.XmlPullParser; 120 import org.xmlpull.v1.XmlPullParserException; 121 import org.xmlpull.v1.XmlSerializer; 122 123 import java.io.File; 124 import java.io.FileDescriptor; 125 import java.io.FileInputStream; 126 import java.io.FileNotFoundException; 127 import java.io.FileOutputStream; 128 import java.io.IOException; 129 import java.io.PrintWriter; 130 import java.math.BigInteger; 131 import java.nio.charset.StandardCharsets; 132 import java.security.NoSuchAlgorithmException; 133 import java.security.spec.InvalidKeySpecException; 134 import java.security.spec.KeySpec; 135 import java.util.ArrayList; 136 import java.util.Arrays; 137 import java.util.HashMap; 138 import java.util.HashSet; 139 import java.util.Iterator; 140 import java.util.LinkedList; 141 import java.util.List; 142 import java.util.Locale; 143 import java.util.Map; 144 import java.util.Map.Entry; 145 import java.util.Objects; 146 import java.util.concurrent.ArrayBlockingQueue; 147 import java.util.concurrent.CopyOnWriteArrayList; 148 import java.util.concurrent.CountDownLatch; 149 import java.util.concurrent.TimeUnit; 150 import java.util.concurrent.TimeoutException; 151 152 import javax.crypto.SecretKey; 153 import javax.crypto.SecretKeyFactory; 154 import javax.crypto.spec.PBEKeySpec; 155 156 /** 157 * Service responsible for various storage media. Connects to {@code vold} to 158 * watch for and manage dynamically added storage, such as SD cards and USB mass 159 * storage. Also decides how storage should be presented to users on the device. 160 */ 161 class StorageManagerService extends IStorageManager.Stub 162 implements INativeDaemonConnectorCallbacks, Watchdog.Monitor { 163 164 // Static direct instance pointer for the tightly-coupled idle service to use 165 static StorageManagerService sSelf = null; 166 167 public static class Lifecycle extends SystemService { 168 private StorageManagerService mStorageManagerService; 169 170 public Lifecycle(Context context) { 171 super(context); 172 } 173 174 @Override 175 public void onStart() { 176 mStorageManagerService = new StorageManagerService(getContext()); 177 publishBinderService("mount", mStorageManagerService); 178 mStorageManagerService.start(); 179 } 180 181 @Override 182 public void onBootPhase(int phase) { 183 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { 184 mStorageManagerService.systemReady(); 185 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { 186 mStorageManagerService.bootCompleted(); 187 } 188 } 189 190 @Override 191 public void onSwitchUser(int userHandle) { 192 mStorageManagerService.mCurrentUserId = userHandle; 193 } 194 195 @Override 196 public void onUnlockUser(int userHandle) { 197 mStorageManagerService.onUnlockUser(userHandle); 198 } 199 200 @Override 201 public void onCleanupUser(int userHandle) { 202 mStorageManagerService.onCleanupUser(userHandle); 203 } 204 } 205 206 private static final boolean DEBUG_EVENTS = false; 207 private static final boolean DEBUG_OBB = false; 208 209 // Disable this since it messes up long-running cryptfs operations. 210 private static final boolean WATCHDOG_ENABLE = false; 211 212 /** 213 * Our goal is for all Android devices to be usable as development devices, 214 * which includes the new Direct Boot mode added in N. For devices that 215 * don't have native FBE support, we offer an emulation mode for developer 216 * testing purposes, but if it's prohibitively difficult to support this 217 * mode, it can be disabled for specific products using this flag. 218 */ 219 private static final boolean EMULATE_FBE_SUPPORTED = true; 220 221 private static final String TAG = "StorageManagerService"; 222 223 private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark"; 224 private static final String TAG_STORAGE_TRIM = "storage_trim"; 225 226 private static final String VOLD_TAG = "VoldConnector"; 227 private static final String CRYPTD_TAG = "CryptdConnector"; 228 229 /** Maximum number of ASEC containers allowed to be mounted. */ 230 private static final int MAX_CONTAINERS = 250; 231 232 /** Magic value sent by MoveTask.cpp */ 233 private static final int MOVE_STATUS_COPY_FINISHED = 82; 234 235 /* 236 * Internal vold response code constants 237 */ 238 class VoldResponseCode { 239 /* 240 * 100 series - Requestion action was initiated; expect another reply 241 * before proceeding with a new command. 242 */ 243 public static final int VolumeListResult = 110; 244 public static final int AsecListResult = 111; 245 public static final int StorageUsersListResult = 112; 246 public static final int CryptfsGetfieldResult = 113; 247 248 /* 249 * 200 series - Requestion action has been successfully completed. 250 */ 251 public static final int ShareStatusResult = 210; 252 public static final int AsecPathResult = 211; 253 public static final int ShareEnabledResult = 212; 254 255 /* 256 * 400 series - Command was accepted, but the requested action 257 * did not take place. 258 */ 259 public static final int OpFailedNoMedia = 401; 260 public static final int OpFailedMediaBlank = 402; 261 public static final int OpFailedMediaCorrupt = 403; 262 public static final int OpFailedVolNotMounted = 404; 263 public static final int OpFailedStorageBusy = 405; 264 public static final int OpFailedStorageNotFound = 406; 265 266 /* 267 * 600 series - Unsolicited broadcasts. 268 */ 269 public static final int DISK_CREATED = 640; 270 public static final int DISK_SIZE_CHANGED = 641; 271 public static final int DISK_LABEL_CHANGED = 642; 272 public static final int DISK_SCANNED = 643; 273 public static final int DISK_SYS_PATH_CHANGED = 644; 274 public static final int DISK_DESTROYED = 649; 275 276 public static final int VOLUME_CREATED = 650; 277 public static final int VOLUME_STATE_CHANGED = 651; 278 public static final int VOLUME_FS_TYPE_CHANGED = 652; 279 public static final int VOLUME_FS_UUID_CHANGED = 653; 280 public static final int VOLUME_FS_LABEL_CHANGED = 654; 281 public static final int VOLUME_PATH_CHANGED = 655; 282 public static final int VOLUME_INTERNAL_PATH_CHANGED = 656; 283 public static final int VOLUME_DESTROYED = 659; 284 285 public static final int MOVE_STATUS = 660; 286 public static final int BENCHMARK_RESULT = 661; 287 public static final int TRIM_RESULT = 662; 288 } 289 290 private static final int VERSION_INIT = 1; 291 private static final int VERSION_ADD_PRIMARY = 2; 292 private static final int VERSION_FIX_PRIMARY = 3; 293 294 private static final String TAG_VOLUMES = "volumes"; 295 private static final String ATTR_VERSION = "version"; 296 private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid"; 297 private static final String ATTR_FORCE_ADOPTABLE = "forceAdoptable"; 298 private static final String TAG_VOLUME = "volume"; 299 private static final String ATTR_TYPE = "type"; 300 private static final String ATTR_FS_UUID = "fsUuid"; 301 private static final String ATTR_PART_GUID = "partGuid"; 302 private static final String ATTR_NICKNAME = "nickname"; 303 private static final String ATTR_USER_FLAGS = "userFlags"; 304 private static final String ATTR_CREATED_MILLIS = "createdMillis"; 305 private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis"; 306 private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis"; 307 308 private final AtomicFile mSettingsFile; 309 310 /** 311 * <em>Never</em> hold the lock while performing downcalls into vold, since 312 * unsolicited events can suddenly appear to update data structures. 313 */ 314 private final Object mLock = LockGuard.installNewLock(LockGuard.INDEX_STORAGE); 315 316 /** Set of users that we know are unlocked. */ 317 @GuardedBy("mLock") 318 private int[] mLocalUnlockedUsers = EmptyArray.INT; 319 /** Set of users that system knows are unlocked. */ 320 @GuardedBy("mLock") 321 private int[] mSystemUnlockedUsers = EmptyArray.INT; 322 323 /** Map from disk ID to disk */ 324 @GuardedBy("mLock") 325 private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>(); 326 /** Map from volume ID to disk */ 327 @GuardedBy("mLock") 328 private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>(); 329 330 /** Map from UUID to record */ 331 @GuardedBy("mLock") 332 private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>(); 333 @GuardedBy("mLock") 334 private String mPrimaryStorageUuid; 335 @GuardedBy("mLock") 336 private boolean mForceAdoptable; 337 338 /** Map from disk ID to latches */ 339 @GuardedBy("mLock") 340 private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>(); 341 342 @GuardedBy("mLock") 343 private IPackageMoveObserver mMoveCallback; 344 @GuardedBy("mLock") 345 private String mMoveTargetUuid; 346 347 private volatile int mCurrentUserId = UserHandle.USER_SYSTEM; 348 349 /** Holding lock for AppFuse business */ 350 private final Object mAppFuseLock = new Object(); 351 352 @GuardedBy("mAppFuseLock") 353 private int mNextAppFuseName = 0; 354 355 @GuardedBy("mAppFuseLock") 356 private AppFuseBridge mAppFuseBridge = null; 357 358 private VolumeInfo findVolumeByIdOrThrow(String id) { 359 synchronized (mLock) { 360 final VolumeInfo vol = mVolumes.get(id); 361 if (vol != null) { 362 return vol; 363 } 364 } 365 throw new IllegalArgumentException("No volume found for ID " + id); 366 } 367 368 private String findVolumeIdForPathOrThrow(String path) { 369 synchronized (mLock) { 370 for (int i = 0; i < mVolumes.size(); i++) { 371 final VolumeInfo vol = mVolumes.valueAt(i); 372 if (vol.path != null && path.startsWith(vol.path)) { 373 return vol.id; 374 } 375 } 376 } 377 throw new IllegalArgumentException("No volume found for path " + path); 378 } 379 380 private VolumeRecord findRecordForPath(String path) { 381 synchronized (mLock) { 382 for (int i = 0; i < mVolumes.size(); i++) { 383 final VolumeInfo vol = mVolumes.valueAt(i); 384 if (vol.path != null && path.startsWith(vol.path)) { 385 return mRecords.get(vol.fsUuid); 386 } 387 } 388 } 389 return null; 390 } 391 392 private String scrubPath(String path) { 393 if (path.startsWith(Environment.getDataDirectory().getAbsolutePath())) { 394 return "internal"; 395 } 396 final VolumeRecord rec = findRecordForPath(path); 397 if (rec == null || rec.createdMillis == 0) { 398 return "unknown"; 399 } else { 400 return "ext:" + (int) ((System.currentTimeMillis() - rec.createdMillis) 401 / DateUtils.WEEK_IN_MILLIS) + "w"; 402 } 403 } 404 405 private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) { 406 final StorageManager storage = mContext.getSystemService(StorageManager.class); 407 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) { 408 return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL); 409 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) { 410 return storage.getPrimaryPhysicalVolume(); 411 } else { 412 return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid)); 413 } 414 } 415 416 private boolean shouldBenchmark() { 417 final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(), 418 Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS); 419 if (benchInterval == -1) { 420 return false; 421 } else if (benchInterval == 0) { 422 return true; 423 } 424 425 synchronized (mLock) { 426 for (int i = 0; i < mVolumes.size(); i++) { 427 final VolumeInfo vol = mVolumes.valueAt(i); 428 final VolumeRecord rec = mRecords.get(vol.fsUuid); 429 if (vol.isMountedWritable() && rec != null) { 430 final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis; 431 if (benchAge >= benchInterval) { 432 return true; 433 } 434 } 435 } 436 return false; 437 } 438 } 439 440 private CountDownLatch findOrCreateDiskScanLatch(String diskId) { 441 synchronized (mLock) { 442 CountDownLatch latch = mDiskScanLatches.get(diskId); 443 if (latch == null) { 444 latch = new CountDownLatch(1); 445 mDiskScanLatches.put(diskId, latch); 446 } 447 return latch; 448 } 449 } 450 451 private static String escapeNull(String arg) { 452 if (TextUtils.isEmpty(arg)) { 453 return "!"; 454 } else { 455 if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) { 456 throw new IllegalArgumentException(arg); 457 } 458 return arg; 459 } 460 } 461 462 /** List of crypto types. 463 * These must match CRYPT_TYPE_XXX in cryptfs.h AND their 464 * corresponding commands in CommandListener.cpp */ 465 public static final String[] CRYPTO_TYPES 466 = { "password", "default", "pattern", "pin" }; 467 468 private final Context mContext; 469 470 private final NativeDaemonConnector mConnector; 471 private final NativeDaemonConnector mCryptConnector; 472 473 private final Thread mConnectorThread; 474 private final Thread mCryptConnectorThread; 475 476 private volatile boolean mSystemReady = false; 477 private volatile boolean mBootCompleted = false; 478 private volatile boolean mDaemonConnected = false; 479 480 private PackageManagerService mPms; 481 482 private final Callbacks mCallbacks; 483 private final LockPatternUtils mLockPatternUtils; 484 485 // Two connectors - mConnector & mCryptConnector 486 private final CountDownLatch mConnectedSignal = new CountDownLatch(2); 487 private final CountDownLatch mAsecsScanned = new CountDownLatch(1); 488 489 private final Object mUnmountLock = new Object(); 490 @GuardedBy("mUnmountLock") 491 private CountDownLatch mUnmountSignal; 492 493 /** 494 * Private hash of currently mounted secure containers. 495 * Used as a lock in methods to manipulate secure containers. 496 */ 497 final private HashSet<String> mAsecMountSet = new HashSet<String>(); 498 499 /** 500 * The size of the crypto algorithm key in bits for OBB files. Currently 501 * Twofish is used which takes 128-bit keys. 502 */ 503 private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128; 504 505 /** 506 * The number of times to run SHA1 in the PBKDF2 function for OBB files. 507 * 1024 is reasonably secure and not too slow. 508 */ 509 private static final int PBKDF2_HASH_ROUNDS = 1024; 510 511 /** 512 * Mounted OBB tracking information. Used to track the current state of all 513 * OBBs. 514 */ 515 final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>(); 516 517 /** Map from raw paths to {@link ObbState}. */ 518 final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>(); 519 520 // Not guarded by a lock. 521 private final StorageManagerInternalImpl mStorageManagerInternal 522 = new StorageManagerInternalImpl(); 523 524 class ObbState implements IBinder.DeathRecipient { 525 public ObbState(String rawPath, String canonicalPath, int callingUid, 526 IObbActionListener token, int nonce) { 527 this.rawPath = rawPath; 528 this.canonicalPath = canonicalPath; 529 530 this.ownerGid = UserHandle.getSharedAppGid(callingUid); 531 this.token = token; 532 this.nonce = nonce; 533 } 534 535 final String rawPath; 536 final String canonicalPath; 537 538 final int ownerGid; 539 540 // Token of remote Binder caller 541 final IObbActionListener token; 542 543 // Identifier to pass back to the token 544 final int nonce; 545 546 public IBinder getBinder() { 547 return token.asBinder(); 548 } 549 550 @Override 551 public void binderDied() { 552 ObbAction action = new UnmountObbAction(this, true); 553 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 554 } 555 556 public void link() throws RemoteException { 557 getBinder().linkToDeath(this, 0); 558 } 559 560 public void unlink() { 561 getBinder().unlinkToDeath(this, 0); 562 } 563 564 @Override 565 public String toString() { 566 StringBuilder sb = new StringBuilder("ObbState{"); 567 sb.append("rawPath=").append(rawPath); 568 sb.append(",canonicalPath=").append(canonicalPath); 569 sb.append(",ownerGid=").append(ownerGid); 570 sb.append(",token=").append(token); 571 sb.append(",binder=").append(getBinder()); 572 sb.append('}'); 573 return sb.toString(); 574 } 575 } 576 577 // OBB Action Handler 578 final private ObbActionHandler mObbActionHandler; 579 580 // OBB action handler messages 581 private static final int OBB_RUN_ACTION = 1; 582 private static final int OBB_MCS_BOUND = 2; 583 private static final int OBB_MCS_UNBIND = 3; 584 private static final int OBB_MCS_RECONNECT = 4; 585 private static final int OBB_FLUSH_MOUNT_STATE = 5; 586 587 /* 588 * Default Container Service information 589 */ 590 static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( 591 "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService"); 592 593 final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection(); 594 595 class DefaultContainerConnection implements ServiceConnection { 596 @Override 597 public void onServiceConnected(ComponentName name, IBinder service) { 598 if (DEBUG_OBB) 599 Slog.i(TAG, "onServiceConnected"); 600 IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service); 601 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs)); 602 } 603 604 @Override 605 public void onServiceDisconnected(ComponentName name) { 606 if (DEBUG_OBB) 607 Slog.i(TAG, "onServiceDisconnected"); 608 } 609 }; 610 611 // Used in the ObbActionHandler 612 private IMediaContainerService mContainerService = null; 613 614 // Last fstrim operation tracking 615 private static final String LAST_FSTRIM_FILE = "last-fstrim"; 616 private final File mLastMaintenanceFile; 617 private long mLastMaintenance; 618 619 // Handler messages 620 private static final int H_SYSTEM_READY = 1; 621 private static final int H_DAEMON_CONNECTED = 2; 622 private static final int H_SHUTDOWN = 3; 623 private static final int H_FSTRIM = 4; 624 private static final int H_VOLUME_MOUNT = 5; 625 private static final int H_VOLUME_BROADCAST = 6; 626 private static final int H_INTERNAL_BROADCAST = 7; 627 private static final int H_VOLUME_UNMOUNT = 8; 628 private static final int H_PARTITION_FORGET = 9; 629 private static final int H_RESET = 10; 630 631 class StorageManagerServiceHandler extends Handler { 632 public StorageManagerServiceHandler(Looper looper) { 633 super(looper); 634 } 635 636 @Override 637 public void handleMessage(Message msg) { 638 switch (msg.what) { 639 case H_SYSTEM_READY: { 640 handleSystemReady(); 641 break; 642 } 643 case H_DAEMON_CONNECTED: { 644 handleDaemonConnected(); 645 break; 646 } 647 case H_FSTRIM: { 648 if (!isReady()) { 649 Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again"); 650 sendMessageDelayed(obtainMessage(H_FSTRIM, msg.obj), 651 DateUtils.SECOND_IN_MILLIS); 652 break; 653 } 654 655 Slog.i(TAG, "Running fstrim idle maintenance"); 656 657 // Remember when we kicked it off 658 try { 659 mLastMaintenance = System.currentTimeMillis(); 660 mLastMaintenanceFile.setLastModified(mLastMaintenance); 661 } catch (Exception e) { 662 Slog.e(TAG, "Unable to record last fstrim!"); 663 } 664 665 final int flags = shouldBenchmark() ? StorageManager.FSTRIM_FLAG_BENCHMARK : 0; 666 fstrim(flags); 667 668 // invoke the completion callback, if any 669 // TODO: fstrim is non-blocking, so remove this useless callback 670 Runnable callback = (Runnable) msg.obj; 671 if (callback != null) { 672 callback.run(); 673 } 674 break; 675 } 676 case H_SHUTDOWN: { 677 final IStorageShutdownObserver obs = (IStorageShutdownObserver) msg.obj; 678 boolean success = false; 679 try { 680 success = mConnector.execute("volume", "shutdown").isClassOk(); 681 } catch (NativeDaemonConnectorException ignored) { 682 } 683 if (obs != null) { 684 try { 685 obs.onShutDownComplete(success ? 0 : -1); 686 } catch (RemoteException ignored) { 687 } 688 } 689 break; 690 } 691 case H_VOLUME_MOUNT: { 692 final VolumeInfo vol = (VolumeInfo) msg.obj; 693 if (isMountDisallowed(vol)) { 694 Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy"); 695 break; 696 } 697 try { 698 mConnector.execute("volume", "mount", vol.id, vol.mountFlags, 699 vol.mountUserId); 700 } catch (NativeDaemonConnectorException ignored) { 701 } 702 break; 703 } 704 case H_VOLUME_UNMOUNT: { 705 final VolumeInfo vol = (VolumeInfo) msg.obj; 706 unmount(vol.getId()); 707 break; 708 } 709 case H_VOLUME_BROADCAST: { 710 final StorageVolume userVol = (StorageVolume) msg.obj; 711 final String envState = userVol.getState(); 712 Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to " 713 + userVol.getOwner()); 714 715 final String action = VolumeInfo.getBroadcastForEnvironment(envState); 716 if (action != null) { 717 final Intent intent = new Intent(action, 718 Uri.fromFile(userVol.getPathFile())); 719 intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol); 720 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 721 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 722 mContext.sendBroadcastAsUser(intent, userVol.getOwner()); 723 } 724 break; 725 } 726 case H_INTERNAL_BROADCAST: { 727 // Internal broadcasts aimed at system components, not for 728 // third-party apps. 729 final Intent intent = (Intent) msg.obj; 730 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 731 android.Manifest.permission.WRITE_MEDIA_STORAGE); 732 break; 733 } 734 case H_PARTITION_FORGET: { 735 final String partGuid = (String) msg.obj; 736 forgetPartition(partGuid); 737 break; 738 } 739 case H_RESET: { 740 resetIfReadyAndConnected(); 741 break; 742 } 743 } 744 } 745 } 746 747 private final Handler mHandler; 748 749 private BroadcastReceiver mUserReceiver = new BroadcastReceiver() { 750 @Override 751 public void onReceive(Context context, Intent intent) { 752 final String action = intent.getAction(); 753 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 754 Preconditions.checkArgument(userId >= 0); 755 756 try { 757 if (Intent.ACTION_USER_ADDED.equals(action)) { 758 final UserManager um = mContext.getSystemService(UserManager.class); 759 final int userSerialNumber = um.getUserSerialNumber(userId); 760 mConnector.execute("volume", "user_added", userId, userSerialNumber); 761 } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 762 synchronized (mVolumes) { 763 final int size = mVolumes.size(); 764 for (int i = 0; i < size; i++) { 765 final VolumeInfo vol = mVolumes.valueAt(i); 766 if (vol.mountUserId == userId) { 767 vol.mountUserId = UserHandle.USER_NULL; 768 mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget(); 769 } 770 } 771 } 772 mConnector.execute("volume", "user_removed", userId); 773 } 774 } catch (NativeDaemonConnectorException e) { 775 Slog.w(TAG, "Failed to send user details to vold", e); 776 } 777 } 778 }; 779 780 @Override 781 public void waitForAsecScan() { 782 waitForLatch(mAsecsScanned, "mAsecsScanned"); 783 } 784 785 private void waitForReady() { 786 waitForLatch(mConnectedSignal, "mConnectedSignal"); 787 } 788 789 private void waitForLatch(CountDownLatch latch, String condition) { 790 try { 791 waitForLatch(latch, condition, -1); 792 } catch (TimeoutException ignored) { 793 } 794 } 795 796 private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis) 797 throws TimeoutException { 798 final long startMillis = SystemClock.elapsedRealtime(); 799 while (true) { 800 try { 801 if (latch.await(5000, TimeUnit.MILLISECONDS)) { 802 return; 803 } else { 804 Slog.w(TAG, "Thread " + Thread.currentThread().getName() 805 + " still waiting for " + condition + "..."); 806 } 807 } catch (InterruptedException e) { 808 Slog.w(TAG, "Interrupt while waiting for " + condition); 809 } 810 if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) { 811 throw new TimeoutException("Thread " + Thread.currentThread().getName() 812 + " gave up waiting for " + condition + " after " + timeoutMillis + "ms"); 813 } 814 } 815 } 816 817 private boolean isReady() { 818 try { 819 return mConnectedSignal.await(0, TimeUnit.MILLISECONDS); 820 } catch (InterruptedException e) { 821 return false; 822 } 823 } 824 825 private void handleSystemReady() { 826 initIfReadyAndConnected(); 827 resetIfReadyAndConnected(); 828 829 // Start scheduling nominally-daily fstrim operations 830 MountServiceIdler.scheduleIdlePass(mContext); 831 } 832 833 /** 834 * MediaProvider has a ton of code that makes assumptions about storage 835 * paths never changing, so we outright kill them to pick up new state. 836 */ 837 @Deprecated 838 private void killMediaProvider(List<UserInfo> users) { 839 if (users == null) return; 840 841 final long token = Binder.clearCallingIdentity(); 842 try { 843 for (UserInfo user : users) { 844 // System user does not have media provider, so skip. 845 if (user.isSystemOnly()) continue; 846 847 final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY, 848 PackageManager.MATCH_DIRECT_BOOT_AWARE 849 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 850 user.id); 851 if (provider != null) { 852 final IActivityManager am = ActivityManager.getService(); 853 try { 854 am.killApplication(provider.applicationInfo.packageName, 855 UserHandle.getAppId(provider.applicationInfo.uid), 856 UserHandle.USER_ALL, "vold reset"); 857 // We only need to run this once. It will kill all users' media processes. 858 break; 859 } catch (RemoteException e) { 860 } 861 } 862 } 863 } finally { 864 Binder.restoreCallingIdentity(token); 865 } 866 } 867 868 private void addInternalVolumeLocked() { 869 // Create a stub volume that represents internal storage 870 final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL, 871 VolumeInfo.TYPE_PRIVATE, null, null); 872 internal.state = VolumeInfo.STATE_MOUNTED; 873 internal.path = Environment.getDataDirectory().getAbsolutePath(); 874 mVolumes.put(internal.id, internal); 875 } 876 877 private void initIfReadyAndConnected() { 878 Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady 879 + ", mDaemonConnected=" + mDaemonConnected); 880 if (mSystemReady && mDaemonConnected 881 && !StorageManager.isFileEncryptedNativeOnly()) { 882 // When booting a device without native support, make sure that our 883 // user directories are locked or unlocked based on the current 884 // emulation status. 885 final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly(); 886 Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked); 887 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers(); 888 for (UserInfo user : users) { 889 try { 890 if (initLocked) { 891 mCryptConnector.execute("cryptfs", "lock_user_key", user.id); 892 } else { 893 mCryptConnector.execute("cryptfs", "unlock_user_key", user.id, 894 user.serialNumber, "!", "!"); 895 } 896 } catch (NativeDaemonConnectorException e) { 897 Slog.w(TAG, "Failed to init vold", e); 898 } 899 } 900 } 901 } 902 903 private void resetIfReadyAndConnected() { 904 Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady 905 + ", mDaemonConnected=" + mDaemonConnected); 906 if (mSystemReady && mDaemonConnected) { 907 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers(); 908 killMediaProvider(users); 909 910 final int[] systemUnlockedUsers; 911 synchronized (mLock) { 912 systemUnlockedUsers = mSystemUnlockedUsers; 913 914 mDisks.clear(); 915 mVolumes.clear(); 916 917 addInternalVolumeLocked(); 918 } 919 920 try { 921 mConnector.execute("volume", "reset"); 922 923 // Tell vold about all existing and started users 924 for (UserInfo user : users) { 925 mConnector.execute("volume", "user_added", user.id, user.serialNumber); 926 } 927 for (int userId : systemUnlockedUsers) { 928 mConnector.execute("volume", "user_started", userId); 929 } 930 } catch (NativeDaemonConnectorException e) { 931 Slog.w(TAG, "Failed to reset vold", e); 932 } 933 } 934 } 935 936 private void onUnlockUser(int userId) { 937 Slog.d(TAG, "onUnlockUser " + userId); 938 939 // We purposefully block here to make sure that user-specific 940 // staging area is ready so it's ready for zygote-forked apps to 941 // bind mount against. 942 try { 943 mConnector.execute("volume", "user_started", userId); 944 } catch (NativeDaemonConnectorException ignored) { 945 } 946 947 // Record user as started so newly mounted volumes kick off events 948 // correctly, then synthesize events for any already-mounted volumes. 949 synchronized (mLock) { 950 for (int i = 0; i < mVolumes.size(); i++) { 951 final VolumeInfo vol = mVolumes.valueAt(i); 952 if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) { 953 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false); 954 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget(); 955 956 final String envState = VolumeInfo.getEnvironmentForState(vol.getState()); 957 mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState); 958 } 959 } 960 mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId); 961 } 962 } 963 964 private void onCleanupUser(int userId) { 965 Slog.d(TAG, "onCleanupUser " + userId); 966 967 try { 968 mConnector.execute("volume", "user_stopped", userId); 969 } catch (NativeDaemonConnectorException ignored) { 970 } 971 972 synchronized (mLock) { 973 mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId); 974 } 975 } 976 977 void runIdleMaintenance(Runnable callback) { 978 mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback)); 979 } 980 981 // Binder entry point for kicking off an immediate fstrim 982 @Override 983 public void runMaintenance() { 984 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 985 runIdleMaintenance(null); 986 } 987 988 @Override 989 public long lastMaintenance() { 990 return mLastMaintenance; 991 } 992 993 /** 994 * Callback from NativeDaemonConnector 995 */ 996 @Override 997 public void onDaemonConnected() { 998 mDaemonConnected = true; 999 mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget(); 1000 } 1001 1002 private void handleDaemonConnected() { 1003 initIfReadyAndConnected(); 1004 resetIfReadyAndConnected(); 1005 1006 /* 1007 * Now that we've done our initialization, release 1008 * the hounds! 1009 */ 1010 mConnectedSignal.countDown(); 1011 if (mConnectedSignal.getCount() != 0) { 1012 // More daemons need to connect 1013 return; 1014 } 1015 1016 // On an encrypted device we can't see system properties yet, so pull 1017 // the system locale out of the mount service. 1018 if ("".equals(SystemProperties.get("vold.encrypt_progress"))) { 1019 copyLocaleFromMountService(); 1020 } 1021 1022 // Let package manager load internal ASECs. 1023 mPms.scanAvailableAsecs(); 1024 1025 // Notify people waiting for ASECs to be scanned that it's done. 1026 mAsecsScanned.countDown(); 1027 } 1028 1029 private void copyLocaleFromMountService() { 1030 String systemLocale; 1031 try { 1032 systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY); 1033 } catch (RemoteException e) { 1034 return; 1035 } 1036 if (TextUtils.isEmpty(systemLocale)) { 1037 return; 1038 } 1039 1040 Slog.d(TAG, "Got locale " + systemLocale + " from mount service"); 1041 Locale locale = Locale.forLanguageTag(systemLocale); 1042 Configuration config = new Configuration(); 1043 config.setLocale(locale); 1044 try { 1045 ActivityManager.getService().updatePersistentConfiguration(config); 1046 } catch (RemoteException e) { 1047 Slog.e(TAG, "Error setting system locale from mount service", e); 1048 } 1049 1050 // Temporary workaround for http://b/17945169. 1051 Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service"); 1052 SystemProperties.set("persist.sys.locale", locale.toLanguageTag()); 1053 } 1054 1055 /** 1056 * Callback from NativeDaemonConnector 1057 */ 1058 @Override 1059 public boolean onCheckHoldWakeLock(int code) { 1060 return false; 1061 } 1062 1063 /** 1064 * Callback from NativeDaemonConnector 1065 */ 1066 @Override 1067 public boolean onEvent(int code, String raw, String[] cooked) { 1068 synchronized (mLock) { 1069 return onEventLocked(code, raw, cooked); 1070 } 1071 } 1072 1073 private boolean onEventLocked(int code, String raw, String[] cooked) { 1074 switch (code) { 1075 case VoldResponseCode.DISK_CREATED: { 1076 if (cooked.length != 3) break; 1077 final String id = cooked[1]; 1078 int flags = Integer.parseInt(cooked[2]); 1079 if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false) 1080 || mForceAdoptable) { 1081 flags |= DiskInfo.FLAG_ADOPTABLE; 1082 } 1083 // Adoptable storage isn't currently supported on FBE devices 1084 if (StorageManager.isFileEncryptedNativeOnly()) { 1085 flags &= ~DiskInfo.FLAG_ADOPTABLE; 1086 } 1087 mDisks.put(id, new DiskInfo(id, flags)); 1088 break; 1089 } 1090 case VoldResponseCode.DISK_SIZE_CHANGED: { 1091 if (cooked.length != 3) break; 1092 final DiskInfo disk = mDisks.get(cooked[1]); 1093 if (disk != null) { 1094 disk.size = Long.parseLong(cooked[2]); 1095 } 1096 break; 1097 } 1098 case VoldResponseCode.DISK_LABEL_CHANGED: { 1099 final DiskInfo disk = mDisks.get(cooked[1]); 1100 if (disk != null) { 1101 final StringBuilder builder = new StringBuilder(); 1102 for (int i = 2; i < cooked.length; i++) { 1103 builder.append(cooked[i]).append(' '); 1104 } 1105 disk.label = builder.toString().trim(); 1106 } 1107 break; 1108 } 1109 case VoldResponseCode.DISK_SCANNED: { 1110 if (cooked.length != 2) break; 1111 final DiskInfo disk = mDisks.get(cooked[1]); 1112 if (disk != null) { 1113 onDiskScannedLocked(disk); 1114 } 1115 break; 1116 } 1117 case VoldResponseCode.DISK_SYS_PATH_CHANGED: { 1118 if (cooked.length != 3) break; 1119 final DiskInfo disk = mDisks.get(cooked[1]); 1120 if (disk != null) { 1121 disk.sysPath = cooked[2]; 1122 } 1123 break; 1124 } 1125 case VoldResponseCode.DISK_DESTROYED: { 1126 if (cooked.length != 2) break; 1127 final DiskInfo disk = mDisks.remove(cooked[1]); 1128 if (disk != null) { 1129 mCallbacks.notifyDiskDestroyed(disk); 1130 } 1131 break; 1132 } 1133 1134 case VoldResponseCode.VOLUME_CREATED: { 1135 final String id = cooked[1]; 1136 final int type = Integer.parseInt(cooked[2]); 1137 final String diskId = TextUtils.nullIfEmpty(cooked[3]); 1138 final String partGuid = TextUtils.nullIfEmpty(cooked[4]); 1139 1140 final DiskInfo disk = mDisks.get(diskId); 1141 final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid); 1142 mVolumes.put(id, vol); 1143 onVolumeCreatedLocked(vol); 1144 break; 1145 } 1146 case VoldResponseCode.VOLUME_STATE_CHANGED: { 1147 if (cooked.length != 3) break; 1148 final VolumeInfo vol = mVolumes.get(cooked[1]); 1149 if (vol != null) { 1150 final int oldState = vol.state; 1151 final int newState = Integer.parseInt(cooked[2]); 1152 vol.state = newState; 1153 onVolumeStateChangedLocked(vol, oldState, newState); 1154 } 1155 break; 1156 } 1157 case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: { 1158 if (cooked.length != 3) break; 1159 final VolumeInfo vol = mVolumes.get(cooked[1]); 1160 if (vol != null) { 1161 vol.fsType = cooked[2]; 1162 } 1163 break; 1164 } 1165 case VoldResponseCode.VOLUME_FS_UUID_CHANGED: { 1166 if (cooked.length != 3) break; 1167 final VolumeInfo vol = mVolumes.get(cooked[1]); 1168 if (vol != null) { 1169 vol.fsUuid = cooked[2]; 1170 } 1171 break; 1172 } 1173 case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: { 1174 final VolumeInfo vol = mVolumes.get(cooked[1]); 1175 if (vol != null) { 1176 final StringBuilder builder = new StringBuilder(); 1177 for (int i = 2; i < cooked.length; i++) { 1178 builder.append(cooked[i]).append(' '); 1179 } 1180 vol.fsLabel = builder.toString().trim(); 1181 } 1182 // TODO: notify listeners that label changed 1183 break; 1184 } 1185 case VoldResponseCode.VOLUME_PATH_CHANGED: { 1186 if (cooked.length != 3) break; 1187 final VolumeInfo vol = mVolumes.get(cooked[1]); 1188 if (vol != null) { 1189 vol.path = cooked[2]; 1190 } 1191 break; 1192 } 1193 case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: { 1194 if (cooked.length != 3) break; 1195 final VolumeInfo vol = mVolumes.get(cooked[1]); 1196 if (vol != null) { 1197 vol.internalPath = cooked[2]; 1198 } 1199 break; 1200 } 1201 case VoldResponseCode.VOLUME_DESTROYED: { 1202 if (cooked.length != 2) break; 1203 mVolumes.remove(cooked[1]); 1204 break; 1205 } 1206 1207 case VoldResponseCode.MOVE_STATUS: { 1208 final int status = Integer.parseInt(cooked[1]); 1209 onMoveStatusLocked(status); 1210 break; 1211 } 1212 case VoldResponseCode.BENCHMARK_RESULT: { 1213 if (cooked.length != 7) break; 1214 final String path = cooked[1]; 1215 final String ident = cooked[2]; 1216 final long create = Long.parseLong(cooked[3]); 1217 final long drop = Long.parseLong(cooked[4]); 1218 final long run = Long.parseLong(cooked[5]); 1219 final long destroy = Long.parseLong(cooked[6]); 1220 1221 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class); 1222 dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path) 1223 + " " + ident + " " + create + " " + run + " " + destroy); 1224 1225 final VolumeRecord rec = findRecordForPath(path); 1226 if (rec != null) { 1227 rec.lastBenchMillis = System.currentTimeMillis(); 1228 writeSettingsLocked(); 1229 } 1230 1231 break; 1232 } 1233 case VoldResponseCode.TRIM_RESULT: { 1234 if (cooked.length != 4) break; 1235 final String path = cooked[1]; 1236 final long bytes = Long.parseLong(cooked[2]); 1237 final long time = Long.parseLong(cooked[3]); 1238 1239 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class); 1240 dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path) 1241 + " " + bytes + " " + time); 1242 1243 final VolumeRecord rec = findRecordForPath(path); 1244 if (rec != null) { 1245 rec.lastTrimMillis = System.currentTimeMillis(); 1246 writeSettingsLocked(); 1247 } 1248 1249 break; 1250 } 1251 1252 default: { 1253 Slog.d(TAG, "Unhandled vold event " + code); 1254 } 1255 } 1256 1257 return true; 1258 } 1259 1260 private void onDiskScannedLocked(DiskInfo disk) { 1261 int volumeCount = 0; 1262 for (int i = 0; i < mVolumes.size(); i++) { 1263 final VolumeInfo vol = mVolumes.valueAt(i); 1264 if (Objects.equals(disk.id, vol.getDiskId())) { 1265 volumeCount++; 1266 } 1267 } 1268 1269 final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED); 1270 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 1271 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1272 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id); 1273 intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount); 1274 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget(); 1275 1276 final CountDownLatch latch = mDiskScanLatches.remove(disk.id); 1277 if (latch != null) { 1278 latch.countDown(); 1279 } 1280 1281 disk.volumeCount = volumeCount; 1282 mCallbacks.notifyDiskScanned(disk, volumeCount); 1283 } 1284 1285 private void onVolumeCreatedLocked(VolumeInfo vol) { 1286 if (mPms.isOnlyCoreApps()) { 1287 Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId()); 1288 return; 1289 } 1290 1291 if (vol.type == VolumeInfo.TYPE_EMULATED) { 1292 final StorageManager storage = mContext.getSystemService(StorageManager.class); 1293 final VolumeInfo privateVol = storage.findPrivateForEmulated(vol); 1294 1295 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid) 1296 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) { 1297 Slog.v(TAG, "Found primary storage at " + vol); 1298 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY; 1299 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE; 1300 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); 1301 1302 } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) { 1303 Slog.v(TAG, "Found primary storage at " + vol); 1304 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY; 1305 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE; 1306 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); 1307 } 1308 1309 } else if (vol.type == VolumeInfo.TYPE_PUBLIC) { 1310 // TODO: only look at first public partition 1311 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid) 1312 && vol.disk.isDefaultPrimary()) { 1313 Slog.v(TAG, "Found primary storage at " + vol); 1314 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY; 1315 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE; 1316 } 1317 1318 // Adoptable public disks are visible to apps, since they meet 1319 // public API requirement of being in a stable location. 1320 if (vol.disk.isAdoptable()) { 1321 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE; 1322 } 1323 1324 vol.mountUserId = mCurrentUserId; 1325 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); 1326 1327 } else if (vol.type == VolumeInfo.TYPE_PRIVATE) { 1328 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); 1329 1330 } else { 1331 Slog.d(TAG, "Skipping automatic mounting of " + vol); 1332 } 1333 } 1334 1335 private boolean isBroadcastWorthy(VolumeInfo vol) { 1336 switch (vol.getType()) { 1337 case VolumeInfo.TYPE_PRIVATE: 1338 case VolumeInfo.TYPE_PUBLIC: 1339 case VolumeInfo.TYPE_EMULATED: 1340 break; 1341 default: 1342 return false; 1343 } 1344 1345 switch (vol.getState()) { 1346 case VolumeInfo.STATE_MOUNTED: 1347 case VolumeInfo.STATE_MOUNTED_READ_ONLY: 1348 case VolumeInfo.STATE_EJECTING: 1349 case VolumeInfo.STATE_UNMOUNTED: 1350 case VolumeInfo.STATE_UNMOUNTABLE: 1351 case VolumeInfo.STATE_BAD_REMOVAL: 1352 break; 1353 default: 1354 return false; 1355 } 1356 1357 return true; 1358 } 1359 1360 private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) { 1361 // Remember that we saw this volume so we're ready to accept user 1362 // metadata, or so we can annoy them when a private volume is ejected 1363 if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) { 1364 VolumeRecord rec = mRecords.get(vol.fsUuid); 1365 if (rec == null) { 1366 rec = new VolumeRecord(vol.type, vol.fsUuid); 1367 rec.partGuid = vol.partGuid; 1368 rec.createdMillis = System.currentTimeMillis(); 1369 if (vol.type == VolumeInfo.TYPE_PRIVATE) { 1370 rec.nickname = vol.disk.getDescription(); 1371 } 1372 mRecords.put(rec.fsUuid, rec); 1373 writeSettingsLocked(); 1374 } else { 1375 // Handle upgrade case where we didn't store partition GUID 1376 if (TextUtils.isEmpty(rec.partGuid)) { 1377 rec.partGuid = vol.partGuid; 1378 writeSettingsLocked(); 1379 } 1380 } 1381 } 1382 1383 mCallbacks.notifyVolumeStateChanged(vol, oldState, newState); 1384 1385 // Do not broadcast before boot has completed to avoid launching the 1386 // processes that receive the intent unnecessarily. 1387 if (mBootCompleted && isBroadcastWorthy(vol)) { 1388 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED); 1389 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id); 1390 intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState); 1391 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid); 1392 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 1393 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1394 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget(); 1395 } 1396 1397 final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState); 1398 final String newStateEnv = VolumeInfo.getEnvironmentForState(newState); 1399 1400 if (!Objects.equals(oldStateEnv, newStateEnv)) { 1401 // Kick state changed event towards all started users. Any users 1402 // started after this point will trigger additional 1403 // user-specific broadcasts. 1404 for (int userId : mSystemUnlockedUsers) { 1405 if (vol.isVisibleForRead(userId)) { 1406 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false); 1407 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget(); 1408 1409 mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv, 1410 newStateEnv); 1411 } 1412 } 1413 } 1414 1415 if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) { 1416 // TODO: this should eventually be handled by new ObbVolume state changes 1417 /* 1418 * Some OBBs might have been unmounted when this volume was 1419 * unmounted, so send a message to the handler to let it know to 1420 * remove those from the list of mounted OBBS. 1421 */ 1422 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage( 1423 OBB_FLUSH_MOUNT_STATE, vol.path)); 1424 } 1425 } 1426 1427 private void onMoveStatusLocked(int status) { 1428 if (mMoveCallback == null) { 1429 Slog.w(TAG, "Odd, status but no move requested"); 1430 return; 1431 } 1432 1433 // TODO: estimate remaining time 1434 try { 1435 mMoveCallback.onStatusChanged(-1, status, -1); 1436 } catch (RemoteException ignored) { 1437 } 1438 1439 // We've finished copying and we're about to clean up old data, so 1440 // remember that move was successful if we get rebooted 1441 if (status == MOVE_STATUS_COPY_FINISHED) { 1442 Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting"); 1443 1444 mPrimaryStorageUuid = mMoveTargetUuid; 1445 writeSettingsLocked(); 1446 } 1447 1448 if (PackageManager.isMoveStatusFinished(status)) { 1449 Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status); 1450 1451 mMoveCallback = null; 1452 mMoveTargetUuid = null; 1453 } 1454 } 1455 1456 private void enforcePermission(String perm) { 1457 mContext.enforceCallingOrSelfPermission(perm, perm); 1458 } 1459 1460 /** 1461 * Decide if volume is mountable per device policies. 1462 */ 1463 private boolean isMountDisallowed(VolumeInfo vol) { 1464 UserManager userManager = mContext.getSystemService(UserManager.class); 1465 1466 boolean isUsbRestricted = false; 1467 if (vol.disk != null && vol.disk.isUsb()) { 1468 isUsbRestricted = userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER, 1469 Binder.getCallingUserHandle()); 1470 } 1471 1472 boolean isTypeRestricted = false; 1473 if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) { 1474 isTypeRestricted = userManager 1475 .hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, 1476 Binder.getCallingUserHandle()); 1477 } 1478 1479 return isUsbRestricted || isTypeRestricted; 1480 } 1481 1482 private void enforceAdminUser() { 1483 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 1484 final int callingUserId = UserHandle.getCallingUserId(); 1485 boolean isAdmin; 1486 long token = Binder.clearCallingIdentity(); 1487 try { 1488 isAdmin = um.getUserInfo(callingUserId).isAdmin(); 1489 } finally { 1490 Binder.restoreCallingIdentity(token); 1491 } 1492 if (!isAdmin) { 1493 throw new SecurityException("Only admin users can adopt sd cards"); 1494 } 1495 } 1496 1497 /** 1498 * Constructs a new StorageManagerService instance 1499 * 1500 * @param context Binder context for this service 1501 */ 1502 public StorageManagerService(Context context) { 1503 sSelf = this; 1504 1505 mContext = context; 1506 mCallbacks = new Callbacks(FgThread.get().getLooper()); 1507 mLockPatternUtils = new LockPatternUtils(mContext); 1508 1509 // XXX: This will go away soon in favor of IMountServiceObserver 1510 mPms = (PackageManagerService) ServiceManager.getService("package"); 1511 1512 HandlerThread hthread = new HandlerThread(TAG); 1513 hthread.start(); 1514 mHandler = new StorageManagerServiceHandler(hthread.getLooper()); 1515 1516 // Add OBB Action Handler to StorageManagerService thread. 1517 mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper()); 1518 1519 // Initialize the last-fstrim tracking if necessary 1520 File dataDir = Environment.getDataDirectory(); 1521 File systemDir = new File(dataDir, "system"); 1522 mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE); 1523 if (!mLastMaintenanceFile.exists()) { 1524 // Not setting mLastMaintenance here means that we will force an 1525 // fstrim during reboot following the OTA that installs this code. 1526 try { 1527 (new FileOutputStream(mLastMaintenanceFile)).close(); 1528 } catch (IOException e) { 1529 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath()); 1530 } 1531 } else { 1532 mLastMaintenance = mLastMaintenanceFile.lastModified(); 1533 } 1534 1535 mSettingsFile = new AtomicFile( 1536 new File(Environment.getDataSystemDirectory(), "storage.xml")); 1537 1538 synchronized (mLock) { 1539 readSettingsLocked(); 1540 } 1541 1542 LocalServices.addService(StorageManagerInternal.class, mStorageManagerInternal); 1543 1544 /* 1545 * Create the connection to vold with a maximum queue of twice the 1546 * amount of containers we'd ever expect to have. This keeps an 1547 * "asec list" from blocking a thread repeatedly. 1548 */ 1549 1550 mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25, 1551 null); 1552 mConnector.setDebug(true); 1553 mConnector.setWarnIfHeld(mLock); 1554 mConnectorThread = new Thread(mConnector, VOLD_TAG); 1555 1556 // Reuse parameters from first connector since they are tested and safe 1557 mCryptConnector = new NativeDaemonConnector(this, "cryptd", 1558 MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null); 1559 mCryptConnector.setDebug(true); 1560 mCryptConnectorThread = new Thread(mCryptConnector, CRYPTD_TAG); 1561 1562 final IntentFilter userFilter = new IntentFilter(); 1563 userFilter.addAction(Intent.ACTION_USER_ADDED); 1564 userFilter.addAction(Intent.ACTION_USER_REMOVED); 1565 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler); 1566 1567 synchronized (mLock) { 1568 addInternalVolumeLocked(); 1569 } 1570 1571 // Add ourself to the Watchdog monitors if enabled. 1572 if (WATCHDOG_ENABLE) { 1573 Watchdog.getInstance().addMonitor(this); 1574 } 1575 } 1576 1577 private void start() { 1578 mConnectorThread.start(); 1579 mCryptConnectorThread.start(); 1580 } 1581 1582 private void systemReady() { 1583 mSystemReady = true; 1584 mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget(); 1585 } 1586 1587 private void bootCompleted() { 1588 mBootCompleted = true; 1589 } 1590 1591 private String getDefaultPrimaryStorageUuid() { 1592 if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) { 1593 return StorageManager.UUID_PRIMARY_PHYSICAL; 1594 } else { 1595 return StorageManager.UUID_PRIVATE_INTERNAL; 1596 } 1597 } 1598 1599 private void readSettingsLocked() { 1600 mRecords.clear(); 1601 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid(); 1602 mForceAdoptable = false; 1603 1604 FileInputStream fis = null; 1605 try { 1606 fis = mSettingsFile.openRead(); 1607 final XmlPullParser in = Xml.newPullParser(); 1608 in.setInput(fis, StandardCharsets.UTF_8.name()); 1609 1610 int type; 1611 while ((type = in.next()) != END_DOCUMENT) { 1612 if (type == START_TAG) { 1613 final String tag = in.getName(); 1614 if (TAG_VOLUMES.equals(tag)) { 1615 final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT); 1616 final boolean primaryPhysical = SystemProperties.getBoolean( 1617 StorageManager.PROP_PRIMARY_PHYSICAL, false); 1618 final boolean validAttr = (version >= VERSION_FIX_PRIMARY) 1619 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical); 1620 if (validAttr) { 1621 mPrimaryStorageUuid = readStringAttribute(in, 1622 ATTR_PRIMARY_STORAGE_UUID); 1623 } 1624 mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false); 1625 1626 } else if (TAG_VOLUME.equals(tag)) { 1627 final VolumeRecord rec = readVolumeRecord(in); 1628 mRecords.put(rec.fsUuid, rec); 1629 } 1630 } 1631 } 1632 } catch (FileNotFoundException e) { 1633 // Missing metadata is okay, probably first boot 1634 } catch (IOException e) { 1635 Slog.wtf(TAG, "Failed reading metadata", e); 1636 } catch (XmlPullParserException e) { 1637 Slog.wtf(TAG, "Failed reading metadata", e); 1638 } finally { 1639 IoUtils.closeQuietly(fis); 1640 } 1641 } 1642 1643 private void writeSettingsLocked() { 1644 FileOutputStream fos = null; 1645 try { 1646 fos = mSettingsFile.startWrite(); 1647 1648 XmlSerializer out = new FastXmlSerializer(); 1649 out.setOutput(fos, StandardCharsets.UTF_8.name()); 1650 out.startDocument(null, true); 1651 out.startTag(null, TAG_VOLUMES); 1652 writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY); 1653 writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid); 1654 writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable); 1655 final int size = mRecords.size(); 1656 for (int i = 0; i < size; i++) { 1657 final VolumeRecord rec = mRecords.valueAt(i); 1658 writeVolumeRecord(out, rec); 1659 } 1660 out.endTag(null, TAG_VOLUMES); 1661 out.endDocument(); 1662 1663 mSettingsFile.finishWrite(fos); 1664 } catch (IOException e) { 1665 if (fos != null) { 1666 mSettingsFile.failWrite(fos); 1667 } 1668 } 1669 } 1670 1671 public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException { 1672 final int type = readIntAttribute(in, ATTR_TYPE); 1673 final String fsUuid = readStringAttribute(in, ATTR_FS_UUID); 1674 final VolumeRecord meta = new VolumeRecord(type, fsUuid); 1675 meta.partGuid = readStringAttribute(in, ATTR_PART_GUID); 1676 meta.nickname = readStringAttribute(in, ATTR_NICKNAME); 1677 meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS); 1678 meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS); 1679 meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS); 1680 meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS); 1681 return meta; 1682 } 1683 1684 public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException { 1685 out.startTag(null, TAG_VOLUME); 1686 writeIntAttribute(out, ATTR_TYPE, rec.type); 1687 writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid); 1688 writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid); 1689 writeStringAttribute(out, ATTR_NICKNAME, rec.nickname); 1690 writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags); 1691 writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis); 1692 writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis); 1693 writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis); 1694 out.endTag(null, TAG_VOLUME); 1695 } 1696 1697 /** 1698 * Exposed API calls below here 1699 */ 1700 1701 @Override 1702 public void registerListener(IStorageEventListener listener) { 1703 mCallbacks.register(listener); 1704 } 1705 1706 @Override 1707 public void unregisterListener(IStorageEventListener listener) { 1708 mCallbacks.unregister(listener); 1709 } 1710 1711 @Override 1712 public void shutdown(final IStorageShutdownObserver observer) { 1713 enforcePermission(android.Manifest.permission.SHUTDOWN); 1714 1715 Slog.i(TAG, "Shutting down"); 1716 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget(); 1717 } 1718 1719 @Override 1720 public boolean isUsbMassStorageConnected() { 1721 throw new UnsupportedOperationException(); 1722 } 1723 1724 @Override 1725 public void setUsbMassStorageEnabled(boolean enable) { 1726 throw new UnsupportedOperationException(); 1727 } 1728 1729 @Override 1730 public boolean isUsbMassStorageEnabled() { 1731 throw new UnsupportedOperationException(); 1732 } 1733 1734 @Override 1735 public String getVolumeState(String mountPoint) { 1736 throw new UnsupportedOperationException(); 1737 } 1738 1739 @Override 1740 public boolean isExternalStorageEmulated() { 1741 throw new UnsupportedOperationException(); 1742 } 1743 1744 @Override 1745 public int mountVolume(String path) { 1746 mount(findVolumeIdForPathOrThrow(path)); 1747 return 0; 1748 } 1749 1750 @Override 1751 public void unmountVolume(String path, boolean force, boolean removeEncryption) { 1752 unmount(findVolumeIdForPathOrThrow(path)); 1753 } 1754 1755 @Override 1756 public int formatVolume(String path) { 1757 format(findVolumeIdForPathOrThrow(path)); 1758 return 0; 1759 } 1760 1761 @Override 1762 public void mount(String volId) { 1763 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1764 waitForReady(); 1765 1766 final VolumeInfo vol = findVolumeByIdOrThrow(volId); 1767 if (isMountDisallowed(vol)) { 1768 throw new SecurityException("Mounting " + volId + " restricted by policy"); 1769 } 1770 try { 1771 mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId); 1772 } catch (NativeDaemonConnectorException e) { 1773 throw e.rethrowAsParcelableException(); 1774 } 1775 } 1776 1777 @Override 1778 public void unmount(String volId) { 1779 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1780 waitForReady(); 1781 1782 final VolumeInfo vol = findVolumeByIdOrThrow(volId); 1783 1784 // TODO: expand PMS to know about multiple volumes 1785 if (vol.isPrimaryPhysical()) { 1786 final long ident = Binder.clearCallingIdentity(); 1787 try { 1788 synchronized (mUnmountLock) { 1789 mUnmountSignal = new CountDownLatch(1); 1790 mPms.updateExternalMediaStatus(false, true); 1791 waitForLatch(mUnmountSignal, "mUnmountSignal"); 1792 mUnmountSignal = null; 1793 } 1794 } finally { 1795 Binder.restoreCallingIdentity(ident); 1796 } 1797 } 1798 1799 try { 1800 mConnector.execute("volume", "unmount", vol.id); 1801 } catch (NativeDaemonConnectorException e) { 1802 throw e.rethrowAsParcelableException(); 1803 } 1804 } 1805 1806 @Override 1807 public void format(String volId) { 1808 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); 1809 waitForReady(); 1810 1811 final VolumeInfo vol = findVolumeByIdOrThrow(volId); 1812 try { 1813 mConnector.execute("volume", "format", vol.id, "auto"); 1814 } catch (NativeDaemonConnectorException e) { 1815 throw e.rethrowAsParcelableException(); 1816 } 1817 } 1818 1819 @Override 1820 public long benchmark(String volId) { 1821 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); 1822 waitForReady(); 1823 1824 try { 1825 // TODO: make benchmark async so we don't block other commands 1826 final NativeDaemonEvent res = mConnector.execute(3 * DateUtils.MINUTE_IN_MILLIS, 1827 "volume", "benchmark", volId); 1828 return Long.parseLong(res.getMessage()); 1829 } catch (NativeDaemonTimeoutException e) { 1830 return Long.MAX_VALUE; 1831 } catch (NativeDaemonConnectorException e) { 1832 throw e.rethrowAsParcelableException(); 1833 } 1834 } 1835 1836 @Override 1837 public void partitionPublic(String diskId) { 1838 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); 1839 waitForReady(); 1840 1841 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId); 1842 try { 1843 mConnector.execute("volume", "partition", diskId, "public"); 1844 waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS); 1845 } catch (NativeDaemonConnectorException e) { 1846 throw e.rethrowAsParcelableException(); 1847 } catch (TimeoutException e) { 1848 throw new IllegalStateException(e); 1849 } 1850 } 1851 1852 @Override 1853 public void partitionPrivate(String diskId) { 1854 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); 1855 enforceAdminUser(); 1856 waitForReady(); 1857 1858 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId); 1859 try { 1860 mConnector.execute("volume", "partition", diskId, "private"); 1861 waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS); 1862 } catch (NativeDaemonConnectorException e) { 1863 throw e.rethrowAsParcelableException(); 1864 } catch (TimeoutException e) { 1865 throw new IllegalStateException(e); 1866 } 1867 } 1868 1869 @Override 1870 public void partitionMixed(String diskId, int ratio) { 1871 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); 1872 enforceAdminUser(); 1873 waitForReady(); 1874 1875 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId); 1876 try { 1877 mConnector.execute("volume", "partition", diskId, "mixed", ratio); 1878 waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS); 1879 } catch (NativeDaemonConnectorException e) { 1880 throw e.rethrowAsParcelableException(); 1881 } catch (TimeoutException e) { 1882 throw new IllegalStateException(e); 1883 } 1884 } 1885 1886 @Override 1887 public void setVolumeNickname(String fsUuid, String nickname) { 1888 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1889 waitForReady(); 1890 1891 Preconditions.checkNotNull(fsUuid); 1892 synchronized (mLock) { 1893 final VolumeRecord rec = mRecords.get(fsUuid); 1894 rec.nickname = nickname; 1895 mCallbacks.notifyVolumeRecordChanged(rec); 1896 writeSettingsLocked(); 1897 } 1898 } 1899 1900 @Override 1901 public void setVolumeUserFlags(String fsUuid, int flags, int mask) { 1902 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1903 waitForReady(); 1904 1905 Preconditions.checkNotNull(fsUuid); 1906 synchronized (mLock) { 1907 final VolumeRecord rec = mRecords.get(fsUuid); 1908 rec.userFlags = (rec.userFlags & ~mask) | (flags & mask); 1909 mCallbacks.notifyVolumeRecordChanged(rec); 1910 writeSettingsLocked(); 1911 } 1912 } 1913 1914 @Override 1915 public void forgetVolume(String fsUuid) { 1916 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1917 waitForReady(); 1918 1919 Preconditions.checkNotNull(fsUuid); 1920 1921 synchronized (mLock) { 1922 final VolumeRecord rec = mRecords.remove(fsUuid); 1923 if (rec != null && !TextUtils.isEmpty(rec.partGuid)) { 1924 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget(); 1925 } 1926 mCallbacks.notifyVolumeForgotten(fsUuid); 1927 1928 // If this had been primary storage, revert back to internal and 1929 // reset vold so we bind into new volume into place. 1930 if (Objects.equals(mPrimaryStorageUuid, fsUuid)) { 1931 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid(); 1932 mHandler.obtainMessage(H_RESET).sendToTarget(); 1933 } 1934 1935 writeSettingsLocked(); 1936 } 1937 } 1938 1939 @Override 1940 public void forgetAllVolumes() { 1941 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1942 waitForReady(); 1943 1944 synchronized (mLock) { 1945 for (int i = 0; i < mRecords.size(); i++) { 1946 final String fsUuid = mRecords.keyAt(i); 1947 final VolumeRecord rec = mRecords.valueAt(i); 1948 if (!TextUtils.isEmpty(rec.partGuid)) { 1949 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget(); 1950 } 1951 mCallbacks.notifyVolumeForgotten(fsUuid); 1952 } 1953 mRecords.clear(); 1954 1955 if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) { 1956 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid(); 1957 } 1958 1959 writeSettingsLocked(); 1960 mHandler.obtainMessage(H_RESET).sendToTarget(); 1961 } 1962 } 1963 1964 private void forgetPartition(String partGuid) { 1965 try { 1966 mConnector.execute("volume", "forget_partition", partGuid); 1967 } catch (NativeDaemonConnectorException e) { 1968 Slog.w(TAG, "Failed to forget key for " + partGuid + ": " + e); 1969 } 1970 } 1971 1972 @Override 1973 public void fstrim(int flags) { 1974 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); 1975 waitForReady(); 1976 1977 String cmd; 1978 if ((flags & StorageManager.FSTRIM_FLAG_DEEP) != 0) { 1979 cmd = "dodtrim"; 1980 } else { 1981 cmd = "dotrim"; 1982 } 1983 if ((flags & StorageManager.FSTRIM_FLAG_BENCHMARK) != 0) { 1984 cmd += "bench"; 1985 } 1986 1987 try { 1988 mConnector.execute("fstrim", cmd); 1989 } catch (NativeDaemonConnectorException e) { 1990 Slog.e(TAG, "Failed to run fstrim: " + e); 1991 } 1992 } 1993 1994 private void remountUidExternalStorage(int uid, int mode) { 1995 waitForReady(); 1996 1997 String modeName = "none"; 1998 switch (mode) { 1999 case Zygote.MOUNT_EXTERNAL_DEFAULT: { 2000 modeName = "default"; 2001 } break; 2002 2003 case Zygote.MOUNT_EXTERNAL_READ: { 2004 modeName = "read"; 2005 } break; 2006 2007 case Zygote.MOUNT_EXTERNAL_WRITE: { 2008 modeName = "write"; 2009 } break; 2010 } 2011 2012 try { 2013 mConnector.execute("volume", "remount_uid", uid, modeName); 2014 } catch (NativeDaemonConnectorException e) { 2015 Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e); 2016 } 2017 } 2018 2019 @Override 2020 public void setDebugFlags(int flags, int mask) { 2021 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 2022 waitForReady(); 2023 2024 if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) { 2025 if (!EMULATE_FBE_SUPPORTED) { 2026 throw new IllegalStateException( 2027 "Emulation not supported on this device"); 2028 } 2029 if (StorageManager.isFileEncryptedNativeOnly()) { 2030 throw new IllegalStateException( 2031 "Emulation not supported on device with native FBE"); 2032 } 2033 if (mLockPatternUtils.isCredentialRequiredToDecrypt(false)) { 2034 throw new IllegalStateException( 2035 "Emulation requires disabling 'Secure start-up' in Settings > Security"); 2036 } 2037 2038 final long token = Binder.clearCallingIdentity(); 2039 try { 2040 final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0; 2041 SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe)); 2042 2043 // Perform hard reboot to kick policy into place 2044 mContext.getSystemService(PowerManager.class).reboot(null); 2045 } finally { 2046 Binder.restoreCallingIdentity(token); 2047 } 2048 } 2049 2050 if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) { 2051 if (StorageManager.isFileEncryptedNativeOnly()) { 2052 throw new IllegalStateException( 2053 "Adoptable storage not available on device with native FBE"); 2054 } 2055 2056 synchronized (mLock) { 2057 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0; 2058 2059 writeSettingsLocked(); 2060 mHandler.obtainMessage(H_RESET).sendToTarget(); 2061 } 2062 } 2063 2064 if ((mask & (StorageManager.DEBUG_SDCARDFS_FORCE_ON 2065 | StorageManager.DEBUG_SDCARDFS_FORCE_OFF)) != 0) { 2066 final String value; 2067 if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_ON) != 0) { 2068 value = "force_on"; 2069 } else if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_OFF) != 0) { 2070 value = "force_off"; 2071 } else { 2072 value = ""; 2073 } 2074 2075 final long token = Binder.clearCallingIdentity(); 2076 try { 2077 SystemProperties.set(StorageManager.PROP_SDCARDFS, value); 2078 2079 // Reset storage to kick new setting into place 2080 mHandler.obtainMessage(H_RESET).sendToTarget(); 2081 } finally { 2082 Binder.restoreCallingIdentity(token); 2083 } 2084 } 2085 2086 if ((mask & StorageManager.DEBUG_VIRTUAL_DISK) != 0) { 2087 final boolean enabled = (flags & StorageManager.DEBUG_VIRTUAL_DISK) != 0; 2088 2089 final long token = Binder.clearCallingIdentity(); 2090 try { 2091 SystemProperties.set(StorageManager.PROP_VIRTUAL_DISK, Boolean.toString(enabled)); 2092 2093 // Reset storage to kick new setting into place 2094 mHandler.obtainMessage(H_RESET).sendToTarget(); 2095 } finally { 2096 Binder.restoreCallingIdentity(token); 2097 } 2098 } 2099 } 2100 2101 @Override 2102 public String getPrimaryStorageUuid() { 2103 synchronized (mLock) { 2104 return mPrimaryStorageUuid; 2105 } 2106 } 2107 2108 @Override 2109 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) { 2110 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 2111 waitForReady(); 2112 2113 final VolumeInfo from; 2114 final VolumeInfo to; 2115 2116 synchronized (mLock) { 2117 if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) { 2118 throw new IllegalArgumentException("Primary storage already at " + volumeUuid); 2119 } 2120 2121 if (mMoveCallback != null) { 2122 throw new IllegalStateException("Move already in progress"); 2123 } 2124 mMoveCallback = callback; 2125 mMoveTargetUuid = volumeUuid; 2126 2127 // When moving to/from primary physical volume, we probably just nuked 2128 // the current storage location, so we have nothing to move. 2129 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid) 2130 || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) { 2131 Slog.d(TAG, "Skipping move to/from primary physical"); 2132 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED); 2133 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED); 2134 mHandler.obtainMessage(H_RESET).sendToTarget(); 2135 return; 2136 2137 } else { 2138 from = findStorageForUuid(mPrimaryStorageUuid); 2139 to = findStorageForUuid(volumeUuid); 2140 2141 if (from == null) { 2142 Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid); 2143 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR); 2144 return; 2145 } else if (to == null) { 2146 Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid); 2147 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR); 2148 return; 2149 } 2150 } 2151 } 2152 2153 try { 2154 mConnector.execute("volume", "move_storage", from.id, to.id); 2155 } catch (NativeDaemonConnectorException e) { 2156 throw e.rethrowAsParcelableException(); 2157 } 2158 } 2159 2160 @Override 2161 public int[] getStorageUsers(String path) { 2162 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 2163 waitForReady(); 2164 try { 2165 final String[] r = NativeDaemonEvent.filterMessageList( 2166 mConnector.executeForList("storage", "users", path), 2167 VoldResponseCode.StorageUsersListResult); 2168 2169 // FMT: <pid> <process name> 2170 int[] data = new int[r.length]; 2171 for (int i = 0; i < r.length; i++) { 2172 String[] tok = r[i].split(" "); 2173 try { 2174 data[i] = Integer.parseInt(tok[0]); 2175 } catch (NumberFormatException nfe) { 2176 Slog.e(TAG, String.format("Error parsing pid %s", tok[0])); 2177 return new int[0]; 2178 } 2179 } 2180 return data; 2181 } catch (NativeDaemonConnectorException e) { 2182 Slog.e(TAG, "Failed to retrieve storage users list", e); 2183 return new int[0]; 2184 } 2185 } 2186 2187 private void warnOnNotMounted() { 2188 synchronized (mLock) { 2189 for (int i = 0; i < mVolumes.size(); i++) { 2190 final VolumeInfo vol = mVolumes.valueAt(i); 2191 if (vol.isPrimary() && vol.isMountedWritable()) { 2192 // Cool beans, we have a mounted primary volume 2193 return; 2194 } 2195 } 2196 } 2197 2198 Slog.w(TAG, "No primary storage mounted!"); 2199 } 2200 2201 public String[] getSecureContainerList() { 2202 enforcePermission(android.Manifest.permission.ASEC_ACCESS); 2203 waitForReady(); 2204 warnOnNotMounted(); 2205 2206 try { 2207 return NativeDaemonEvent.filterMessageList( 2208 mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult); 2209 } catch (NativeDaemonConnectorException e) { 2210 return new String[0]; 2211 } 2212 } 2213 2214 public int createSecureContainer(String id, int sizeMb, String fstype, String key, 2215 int ownerUid, boolean external) { 2216 enforcePermission(android.Manifest.permission.ASEC_CREATE); 2217 waitForReady(); 2218 warnOnNotMounted(); 2219 2220 int rc = StorageResultCode.OperationSucceeded; 2221 try { 2222 mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key), 2223 ownerUid, external ? "1" : "0"); 2224 } catch (NativeDaemonConnectorException e) { 2225 rc = StorageResultCode.OperationFailedInternalError; 2226 } 2227 2228 if (rc == StorageResultCode.OperationSucceeded) { 2229 synchronized (mAsecMountSet) { 2230 mAsecMountSet.add(id); 2231 } 2232 } 2233 return rc; 2234 } 2235 2236 @Override 2237 public int resizeSecureContainer(String id, int sizeMb, String key) { 2238 enforcePermission(android.Manifest.permission.ASEC_CREATE); 2239 waitForReady(); 2240 warnOnNotMounted(); 2241 2242 int rc = StorageResultCode.OperationSucceeded; 2243 try { 2244 mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key)); 2245 } catch (NativeDaemonConnectorException e) { 2246 rc = StorageResultCode.OperationFailedInternalError; 2247 } 2248 return rc; 2249 } 2250 2251 public int finalizeSecureContainer(String id) { 2252 enforcePermission(android.Manifest.permission.ASEC_CREATE); 2253 warnOnNotMounted(); 2254 2255 int rc = StorageResultCode.OperationSucceeded; 2256 try { 2257 mConnector.execute("asec", "finalize", id); 2258 /* 2259 * Finalization does a remount, so no need 2260 * to update mAsecMountSet 2261 */ 2262 } catch (NativeDaemonConnectorException e) { 2263 rc = StorageResultCode.OperationFailedInternalError; 2264 } 2265 return rc; 2266 } 2267 2268 public int fixPermissionsSecureContainer(String id, int gid, String filename) { 2269 enforcePermission(android.Manifest.permission.ASEC_CREATE); 2270 warnOnNotMounted(); 2271 2272 int rc = StorageResultCode.OperationSucceeded; 2273 try { 2274 mConnector.execute("asec", "fixperms", id, gid, filename); 2275 /* 2276 * Fix permissions does a remount, so no need to update 2277 * mAsecMountSet 2278 */ 2279 } catch (NativeDaemonConnectorException e) { 2280 rc = StorageResultCode.OperationFailedInternalError; 2281 } 2282 return rc; 2283 } 2284 2285 public int destroySecureContainer(String id, boolean force) { 2286 enforcePermission(android.Manifest.permission.ASEC_DESTROY); 2287 waitForReady(); 2288 warnOnNotMounted(); 2289 2290 /* 2291 * Force a GC to make sure AssetManagers in other threads of the 2292 * system_server are cleaned up. We have to do this since AssetManager 2293 * instances are kept as a WeakReference and it's possible we have files 2294 * open on the external storage. 2295 */ 2296 Runtime.getRuntime().gc(); 2297 2298 int rc = StorageResultCode.OperationSucceeded; 2299 try { 2300 final Command cmd = new Command("asec", "destroy", id); 2301 if (force) { 2302 cmd.appendArg("force"); 2303 } 2304 mConnector.execute(cmd); 2305 } catch (NativeDaemonConnectorException e) { 2306 int code = e.getCode(); 2307 if (code == VoldResponseCode.OpFailedStorageBusy) { 2308 rc = StorageResultCode.OperationFailedStorageBusy; 2309 } else { 2310 rc = StorageResultCode.OperationFailedInternalError; 2311 } 2312 } 2313 2314 if (rc == StorageResultCode.OperationSucceeded) { 2315 synchronized (mAsecMountSet) { 2316 if (mAsecMountSet.contains(id)) { 2317 mAsecMountSet.remove(id); 2318 } 2319 } 2320 } 2321 2322 return rc; 2323 } 2324 2325 public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) { 2326 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 2327 waitForReady(); 2328 warnOnNotMounted(); 2329 2330 synchronized (mAsecMountSet) { 2331 if (mAsecMountSet.contains(id)) { 2332 return StorageResultCode.OperationFailedStorageMounted; 2333 } 2334 } 2335 2336 int rc = StorageResultCode.OperationSucceeded; 2337 try { 2338 mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid, 2339 readOnly ? "ro" : "rw"); 2340 } catch (NativeDaemonConnectorException e) { 2341 int code = e.getCode(); 2342 if (code != VoldResponseCode.OpFailedStorageBusy) { 2343 rc = StorageResultCode.OperationFailedInternalError; 2344 } 2345 } 2346 2347 if (rc == StorageResultCode.OperationSucceeded) { 2348 synchronized (mAsecMountSet) { 2349 mAsecMountSet.add(id); 2350 } 2351 } 2352 return rc; 2353 } 2354 2355 public int unmountSecureContainer(String id, boolean force) { 2356 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 2357 waitForReady(); 2358 warnOnNotMounted(); 2359 2360 synchronized (mAsecMountSet) { 2361 if (!mAsecMountSet.contains(id)) { 2362 return StorageResultCode.OperationFailedStorageNotMounted; 2363 } 2364 } 2365 2366 /* 2367 * Force a GC to make sure AssetManagers in other threads of the 2368 * system_server are cleaned up. We have to do this since AssetManager 2369 * instances are kept as a WeakReference and it's possible we have files 2370 * open on the external storage. 2371 */ 2372 Runtime.getRuntime().gc(); 2373 2374 int rc = StorageResultCode.OperationSucceeded; 2375 try { 2376 final Command cmd = new Command("asec", "unmount", id); 2377 if (force) { 2378 cmd.appendArg("force"); 2379 } 2380 mConnector.execute(cmd); 2381 } catch (NativeDaemonConnectorException e) { 2382 int code = e.getCode(); 2383 if (code == VoldResponseCode.OpFailedStorageBusy) { 2384 rc = StorageResultCode.OperationFailedStorageBusy; 2385 } else { 2386 rc = StorageResultCode.OperationFailedInternalError; 2387 } 2388 } 2389 2390 if (rc == StorageResultCode.OperationSucceeded) { 2391 synchronized (mAsecMountSet) { 2392 mAsecMountSet.remove(id); 2393 } 2394 } 2395 return rc; 2396 } 2397 2398 public boolean isSecureContainerMounted(String id) { 2399 enforcePermission(android.Manifest.permission.ASEC_ACCESS); 2400 waitForReady(); 2401 warnOnNotMounted(); 2402 2403 synchronized (mAsecMountSet) { 2404 return mAsecMountSet.contains(id); 2405 } 2406 } 2407 2408 public int renameSecureContainer(String oldId, String newId) { 2409 enforcePermission(android.Manifest.permission.ASEC_RENAME); 2410 waitForReady(); 2411 warnOnNotMounted(); 2412 2413 synchronized (mAsecMountSet) { 2414 /* 2415 * Because a mounted container has active internal state which cannot be 2416 * changed while active, we must ensure both ids are not currently mounted. 2417 */ 2418 if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) { 2419 return StorageResultCode.OperationFailedStorageMounted; 2420 } 2421 } 2422 2423 int rc = StorageResultCode.OperationSucceeded; 2424 try { 2425 mConnector.execute("asec", "rename", oldId, newId); 2426 } catch (NativeDaemonConnectorException e) { 2427 rc = StorageResultCode.OperationFailedInternalError; 2428 } 2429 2430 return rc; 2431 } 2432 2433 public String getSecureContainerPath(String id) { 2434 enforcePermission(android.Manifest.permission.ASEC_ACCESS); 2435 waitForReady(); 2436 warnOnNotMounted(); 2437 2438 final NativeDaemonEvent event; 2439 try { 2440 event = mConnector.execute("asec", "path", id); 2441 event.checkCode(VoldResponseCode.AsecPathResult); 2442 return event.getMessage(); 2443 } catch (NativeDaemonConnectorException e) { 2444 int code = e.getCode(); 2445 if (code == VoldResponseCode.OpFailedStorageNotFound) { 2446 Slog.i(TAG, String.format("Container '%s' not found", id)); 2447 return null; 2448 } else { 2449 throw new IllegalStateException(String.format("Unexpected response code %d", code)); 2450 } 2451 } 2452 } 2453 2454 public String getSecureContainerFilesystemPath(String id) { 2455 enforcePermission(android.Manifest.permission.ASEC_ACCESS); 2456 waitForReady(); 2457 warnOnNotMounted(); 2458 2459 final NativeDaemonEvent event; 2460 try { 2461 event = mConnector.execute("asec", "fspath", id); 2462 event.checkCode(VoldResponseCode.AsecPathResult); 2463 return event.getMessage(); 2464 } catch (NativeDaemonConnectorException e) { 2465 int code = e.getCode(); 2466 if (code == VoldResponseCode.OpFailedStorageNotFound) { 2467 Slog.i(TAG, String.format("Container '%s' not found", id)); 2468 return null; 2469 } else { 2470 throw new IllegalStateException(String.format("Unexpected response code %d", code)); 2471 } 2472 } 2473 } 2474 2475 @Override 2476 public void finishMediaUpdate() { 2477 if (Binder.getCallingUid() != Process.SYSTEM_UID) { 2478 throw new SecurityException("no permission to call finishMediaUpdate()"); 2479 } 2480 if (mUnmountSignal != null) { 2481 mUnmountSignal.countDown(); 2482 } else { 2483 Slog.w(TAG, "Odd, nobody asked to unmount?"); 2484 } 2485 } 2486 2487 private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) { 2488 if (callerUid == android.os.Process.SYSTEM_UID) { 2489 return true; 2490 } 2491 2492 if (packageName == null) { 2493 return false; 2494 } 2495 2496 final int packageUid = mPms.getPackageUid(packageName, 2497 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callerUid)); 2498 2499 if (DEBUG_OBB) { 2500 Slog.d(TAG, "packageName = " + packageName + ", packageUid = " + 2501 packageUid + ", callerUid = " + callerUid); 2502 } 2503 2504 return callerUid == packageUid; 2505 } 2506 2507 public String getMountedObbPath(String rawPath) { 2508 Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 2509 2510 waitForReady(); 2511 warnOnNotMounted(); 2512 2513 final ObbState state; 2514 synchronized (mObbMounts) { 2515 state = mObbPathToStateMap.get(rawPath); 2516 } 2517 if (state == null) { 2518 Slog.w(TAG, "Failed to find OBB mounted at " + rawPath); 2519 return null; 2520 } 2521 2522 final NativeDaemonEvent event; 2523 try { 2524 event = mConnector.execute("obb", "path", state.canonicalPath); 2525 event.checkCode(VoldResponseCode.AsecPathResult); 2526 return event.getMessage(); 2527 } catch (NativeDaemonConnectorException e) { 2528 int code = e.getCode(); 2529 if (code == VoldResponseCode.OpFailedStorageNotFound) { 2530 return null; 2531 } else { 2532 throw new IllegalStateException(String.format("Unexpected response code %d", code)); 2533 } 2534 } 2535 } 2536 2537 @Override 2538 public boolean isObbMounted(String rawPath) { 2539 Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 2540 synchronized (mObbMounts) { 2541 return mObbPathToStateMap.containsKey(rawPath); 2542 } 2543 } 2544 2545 @Override 2546 public void mountObb( 2547 String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) { 2548 Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 2549 Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null"); 2550 Preconditions.checkNotNull(token, "token cannot be null"); 2551 2552 final int callingUid = Binder.getCallingUid(); 2553 final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce); 2554 final ObbAction action = new MountObbAction(obbState, key, callingUid); 2555 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 2556 2557 if (DEBUG_OBB) 2558 Slog.i(TAG, "Send to OBB handler: " + action.toString()); 2559 } 2560 2561 @Override 2562 public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) { 2563 Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 2564 2565 final ObbState existingState; 2566 synchronized (mObbMounts) { 2567 existingState = mObbPathToStateMap.get(rawPath); 2568 } 2569 2570 if (existingState != null) { 2571 // TODO: separate state object from request data 2572 final int callingUid = Binder.getCallingUid(); 2573 final ObbState newState = new ObbState( 2574 rawPath, existingState.canonicalPath, callingUid, token, nonce); 2575 final ObbAction action = new UnmountObbAction(newState, force); 2576 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 2577 2578 if (DEBUG_OBB) 2579 Slog.i(TAG, "Send to OBB handler: " + action.toString()); 2580 } else { 2581 Slog.w(TAG, "Unknown OBB mount at " + rawPath); 2582 } 2583 } 2584 2585 @Override 2586 public int getEncryptionState() { 2587 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 2588 "no permission to access the crypt keeper"); 2589 2590 waitForReady(); 2591 2592 final NativeDaemonEvent event; 2593 try { 2594 event = mCryptConnector.execute("cryptfs", "cryptocomplete"); 2595 return Integer.parseInt(event.getMessage()); 2596 } catch (NumberFormatException e) { 2597 // Bad result - unexpected. 2598 Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete"); 2599 return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN; 2600 } catch (NativeDaemonConnectorException e) { 2601 // Something bad happened. 2602 Slog.w(TAG, "Error in communicating with cryptfs in validating"); 2603 return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN; 2604 } 2605 } 2606 2607 @Override 2608 public int decryptStorage(String password) { 2609 if (TextUtils.isEmpty(password)) { 2610 throw new IllegalArgumentException("password cannot be empty"); 2611 } 2612 2613 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 2614 "no permission to access the crypt keeper"); 2615 2616 waitForReady(); 2617 2618 if (DEBUG_EVENTS) { 2619 Slog.i(TAG, "decrypting storage..."); 2620 } 2621 2622 final NativeDaemonEvent event; 2623 try { 2624 event = mCryptConnector.execute("cryptfs", "checkpw", new SensitiveArg(password)); 2625 2626 final int code = Integer.parseInt(event.getMessage()); 2627 if (code == 0) { 2628 // Decrypt was successful. Post a delayed message before restarting in order 2629 // to let the UI to clear itself 2630 mHandler.postDelayed(new Runnable() { 2631 public void run() { 2632 try { 2633 mCryptConnector.execute("cryptfs", "restart"); 2634 } catch (NativeDaemonConnectorException e) { 2635 Slog.e(TAG, "problem executing in background", e); 2636 } 2637 } 2638 }, 1000); // 1 second 2639 } 2640 2641 return code; 2642 } catch (NativeDaemonConnectorException e) { 2643 // Decryption failed 2644 return e.getCode(); 2645 } 2646 } 2647 2648 public int encryptStorage(int type, String password) { 2649 if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) { 2650 throw new IllegalArgumentException("password cannot be empty"); 2651 } 2652 2653 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 2654 "no permission to access the crypt keeper"); 2655 2656 waitForReady(); 2657 2658 if (DEBUG_EVENTS) { 2659 Slog.i(TAG, "encrypting storage..."); 2660 } 2661 2662 try { 2663 if (type == StorageManager.CRYPT_TYPE_DEFAULT) { 2664 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace", 2665 CRYPTO_TYPES[type]); 2666 } else { 2667 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace", 2668 CRYPTO_TYPES[type], new SensitiveArg(password)); 2669 } 2670 } catch (NativeDaemonConnectorException e) { 2671 // Encryption failed 2672 return e.getCode(); 2673 } 2674 2675 return 0; 2676 } 2677 2678 /** Set the password for encrypting the master key. 2679 * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager. 2680 * @param password The password to set. 2681 */ 2682 public int changeEncryptionPassword(int type, String password) { 2683 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 2684 "no permission to access the crypt keeper"); 2685 2686 waitForReady(); 2687 2688 if (DEBUG_EVENTS) { 2689 Slog.i(TAG, "changing encryption password..."); 2690 } 2691 2692 try { 2693 NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type], 2694 new SensitiveArg(password)); 2695 return Integer.parseInt(event.getMessage()); 2696 } catch (NativeDaemonConnectorException e) { 2697 // Encryption failed 2698 return e.getCode(); 2699 } 2700 } 2701 2702 /** 2703 * Validate a user-supplied password string with cryptfs 2704 */ 2705 @Override 2706 public int verifyEncryptionPassword(String password) throws RemoteException { 2707 // Only the system process is permitted to validate passwords 2708 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { 2709 throw new SecurityException("no permission to access the crypt keeper"); 2710 } 2711 2712 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 2713 "no permission to access the crypt keeper"); 2714 2715 if (TextUtils.isEmpty(password)) { 2716 throw new IllegalArgumentException("password cannot be empty"); 2717 } 2718 2719 waitForReady(); 2720 2721 if (DEBUG_EVENTS) { 2722 Slog.i(TAG, "validating encryption password..."); 2723 } 2724 2725 final NativeDaemonEvent event; 2726 try { 2727 event = mCryptConnector.execute("cryptfs", "verifypw", new SensitiveArg(password)); 2728 Slog.i(TAG, "cryptfs verifypw => " + event.getMessage()); 2729 return Integer.parseInt(event.getMessage()); 2730 } catch (NativeDaemonConnectorException e) { 2731 // Encryption failed 2732 return e.getCode(); 2733 } 2734 } 2735 2736 /** 2737 * Get the type of encryption used to encrypt the master key. 2738 * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager. 2739 */ 2740 @Override 2741 public int getPasswordType() { 2742 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 2743 "no permission to access the crypt keeper"); 2744 2745 waitForReady(); 2746 2747 final NativeDaemonEvent event; 2748 try { 2749 event = mCryptConnector.execute("cryptfs", "getpwtype"); 2750 for (int i = 0; i < CRYPTO_TYPES.length; ++i) { 2751 if (CRYPTO_TYPES[i].equals(event.getMessage())) 2752 return i; 2753 } 2754 2755 throw new IllegalStateException("unexpected return from cryptfs"); 2756 } catch (NativeDaemonConnectorException e) { 2757 throw e.rethrowAsParcelableException(); 2758 } 2759 } 2760 2761 /** 2762 * Set a field in the crypto header. 2763 * @param field field to set 2764 * @param contents contents to set in field 2765 */ 2766 @Override 2767 public void setField(String field, String contents) throws RemoteException { 2768 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 2769 "no permission to access the crypt keeper"); 2770 2771 waitForReady(); 2772 2773 final NativeDaemonEvent event; 2774 try { 2775 event = mCryptConnector.execute("cryptfs", "setfield", field, contents); 2776 } catch (NativeDaemonConnectorException e) { 2777 throw e.rethrowAsParcelableException(); 2778 } 2779 } 2780 2781 /** 2782 * Gets a field from the crypto header. 2783 * @param field field to get 2784 * @return contents of field 2785 */ 2786 @Override 2787 public String getField(String field) throws RemoteException { 2788 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 2789 "no permission to access the crypt keeper"); 2790 2791 waitForReady(); 2792 2793 final NativeDaemonEvent event; 2794 try { 2795 final String[] contents = NativeDaemonEvent.filterMessageList( 2796 mCryptConnector.executeForList("cryptfs", "getfield", field), 2797 VoldResponseCode.CryptfsGetfieldResult); 2798 String result = new String(); 2799 for (String content : contents) { 2800 result += content; 2801 } 2802 return result; 2803 } catch (NativeDaemonConnectorException e) { 2804 throw e.rethrowAsParcelableException(); 2805 } 2806 } 2807 2808 /** 2809 * Is userdata convertible to file based encryption? 2810 * @return non zero for convertible 2811 */ 2812 @Override 2813 public boolean isConvertibleToFBE() throws RemoteException { 2814 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 2815 "no permission to access the crypt keeper"); 2816 2817 waitForReady(); 2818 2819 final NativeDaemonEvent event; 2820 try { 2821 event = mCryptConnector.execute("cryptfs", "isConvertibleToFBE"); 2822 return Integer.parseInt(event.getMessage()) != 0; 2823 } catch (NativeDaemonConnectorException e) { 2824 throw e.rethrowAsParcelableException(); 2825 } 2826 } 2827 2828 @Override 2829 public String getPassword() throws RemoteException { 2830 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 2831 "only keyguard can retrieve password"); 2832 2833 if (!isReady()) { 2834 return new String(); 2835 } 2836 2837 final NativeDaemonEvent event; 2838 try { 2839 event = mCryptConnector.execute("cryptfs", "getpw"); 2840 if ("-1".equals(event.getMessage())) { 2841 // -1 equals no password 2842 return null; 2843 } 2844 return event.getMessage(); 2845 } catch (NativeDaemonConnectorException e) { 2846 throw e.rethrowAsParcelableException(); 2847 } catch (IllegalArgumentException e) { 2848 Slog.e(TAG, "Invalid response to getPassword"); 2849 return null; 2850 } 2851 } 2852 2853 @Override 2854 public void clearPassword() throws RemoteException { 2855 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 2856 "only keyguard can clear password"); 2857 2858 if (!isReady()) { 2859 return; 2860 } 2861 2862 final NativeDaemonEvent event; 2863 try { 2864 event = mCryptConnector.execute("cryptfs", "clearpw"); 2865 } catch (NativeDaemonConnectorException e) { 2866 throw e.rethrowAsParcelableException(); 2867 } 2868 } 2869 2870 @Override 2871 public void createUserKey(int userId, int serialNumber, boolean ephemeral) { 2872 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 2873 waitForReady(); 2874 2875 try { 2876 mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber, 2877 ephemeral ? 1 : 0); 2878 } catch (NativeDaemonConnectorException e) { 2879 throw e.rethrowAsParcelableException(); 2880 } 2881 } 2882 2883 @Override 2884 public void destroyUserKey(int userId) { 2885 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 2886 waitForReady(); 2887 2888 try { 2889 mCryptConnector.execute("cryptfs", "destroy_user_key", userId); 2890 } catch (NativeDaemonConnectorException e) { 2891 throw e.rethrowAsParcelableException(); 2892 } 2893 } 2894 2895 private SensitiveArg encodeBytes(byte[] bytes) { 2896 if (ArrayUtils.isEmpty(bytes)) { 2897 return new SensitiveArg("!"); 2898 } else { 2899 return new SensitiveArg(HexDump.toHexString(bytes)); 2900 } 2901 } 2902 2903 /* 2904 * Add this token/secret pair to the set of ways we can recover a disk encryption key. 2905 * Changing the token/secret for a disk encryption key is done in two phases: first, adding 2906 * a new token/secret pair with this call, then delting all other pairs with 2907 * fixateNewestUserKeyAuth. This allows other places where a credential is used, such as 2908 * Gatekeeper, to be updated between the two calls. 2909 */ 2910 @Override 2911 public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) { 2912 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 2913 waitForReady(); 2914 2915 try { 2916 mCryptConnector.execute("cryptfs", "add_user_key_auth", userId, serialNumber, 2917 encodeBytes(token), encodeBytes(secret)); 2918 } catch (NativeDaemonConnectorException e) { 2919 throw e.rethrowAsParcelableException(); 2920 } 2921 } 2922 2923 /* 2924 * Delete all disk encryption token/secret pairs except the most recently added one 2925 */ 2926 @Override 2927 public void fixateNewestUserKeyAuth(int userId) { 2928 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 2929 waitForReady(); 2930 2931 try { 2932 mCryptConnector.execute("cryptfs", "fixate_newest_user_key_auth", userId); 2933 } catch (NativeDaemonConnectorException e) { 2934 throw e.rethrowAsParcelableException(); 2935 } 2936 } 2937 2938 @Override 2939 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) { 2940 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 2941 waitForReady(); 2942 2943 if (StorageManager.isFileEncryptedNativeOrEmulated()) { 2944 // When a user has secure lock screen, require secret to actually unlock. 2945 // This check is mostly in place for emulation mode. 2946 if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(secret)) { 2947 throw new IllegalStateException("Secret required to unlock secure user " + userId); 2948 } 2949 2950 try { 2951 mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber, 2952 encodeBytes(token), encodeBytes(secret)); 2953 } catch (NativeDaemonConnectorException e) { 2954 throw e.rethrowAsParcelableException(); 2955 } 2956 } 2957 2958 synchronized (mLock) { 2959 mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId); 2960 } 2961 } 2962 2963 @Override 2964 public void lockUserKey(int userId) { 2965 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 2966 waitForReady(); 2967 2968 try { 2969 mCryptConnector.execute("cryptfs", "lock_user_key", userId); 2970 } catch (NativeDaemonConnectorException e) { 2971 throw e.rethrowAsParcelableException(); 2972 } 2973 2974 synchronized (mLock) { 2975 mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId); 2976 } 2977 } 2978 2979 @Override 2980 public boolean isUserKeyUnlocked(int userId) { 2981 synchronized (mLock) { 2982 return ArrayUtils.contains(mLocalUnlockedUsers, userId); 2983 } 2984 } 2985 2986 @Override 2987 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) { 2988 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 2989 waitForReady(); 2990 2991 try { 2992 mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid), 2993 userId, serialNumber, flags); 2994 } catch (NativeDaemonConnectorException e) { 2995 throw e.rethrowAsParcelableException(); 2996 } 2997 } 2998 2999 @Override 3000 public void destroyUserStorage(String volumeUuid, int userId, int flags) { 3001 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 3002 waitForReady(); 3003 3004 try { 3005 mCryptConnector.execute("cryptfs", "destroy_user_storage", escapeNull(volumeUuid), 3006 userId, flags); 3007 } catch (NativeDaemonConnectorException e) { 3008 throw e.rethrowAsParcelableException(); 3009 } 3010 } 3011 3012 @Override 3013 public void secdiscard(String path) { 3014 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 3015 waitForReady(); 3016 3017 try { 3018 mCryptConnector.execute("cryptfs", "secdiscard", escapeNull(path)); 3019 } catch (NativeDaemonConnectorException e) { 3020 throw e.rethrowAsParcelableException(); 3021 } 3022 } 3023 3024 class AppFuseMountScope extends AppFuseBridge.MountScope { 3025 boolean opened = false; 3026 3027 public AppFuseMountScope(int uid, int pid, int mountId) { 3028 super(uid, pid, mountId); 3029 } 3030 3031 @Override 3032 public ParcelFileDescriptor open() throws NativeDaemonConnectorException { 3033 final NativeDaemonEvent event = StorageManagerService.this.mConnector.execute( 3034 "appfuse", "mount", uid, Process.myPid(), mountId); 3035 opened = true; 3036 if (event.getFileDescriptors() == null || 3037 event.getFileDescriptors().length == 0) { 3038 throw new NativeDaemonConnectorException("Cannot obtain device FD"); 3039 } 3040 return new ParcelFileDescriptor(event.getFileDescriptors()[0]); 3041 } 3042 3043 @Override 3044 public void close() throws Exception { 3045 if (opened) { 3046 mConnector.execute("appfuse", "unmount", uid, Process.myPid(), mountId); 3047 opened = false; 3048 } 3049 } 3050 } 3051 3052 @Override 3053 public @Nullable AppFuseMount mountProxyFileDescriptorBridge() { 3054 Slog.v(TAG, "mountProxyFileDescriptorBridge"); 3055 final int uid = Binder.getCallingUid(); 3056 final int pid = Binder.getCallingPid(); 3057 3058 while (true) { 3059 synchronized (mAppFuseLock) { 3060 boolean newlyCreated = false; 3061 if (mAppFuseBridge == null) { 3062 mAppFuseBridge = new AppFuseBridge(); 3063 new Thread(mAppFuseBridge, AppFuseBridge.TAG).start(); 3064 newlyCreated = true; 3065 } 3066 try { 3067 final int name = mNextAppFuseName++; 3068 try { 3069 return new AppFuseMount( 3070 name, mAppFuseBridge.addBridge(new AppFuseMountScope(uid, pid, name))); 3071 } catch (FuseUnavailableMountException e) { 3072 if (newlyCreated) { 3073 // If newly created bridge fails, it's a real error. 3074 Slog.e(TAG, "", e); 3075 return null; 3076 } 3077 // It seems the thread of mAppFuseBridge has already been terminated. 3078 mAppFuseBridge = null; 3079 } 3080 } catch (NativeDaemonConnectorException e) { 3081 throw e.rethrowAsParcelableException(); 3082 } 3083 } 3084 } 3085 } 3086 3087 @Override 3088 public @Nullable ParcelFileDescriptor openProxyFileDescriptor( 3089 int mountId, int fileId, int mode) { 3090 Slog.v(TAG, "mountProxyFileDescriptor"); 3091 final int pid = Binder.getCallingPid(); 3092 try { 3093 synchronized (mAppFuseLock) { 3094 if (mAppFuseBridge == null) { 3095 Slog.e(TAG, "FuseBridge has not been created"); 3096 return null; 3097 } 3098 return mAppFuseBridge.openFile(pid, mountId, fileId, mode); 3099 } 3100 } catch (FuseUnavailableMountException | InterruptedException error) { 3101 Slog.v(TAG, "The mount point has already been invalid", error); 3102 return null; 3103 } 3104 } 3105 3106 @Override 3107 public int mkdirs(String callingPkg, String appPath) { 3108 final int userId = UserHandle.getUserId(Binder.getCallingUid()); 3109 final UserEnvironment userEnv = new UserEnvironment(userId); 3110 3111 // Validate that reported package name belongs to caller 3112 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService( 3113 Context.APP_OPS_SERVICE); 3114 appOps.checkPackage(Binder.getCallingUid(), callingPkg); 3115 3116 File appFile = null; 3117 try { 3118 appFile = new File(appPath).getCanonicalFile(); 3119 } catch (IOException e) { 3120 Slog.e(TAG, "Failed to resolve " + appPath + ": " + e); 3121 return -1; 3122 } 3123 3124 // Try translating the app path into a vold path, but require that it 3125 // belong to the calling package. 3126 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) || 3127 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) || 3128 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) { 3129 appPath = appFile.getAbsolutePath(); 3130 if (!appPath.endsWith("/")) { 3131 appPath = appPath + "/"; 3132 } 3133 3134 try { 3135 mConnector.execute("volume", "mkdirs", appPath); 3136 return 0; 3137 } catch (NativeDaemonConnectorException e) { 3138 return e.getCode(); 3139 } 3140 } 3141 3142 throw new SecurityException("Invalid mkdirs path: " + appFile); 3143 } 3144 3145 @Override 3146 public StorageVolume[] getVolumeList(int uid, String packageName, int flags) { 3147 final int userId = UserHandle.getUserId(uid); 3148 3149 final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0; 3150 final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0; 3151 final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0; 3152 3153 final boolean userKeyUnlocked; 3154 final boolean storagePermission; 3155 final long token = Binder.clearCallingIdentity(); 3156 try { 3157 userKeyUnlocked = isUserKeyUnlocked(userId); 3158 storagePermission = mStorageManagerInternal.hasExternalStorage(uid, packageName); 3159 } finally { 3160 Binder.restoreCallingIdentity(token); 3161 } 3162 3163 boolean foundPrimary = false; 3164 3165 final ArrayList<StorageVolume> res = new ArrayList<>(); 3166 synchronized (mLock) { 3167 for (int i = 0; i < mVolumes.size(); i++) { 3168 final VolumeInfo vol = mVolumes.valueAt(i); 3169 switch (vol.getType()) { 3170 case VolumeInfo.TYPE_PUBLIC: 3171 case VolumeInfo.TYPE_EMULATED: 3172 break; 3173 default: 3174 continue; 3175 } 3176 3177 boolean match = false; 3178 if (forWrite) { 3179 match = vol.isVisibleForWrite(userId); 3180 } else { 3181 match = vol.isVisibleForRead(userId) 3182 || (includeInvisible && vol.getPath() != null); 3183 } 3184 if (!match) continue; 3185 3186 boolean reportUnmounted = false; 3187 if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) { 3188 reportUnmounted = true; 3189 } else if (!storagePermission && !realState) { 3190 reportUnmounted = true; 3191 } 3192 3193 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, 3194 reportUnmounted); 3195 if (vol.isPrimary()) { 3196 res.add(0, userVol); 3197 foundPrimary = true; 3198 } else { 3199 res.add(userVol); 3200 } 3201 } 3202 } 3203 3204 if (!foundPrimary) { 3205 Log.w(TAG, "No primary storage defined yet; hacking together a stub"); 3206 3207 final boolean primaryPhysical = SystemProperties.getBoolean( 3208 StorageManager.PROP_PRIMARY_PHYSICAL, false); 3209 3210 final String id = "stub_primary"; 3211 final File path = Environment.getLegacyExternalStorageDirectory(); 3212 final String description = mContext.getString(android.R.string.unknownName); 3213 final boolean primary = true; 3214 final boolean removable = primaryPhysical; 3215 final boolean emulated = !primaryPhysical; 3216 final long mtpReserveSize = 0L; 3217 final boolean allowMassStorage = false; 3218 final long maxFileSize = 0L; 3219 final UserHandle owner = new UserHandle(userId); 3220 final String uuid = null; 3221 final String state = Environment.MEDIA_REMOVED; 3222 3223 res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path, 3224 description, primary, removable, emulated, mtpReserveSize, 3225 allowMassStorage, maxFileSize, owner, uuid, state)); 3226 } 3227 3228 return res.toArray(new StorageVolume[res.size()]); 3229 } 3230 3231 @Override 3232 public DiskInfo[] getDisks() { 3233 synchronized (mLock) { 3234 final DiskInfo[] res = new DiskInfo[mDisks.size()]; 3235 for (int i = 0; i < mDisks.size(); i++) { 3236 res[i] = mDisks.valueAt(i); 3237 } 3238 return res; 3239 } 3240 } 3241 3242 @Override 3243 public VolumeInfo[] getVolumes(int flags) { 3244 synchronized (mLock) { 3245 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()]; 3246 for (int i = 0; i < mVolumes.size(); i++) { 3247 res[i] = mVolumes.valueAt(i); 3248 } 3249 return res; 3250 } 3251 } 3252 3253 @Override 3254 public VolumeRecord[] getVolumeRecords(int flags) { 3255 synchronized (mLock) { 3256 final VolumeRecord[] res = new VolumeRecord[mRecords.size()]; 3257 for (int i = 0; i < mRecords.size(); i++) { 3258 res[i] = mRecords.valueAt(i); 3259 } 3260 return res; 3261 } 3262 } 3263 3264 @Override 3265 public long getCacheQuotaBytes(String volumeUuid, int uid) { 3266 if (uid != Binder.getCallingUid()) { 3267 mContext.enforceCallingPermission(android.Manifest.permission.STORAGE_INTERNAL, TAG); 3268 } 3269 final long token = Binder.clearCallingIdentity(); 3270 final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class); 3271 try { 3272 return stats.getCacheQuotaBytes(volumeUuid, uid); 3273 } finally { 3274 Binder.restoreCallingIdentity(token); 3275 } 3276 } 3277 3278 @Override 3279 public long getCacheSizeBytes(String volumeUuid, int uid) { 3280 if (uid != Binder.getCallingUid()) { 3281 mContext.enforceCallingPermission(android.Manifest.permission.STORAGE_INTERNAL, TAG); 3282 } 3283 final long token = Binder.clearCallingIdentity(); 3284 try { 3285 return mContext.getSystemService(StorageStatsManager.class) 3286 .queryStatsForUid(volumeUuid, uid).getCacheBytes(); 3287 } catch (IOException e) { 3288 throw new ParcelableException(e); 3289 } finally { 3290 Binder.restoreCallingIdentity(token); 3291 } 3292 } 3293 3294 @Override 3295 public long getAllocatableBytes(String volumeUuid, int flags) { 3296 final StorageManager storage = mContext.getSystemService(StorageManager.class); 3297 final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class); 3298 3299 // Apps can't defy reserved space 3300 flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_RESERVED; 3301 3302 final boolean aggressive = (flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0; 3303 if (aggressive) { 3304 mContext.enforceCallingOrSelfPermission( 3305 android.Manifest.permission.ALLOCATE_AGGRESSIVE, TAG); 3306 } 3307 3308 final long token = Binder.clearCallingIdentity(); 3309 try { 3310 // In general, apps can allocate as much space as they want, except 3311 // we never let them eat into either the minimum cache space or into 3312 // the low disk warning space. To avoid user confusion, this logic 3313 // should be kept in sync with getFreeBytes(). 3314 final File path = storage.findPathForUuid(volumeUuid); 3315 3316 final long usable = path.getUsableSpace(); 3317 final long lowReserved = storage.getStorageLowBytes(path); 3318 final long fullReserved = storage.getStorageFullBytes(path); 3319 3320 if (stats.isQuotaSupported(volumeUuid)) { 3321 final long cacheTotal = stats.getCacheBytes(volumeUuid); 3322 final long cacheReserved = storage.getStorageCacheBytes(path); 3323 final long cacheClearable = Math.max(0, cacheTotal - cacheReserved); 3324 3325 if (aggressive) { 3326 return Math.max(0, (usable + cacheTotal) - fullReserved); 3327 } else { 3328 return Math.max(0, (usable + cacheClearable) - lowReserved); 3329 } 3330 } else { 3331 // When we don't have fast quota information, we ignore cached 3332 // data and only consider unused bytes. 3333 if (aggressive) { 3334 return Math.max(0, usable - fullReserved); 3335 } else { 3336 return Math.max(0, usable - lowReserved); 3337 } 3338 } 3339 } catch (IOException e) { 3340 throw new ParcelableException(e); 3341 } finally { 3342 Binder.restoreCallingIdentity(token); 3343 } 3344 } 3345 3346 @Override 3347 public void allocateBytes(String volumeUuid, long bytes, int flags) { 3348 final StorageManager storage = mContext.getSystemService(StorageManager.class); 3349 3350 // Apps can't defy reserved space 3351 flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_RESERVED; 3352 3353 // This method call will enforce FLAG_ALLOCATE_AGGRESSIVE permissions so 3354 // we don't have to enforce them locally 3355 final long allocatableBytes = getAllocatableBytes(volumeUuid, flags); 3356 if (bytes > allocatableBytes) { 3357 throw new ParcelableException(new IOException("Failed to allocate " + bytes 3358 + " because only " + allocatableBytes + " allocatable")); 3359 } 3360 3361 final long token = Binder.clearCallingIdentity(); 3362 try { 3363 // Free up enough disk space to satisfy both the requested allocation 3364 // and our low disk warning space. 3365 final File path = storage.findPathForUuid(volumeUuid); 3366 if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) { 3367 bytes += storage.getStorageFullBytes(path); 3368 } else { 3369 bytes += storage.getStorageLowBytes(path); 3370 } 3371 3372 mPms.freeStorage(volumeUuid, bytes, flags); 3373 } catch (IOException e) { 3374 throw new ParcelableException(e); 3375 } finally { 3376 Binder.restoreCallingIdentity(token); 3377 } 3378 } 3379 3380 private void addObbStateLocked(ObbState obbState) throws RemoteException { 3381 final IBinder binder = obbState.getBinder(); 3382 List<ObbState> obbStates = mObbMounts.get(binder); 3383 3384 if (obbStates == null) { 3385 obbStates = new ArrayList<ObbState>(); 3386 mObbMounts.put(binder, obbStates); 3387 } else { 3388 for (final ObbState o : obbStates) { 3389 if (o.rawPath.equals(obbState.rawPath)) { 3390 throw new IllegalStateException("Attempt to add ObbState twice. " 3391 + "This indicates an error in the StorageManagerService logic."); 3392 } 3393 } 3394 } 3395 3396 obbStates.add(obbState); 3397 try { 3398 obbState.link(); 3399 } catch (RemoteException e) { 3400 /* 3401 * The binder died before we could link it, so clean up our state 3402 * and return failure. 3403 */ 3404 obbStates.remove(obbState); 3405 if (obbStates.isEmpty()) { 3406 mObbMounts.remove(binder); 3407 } 3408 3409 // Rethrow the error so mountObb can get it 3410 throw e; 3411 } 3412 3413 mObbPathToStateMap.put(obbState.rawPath, obbState); 3414 } 3415 3416 private void removeObbStateLocked(ObbState obbState) { 3417 final IBinder binder = obbState.getBinder(); 3418 final List<ObbState> obbStates = mObbMounts.get(binder); 3419 if (obbStates != null) { 3420 if (obbStates.remove(obbState)) { 3421 obbState.unlink(); 3422 } 3423 if (obbStates.isEmpty()) { 3424 mObbMounts.remove(binder); 3425 } 3426 } 3427 3428 mObbPathToStateMap.remove(obbState.rawPath); 3429 } 3430 3431 private class ObbActionHandler extends Handler { 3432 private boolean mBound = false; 3433 private final List<ObbAction> mActions = new LinkedList<ObbAction>(); 3434 3435 ObbActionHandler(Looper l) { 3436 super(l); 3437 } 3438 3439 @Override 3440 public void handleMessage(Message msg) { 3441 switch (msg.what) { 3442 case OBB_RUN_ACTION: { 3443 final ObbAction action = (ObbAction) msg.obj; 3444 3445 if (DEBUG_OBB) 3446 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString()); 3447 3448 // If a bind was already initiated we don't really 3449 // need to do anything. The pending install 3450 // will be processed later on. 3451 if (!mBound) { 3452 // If this is the only one pending we might 3453 // have to bind to the service again. 3454 if (!connectToService()) { 3455 Slog.e(TAG, "Failed to bind to media container service"); 3456 action.handleError(); 3457 return; 3458 } 3459 } 3460 3461 mActions.add(action); 3462 break; 3463 } 3464 case OBB_MCS_BOUND: { 3465 if (DEBUG_OBB) 3466 Slog.i(TAG, "OBB_MCS_BOUND"); 3467 if (msg.obj != null) { 3468 mContainerService = (IMediaContainerService) msg.obj; 3469 } 3470 if (mContainerService == null) { 3471 // Something seriously wrong. Bail out 3472 Slog.e(TAG, "Cannot bind to media container service"); 3473 for (ObbAction action : mActions) { 3474 // Indicate service bind error 3475 action.handleError(); 3476 } 3477 mActions.clear(); 3478 } else if (mActions.size() > 0) { 3479 final ObbAction action = mActions.get(0); 3480 if (action != null) { 3481 action.execute(this); 3482 } 3483 } else { 3484 // Should never happen ideally. 3485 Slog.w(TAG, "Empty queue"); 3486 } 3487 break; 3488 } 3489 case OBB_MCS_RECONNECT: { 3490 if (DEBUG_OBB) 3491 Slog.i(TAG, "OBB_MCS_RECONNECT"); 3492 if (mActions.size() > 0) { 3493 if (mBound) { 3494 disconnectService(); 3495 } 3496 if (!connectToService()) { 3497 Slog.e(TAG, "Failed to bind to media container service"); 3498 for (ObbAction action : mActions) { 3499 // Indicate service bind error 3500 action.handleError(); 3501 } 3502 mActions.clear(); 3503 } 3504 } 3505 break; 3506 } 3507 case OBB_MCS_UNBIND: { 3508 if (DEBUG_OBB) 3509 Slog.i(TAG, "OBB_MCS_UNBIND"); 3510 3511 // Delete pending install 3512 if (mActions.size() > 0) { 3513 mActions.remove(0); 3514 } 3515 if (mActions.size() == 0) { 3516 if (mBound) { 3517 disconnectService(); 3518 } 3519 } else { 3520 // There are more pending requests in queue. 3521 // Just post MCS_BOUND message to trigger processing 3522 // of next pending install. 3523 mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND); 3524 } 3525 break; 3526 } 3527 case OBB_FLUSH_MOUNT_STATE: { 3528 final String path = (String) msg.obj; 3529 3530 if (DEBUG_OBB) 3531 Slog.i(TAG, "Flushing all OBB state for path " + path); 3532 3533 synchronized (mObbMounts) { 3534 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>(); 3535 3536 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator(); 3537 while (i.hasNext()) { 3538 final ObbState state = i.next(); 3539 3540 /* 3541 * If this entry's source file is in the volume path 3542 * that got unmounted, remove it because it's no 3543 * longer valid. 3544 */ 3545 if (state.canonicalPath.startsWith(path)) { 3546 obbStatesToRemove.add(state); 3547 } 3548 } 3549 3550 for (final ObbState obbState : obbStatesToRemove) { 3551 if (DEBUG_OBB) 3552 Slog.i(TAG, "Removing state for " + obbState.rawPath); 3553 3554 removeObbStateLocked(obbState); 3555 3556 try { 3557 obbState.token.onObbResult(obbState.rawPath, obbState.nonce, 3558 OnObbStateChangeListener.UNMOUNTED); 3559 } catch (RemoteException e) { 3560 Slog.i(TAG, "Couldn't send unmount notification for OBB: " 3561 + obbState.rawPath); 3562 } 3563 } 3564 } 3565 break; 3566 } 3567 } 3568 } 3569 3570 private boolean connectToService() { 3571 if (DEBUG_OBB) 3572 Slog.i(TAG, "Trying to bind to DefaultContainerService"); 3573 3574 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); 3575 if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE, 3576 UserHandle.SYSTEM)) { 3577 mBound = true; 3578 return true; 3579 } 3580 return false; 3581 } 3582 3583 private void disconnectService() { 3584 mContainerService = null; 3585 mBound = false; 3586 mContext.unbindService(mDefContainerConn); 3587 } 3588 } 3589 3590 abstract class ObbAction { 3591 private static final int MAX_RETRIES = 3; 3592 private int mRetries; 3593 3594 ObbState mObbState; 3595 3596 ObbAction(ObbState obbState) { 3597 mObbState = obbState; 3598 } 3599 3600 public void execute(ObbActionHandler handler) { 3601 try { 3602 if (DEBUG_OBB) 3603 Slog.i(TAG, "Starting to execute action: " + toString()); 3604 mRetries++; 3605 if (mRetries > MAX_RETRIES) { 3606 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); 3607 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 3608 handleError(); 3609 } else { 3610 handleExecute(); 3611 if (DEBUG_OBB) 3612 Slog.i(TAG, "Posting install MCS_UNBIND"); 3613 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 3614 } 3615 } catch (RemoteException e) { 3616 if (DEBUG_OBB) 3617 Slog.i(TAG, "Posting install MCS_RECONNECT"); 3618 mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT); 3619 } catch (Exception e) { 3620 if (DEBUG_OBB) 3621 Slog.d(TAG, "Error handling OBB action", e); 3622 handleError(); 3623 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 3624 } 3625 } 3626 3627 abstract void handleExecute() throws RemoteException, IOException; 3628 abstract void handleError(); 3629 3630 protected ObbInfo getObbInfo() throws IOException { 3631 ObbInfo obbInfo; 3632 try { 3633 obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath); 3634 } catch (RemoteException e) { 3635 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for " 3636 + mObbState.canonicalPath); 3637 obbInfo = null; 3638 } 3639 if (obbInfo == null) { 3640 throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath); 3641 } 3642 return obbInfo; 3643 } 3644 3645 protected void sendNewStatusOrIgnore(int status) { 3646 if (mObbState == null || mObbState.token == null) { 3647 return; 3648 } 3649 3650 try { 3651 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status); 3652 } catch (RemoteException e) { 3653 Slog.w(TAG, "StorageEventListener went away while calling onObbStateChanged"); 3654 } 3655 } 3656 } 3657 3658 class MountObbAction extends ObbAction { 3659 private final String mKey; 3660 private final int mCallingUid; 3661 3662 MountObbAction(ObbState obbState, String key, int callingUid) { 3663 super(obbState); 3664 mKey = key; 3665 mCallingUid = callingUid; 3666 } 3667 3668 @Override 3669 public void handleExecute() throws IOException, RemoteException { 3670 waitForReady(); 3671 warnOnNotMounted(); 3672 3673 final ObbInfo obbInfo = getObbInfo(); 3674 3675 if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) { 3676 Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename 3677 + " which is owned by " + obbInfo.packageName); 3678 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 3679 return; 3680 } 3681 3682 final boolean isMounted; 3683 synchronized (mObbMounts) { 3684 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath); 3685 } 3686 if (isMounted) { 3687 Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename); 3688 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED); 3689 return; 3690 } 3691 3692 final String hashedKey; 3693 if (mKey == null) { 3694 hashedKey = "none"; 3695 } else { 3696 try { 3697 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 3698 3699 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt, 3700 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE); 3701 SecretKey key = factory.generateSecret(ks); 3702 BigInteger bi = new BigInteger(key.getEncoded()); 3703 hashedKey = bi.toString(16); 3704 } catch (NoSuchAlgorithmException e) { 3705 Slog.e(TAG, "Could not load PBKDF2 algorithm", e); 3706 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 3707 return; 3708 } catch (InvalidKeySpecException e) { 3709 Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e); 3710 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 3711 return; 3712 } 3713 } 3714 3715 int rc = StorageResultCode.OperationSucceeded; 3716 try { 3717 mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey), 3718 mObbState.ownerGid); 3719 } catch (NativeDaemonConnectorException e) { 3720 int code = e.getCode(); 3721 if (code != VoldResponseCode.OpFailedStorageBusy) { 3722 rc = StorageResultCode.OperationFailedInternalError; 3723 } 3724 } 3725 3726 if (rc == StorageResultCode.OperationSucceeded) { 3727 if (DEBUG_OBB) 3728 Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath); 3729 3730 synchronized (mObbMounts) { 3731 addObbStateLocked(mObbState); 3732 } 3733 3734 sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED); 3735 } else { 3736 Slog.e(TAG, "Couldn't mount OBB file: " + rc); 3737 3738 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT); 3739 } 3740 } 3741 3742 @Override 3743 public void handleError() { 3744 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 3745 } 3746 3747 @Override 3748 public String toString() { 3749 StringBuilder sb = new StringBuilder(); 3750 sb.append("MountObbAction{"); 3751 sb.append(mObbState); 3752 sb.append('}'); 3753 return sb.toString(); 3754 } 3755 } 3756 3757 class UnmountObbAction extends ObbAction { 3758 private final boolean mForceUnmount; 3759 3760 UnmountObbAction(ObbState obbState, boolean force) { 3761 super(obbState); 3762 mForceUnmount = force; 3763 } 3764 3765 @Override 3766 public void handleExecute() throws IOException { 3767 waitForReady(); 3768 warnOnNotMounted(); 3769 3770 final ObbState existingState; 3771 synchronized (mObbMounts) { 3772 existingState = mObbPathToStateMap.get(mObbState.rawPath); 3773 } 3774 3775 if (existingState == null) { 3776 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED); 3777 return; 3778 } 3779 3780 if (existingState.ownerGid != mObbState.ownerGid) { 3781 Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath 3782 + " (owned by GID " + existingState.ownerGid + ")"); 3783 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 3784 return; 3785 } 3786 3787 int rc = StorageResultCode.OperationSucceeded; 3788 try { 3789 final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath); 3790 if (mForceUnmount) { 3791 cmd.appendArg("force"); 3792 } 3793 mConnector.execute(cmd); 3794 } catch (NativeDaemonConnectorException e) { 3795 int code = e.getCode(); 3796 if (code == VoldResponseCode.OpFailedStorageBusy) { 3797 rc = StorageResultCode.OperationFailedStorageBusy; 3798 } else if (code == VoldResponseCode.OpFailedStorageNotFound) { 3799 // If it's not mounted then we've already won. 3800 rc = StorageResultCode.OperationSucceeded; 3801 } else { 3802 rc = StorageResultCode.OperationFailedInternalError; 3803 } 3804 } 3805 3806 if (rc == StorageResultCode.OperationSucceeded) { 3807 synchronized (mObbMounts) { 3808 removeObbStateLocked(existingState); 3809 } 3810 3811 sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED); 3812 } else { 3813 Slog.w(TAG, "Could not unmount OBB: " + existingState); 3814 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT); 3815 } 3816 } 3817 3818 @Override 3819 public void handleError() { 3820 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 3821 } 3822 3823 @Override 3824 public String toString() { 3825 StringBuilder sb = new StringBuilder(); 3826 sb.append("UnmountObbAction{"); 3827 sb.append(mObbState); 3828 sb.append(",force="); 3829 sb.append(mForceUnmount); 3830 sb.append('}'); 3831 return sb.toString(); 3832 } 3833 } 3834 3835 private static class Callbacks extends Handler { 3836 private static final int MSG_STORAGE_STATE_CHANGED = 1; 3837 private static final int MSG_VOLUME_STATE_CHANGED = 2; 3838 private static final int MSG_VOLUME_RECORD_CHANGED = 3; 3839 private static final int MSG_VOLUME_FORGOTTEN = 4; 3840 private static final int MSG_DISK_SCANNED = 5; 3841 private static final int MSG_DISK_DESTROYED = 6; 3842 3843 private final RemoteCallbackList<IStorageEventListener> 3844 mCallbacks = new RemoteCallbackList<>(); 3845 3846 public Callbacks(Looper looper) { 3847 super(looper); 3848 } 3849 3850 public void register(IStorageEventListener callback) { 3851 mCallbacks.register(callback); 3852 } 3853 3854 public void unregister(IStorageEventListener callback) { 3855 mCallbacks.unregister(callback); 3856 } 3857 3858 @Override 3859 public void handleMessage(Message msg) { 3860 final SomeArgs args = (SomeArgs) msg.obj; 3861 final int n = mCallbacks.beginBroadcast(); 3862 for (int i = 0; i < n; i++) { 3863 final IStorageEventListener callback = mCallbacks.getBroadcastItem(i); 3864 try { 3865 invokeCallback(callback, msg.what, args); 3866 } catch (RemoteException ignored) { 3867 } 3868 } 3869 mCallbacks.finishBroadcast(); 3870 args.recycle(); 3871 } 3872 3873 private void invokeCallback(IStorageEventListener callback, int what, SomeArgs args) 3874 throws RemoteException { 3875 switch (what) { 3876 case MSG_STORAGE_STATE_CHANGED: { 3877 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2, 3878 (String) args.arg3); 3879 break; 3880 } 3881 case MSG_VOLUME_STATE_CHANGED: { 3882 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3); 3883 break; 3884 } 3885 case MSG_VOLUME_RECORD_CHANGED: { 3886 callback.onVolumeRecordChanged((VolumeRecord) args.arg1); 3887 break; 3888 } 3889 case MSG_VOLUME_FORGOTTEN: { 3890 callback.onVolumeForgotten((String) args.arg1); 3891 break; 3892 } 3893 case MSG_DISK_SCANNED: { 3894 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2); 3895 break; 3896 } 3897 case MSG_DISK_DESTROYED: { 3898 callback.onDiskDestroyed((DiskInfo) args.arg1); 3899 break; 3900 } 3901 } 3902 } 3903 3904 private void notifyStorageStateChanged(String path, String oldState, String newState) { 3905 final SomeArgs args = SomeArgs.obtain(); 3906 args.arg1 = path; 3907 args.arg2 = oldState; 3908 args.arg3 = newState; 3909 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget(); 3910 } 3911 3912 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { 3913 final SomeArgs args = SomeArgs.obtain(); 3914 args.arg1 = vol.clone(); 3915 args.argi2 = oldState; 3916 args.argi3 = newState; 3917 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget(); 3918 } 3919 3920 private void notifyVolumeRecordChanged(VolumeRecord rec) { 3921 final SomeArgs args = SomeArgs.obtain(); 3922 args.arg1 = rec.clone(); 3923 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget(); 3924 } 3925 3926 private void notifyVolumeForgotten(String fsUuid) { 3927 final SomeArgs args = SomeArgs.obtain(); 3928 args.arg1 = fsUuid; 3929 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget(); 3930 } 3931 3932 private void notifyDiskScanned(DiskInfo disk, int volumeCount) { 3933 final SomeArgs args = SomeArgs.obtain(); 3934 args.arg1 = disk.clone(); 3935 args.argi2 = volumeCount; 3936 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget(); 3937 } 3938 3939 private void notifyDiskDestroyed(DiskInfo disk) { 3940 final SomeArgs args = SomeArgs.obtain(); 3941 args.arg1 = disk.clone(); 3942 obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget(); 3943 } 3944 } 3945 3946 @Override 3947 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 3948 if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return; 3949 3950 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160); 3951 synchronized (mLock) { 3952 pw.println("Disks:"); 3953 pw.increaseIndent(); 3954 for (int i = 0; i < mDisks.size(); i++) { 3955 final DiskInfo disk = mDisks.valueAt(i); 3956 disk.dump(pw); 3957 } 3958 pw.decreaseIndent(); 3959 3960 pw.println(); 3961 pw.println("Volumes:"); 3962 pw.increaseIndent(); 3963 for (int i = 0; i < mVolumes.size(); i++) { 3964 final VolumeInfo vol = mVolumes.valueAt(i); 3965 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue; 3966 vol.dump(pw); 3967 } 3968 pw.decreaseIndent(); 3969 3970 pw.println(); 3971 pw.println("Records:"); 3972 pw.increaseIndent(); 3973 for (int i = 0; i < mRecords.size(); i++) { 3974 final VolumeRecord note = mRecords.valueAt(i); 3975 note.dump(pw); 3976 } 3977 pw.decreaseIndent(); 3978 3979 pw.println(); 3980 pw.println("Primary storage UUID: " + mPrimaryStorageUuid); 3981 final Pair<String, Long> pair = StorageManager.getPrimaryStoragePathAndSize(); 3982 if (pair == null) { 3983 pw.println("Internal storage total size: N/A"); 3984 } else { 3985 pw.print("Internal storage ("); 3986 pw.print(pair.first); 3987 pw.print(") total size: "); 3988 pw.print(pair.second); 3989 pw.print(" ("); 3990 pw.print((float) pair.second / TrafficStats.GB_IN_BYTES); 3991 pw.println(" GB)"); 3992 } 3993 pw.println("Force adoptable: " + mForceAdoptable); 3994 pw.println(); 3995 pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers)); 3996 pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers)); 3997 } 3998 3999 synchronized (mObbMounts) { 4000 pw.println(); 4001 pw.println("mObbMounts:"); 4002 pw.increaseIndent(); 4003 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet() 4004 .iterator(); 4005 while (binders.hasNext()) { 4006 Entry<IBinder, List<ObbState>> e = binders.next(); 4007 pw.println(e.getKey() + ":"); 4008 pw.increaseIndent(); 4009 final List<ObbState> obbStates = e.getValue(); 4010 for (final ObbState obbState : obbStates) { 4011 pw.println(obbState); 4012 } 4013 pw.decreaseIndent(); 4014 } 4015 pw.decreaseIndent(); 4016 4017 pw.println(); 4018 pw.println("mObbPathToStateMap:"); 4019 pw.increaseIndent(); 4020 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator(); 4021 while (maps.hasNext()) { 4022 final Entry<String, ObbState> e = maps.next(); 4023 pw.print(e.getKey()); 4024 pw.print(" -> "); 4025 pw.println(e.getValue()); 4026 } 4027 pw.decreaseIndent(); 4028 } 4029 4030 pw.println(); 4031 pw.println("mConnector:"); 4032 pw.increaseIndent(); 4033 mConnector.dump(fd, pw, args); 4034 pw.decreaseIndent(); 4035 4036 pw.println(); 4037 pw.println("mCryptConnector:"); 4038 pw.increaseIndent(); 4039 mCryptConnector.dump(fd, pw, args); 4040 pw.decreaseIndent(); 4041 4042 pw.println(); 4043 pw.print("Last maintenance: "); 4044 pw.println(TimeUtils.formatForLogging(mLastMaintenance)); 4045 } 4046 4047 /** {@inheritDoc} */ 4048 @Override 4049 public void monitor() { 4050 if (mConnector != null) { 4051 mConnector.monitor(); 4052 } 4053 if (mCryptConnector != null) { 4054 mCryptConnector.monitor(); 4055 } 4056 } 4057 4058 private final class StorageManagerInternalImpl extends StorageManagerInternal { 4059 // Not guarded by a lock. 4060 private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies = 4061 new CopyOnWriteArrayList<>(); 4062 4063 @Override 4064 public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) { 4065 // No locking - CopyOnWriteArrayList 4066 mPolicies.add(policy); 4067 } 4068 4069 @Override 4070 public void onExternalStoragePolicyChanged(int uid, String packageName) { 4071 final int mountMode = getExternalStorageMountMode(uid, packageName); 4072 remountUidExternalStorage(uid, mountMode); 4073 } 4074 4075 @Override 4076 public int getExternalStorageMountMode(int uid, String packageName) { 4077 // No locking - CopyOnWriteArrayList 4078 int mountMode = Integer.MAX_VALUE; 4079 for (ExternalStorageMountPolicy policy : mPolicies) { 4080 final int policyMode = policy.getMountMode(uid, packageName); 4081 if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) { 4082 return Zygote.MOUNT_EXTERNAL_NONE; 4083 } 4084 mountMode = Math.min(mountMode, policyMode); 4085 } 4086 if (mountMode == Integer.MAX_VALUE) { 4087 return Zygote.MOUNT_EXTERNAL_NONE; 4088 } 4089 return mountMode; 4090 } 4091 4092 public boolean hasExternalStorage(int uid, String packageName) { 4093 // No need to check for system uid. This avoids a deadlock between 4094 // PackageManagerService and AppOpsService. 4095 if (uid == Process.SYSTEM_UID) { 4096 return true; 4097 } 4098 // No locking - CopyOnWriteArrayList 4099 for (ExternalStorageMountPolicy policy : mPolicies) { 4100 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName); 4101 if (!policyHasStorage) { 4102 return false; 4103 } 4104 } 4105 return true; 4106 } 4107 } 4108 } 4109