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