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