1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import static com.android.internal.util.XmlUtils.readBooleanAttribute;
20import static com.android.internal.util.XmlUtils.readIntAttribute;
21import static com.android.internal.util.XmlUtils.readLongAttribute;
22import static com.android.internal.util.XmlUtils.readStringAttribute;
23import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
24import static com.android.internal.util.XmlUtils.writeIntAttribute;
25import static com.android.internal.util.XmlUtils.writeLongAttribute;
26import static com.android.internal.util.XmlUtils.writeStringAttribute;
27
28import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
29import static org.xmlpull.v1.XmlPullParser.START_TAG;
30
31import android.Manifest;
32import android.annotation.Nullable;
33import android.app.ActivityManager;
34import android.app.ActivityManagerNative;
35import android.app.AppOpsManager;
36import android.app.IActivityManager;
37import android.content.BroadcastReceiver;
38import android.content.ComponentName;
39import android.content.Context;
40import android.content.Intent;
41import android.content.IntentFilter;
42import android.content.ServiceConnection;
43import android.content.pm.IPackageMoveObserver;
44import android.content.pm.PackageManager;
45import android.content.pm.ProviderInfo;
46import android.content.pm.UserInfo;
47import android.content.res.Configuration;
48import android.content.res.ObbInfo;
49import android.net.Uri;
50import android.os.Binder;
51import android.os.DropBoxManager;
52import android.os.Environment;
53import android.os.Environment.UserEnvironment;
54import android.os.FileUtils;
55import android.os.Handler;
56import android.os.HandlerThread;
57import android.os.IBinder;
58import android.os.Looper;
59import android.os.Message;
60import android.os.ParcelFileDescriptor;
61import android.os.PowerManager;
62import android.os.Process;
63import android.os.RemoteCallbackList;
64import android.os.RemoteException;
65import android.os.ServiceManager;
66import android.os.SystemClock;
67import android.os.SystemProperties;
68import android.os.UserHandle;
69import android.os.UserManager;
70import android.os.storage.DiskInfo;
71import android.os.storage.IMountService;
72import android.os.storage.IMountServiceListener;
73import android.os.storage.IMountShutdownObserver;
74import android.os.storage.IObbActionListener;
75import android.os.storage.MountServiceInternal;
76import android.os.storage.OnObbStateChangeListener;
77import android.os.storage.StorageManager;
78import android.os.storage.StorageResultCode;
79import android.os.storage.StorageVolume;
80import android.os.storage.VolumeInfo;
81import android.os.storage.VolumeRecord;
82import android.provider.MediaStore;
83import android.provider.Settings;
84import android.text.TextUtils;
85import android.text.format.DateUtils;
86import android.util.ArrayMap;
87import android.util.AtomicFile;
88import android.util.Log;
89import android.util.Slog;
90import android.util.TimeUtils;
91import android.util.Xml;
92
93import com.android.internal.annotations.GuardedBy;
94import com.android.internal.app.IMediaContainerService;
95import com.android.internal.os.SomeArgs;
96import com.android.internal.os.Zygote;
97import com.android.internal.util.ArrayUtils;
98import com.android.internal.util.FastXmlSerializer;
99import com.android.internal.util.HexDump;
100import com.android.internal.util.IndentingPrintWriter;
101import com.android.internal.util.Preconditions;
102import com.android.internal.widget.LockPatternUtils;
103import com.android.server.NativeDaemonConnector.Command;
104import com.android.server.NativeDaemonConnector.SensitiveArg;
105import com.android.server.pm.PackageManagerService;
106
107import libcore.io.IoUtils;
108import libcore.util.EmptyArray;
109
110import org.xmlpull.v1.XmlPullParser;
111import org.xmlpull.v1.XmlPullParserException;
112import org.xmlpull.v1.XmlSerializer;
113
114import java.io.File;
115import java.io.FileDescriptor;
116import java.io.FileInputStream;
117import java.io.FileNotFoundException;
118import java.io.FileOutputStream;
119import java.io.IOException;
120import java.io.PrintWriter;
121import java.math.BigInteger;
122import java.nio.charset.StandardCharsets;
123import java.security.NoSuchAlgorithmException;
124import java.security.spec.InvalidKeySpecException;
125import java.security.spec.KeySpec;
126import java.util.ArrayList;
127import java.util.Arrays;
128import java.util.HashMap;
129import java.util.HashSet;
130import java.util.Iterator;
131import java.util.LinkedList;
132import java.util.List;
133import java.util.Locale;
134import java.util.Map;
135import java.util.Map.Entry;
136import java.util.Objects;
137import java.util.concurrent.CopyOnWriteArrayList;
138import java.util.concurrent.CountDownLatch;
139import java.util.concurrent.TimeUnit;
140import java.util.concurrent.TimeoutException;
141
142import javax.crypto.SecretKey;
143import javax.crypto.SecretKeyFactory;
144import javax.crypto.spec.PBEKeySpec;
145
146/**
147 * Service responsible for various storage media. Connects to {@code vold} to
148 * watch for and manage dynamically added storage, such as SD cards and USB mass
149 * storage. Also decides how storage should be presented to users on the device.
150 */
151class MountService extends IMountService.Stub
152        implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
153
154    // Static direct instance pointer for the tightly-coupled idle service to use
155    static MountService sSelf = null;
156
157    public static class Lifecycle extends SystemService {
158        private MountService mMountService;
159
160        public Lifecycle(Context context) {
161            super(context);
162        }
163
164        @Override
165        public void onStart() {
166            mMountService = new MountService(getContext());
167            publishBinderService("mount", mMountService);
168            mMountService.start();
169        }
170
171        @Override
172        public void onBootPhase(int phase) {
173            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
174                mMountService.systemReady();
175            } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
176                mMountService.bootCompleted();
177            }
178        }
179
180        @Override
181        public void 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