MountService.java revision fcf1e55821b694df3b8434f40aa3b6d3c3e7ea50
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 2652 waitForReady(); 2653 2654 final NativeDaemonEvent event; 2655 try { 2656 event = mCryptConnector.execute("cryptfs", "getpwtype"); 2657 for (int i = 0; i < CRYPTO_TYPES.length; ++i) { 2658 if (CRYPTO_TYPES[i].equals(event.getMessage())) 2659 return i; 2660 } 2661 2662 throw new IllegalStateException("unexpected return from cryptfs"); 2663 } catch (NativeDaemonConnectorException e) { 2664 throw e.rethrowAsParcelableException(); 2665 } 2666 } 2667 2668 /** 2669 * Set a field in the crypto header. 2670 * @param field field to set 2671 * @param contents contents to set in field 2672 */ 2673 @Override 2674 public void setField(String field, String contents) throws RemoteException { 2675 2676 waitForReady(); 2677 2678 final NativeDaemonEvent event; 2679 try { 2680 event = mCryptConnector.execute("cryptfs", "setfield", field, contents); 2681 } catch (NativeDaemonConnectorException e) { 2682 throw e.rethrowAsParcelableException(); 2683 } 2684 } 2685 2686 /** 2687 * Gets a field from the crypto header. 2688 * @param field field to get 2689 * @return contents of field 2690 */ 2691 @Override 2692 public String getField(String field) throws RemoteException { 2693 2694 waitForReady(); 2695 2696 final NativeDaemonEvent event; 2697 try { 2698 final String[] contents = NativeDaemonEvent.filterMessageList( 2699 mCryptConnector.executeForList("cryptfs", "getfield", field), 2700 VoldResponseCode.CryptfsGetfieldResult); 2701 String result = new String(); 2702 for (String content : contents) { 2703 result += content; 2704 } 2705 return result; 2706 } catch (NativeDaemonConnectorException e) { 2707 throw e.rethrowAsParcelableException(); 2708 } 2709 } 2710 2711 /** 2712 * Is userdata convertible to file based encryption? 2713 * @return non zero for convertible 2714 */ 2715 @Override 2716 public boolean isConvertibleToFBE() throws RemoteException { 2717 2718 waitForReady(); 2719 2720 final NativeDaemonEvent event; 2721 try { 2722 event = mCryptConnector.execute("cryptfs", "isConvertibleToFBE"); 2723 return Integer.parseInt(event.getMessage()) != 0; 2724 } catch (NativeDaemonConnectorException e) { 2725 throw e.rethrowAsParcelableException(); 2726 } 2727 } 2728 2729 @Override 2730 public String getPassword() throws RemoteException { 2731 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, 2732 "only keyguard can retrieve password"); 2733 if (!isReady()) { 2734 return new String(); 2735 } 2736 2737 final NativeDaemonEvent event; 2738 try { 2739 event = mCryptConnector.execute("cryptfs", "getpw"); 2740 if ("-1".equals(event.getMessage())) { 2741 // -1 equals no password 2742 return null; 2743 } 2744 return event.getMessage(); 2745 } catch (NativeDaemonConnectorException e) { 2746 throw e.rethrowAsParcelableException(); 2747 } catch (IllegalArgumentException e) { 2748 Slog.e(TAG, "Invalid response to getPassword"); 2749 return null; 2750 } 2751 } 2752 2753 @Override 2754 public void clearPassword() throws RemoteException { 2755 if (!isReady()) { 2756 return; 2757 } 2758 2759 final NativeDaemonEvent event; 2760 try { 2761 event = mCryptConnector.execute("cryptfs", "clearpw"); 2762 } catch (NativeDaemonConnectorException e) { 2763 throw e.rethrowAsParcelableException(); 2764 } 2765 } 2766 2767 @Override 2768 public void createUserKey(int userId, int serialNumber, boolean ephemeral) { 2769 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 2770 waitForReady(); 2771 2772 try { 2773 mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber, 2774 ephemeral ? 1 : 0); 2775 } catch (NativeDaemonConnectorException e) { 2776 throw e.rethrowAsParcelableException(); 2777 } 2778 } 2779 2780 @Override 2781 public void destroyUserKey(int userId) { 2782 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 2783 waitForReady(); 2784 2785 try { 2786 mCryptConnector.execute("cryptfs", "destroy_user_key", userId); 2787 } catch (NativeDaemonConnectorException e) { 2788 throw e.rethrowAsParcelableException(); 2789 } 2790 } 2791 2792 private SensitiveArg encodeBytes(byte[] bytes) { 2793 if (ArrayUtils.isEmpty(bytes)) { 2794 return new SensitiveArg("!"); 2795 } else { 2796 return new SensitiveArg(HexDump.toHexString(bytes)); 2797 } 2798 } 2799 2800 @Override 2801 public void changeUserKey(int userId, int serialNumber, 2802 byte[] token, byte[] oldSecret, byte[] newSecret) { 2803 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 2804 waitForReady(); 2805 2806 try { 2807 mCryptConnector.execute("cryptfs", "change_user_key", userId, serialNumber, 2808 encodeBytes(token), encodeBytes(oldSecret), encodeBytes(newSecret)); 2809 } catch (NativeDaemonConnectorException e) { 2810 throw e.rethrowAsParcelableException(); 2811 } 2812 } 2813 2814 @Override 2815 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) { 2816 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 2817 waitForReady(); 2818 2819 // When a user has secure lock screen, require a challenge token to 2820 // actually unlock. This check is mostly in place for emulation mode. 2821 if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(token)) { 2822 throw new IllegalStateException("Token required to unlock secure user " + userId); 2823 } 2824 2825 try { 2826 mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber, 2827 encodeBytes(token), encodeBytes(secret)); 2828 } catch (NativeDaemonConnectorException e) { 2829 throw e.rethrowAsParcelableException(); 2830 } 2831 2832 synchronized (mLock) { 2833 mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId); 2834 } 2835 } 2836 2837 @Override 2838 public void lockUserKey(int userId) { 2839 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 2840 waitForReady(); 2841 2842 try { 2843 mCryptConnector.execute("cryptfs", "lock_user_key", userId); 2844 } catch (NativeDaemonConnectorException e) { 2845 throw e.rethrowAsParcelableException(); 2846 } 2847 2848 synchronized (mLock) { 2849 mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId); 2850 } 2851 } 2852 2853 @Override 2854 public boolean isUserKeyUnlocked(int userId) { 2855 if (StorageManager.isFileEncryptedNativeOrEmulated()) { 2856 synchronized (mLock) { 2857 return ArrayUtils.contains(mLocalUnlockedUsers, userId); 2858 } 2859 } else { 2860 return true; 2861 } 2862 } 2863 2864 @Override 2865 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) { 2866 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 2867 waitForReady(); 2868 2869 try { 2870 mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid), 2871 userId, serialNumber, flags); 2872 } catch (NativeDaemonConnectorException e) { 2873 throw e.rethrowAsParcelableException(); 2874 } 2875 } 2876 2877 @Override 2878 public void destroyUserStorage(String volumeUuid, int userId, int flags) { 2879 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); 2880 waitForReady(); 2881 2882 try { 2883 mCryptConnector.execute("cryptfs", "destroy_user_storage", escapeNull(volumeUuid), 2884 userId, flags); 2885 } catch (NativeDaemonConnectorException e) { 2886 throw e.rethrowAsParcelableException(); 2887 } 2888 } 2889 2890 @Override 2891 public ParcelFileDescriptor mountAppFuse(final String name) throws RemoteException { 2892 try { 2893 final int uid = Binder.getCallingUid(); 2894 final int pid = Binder.getCallingPid(); 2895 final NativeDaemonEvent event = 2896 mConnector.execute("appfuse", "mount", uid, pid, name); 2897 if (event.getFileDescriptors() == null) { 2898 throw new RemoteException("AppFuse FD from vold is null."); 2899 } 2900 return ParcelFileDescriptor.fromFd( 2901 event.getFileDescriptors()[0], 2902 mHandler, 2903 new ParcelFileDescriptor.OnCloseListener() { 2904 @Override 2905 public void onClose(IOException e) { 2906 try { 2907 final NativeDaemonEvent event = mConnector.execute( 2908 "appfuse", "unmount", uid, pid, name); 2909 } catch (NativeDaemonConnectorException unmountException) { 2910 Log.e(TAG, "Failed to unmount appfuse."); 2911 } 2912 } 2913 }); 2914 } catch (NativeDaemonConnectorException e) { 2915 throw e.rethrowAsParcelableException(); 2916 } catch (IOException e) { 2917 throw new RemoteException(e.getMessage()); 2918 } 2919 } 2920 2921 @Override 2922 public int mkdirs(String callingPkg, String appPath) { 2923 final int userId = UserHandle.getUserId(Binder.getCallingUid()); 2924 final UserEnvironment userEnv = new UserEnvironment(userId); 2925 2926 // Validate that reported package name belongs to caller 2927 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService( 2928 Context.APP_OPS_SERVICE); 2929 appOps.checkPackage(Binder.getCallingUid(), callingPkg); 2930 2931 File appFile = null; 2932 try { 2933 appFile = new File(appPath).getCanonicalFile(); 2934 } catch (IOException e) { 2935 Slog.e(TAG, "Failed to resolve " + appPath + ": " + e); 2936 return -1; 2937 } 2938 2939 // Try translating the app path into a vold path, but require that it 2940 // belong to the calling package. 2941 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) || 2942 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) || 2943 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) { 2944 appPath = appFile.getAbsolutePath(); 2945 if (!appPath.endsWith("/")) { 2946 appPath = appPath + "/"; 2947 } 2948 2949 try { 2950 mConnector.execute("volume", "mkdirs", appPath); 2951 return 0; 2952 } catch (NativeDaemonConnectorException e) { 2953 return e.getCode(); 2954 } 2955 } 2956 2957 throw new SecurityException("Invalid mkdirs path: " + appFile); 2958 } 2959 2960 @Override 2961 public StorageVolume[] getVolumeList(int uid, String packageName, int flags) { 2962 final int userId = UserHandle.getUserId(uid); 2963 2964 final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0; 2965 final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0; 2966 final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0; 2967 2968 final boolean userKeyUnlocked; 2969 final boolean storagePermission; 2970 final long token = Binder.clearCallingIdentity(); 2971 try { 2972 userKeyUnlocked = isUserKeyUnlocked(userId); 2973 storagePermission = mMountServiceInternal.hasExternalStorage(uid, packageName); 2974 } finally { 2975 Binder.restoreCallingIdentity(token); 2976 } 2977 2978 boolean foundPrimary = false; 2979 2980 final ArrayList<StorageVolume> res = new ArrayList<>(); 2981 synchronized (mLock) { 2982 for (int i = 0; i < mVolumes.size(); i++) { 2983 final VolumeInfo vol = mVolumes.valueAt(i); 2984 switch (vol.getType()) { 2985 case VolumeInfo.TYPE_PUBLIC: 2986 case VolumeInfo.TYPE_EMULATED: 2987 break; 2988 default: 2989 continue; 2990 } 2991 2992 boolean match = false; 2993 if (forWrite) { 2994 match = vol.isVisibleForWrite(userId); 2995 } else { 2996 match = vol.isVisibleForRead(userId) || includeInvisible; 2997 } 2998 if (!match) continue; 2999 3000 boolean reportUnmounted = false; 3001 if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) { 3002 reportUnmounted = true; 3003 } else if (!storagePermission && !realState) { 3004 reportUnmounted = true; 3005 } 3006 3007 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, 3008 reportUnmounted); 3009 if (vol.isPrimary()) { 3010 res.add(0, userVol); 3011 foundPrimary = true; 3012 } else { 3013 res.add(userVol); 3014 } 3015 } 3016 } 3017 3018 if (!foundPrimary) { 3019 Log.w(TAG, "No primary storage defined yet; hacking together a stub"); 3020 3021 final boolean primaryPhysical = SystemProperties.getBoolean( 3022 StorageManager.PROP_PRIMARY_PHYSICAL, false); 3023 3024 final String id = "stub_primary"; 3025 final File path = Environment.getLegacyExternalStorageDirectory(); 3026 final String description = mContext.getString(android.R.string.unknownName); 3027 final boolean primary = true; 3028 final boolean removable = primaryPhysical; 3029 final boolean emulated = !primaryPhysical; 3030 final long mtpReserveSize = 0L; 3031 final boolean allowMassStorage = false; 3032 final long maxFileSize = 0L; 3033 final UserHandle owner = new UserHandle(userId); 3034 final String uuid = null; 3035 final String state = Environment.MEDIA_REMOVED; 3036 3037 res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path, 3038 description, primary, removable, emulated, mtpReserveSize, 3039 allowMassStorage, maxFileSize, owner, uuid, state)); 3040 } 3041 3042 return res.toArray(new StorageVolume[res.size()]); 3043 } 3044 3045 @Override 3046 public DiskInfo[] getDisks() { 3047 synchronized (mLock) { 3048 final DiskInfo[] res = new DiskInfo[mDisks.size()]; 3049 for (int i = 0; i < mDisks.size(); i++) { 3050 res[i] = mDisks.valueAt(i); 3051 } 3052 return res; 3053 } 3054 } 3055 3056 @Override 3057 public VolumeInfo[] getVolumes(int flags) { 3058 synchronized (mLock) { 3059 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()]; 3060 for (int i = 0; i < mVolumes.size(); i++) { 3061 res[i] = mVolumes.valueAt(i); 3062 } 3063 return res; 3064 } 3065 } 3066 3067 @Override 3068 public VolumeRecord[] getVolumeRecords(int flags) { 3069 synchronized (mLock) { 3070 final VolumeRecord[] res = new VolumeRecord[mRecords.size()]; 3071 for (int i = 0; i < mRecords.size(); i++) { 3072 res[i] = mRecords.valueAt(i); 3073 } 3074 return res; 3075 } 3076 } 3077 3078 private void addObbStateLocked(ObbState obbState) throws RemoteException { 3079 final IBinder binder = obbState.getBinder(); 3080 List<ObbState> obbStates = mObbMounts.get(binder); 3081 3082 if (obbStates == null) { 3083 obbStates = new ArrayList<ObbState>(); 3084 mObbMounts.put(binder, obbStates); 3085 } else { 3086 for (final ObbState o : obbStates) { 3087 if (o.rawPath.equals(obbState.rawPath)) { 3088 throw new IllegalStateException("Attempt to add ObbState twice. " 3089 + "This indicates an error in the MountService logic."); 3090 } 3091 } 3092 } 3093 3094 obbStates.add(obbState); 3095 try { 3096 obbState.link(); 3097 } catch (RemoteException e) { 3098 /* 3099 * The binder died before we could link it, so clean up our state 3100 * and return failure. 3101 */ 3102 obbStates.remove(obbState); 3103 if (obbStates.isEmpty()) { 3104 mObbMounts.remove(binder); 3105 } 3106 3107 // Rethrow the error so mountObb can get it 3108 throw e; 3109 } 3110 3111 mObbPathToStateMap.put(obbState.rawPath, obbState); 3112 } 3113 3114 private void removeObbStateLocked(ObbState obbState) { 3115 final IBinder binder = obbState.getBinder(); 3116 final List<ObbState> obbStates = mObbMounts.get(binder); 3117 if (obbStates != null) { 3118 if (obbStates.remove(obbState)) { 3119 obbState.unlink(); 3120 } 3121 if (obbStates.isEmpty()) { 3122 mObbMounts.remove(binder); 3123 } 3124 } 3125 3126 mObbPathToStateMap.remove(obbState.rawPath); 3127 } 3128 3129 private class ObbActionHandler extends Handler { 3130 private boolean mBound = false; 3131 private final List<ObbAction> mActions = new LinkedList<ObbAction>(); 3132 3133 ObbActionHandler(Looper l) { 3134 super(l); 3135 } 3136 3137 @Override 3138 public void handleMessage(Message msg) { 3139 switch (msg.what) { 3140 case OBB_RUN_ACTION: { 3141 final ObbAction action = (ObbAction) msg.obj; 3142 3143 if (DEBUG_OBB) 3144 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString()); 3145 3146 // If a bind was already initiated we don't really 3147 // need to do anything. The pending install 3148 // will be processed later on. 3149 if (!mBound) { 3150 // If this is the only one pending we might 3151 // have to bind to the service again. 3152 if (!connectToService()) { 3153 Slog.e(TAG, "Failed to bind to media container service"); 3154 action.handleError(); 3155 return; 3156 } 3157 } 3158 3159 mActions.add(action); 3160 break; 3161 } 3162 case OBB_MCS_BOUND: { 3163 if (DEBUG_OBB) 3164 Slog.i(TAG, "OBB_MCS_BOUND"); 3165 if (msg.obj != null) { 3166 mContainerService = (IMediaContainerService) msg.obj; 3167 } 3168 if (mContainerService == null) { 3169 // Something seriously wrong. Bail out 3170 Slog.e(TAG, "Cannot bind to media container service"); 3171 for (ObbAction action : mActions) { 3172 // Indicate service bind error 3173 action.handleError(); 3174 } 3175 mActions.clear(); 3176 } else if (mActions.size() > 0) { 3177 final ObbAction action = mActions.get(0); 3178 if (action != null) { 3179 action.execute(this); 3180 } 3181 } else { 3182 // Should never happen ideally. 3183 Slog.w(TAG, "Empty queue"); 3184 } 3185 break; 3186 } 3187 case OBB_MCS_RECONNECT: { 3188 if (DEBUG_OBB) 3189 Slog.i(TAG, "OBB_MCS_RECONNECT"); 3190 if (mActions.size() > 0) { 3191 if (mBound) { 3192 disconnectService(); 3193 } 3194 if (!connectToService()) { 3195 Slog.e(TAG, "Failed to bind to media container service"); 3196 for (ObbAction action : mActions) { 3197 // Indicate service bind error 3198 action.handleError(); 3199 } 3200 mActions.clear(); 3201 } 3202 } 3203 break; 3204 } 3205 case OBB_MCS_UNBIND: { 3206 if (DEBUG_OBB) 3207 Slog.i(TAG, "OBB_MCS_UNBIND"); 3208 3209 // Delete pending install 3210 if (mActions.size() > 0) { 3211 mActions.remove(0); 3212 } 3213 if (mActions.size() == 0) { 3214 if (mBound) { 3215 disconnectService(); 3216 } 3217 } else { 3218 // There are more pending requests in queue. 3219 // Just post MCS_BOUND message to trigger processing 3220 // of next pending install. 3221 mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND); 3222 } 3223 break; 3224 } 3225 case OBB_FLUSH_MOUNT_STATE: { 3226 final String path = (String) msg.obj; 3227 3228 if (DEBUG_OBB) 3229 Slog.i(TAG, "Flushing all OBB state for path " + path); 3230 3231 synchronized (mObbMounts) { 3232 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>(); 3233 3234 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator(); 3235 while (i.hasNext()) { 3236 final ObbState state = i.next(); 3237 3238 /* 3239 * If this entry's source file is in the volume path 3240 * that got unmounted, remove it because it's no 3241 * longer valid. 3242 */ 3243 if (state.canonicalPath.startsWith(path)) { 3244 obbStatesToRemove.add(state); 3245 } 3246 } 3247 3248 for (final ObbState obbState : obbStatesToRemove) { 3249 if (DEBUG_OBB) 3250 Slog.i(TAG, "Removing state for " + obbState.rawPath); 3251 3252 removeObbStateLocked(obbState); 3253 3254 try { 3255 obbState.token.onObbResult(obbState.rawPath, obbState.nonce, 3256 OnObbStateChangeListener.UNMOUNTED); 3257 } catch (RemoteException e) { 3258 Slog.i(TAG, "Couldn't send unmount notification for OBB: " 3259 + obbState.rawPath); 3260 } 3261 } 3262 } 3263 break; 3264 } 3265 } 3266 } 3267 3268 private boolean connectToService() { 3269 if (DEBUG_OBB) 3270 Slog.i(TAG, "Trying to bind to DefaultContainerService"); 3271 3272 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); 3273 if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE, 3274 UserHandle.SYSTEM)) { 3275 mBound = true; 3276 return true; 3277 } 3278 return false; 3279 } 3280 3281 private void disconnectService() { 3282 mContainerService = null; 3283 mBound = false; 3284 mContext.unbindService(mDefContainerConn); 3285 } 3286 } 3287 3288 abstract class ObbAction { 3289 private static final int MAX_RETRIES = 3; 3290 private int mRetries; 3291 3292 ObbState mObbState; 3293 3294 ObbAction(ObbState obbState) { 3295 mObbState = obbState; 3296 } 3297 3298 public void execute(ObbActionHandler handler) { 3299 try { 3300 if (DEBUG_OBB) 3301 Slog.i(TAG, "Starting to execute action: " + toString()); 3302 mRetries++; 3303 if (mRetries > MAX_RETRIES) { 3304 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); 3305 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 3306 handleError(); 3307 } else { 3308 handleExecute(); 3309 if (DEBUG_OBB) 3310 Slog.i(TAG, "Posting install MCS_UNBIND"); 3311 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 3312 } 3313 } catch (RemoteException e) { 3314 if (DEBUG_OBB) 3315 Slog.i(TAG, "Posting install MCS_RECONNECT"); 3316 mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT); 3317 } catch (Exception e) { 3318 if (DEBUG_OBB) 3319 Slog.d(TAG, "Error handling OBB action", e); 3320 handleError(); 3321 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 3322 } 3323 } 3324 3325 abstract void handleExecute() throws RemoteException, IOException; 3326 abstract void handleError(); 3327 3328 protected ObbInfo getObbInfo() throws IOException { 3329 ObbInfo obbInfo; 3330 try { 3331 obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath); 3332 } catch (RemoteException e) { 3333 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for " 3334 + mObbState.canonicalPath); 3335 obbInfo = null; 3336 } 3337 if (obbInfo == null) { 3338 throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath); 3339 } 3340 return obbInfo; 3341 } 3342 3343 protected void sendNewStatusOrIgnore(int status) { 3344 if (mObbState == null || mObbState.token == null) { 3345 return; 3346 } 3347 3348 try { 3349 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status); 3350 } catch (RemoteException e) { 3351 Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged"); 3352 } 3353 } 3354 } 3355 3356 class MountObbAction extends ObbAction { 3357 private final String mKey; 3358 private final int mCallingUid; 3359 3360 MountObbAction(ObbState obbState, String key, int callingUid) { 3361 super(obbState); 3362 mKey = key; 3363 mCallingUid = callingUid; 3364 } 3365 3366 @Override 3367 public void handleExecute() throws IOException, RemoteException { 3368 waitForReady(); 3369 warnOnNotMounted(); 3370 3371 final ObbInfo obbInfo = getObbInfo(); 3372 3373 if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) { 3374 Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename 3375 + " which is owned by " + obbInfo.packageName); 3376 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 3377 return; 3378 } 3379 3380 final boolean isMounted; 3381 synchronized (mObbMounts) { 3382 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath); 3383 } 3384 if (isMounted) { 3385 Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename); 3386 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED); 3387 return; 3388 } 3389 3390 final String hashedKey; 3391 if (mKey == null) { 3392 hashedKey = "none"; 3393 } else { 3394 try { 3395 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 3396 3397 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt, 3398 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE); 3399 SecretKey key = factory.generateSecret(ks); 3400 BigInteger bi = new BigInteger(key.getEncoded()); 3401 hashedKey = bi.toString(16); 3402 } catch (NoSuchAlgorithmException e) { 3403 Slog.e(TAG, "Could not load PBKDF2 algorithm", e); 3404 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 3405 return; 3406 } catch (InvalidKeySpecException e) { 3407 Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e); 3408 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 3409 return; 3410 } 3411 } 3412 3413 int rc = StorageResultCode.OperationSucceeded; 3414 try { 3415 mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey), 3416 mObbState.ownerGid); 3417 } catch (NativeDaemonConnectorException e) { 3418 int code = e.getCode(); 3419 if (code != VoldResponseCode.OpFailedStorageBusy) { 3420 rc = StorageResultCode.OperationFailedInternalError; 3421 } 3422 } 3423 3424 if (rc == StorageResultCode.OperationSucceeded) { 3425 if (DEBUG_OBB) 3426 Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath); 3427 3428 synchronized (mObbMounts) { 3429 addObbStateLocked(mObbState); 3430 } 3431 3432 sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED); 3433 } else { 3434 Slog.e(TAG, "Couldn't mount OBB file: " + rc); 3435 3436 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT); 3437 } 3438 } 3439 3440 @Override 3441 public void handleError() { 3442 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 3443 } 3444 3445 @Override 3446 public String toString() { 3447 StringBuilder sb = new StringBuilder(); 3448 sb.append("MountObbAction{"); 3449 sb.append(mObbState); 3450 sb.append('}'); 3451 return sb.toString(); 3452 } 3453 } 3454 3455 class UnmountObbAction extends ObbAction { 3456 private final boolean mForceUnmount; 3457 3458 UnmountObbAction(ObbState obbState, boolean force) { 3459 super(obbState); 3460 mForceUnmount = force; 3461 } 3462 3463 @Override 3464 public void handleExecute() throws IOException { 3465 waitForReady(); 3466 warnOnNotMounted(); 3467 3468 final ObbState existingState; 3469 synchronized (mObbMounts) { 3470 existingState = mObbPathToStateMap.get(mObbState.rawPath); 3471 } 3472 3473 if (existingState == null) { 3474 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED); 3475 return; 3476 } 3477 3478 if (existingState.ownerGid != mObbState.ownerGid) { 3479 Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath 3480 + " (owned by GID " + existingState.ownerGid + ")"); 3481 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 3482 return; 3483 } 3484 3485 int rc = StorageResultCode.OperationSucceeded; 3486 try { 3487 final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath); 3488 if (mForceUnmount) { 3489 cmd.appendArg("force"); 3490 } 3491 mConnector.execute(cmd); 3492 } catch (NativeDaemonConnectorException e) { 3493 int code = e.getCode(); 3494 if (code == VoldResponseCode.OpFailedStorageBusy) { 3495 rc = StorageResultCode.OperationFailedStorageBusy; 3496 } else if (code == VoldResponseCode.OpFailedStorageNotFound) { 3497 // If it's not mounted then we've already won. 3498 rc = StorageResultCode.OperationSucceeded; 3499 } else { 3500 rc = StorageResultCode.OperationFailedInternalError; 3501 } 3502 } 3503 3504 if (rc == StorageResultCode.OperationSucceeded) { 3505 synchronized (mObbMounts) { 3506 removeObbStateLocked(existingState); 3507 } 3508 3509 sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED); 3510 } else { 3511 Slog.w(TAG, "Could not unmount OBB: " + existingState); 3512 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT); 3513 } 3514 } 3515 3516 @Override 3517 public void handleError() { 3518 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 3519 } 3520 3521 @Override 3522 public String toString() { 3523 StringBuilder sb = new StringBuilder(); 3524 sb.append("UnmountObbAction{"); 3525 sb.append(mObbState); 3526 sb.append(",force="); 3527 sb.append(mForceUnmount); 3528 sb.append('}'); 3529 return sb.toString(); 3530 } 3531 } 3532 3533 private static class Callbacks extends Handler { 3534 private static final int MSG_STORAGE_STATE_CHANGED = 1; 3535 private static final int MSG_VOLUME_STATE_CHANGED = 2; 3536 private static final int MSG_VOLUME_RECORD_CHANGED = 3; 3537 private static final int MSG_VOLUME_FORGOTTEN = 4; 3538 private static final int MSG_DISK_SCANNED = 5; 3539 private static final int MSG_DISK_DESTROYED = 6; 3540 3541 private final RemoteCallbackList<IMountServiceListener> 3542 mCallbacks = new RemoteCallbackList<>(); 3543 3544 public Callbacks(Looper looper) { 3545 super(looper); 3546 } 3547 3548 public void register(IMountServiceListener callback) { 3549 mCallbacks.register(callback); 3550 } 3551 3552 public void unregister(IMountServiceListener callback) { 3553 mCallbacks.unregister(callback); 3554 } 3555 3556 @Override 3557 public void handleMessage(Message msg) { 3558 final SomeArgs args = (SomeArgs) msg.obj; 3559 final int n = mCallbacks.beginBroadcast(); 3560 for (int i = 0; i < n; i++) { 3561 final IMountServiceListener callback = mCallbacks.getBroadcastItem(i); 3562 try { 3563 invokeCallback(callback, msg.what, args); 3564 } catch (RemoteException ignored) { 3565 } 3566 } 3567 mCallbacks.finishBroadcast(); 3568 args.recycle(); 3569 } 3570 3571 private void invokeCallback(IMountServiceListener callback, int what, SomeArgs args) 3572 throws RemoteException { 3573 switch (what) { 3574 case MSG_STORAGE_STATE_CHANGED: { 3575 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2, 3576 (String) args.arg3); 3577 break; 3578 } 3579 case MSG_VOLUME_STATE_CHANGED: { 3580 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3); 3581 break; 3582 } 3583 case MSG_VOLUME_RECORD_CHANGED: { 3584 callback.onVolumeRecordChanged((VolumeRecord) args.arg1); 3585 break; 3586 } 3587 case MSG_VOLUME_FORGOTTEN: { 3588 callback.onVolumeForgotten((String) args.arg1); 3589 break; 3590 } 3591 case MSG_DISK_SCANNED: { 3592 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2); 3593 break; 3594 } 3595 case MSG_DISK_DESTROYED: { 3596 callback.onDiskDestroyed((DiskInfo) args.arg1); 3597 break; 3598 } 3599 } 3600 } 3601 3602 private void notifyStorageStateChanged(String path, String oldState, String newState) { 3603 final SomeArgs args = SomeArgs.obtain(); 3604 args.arg1 = path; 3605 args.arg2 = oldState; 3606 args.arg3 = newState; 3607 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget(); 3608 } 3609 3610 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { 3611 final SomeArgs args = SomeArgs.obtain(); 3612 args.arg1 = vol.clone(); 3613 args.argi2 = oldState; 3614 args.argi3 = newState; 3615 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget(); 3616 } 3617 3618 private void notifyVolumeRecordChanged(VolumeRecord rec) { 3619 final SomeArgs args = SomeArgs.obtain(); 3620 args.arg1 = rec.clone(); 3621 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget(); 3622 } 3623 3624 private void notifyVolumeForgotten(String fsUuid) { 3625 final SomeArgs args = SomeArgs.obtain(); 3626 args.arg1 = fsUuid; 3627 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget(); 3628 } 3629 3630 private void notifyDiskScanned(DiskInfo disk, int volumeCount) { 3631 final SomeArgs args = SomeArgs.obtain(); 3632 args.arg1 = disk.clone(); 3633 args.argi2 = volumeCount; 3634 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget(); 3635 } 3636 3637 private void notifyDiskDestroyed(DiskInfo disk) { 3638 final SomeArgs args = SomeArgs.obtain(); 3639 args.arg1 = disk.clone(); 3640 obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget(); 3641 } 3642 } 3643 3644 @Override 3645 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 3646 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 3647 3648 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160); 3649 synchronized (mLock) { 3650 pw.println("Disks:"); 3651 pw.increaseIndent(); 3652 for (int i = 0; i < mDisks.size(); i++) { 3653 final DiskInfo disk = mDisks.valueAt(i); 3654 disk.dump(pw); 3655 } 3656 pw.decreaseIndent(); 3657 3658 pw.println(); 3659 pw.println("Volumes:"); 3660 pw.increaseIndent(); 3661 for (int i = 0; i < mVolumes.size(); i++) { 3662 final VolumeInfo vol = mVolumes.valueAt(i); 3663 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue; 3664 vol.dump(pw); 3665 } 3666 pw.decreaseIndent(); 3667 3668 pw.println(); 3669 pw.println("Records:"); 3670 pw.increaseIndent(); 3671 for (int i = 0; i < mRecords.size(); i++) { 3672 final VolumeRecord note = mRecords.valueAt(i); 3673 note.dump(pw); 3674 } 3675 pw.decreaseIndent(); 3676 3677 pw.println(); 3678 pw.println("Primary storage UUID: " + mPrimaryStorageUuid); 3679 pw.println("Force adoptable: " + mForceAdoptable); 3680 pw.println(); 3681 pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers)); 3682 pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers)); 3683 } 3684 3685 synchronized (mObbMounts) { 3686 pw.println(); 3687 pw.println("mObbMounts:"); 3688 pw.increaseIndent(); 3689 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet() 3690 .iterator(); 3691 while (binders.hasNext()) { 3692 Entry<IBinder, List<ObbState>> e = binders.next(); 3693 pw.println(e.getKey() + ":"); 3694 pw.increaseIndent(); 3695 final List<ObbState> obbStates = e.getValue(); 3696 for (final ObbState obbState : obbStates) { 3697 pw.println(obbState); 3698 } 3699 pw.decreaseIndent(); 3700 } 3701 pw.decreaseIndent(); 3702 3703 pw.println(); 3704 pw.println("mObbPathToStateMap:"); 3705 pw.increaseIndent(); 3706 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator(); 3707 while (maps.hasNext()) { 3708 final Entry<String, ObbState> e = maps.next(); 3709 pw.print(e.getKey()); 3710 pw.print(" -> "); 3711 pw.println(e.getValue()); 3712 } 3713 pw.decreaseIndent(); 3714 } 3715 3716 pw.println(); 3717 pw.println("mConnector:"); 3718 pw.increaseIndent(); 3719 mConnector.dump(fd, pw, args); 3720 pw.decreaseIndent(); 3721 3722 pw.println(); 3723 pw.println("mCryptConnector:"); 3724 pw.increaseIndent(); 3725 mCryptConnector.dump(fd, pw, args); 3726 pw.decreaseIndent(); 3727 3728 pw.println(); 3729 pw.print("Last maintenance: "); 3730 pw.println(TimeUtils.formatForLogging(mLastMaintenance)); 3731 } 3732 3733 /** {@inheritDoc} */ 3734 @Override 3735 public void monitor() { 3736 if (mConnector != null) { 3737 mConnector.monitor(); 3738 } 3739 if (mCryptConnector != null) { 3740 mCryptConnector.monitor(); 3741 } 3742 } 3743 3744 private final class MountServiceInternalImpl extends MountServiceInternal { 3745 // Not guarded by a lock. 3746 private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies = 3747 new CopyOnWriteArrayList<>(); 3748 3749 @Override 3750 public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) { 3751 // No locking - CopyOnWriteArrayList 3752 mPolicies.add(policy); 3753 } 3754 3755 @Override 3756 public void onExternalStoragePolicyChanged(int uid, String packageName) { 3757 final int mountMode = getExternalStorageMountMode(uid, packageName); 3758 remountUidExternalStorage(uid, mountMode); 3759 } 3760 3761 @Override 3762 public int getExternalStorageMountMode(int uid, String packageName) { 3763 // No locking - CopyOnWriteArrayList 3764 int mountMode = Integer.MAX_VALUE; 3765 for (ExternalStorageMountPolicy policy : mPolicies) { 3766 final int policyMode = policy.getMountMode(uid, packageName); 3767 if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) { 3768 return Zygote.MOUNT_EXTERNAL_NONE; 3769 } 3770 mountMode = Math.min(mountMode, policyMode); 3771 } 3772 if (mountMode == Integer.MAX_VALUE) { 3773 return Zygote.MOUNT_EXTERNAL_NONE; 3774 } 3775 return mountMode; 3776 } 3777 3778 public boolean hasExternalStorage(int uid, String packageName) { 3779 // No need to check for system uid. This avoids a deadlock between 3780 // PackageManagerService and AppOpsService. 3781 if (uid == Process.SYSTEM_UID) { 3782 return true; 3783 } 3784 // No locking - CopyOnWriteArrayList 3785 for (ExternalStorageMountPolicy policy : mPolicies) { 3786 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName); 3787 if (!policyHasStorage) { 3788 return false; 3789 } 3790 } 3791 return true; 3792 } 3793 } 3794} 3795