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