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