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