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