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.Manifest.permission.ACCESS_MTP;
20 import static android.Manifest.permission.INSTALL_PACKAGES;
21 import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
22 import static android.app.AppOpsManager.MODE_ALLOWED;
23 import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
24 import static android.app.AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE;
25 import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
26 import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
27 import static android.app.PendingIntent.FLAG_IMMUTABLE;
28 import static android.app.PendingIntent.FLAG_ONE_SHOT;
29 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
30 import static android.content.pm.PackageManager.MATCH_ANY_USER;
31 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
32 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
33 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
34 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
35 import static android.os.IInstalld.IFsveritySetupAuthToken;
36 import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
37 import static android.os.storage.OnObbStateChangeListener.ERROR_ALREADY_MOUNTED;
38 import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT;
39 import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT;
40 import static android.os.storage.OnObbStateChangeListener.ERROR_NOT_MOUNTED;
41 import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIED;
42 import static android.os.storage.OnObbStateChangeListener.MOUNTED;
43 import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
44 
45 import static com.android.internal.util.XmlUtils.readStringAttribute;
46 import static com.android.internal.util.XmlUtils.writeStringAttribute;
47 
48 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
49 import static org.xmlpull.v1.XmlPullParser.START_TAG;
50 
51 import android.annotation.EnforcePermission;
52 import android.annotation.NonNull;
53 import android.annotation.Nullable;
54 import android.annotation.UserIdInt;
55 import android.app.ActivityManager;
56 import android.app.ActivityManagerInternal;
57 import android.app.ActivityOptions;
58 import android.app.AnrController;
59 import android.app.AppOpsManager;
60 import android.app.IActivityManager;
61 import android.app.KeyguardManager;
62 import android.app.PendingIntent;
63 import android.app.admin.SecurityLog;
64 import android.app.usage.StorageStatsManager;
65 import android.content.BroadcastReceiver;
66 import android.content.Context;
67 import android.content.Intent;
68 import android.content.IntentFilter;
69 import android.content.pm.ApplicationInfo;
70 import android.content.pm.IPackageManager;
71 import android.content.pm.IPackageMoveObserver;
72 import android.content.pm.PackageManager;
73 import android.content.pm.PackageManagerInternal;
74 import android.content.pm.ProviderInfo;
75 import android.content.pm.UserInfo;
76 import android.content.res.ObbInfo;
77 import android.database.ContentObserver;
78 import android.media.MediaCodecInfo;
79 import android.media.MediaCodecList;
80 import android.media.MediaFormat;
81 import android.net.Uri;
82 import android.os.BatteryManager;
83 import android.os.Binder;
84 import android.os.Build;
85 import android.os.DropBoxManager;
86 import android.os.Environment;
87 import android.os.Handler;
88 import android.os.HandlerThread;
89 import android.os.IBinder;
90 import android.os.IStoraged;
91 import android.os.IVold;
92 import android.os.IVoldListener;
93 import android.os.IVoldMountCallback;
94 import android.os.IVoldTaskListener;
95 import android.os.Looper;
96 import android.os.Message;
97 import android.os.ParcelFileDescriptor;
98 import android.os.ParcelableException;
99 import android.os.PersistableBundle;
100 import android.os.Process;
101 import android.os.RemoteCallbackList;
102 import android.os.RemoteException;
103 import android.os.ServiceManager;
104 import android.os.ServiceSpecificException;
105 import android.os.SystemClock;
106 import android.os.SystemProperties;
107 import android.os.UserHandle;
108 import android.os.UserManager;
109 import android.os.storage.DiskInfo;
110 import android.os.storage.ICeStorageLockEventListener;
111 import android.os.storage.IObbActionListener;
112 import android.os.storage.IStorageEventListener;
113 import android.os.storage.IStorageManager;
114 import android.os.storage.IStorageShutdownObserver;
115 import android.os.storage.OnObbStateChangeListener;
116 import android.os.storage.StorageManager;
117 import android.os.storage.StorageManagerInternal;
118 import android.os.storage.StorageVolume;
119 import android.os.storage.VolumeInfo;
120 import android.os.storage.VolumeRecord;
121 import android.provider.DeviceConfig;
122 import android.provider.DocumentsContract;
123 import android.provider.Downloads;
124 import android.provider.MediaStore;
125 import android.provider.Settings;
126 import android.service.storage.ExternalStorageService;
127 import android.text.TextUtils;
128 import android.text.format.DateUtils;
129 import android.util.ArrayMap;
130 import android.util.ArraySet;
131 import android.util.AtomicFile;
132 import android.util.DataUnit;
133 import android.util.EventLog;
134 import android.util.Log;
135 import android.util.Pair;
136 import android.util.Slog;
137 import android.util.SparseArray;
138 import android.util.SparseIntArray;
139 import android.util.TimeUtils;
140 import android.util.Xml;
141 
142 import com.android.internal.annotations.GuardedBy;
143 import com.android.internal.annotations.VisibleForTesting;
144 import com.android.internal.app.IAppOpsService;
145 import com.android.internal.content.PackageMonitor;
146 import com.android.internal.os.AppFuseMount;
147 import com.android.internal.os.BackgroundThread;
148 import com.android.internal.os.FuseUnavailableMountException;
149 import com.android.internal.os.SomeArgs;
150 import com.android.internal.util.ArrayUtils;
151 import com.android.internal.util.DumpUtils;
152 import com.android.internal.util.IndentingPrintWriter;
153 import com.android.internal.util.Preconditions;
154 import com.android.modules.utils.TypedXmlPullParser;
155 import com.android.modules.utils.TypedXmlSerializer;
156 import com.android.server.pm.Installer;
157 import com.android.server.pm.UserManagerInternal;
158 import com.android.server.storage.AppFuseBridge;
159 import com.android.server.storage.StorageSessionController;
160 import com.android.server.storage.StorageSessionController.ExternalStorageServiceException;
161 import com.android.server.wm.ActivityTaskManagerInternal;
162 import com.android.server.wm.ActivityTaskManagerInternal.ScreenObserver;
163 
164 import libcore.io.IoUtils;
165 import libcore.util.EmptyArray;
166 
167 import org.xmlpull.v1.XmlPullParserException;
168 
169 import java.io.File;
170 import java.io.FileDescriptor;
171 import java.io.FileInputStream;
172 import java.io.FileNotFoundException;
173 import java.io.FileOutputStream;
174 import java.io.IOException;
175 import java.io.ObjectInputStream;
176 import java.io.ObjectOutputStream;
177 import java.io.PrintWriter;
178 import java.util.ArrayList;
179 import java.util.Arrays;
180 import java.util.HashMap;
181 import java.util.Iterator;
182 import java.util.List;
183 import java.util.Locale;
184 import java.util.Map;
185 import java.util.Map.Entry;
186 import java.util.Objects;
187 import java.util.Set;
188 import java.util.UUID;
189 import java.util.concurrent.CopyOnWriteArrayList;
190 import java.util.concurrent.CopyOnWriteArraySet;
191 import java.util.concurrent.CountDownLatch;
192 import java.util.concurrent.TimeUnit;
193 import java.util.concurrent.TimeoutException;
194 import java.util.regex.Matcher;
195 import java.util.regex.Pattern;
196 
197 /**
198  * Service responsible for various storage media. Connects to {@code vold} to
199  * watch for and manage dynamically added storage, such as SD cards and USB mass
200  * storage. Also decides how storage should be presented to users on the device.
201  */
202 class StorageManagerService extends IStorageManager.Stub
203         implements Watchdog.Monitor, ScreenObserver {
204 
205     // Static direct instance pointer for the tightly-coupled idle service to use
206     static StorageManagerService sSelf = null;
207 
208     /* Read during boot to decide whether to enable zram when available */
209     private static final String ZRAM_ENABLED_PROPERTY =
210             "persist.sys.zram_enabled";
211 
212     // A system property to control if obb app data isolation is enabled in vold.
213     private static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
214             "persist.sys.vold_app_data_isolation_enabled";
215 
216     // How long we wait to reset storage, if we failed to call onMount on the
217     // external storage service.
218     public static final int FAILED_MOUNT_RESET_TIMEOUT_SECONDS = 10;
219 
220     /** Extended timeout for the system server watchdog. */
221     private static final int SLOW_OPERATION_WATCHDOG_TIMEOUT_MS = 20 * 1000;
222 
223     /** Extended timeout for the system server watchdog for vold#partition operation. */
224     private static final int PARTITION_OPERATION_WATCHDOG_TIMEOUT_MS = 3 * 60 * 1000;
225 
226     @GuardedBy("mLock")
227     private final Set<Integer> mFuseMountedUser = new ArraySet<>();
228 
229     @GuardedBy("mLock")
230     private final Set<Integer> mCeStoragePreparedUsers = new ArraySet<>();
231 
232     private volatile long mInternalStorageSize = 0;
233 
234     public static class Lifecycle extends SystemService {
235         private StorageManagerService mStorageManagerService;
236 
Lifecycle(Context context)237         public Lifecycle(Context context) {
238             super(context);
239         }
240 
241         @Override
onStart()242         public void onStart() {
243             mStorageManagerService = new StorageManagerService(getContext());
244             publishBinderService("mount", mStorageManagerService);
245             mStorageManagerService.start();
246         }
247 
248         @Override
onBootPhase(int phase)249         public void onBootPhase(int phase) {
250             if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
251                 mStorageManagerService.servicesReady();
252             } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
253                 mStorageManagerService.systemReady();
254             } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
255                 mStorageManagerService.bootCompleted();
256             }
257         }
258 
259         @Override
onUserSwitching(@ullable TargetUser from, @NonNull TargetUser to)260         public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
261             int currentUserId = to.getUserIdentifier();
262             mStorageManagerService.mCurrentUserId = currentUserId;
263 
264             UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class);
265             if (umInternal.isUserUnlocked(currentUserId)) {
266                 Slog.d(TAG, "Attempt remount volumes for user: " + currentUserId);
267                 mStorageManagerService.maybeRemountVolumes(currentUserId);
268                 mStorageManagerService.mRemountCurrentUserVolumesOnUnlock = false;
269             } else {
270                 Slog.d(TAG, "Attempt remount volumes for user: " + currentUserId + " on unlock");
271                 mStorageManagerService.mRemountCurrentUserVolumesOnUnlock = true;
272             }
273         }
274 
275         @Override
onUserUnlocking(@onNull TargetUser user)276         public void onUserUnlocking(@NonNull TargetUser user) {
277             mStorageManagerService.onUserUnlocking(user.getUserIdentifier());
278         }
279 
280         @Override
onUserStopped(@onNull TargetUser user)281         public void onUserStopped(@NonNull TargetUser user) {
282             mStorageManagerService.onUserStopped(user.getUserIdentifier());
283         }
284 
285         @Override
onUserStopping(@onNull TargetUser user)286         public void onUserStopping(@NonNull TargetUser user) {
287             mStorageManagerService.onUserStopping(user.getUserIdentifier());
288         }
289 
290         @Override
onUserStarting(TargetUser user)291         public void onUserStarting(TargetUser user) {
292             mStorageManagerService.snapshotAndMonitorLegacyStorageAppOp(user.getUserHandle());
293         }
294     }
295 
296     private static final boolean DEBUG_OBB = false;
297 
298     /**
299      * We now talk to vold over Binder, and it has its own internal lock to
300      * serialize certain calls. All long-running operations have been migrated
301      * to be async with callbacks, so we want watchdog to fire if vold wedges.
302      */
303     private static final boolean WATCHDOG_ENABLE = true;
304 
305     private static final String TAG = "StorageManagerService";
306     private static final boolean LOCAL_LOGV = Log.isLoggable(TAG, Log.VERBOSE);
307 
308     private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
309     private static final String TAG_STORAGE_TRIM = "storage_trim";
310 
311     /** Magic value sent by MoveTask.cpp */
312     private static final int MOVE_STATUS_COPY_FINISHED = 82;
313 
314     private static final int VERSION_INIT = 1;
315     private static final int VERSION_ADD_PRIMARY = 2;
316     private static final int VERSION_FIX_PRIMARY = 3;
317 
318     private static final String TAG_VOLUMES = "volumes";
319     private static final String ATTR_VERSION = "version";
320     private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
321     private static final String TAG_VOLUME = "volume";
322     private static final String ATTR_TYPE = "type";
323     private static final String ATTR_FS_UUID = "fsUuid";
324     private static final String ATTR_PART_GUID = "partGuid";
325     private static final String ATTR_NICKNAME = "nickname";
326     private static final String ATTR_USER_FLAGS = "userFlags";
327     private static final String ATTR_CREATED_MILLIS = "createdMillis";
328     private static final String ATTR_LAST_SEEN_MILLIS = "lastSeenMillis";
329     private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
330     private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
331 
332     @Nullable public static String sMediaStoreAuthorityProcessName;
333 
334     // Smart idle maintenance running period in minute
335     static volatile int sSmartIdleMaintPeriod = 60;
336 
337     private final AtomicFile mSettingsFile;
338     private final AtomicFile mWriteRecordFile;
339 
340     // 72 hours (3 days)
341     private static final int MAX_PERIOD_WRITE_RECORD = 72 * 60;
342     private volatile int mMaxWriteRecords;
343 
344     /**
345      * Default config values for smart idle maintenance
346      * Actual values will be controlled by DeviceConfig
347      */
348     // Decide whether smart idle maintenance is enabled or not
349     private static final boolean DEFAULT_SMART_IDLE_MAINT_ENABLED = false;
350     // Run period in minute for smart idle maintenance
351     private static final int DEFAULT_SMART_IDLE_MAINT_PERIOD = 60;
352     private static final int MIN_SMART_IDLE_MAINT_PERIOD = 10;
353     private static final int MAX_SMART_IDLE_MAINT_PERIOD = 24 * 60;
354     // Storage lifetime percentage threshold to decide to turn off the feature
355     private static final int DEFAULT_LIFETIME_PERCENT_THRESHOLD = 70;
356     // Minimum required number of dirty + free segments to trigger GC
357     private static final int DEFAULT_MIN_SEGMENTS_THRESHOLD = 512;
358     // Determine how much portion of current dirty segments will be GCed
359     private static final float DEFAULT_DIRTY_RECLAIM_RATE = 0.5F;
360     // Multiplier to amplify the target segment number for GC
361     private static final float DEFAULT_SEGMENT_RECLAIM_WEIGHT = 1.0F;
362     // Low battery level threshold to decide to turn off the feature
363     private static final float DEFAULT_LOW_BATTERY_LEVEL = 20F;
364     // Decide whether charging is required to turn on the feature
365     private static final boolean DEFAULT_CHARGING_REQUIRED = true;
366     // Minimum GC interval sleep time in ms
367     private static final int DEFAULT_MIN_GC_SLEEPTIME = 10000;
368     // Target dirty segment ratio to aim to
369     private static final int DEFAULT_TARGET_DIRTY_RATIO = 80;
370 
371     private volatile int mLifetimePercentThreshold;
372     private volatile int mMinSegmentsThreshold;
373     private volatile float mDirtyReclaimRate;
374     private volatile float mSegmentReclaimWeight;
375     private volatile float mLowBatteryLevel;
376     private volatile boolean mChargingRequired;
377     private volatile int mMinGCSleepTime;
378     private volatile int mTargetDirtyRatio;
379     private volatile boolean mNeedGC = true;
380 
381     private volatile boolean mPassedLifetimeThresh;
382     // Tracking storage write amounts in one period
383     private volatile int[] mStorageWriteRecords;
384 
385     /**
386      * <em>Never</em> hold the lock while performing downcalls into vold, since
387      * unsolicited events can suddenly appear to update data structures.
388      */
389     private final Object mLock = LockGuard.installNewLock(LockGuard.INDEX_STORAGE);
390 
391     /**
392      * mCeUnlockedUsers affects the return value of {@link UserManager#isUserUnlocked}.  If any
393      * value in the array changes, then the binder cache for {@link UserManager#isUserUnlocked} must
394      * be invalidated.  When adding mutating methods to this class, be sure to invalidate the cache
395      * in the new methods.
396      */
397     private static class WatchedUnlockedUsers {
398         private int[] users = EmptyArray.INT;
WatchedUnlockedUsers()399         public WatchedUnlockedUsers() {
400             invalidateIsUserUnlockedCache();
401         }
append(int userId)402         public void append(int userId) {
403             users = ArrayUtils.appendInt(users, userId);
404             invalidateIsUserUnlockedCache();
405         }
appendAll(int[] userIds)406         public void appendAll(int[] userIds) {
407             for (int userId : userIds) {
408                 users = ArrayUtils.appendInt(users, userId);
409             }
410             invalidateIsUserUnlockedCache();
411         }
remove(int userId)412         public void remove(int userId) {
413             users = ArrayUtils.removeInt(users, userId);
414             invalidateIsUserUnlockedCache();
415         }
contains(int userId)416         public boolean contains(int userId) {
417             return ArrayUtils.contains(users, userId);
418         }
all()419         public int[] all() {
420             return users;
421         }
422         @Override
toString()423         public String toString() {
424             return Arrays.toString(users);
425         }
invalidateIsUserUnlockedCache()426         private void invalidateIsUserUnlockedCache() {
427             UserManager.invalidateIsUserUnlockedCache();
428         }
429     }
430 
431     /** Set of users whose CE storage is unlocked. */
432     @GuardedBy("mLock")
433     private WatchedUnlockedUsers mCeUnlockedUsers = new WatchedUnlockedUsers();
434 
435     /**
436      * Set of users that are in the RUNNING_UNLOCKED state.  This differs from {@link
437      * mCeUnlockedUsers} in that a user can be stopped but still have its CE storage unlocked.
438      */
439     @GuardedBy("mLock")
440     private int[] mSystemUnlockedUsers = EmptyArray.INT;
441 
442     /** Map from disk ID to disk */
443     @GuardedBy("mLock")
444     private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
445     /** Map from volume ID to disk */
446     @GuardedBy("mLock")
447     private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
448 
449     /** Map from UUID to record */
450     @GuardedBy("mLock")
451     private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
452     @GuardedBy("mLock")
453     private String mPrimaryStorageUuid;
454 
455     /** Map from disk ID to latches */
456     @GuardedBy("mLock")
457     private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
458 
459     @GuardedBy("mLock")
460     private IPackageMoveObserver mMoveCallback;
461     @GuardedBy("mLock")
462     private String mMoveTargetUuid;
463 
464     @GuardedBy("mCloudMediaProviders")
465     private final SparseArray<String> mCloudMediaProviders = new SparseArray<>();
466 
467     private volatile int mMediaStoreAuthorityAppId = -1;
468 
469     private volatile int mDownloadsAuthorityAppId = -1;
470 
471     private volatile int mExternalStorageAuthorityAppId = -1;
472 
473     private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
474 
475     private volatile boolean mRemountCurrentUserVolumesOnUnlock = false;
476 
477     private final Installer mInstaller;
478 
479     /** Holding lock for AppFuse business */
480     private final Object mAppFuseLock = new Object();
481 
482     @GuardedBy("mAppFuseLock")
483     private int mNextAppFuseName = 0;
484 
485     @GuardedBy("mAppFuseLock")
486     private AppFuseBridge mAppFuseBridge = null;
487 
488     private final SparseIntArray mUserSharesMediaWith = new SparseIntArray();
489 
490     /** Matches known application dir paths. The first group contains the generic part of the path,
491      * the second group contains the user id (or null if it's a public volume without users), the
492      * third group contains the package name, and the fourth group the remainder of the path.
493      */
494     public static final Pattern KNOWN_APP_DIR_PATHS = Pattern.compile(
495             "(?i)(^/storage/[^/]+/(?:([0-9]+)/)?Android/(?:data|media|obb|sandbox)/)([^/]+)(/.*)?");
496 
497 
findVolumeByIdOrThrow(String id)498     private VolumeInfo findVolumeByIdOrThrow(String id) {
499         synchronized (mLock) {
500             final VolumeInfo vol = mVolumes.get(id);
501             if (vol != null) {
502                 return vol;
503             }
504         }
505         throw new IllegalArgumentException("No volume found for ID " + id);
506     }
507 
findRecordForPath(String path)508     private VolumeRecord findRecordForPath(String path) {
509         synchronized (mLock) {
510             for (int i = 0; i < mVolumes.size(); i++) {
511                 final VolumeInfo vol = mVolumes.valueAt(i);
512                 if (vol.path != null && path.startsWith(vol.path)) {
513                     return mRecords.get(vol.fsUuid);
514                 }
515             }
516         }
517         return null;
518     }
519 
scrubPath(String path)520     private String scrubPath(String path) {
521         if (path.startsWith(Environment.getDataDirectory().getAbsolutePath())) {
522             return "internal";
523         }
524         final VolumeRecord rec = findRecordForPath(path);
525         if (rec == null || rec.createdMillis == 0) {
526             return "unknown";
527         } else {
528             return "ext:" + (int) ((System.currentTimeMillis() - rec.createdMillis)
529                     / DateUtils.WEEK_IN_MILLIS) + "w";
530         }
531     }
532 
findStorageForUuidAsUser(String volumeUuid, @UserIdInt int userId)533     private @Nullable VolumeInfo findStorageForUuidAsUser(String volumeUuid,
534             @UserIdInt int userId) {
535         final StorageManager storage = mContext.getSystemService(StorageManager.class);
536         if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
537             return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL + ";" + userId);
538         } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
539             return storage.getPrimaryPhysicalVolume();
540         } else {
541             VolumeInfo info = storage.findVolumeByUuid(volumeUuid);
542             if (info == null) {
543                 Slog.w(TAG, "findStorageForUuidAsUser cannot find volumeUuid:" + volumeUuid);
544                 return null;
545             }
546             String emulatedUuid = info.getId().replace("private", "emulated") + ";" + userId;
547             return storage.findVolumeById(emulatedUuid);
548         }
549     }
550 
findOrCreateDiskScanLatch(String diskId)551     private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
552         synchronized (mLock) {
553             CountDownLatch latch = mDiskScanLatches.get(diskId);
554             if (latch == null) {
555                 latch = new CountDownLatch(1);
556                 mDiskScanLatches.put(diskId, latch);
557             }
558             return latch;
559         }
560     }
561 
562     private final Context mContext;
563 
564     private volatile IVold mVold;
565     private volatile IStoraged mStoraged;
566 
567     private volatile boolean mBootCompleted = false;
568     private volatile boolean mDaemonConnected = false;
569     private volatile boolean mSecureKeyguardShowing = true;
570 
571     private PackageManagerInternal mPmInternal;
572 
573     private IPackageManager mIPackageManager;
574     private IAppOpsService mIAppOpsService;
575 
576     private final Callbacks mCallbacks;
577 
578     private static final String ANR_DELAY_MILLIS_DEVICE_CONFIG_KEY =
579             "anr_delay_millis";
580 
581     private static final String ANR_DELAY_NOTIFY_EXTERNAL_STORAGE_SERVICE_DEVICE_CONFIG_KEY =
582             "anr_delay_notify_external_storage_service";
583 
584     /**
585      * Mounted OBB tracking information. Used to track the current state of all
586      * OBBs.
587      */
588     final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
589 
590     /** Map from raw paths to {@link ObbState}. */
591     final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
592 
593     // Not guarded by a lock.
594     private final StorageManagerInternalImpl mStorageManagerInternal
595             = new StorageManagerInternalImpl();
596 
597     // Not guarded by a lock.
598     private final StorageSessionController mStorageSessionController;
599 
600     private final boolean mVoldAppDataIsolationEnabled;
601 
602     @GuardedBy("mLock")
603     private final Set<Integer> mUidsWithLegacyExternalStorage = new ArraySet<>();
604     // Not guarded by lock, always used on the ActivityManager thread
605     private final SparseArray<PackageMonitor> mPackageMonitorsForUser = new SparseArray<>();
606 
607     /** List of listeners registered for ce storage callbacks */
608     private final CopyOnWriteArrayList<ICeStorageLockEventListener>
609             mCeStorageEventCallbacks = new CopyOnWriteArrayList<>();
610 
611     class ObbState implements IBinder.DeathRecipient {
ObbState(String rawPath, String canonicalPath, int callingUid, IObbActionListener token, int nonce, String volId)612         public ObbState(String rawPath, String canonicalPath, int callingUid,
613                 IObbActionListener token, int nonce, String volId) {
614             this.rawPath = rawPath;
615             this.canonicalPath = canonicalPath;
616             this.ownerGid = UserHandle.getSharedAppGid(callingUid);
617             this.token = token;
618             this.nonce = nonce;
619             this.volId = volId;
620         }
621 
622         final String rawPath;
623         final String canonicalPath;
624 
625         final int ownerGid;
626 
627         // Token of remote Binder caller
628         final IObbActionListener token;
629 
630         // Identifier to pass back to the token
631         final int nonce;
632 
633         String volId;
634 
getBinder()635         public IBinder getBinder() {
636             return token.asBinder();
637         }
638 
639         @Override
binderDied()640         public void binderDied() {
641             ObbAction action = new UnmountObbAction(this, true);
642             mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
643         }
644 
link()645         public void link() throws RemoteException {
646             getBinder().linkToDeath(this, 0);
647         }
648 
unlink()649         public void unlink() {
650             getBinder().unlinkToDeath(this, 0);
651         }
652 
653         @Override
toString()654         public String toString() {
655             StringBuilder sb = new StringBuilder("ObbState{");
656             sb.append("rawPath=").append(rawPath);
657             sb.append(",canonicalPath=").append(canonicalPath);
658             sb.append(",ownerGid=").append(ownerGid);
659             sb.append(",token=").append(token);
660             sb.append(",binder=").append(getBinder());
661             sb.append(",volId=").append(volId);
662             sb.append('}');
663             return sb.toString();
664         }
665     }
666 
667     // OBB Action Handler
668     final private ObbActionHandler mObbActionHandler;
669 
670     // OBB action handler messages
671     private static final int OBB_RUN_ACTION = 1;
672     private static final int OBB_FLUSH_MOUNT_STATE = 2;
673 
674     // Last fstrim operation tracking
675     private static final String LAST_FSTRIM_FILE = "last-fstrim";
676     private final File mLastMaintenanceFile;
677     private long mLastMaintenance;
678 
679     // Handler messages
680     private static final int H_SYSTEM_READY = 1;
681     private static final int H_DAEMON_CONNECTED = 2;
682     private static final int H_SHUTDOWN = 3;
683     private static final int H_FSTRIM = 4;
684     private static final int H_VOLUME_MOUNT = 5;
685     private static final int H_VOLUME_BROADCAST = 6;
686     private static final int H_INTERNAL_BROADCAST = 7;
687     private static final int H_VOLUME_UNMOUNT = 8;
688     private static final int H_PARTITION_FORGET = 9;
689     private static final int H_RESET = 10;
690     private static final int H_RUN_IDLE_MAINT = 11;
691     private static final int H_ABORT_IDLE_MAINT = 12;
692     private static final int H_BOOT_COMPLETED = 13;
693     private static final int H_COMPLETE_UNLOCK_USER = 14;
694     private static final int H_VOLUME_STATE_CHANGED = 15;
695     private static final int H_CLOUD_MEDIA_PROVIDER_CHANGED = 16;
696     private static final int H_SECURE_KEYGUARD_STATE_CHANGED = 17;
697     private static final int H_REMOUNT_VOLUMES_ON_MOVE = 18;
698 
699     class StorageManagerServiceHandler extends Handler {
StorageManagerServiceHandler(Looper looper)700         public StorageManagerServiceHandler(Looper looper) {
701             super(looper);
702         }
703 
704         @Override
handleMessage(Message msg)705         public void handleMessage(Message msg) {
706             switch (msg.what) {
707                 case H_SYSTEM_READY: {
708                     handleSystemReady();
709                     break;
710                 }
711                 case H_BOOT_COMPLETED: {
712                     handleBootCompleted();
713                     break;
714                 }
715                 case H_DAEMON_CONNECTED: {
716                     handleDaemonConnected();
717                     break;
718                 }
719                 case H_FSTRIM: {
720                     Slog.i(TAG, "Running fstrim idle maintenance");
721 
722                     // Remember when we kicked it off
723                     try {
724                         mLastMaintenance = System.currentTimeMillis();
725                         mLastMaintenanceFile.setLastModified(mLastMaintenance);
726                     } catch (Exception e) {
727                         Slog.e(TAG, "Unable to record last fstrim!");
728                     }
729 
730                     // TODO: Reintroduce shouldBenchmark() test
731                     fstrim(0, null);
732 
733                     // invoke the completion callback, if any
734                     // TODO: fstrim is non-blocking, so remove this useless callback
735                     Runnable callback = (Runnable) msg.obj;
736                     if (callback != null) {
737                         callback.run();
738                     }
739                     break;
740                 }
741                 case H_SHUTDOWN: {
742                     final IStorageShutdownObserver obs = (IStorageShutdownObserver) msg.obj;
743                     boolean success = false;
744                     try {
745                         mVold.shutdown();
746                         success = true;
747                     } catch (Exception e) {
748                         Slog.wtf(TAG, e);
749                     }
750                     if (obs != null) {
751                         try {
752                             obs.onShutDownComplete(success ? 0 : -1);
753                         } catch (Exception ignored) {
754                         }
755                     }
756                     break;
757                 }
758                 case H_VOLUME_MOUNT: {
759                     final VolumeInfo vol = (VolumeInfo) msg.obj;
760                     if (isMountDisallowed(vol)) {
761                         Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
762                         break;
763                     }
764 
765                     mount(vol);
766                     break;
767                 }
768                 case H_VOLUME_UNMOUNT: {
769                     final VolumeInfo vol = (VolumeInfo) msg.obj;
770                     unmount(vol);
771                     break;
772                 }
773                 case H_VOLUME_BROADCAST: {
774                     final StorageVolume userVol = (StorageVolume) msg.obj;
775                     final String envState = userVol.getState();
776                     Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
777                             + userVol.getOwner());
778 
779                     final String action = VolumeInfo.getBroadcastForEnvironment(envState);
780                     if (action != null) {
781                         final Intent intent = new Intent(action,
782                                 Uri.fromFile(userVol.getPathFile()));
783                         intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
784                         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
785                                 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
786                         mContext.sendBroadcastAsUser(intent, userVol.getOwner());
787                     }
788                     break;
789                 }
790                 case H_INTERNAL_BROADCAST: {
791                     // Internal broadcasts aimed at system components, not for
792                     // third-party apps.
793                     final Intent intent = (Intent) msg.obj;
794                     mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
795                             android.Manifest.permission.WRITE_MEDIA_STORAGE);
796                     break;
797                 }
798                 case H_PARTITION_FORGET: {
799                     final VolumeRecord rec = (VolumeRecord) msg.obj;
800                     forgetPartition(rec.partGuid, rec.fsUuid);
801                     break;
802                 }
803                 case H_RESET: {
804                     resetIfBootedAndConnected();
805                     break;
806                 }
807                 case H_RUN_IDLE_MAINT: {
808                     Slog.i(TAG, "Running idle maintenance");
809                     runIdleMaint((Runnable)msg.obj);
810                     break;
811                 }
812                 case H_ABORT_IDLE_MAINT: {
813                     Slog.i(TAG, "Aborting idle maintenance");
814                     abortIdleMaint((Runnable)msg.obj);
815                     break;
816                 }
817                 case H_COMPLETE_UNLOCK_USER: {
818                     completeUnlockUser(msg.arg1);
819                     break;
820                 }
821                 case H_VOLUME_STATE_CHANGED: {
822                     final SomeArgs args = (SomeArgs) msg.obj;
823                     onVolumeStateChangedAsync((VolumeInfo) args.arg1, args.argi1, args.argi2);
824                     args.recycle();
825                     break;
826                 }
827                 case H_CLOUD_MEDIA_PROVIDER_CHANGED: {
828                     // We send this message in two cases:
829                     // 1. After the cloud provider has been set/updated for a user.
830                     //    In this case Message's #arg1 is set to UserId, and #obj is set to the
831                     //    authority of the new cloud provider.
832                     // 2. After a new CloudProviderChangeListener is registered.
833                     //    In this case Message's #obj is set to the CloudProviderChangeListener.
834                     if (msg.obj instanceof StorageManagerInternal.CloudProviderChangeListener) {
835                         final StorageManagerInternal.CloudProviderChangeListener listener =
836                                 (StorageManagerInternal.CloudProviderChangeListener) msg.obj;
837                         notifyCloudMediaProviderChangedAsync(listener);
838                     } else {
839                         final int userId = msg.arg1;
840                         final String authority = (String) msg.obj;
841                         onCloudMediaProviderChangedAsync(userId, authority);
842                     }
843                     break;
844                 }
845                 case H_SECURE_KEYGUARD_STATE_CHANGED: {
846                     try {
847                         mVold.onSecureKeyguardStateChanged((boolean) msg.obj);
848                     } catch (Exception e) {
849                         Slog.wtf(TAG, e);
850                     }
851                     break;
852                 }
853                 case H_REMOUNT_VOLUMES_ON_MOVE: {
854                     remountVolumesForRunningUsersOnMove();
855                     break;
856                 }
857             }
858         }
859     }
860 
861     private final Handler mHandler;
862 
863     private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
864         @Override
865         public void onReceive(Context context, Intent intent) {
866             final String action = intent.getAction();
867             final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
868             Preconditions.checkArgument(userId >= 0);
869 
870             try {
871                 if (Intent.ACTION_USER_ADDED.equals(action)) {
872                     final UserManager um = mContext.getSystemService(UserManager.class);
873                     final int userSerialNumber = um.getUserSerialNumber(userId);
874                     final UserInfo userInfo = um.getUserInfo(userId);
875                     if (userInfo.isCloneProfile()) {
876                         // Only clone profiles share storage with their parent
877                         mVold.onUserAdded(userId, userSerialNumber,
878                                 userInfo.profileGroupId /* sharesStorageWithUserId */);
879                     } else {
880                         mVold.onUserAdded(userId, userSerialNumber,
881                                 -1 /* shareStorageWithUserId */);
882                     }
883                 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
884                     synchronized (mLock) {
885                         final int size = mVolumes.size();
886                         for (int i = 0; i < size; i++) {
887                             final VolumeInfo vol = mVolumes.valueAt(i);
888                             if (vol.mountUserId == userId) {
889                                 vol.mountUserId = UserHandle.USER_NULL;
890                                 mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
891                             }
892                         }
893                     }
894                     mVold.onUserRemoved(userId);
895                 }
896             } catch (Exception e) {
897                 Slog.wtf(TAG, e);
898             }
899         }
900     };
901 
waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)902     private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
903             throws TimeoutException {
904         final long startMillis = SystemClock.elapsedRealtime();
905         while (true) {
906             try {
907                 if (latch.await(5000, TimeUnit.MILLISECONDS)) {
908                     return;
909                 } else {
910                     Slog.w(TAG, "Thread " + Thread.currentThread().getName()
911                             + " still waiting for " + condition + "...");
912                 }
913             } catch (InterruptedException e) {
914                 Slog.w(TAG, "Interrupt while waiting for " + condition);
915             }
916             if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) {
917                 throw new TimeoutException("Thread " + Thread.currentThread().getName()
918                         + " gave up waiting for " + condition + " after " + timeoutMillis + "ms");
919             }
920         }
921     }
922 
handleSystemReady()923     private void handleSystemReady() {
924         if (prepareSmartIdleMaint()) {
925             SmartStorageMaintIdler.scheduleSmartIdlePass(mContext, sSmartIdleMaintPeriod);
926         }
927 
928         // Start scheduling nominally-daily fstrim operations
929         MountServiceIdler.scheduleIdlePass(mContext);
930 
931         // Toggle zram-enable system property in response to settings
932         mContext.getContentResolver().registerContentObserver(
933             Settings.Global.getUriFor(Settings.Global.ZRAM_ENABLED),
934             false /*notifyForDescendants*/,
935             new ContentObserver(null /* current thread */) {
936                 @Override
937                 public void onChange(boolean selfChange) {
938                     refreshZramSettings();
939                 }
940             });
941         refreshZramSettings();
942 
943         // Schedule zram writeback unless zram is disabled by persist.sys.zram_enabled
944         String zramPropValue = SystemProperties.get(ZRAM_ENABLED_PROPERTY);
945         if (!zramPropValue.equals("0")
946                 && mContext.getResources().getBoolean(
947                     com.android.internal.R.bool.config_zramWriteback)) {
948             ZramWriteback.scheduleZramWriteback(mContext);
949         }
950 
951         configureTranscoding();
952     }
953 
954     /**
955      * Update the zram_enabled system property (which init reads to
956      * decide whether to enable zram) to reflect the zram_enabled
957      * preference (which we can change for experimentation purposes).
958      */
refreshZramSettings()959     private void refreshZramSettings() {
960         String propertyValue = SystemProperties.get(ZRAM_ENABLED_PROPERTY);
961         if ("".equals(propertyValue)) {
962             return;  // System doesn't have zram toggling support
963         }
964         String desiredPropertyValue =
965             Settings.Global.getInt(mContext.getContentResolver(),
966                                    Settings.Global.ZRAM_ENABLED,
967                                    1) != 0
968             ? "1" : "0";
969         if (!desiredPropertyValue.equals(propertyValue)) {
970             // Avoid redundant disk writes by setting only if we're
971             // changing the property value. There's no race: we're the
972             // sole writer.
973             SystemProperties.set(ZRAM_ENABLED_PROPERTY, desiredPropertyValue);
974             // Schedule writeback only if zram is being enabled.
975             if (desiredPropertyValue.equals("1")
976                     && mContext.getResources().getBoolean(
977                         com.android.internal.R.bool.config_zramWriteback)) {
978                 ZramWriteback.scheduleZramWriteback(mContext);
979             }
980         }
981     }
982 
isHevcDecoderSupported()983     private boolean isHevcDecoderSupported() {
984         MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
985         MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
986         for (MediaCodecInfo codecInfo : codecInfos) {
987             if (codecInfo.isEncoder()) {
988                 continue;
989             }
990             String[] supportedTypes = codecInfo.getSupportedTypes();
991             for (String type : supportedTypes) {
992                 if (type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
993                     return true;
994                 }
995             }
996         }
997         return false;
998     }
999 
configureTranscoding()1000     private void configureTranscoding() {
1001         // See MediaProvider TranscodeHelper#getBooleanProperty for more information
1002         boolean transcodeEnabled = false;
1003         boolean defaultValue = isHevcDecoderSupported() ? true : false;
1004 
1005         if (SystemProperties.getBoolean("persist.sys.fuse.transcode_user_control", false)) {
1006             transcodeEnabled = SystemProperties.getBoolean("persist.sys.fuse.transcode_enabled",
1007                     defaultValue);
1008         } else {
1009             transcodeEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
1010                     "transcode_enabled", defaultValue);
1011         }
1012         SystemProperties.set("sys.fuse.transcode_enabled", String.valueOf(transcodeEnabled));
1013 
1014         if (transcodeEnabled) {
1015             LocalServices.getService(ActivityManagerInternal.class)
1016                 .registerAnrController(new ExternalStorageServiceAnrController());
1017         }
1018     }
1019 
1020     private class ExternalStorageServiceAnrController implements AnrController {
1021         @Override
getAnrDelayMillis(String packageName, int uid)1022         public long getAnrDelayMillis(String packageName, int uid) {
1023             if (!isAppIoBlocked(uid)) {
1024                 return 0;
1025             }
1026 
1027             int delay = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
1028                     ANR_DELAY_MILLIS_DEVICE_CONFIG_KEY, 5000);
1029             Slog.v(TAG, "getAnrDelayMillis for " + packageName + ". " + delay + "ms");
1030             return delay;
1031         }
1032 
1033         @Override
onAnrDelayStarted(String packageName, int uid)1034         public void onAnrDelayStarted(String packageName, int uid) {
1035             if (!isAppIoBlocked(uid)) {
1036                 return;
1037             }
1038 
1039             boolean notifyExternalStorageService = DeviceConfig.getBoolean(
1040                     DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
1041                     ANR_DELAY_NOTIFY_EXTERNAL_STORAGE_SERVICE_DEVICE_CONFIG_KEY, true);
1042             if (notifyExternalStorageService) {
1043                 Slog.d(TAG, "onAnrDelayStarted for " + packageName
1044                         + ". Notifying external storage service");
1045                 try {
1046                     mStorageSessionController.notifyAnrDelayStarted(packageName, uid, 0 /* tid */,
1047                             StorageManager.APP_IO_BLOCKED_REASON_TRANSCODING);
1048                 } catch (ExternalStorageServiceException e) {
1049                     Slog.e(TAG, "Failed to notify ANR delay started for " + packageName, e);
1050                 }
1051             } else {
1052                 // TODO(b/170973510): Implement framework spinning dialog for ANR delay
1053             }
1054         }
1055 
1056         @Override
onAnrDelayCompleted(String packageName, int uid)1057         public boolean onAnrDelayCompleted(String packageName, int uid) {
1058             if (isAppIoBlocked(uid)) {
1059                 Slog.d(TAG, "onAnrDelayCompleted for " + packageName + ". Showing ANR dialog...");
1060                 return true;
1061             } else {
1062                 Slog.d(TAG, "onAnrDelayCompleted for " + packageName + ". Skipping ANR dialog...");
1063                 return false;
1064             }
1065         }
1066     }
1067 
1068     @GuardedBy("mLock")
addInternalVolumeLocked()1069     private void addInternalVolumeLocked() {
1070         // Create a stub volume that represents internal storage
1071         final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
1072                 VolumeInfo.TYPE_PRIVATE, null, null);
1073         internal.state = VolumeInfo.STATE_MOUNTED;
1074         internal.path = Environment.getDataDirectory().getAbsolutePath();
1075         mVolumes.put(internal.id, internal);
1076     }
1077 
resetIfBootedAndConnected()1078     private void resetIfBootedAndConnected() {
1079         Slog.d(TAG, "Thinking about reset, mBootCompleted=" + mBootCompleted
1080                 + ", mDaemonConnected=" + mDaemonConnected);
1081         if (mBootCompleted && mDaemonConnected) {
1082             final UserManager userManager = mContext.getSystemService(UserManager.class);
1083             final List<UserInfo> users = userManager.getUsers();
1084 
1085             extendWatchdogTimeout("#onReset might be slow");
1086             mStorageSessionController.onReset(mVold, () -> {
1087                 mHandler.removeCallbacksAndMessages(null);
1088             });
1089 
1090             final int[] systemUnlockedUsers;
1091             synchronized (mLock) {
1092                 // make copy as sorting can change order
1093                 systemUnlockedUsers = Arrays.copyOf(mSystemUnlockedUsers,
1094                         mSystemUnlockedUsers.length);
1095 
1096                 mDisks.clear();
1097                 mVolumes.clear();
1098 
1099                 addInternalVolumeLocked();
1100             }
1101 
1102             try {
1103                 // Reset vold to tear down existing disks/volumes and start from
1104                 // a clean state.  Exception: already-unlocked user storage will
1105                 // remain unlocked and is not affected by the reset.
1106                 //
1107                 // TODO(b/135341433): Remove cautious logging when FUSE is stable
1108                 Slog.i(TAG, "Resetting vold...");
1109                 mVold.reset();
1110                 Slog.i(TAG, "Reset vold");
1111 
1112                 // Tell vold about all existing and started users
1113                 for (UserInfo user : users) {
1114                     if (user.isCloneProfile()) {
1115                         mVold.onUserAdded(user.id, user.serialNumber, user.profileGroupId);
1116                     } else {
1117                         mVold.onUserAdded(user.id, user.serialNumber, -1);
1118                     }
1119                 }
1120                 for (int userId : systemUnlockedUsers) {
1121                     mVold.onUserStarted(userId);
1122                     mStoraged.onUserStarted(userId);
1123                 }
1124                 restoreSystemUnlockedUsers(userManager, users, systemUnlockedUsers);
1125                 mVold.onSecureKeyguardStateChanged(mSecureKeyguardShowing);
1126                 mStorageManagerInternal.onReset(mVold);
1127             } catch (Exception e) {
1128                 Slog.wtf(TAG, e);
1129             }
1130         }
1131     }
1132 
restoreSystemUnlockedUsers(UserManager userManager, List<UserInfo> allUsers, int[] systemUnlockedUsers)1133     private void restoreSystemUnlockedUsers(UserManager userManager, List<UserInfo> allUsers,
1134             int[] systemUnlockedUsers) throws Exception {
1135         Arrays.sort(systemUnlockedUsers);
1136         UserManager.invalidateIsUserUnlockedCache();
1137         for (UserInfo user : allUsers) {
1138             int userId = user.id;
1139             if (!userManager.isUserRunning(userId)) {
1140                 continue;
1141             }
1142             if (Arrays.binarySearch(systemUnlockedUsers, userId) >= 0) {
1143                 continue;
1144             }
1145             boolean unlockingOrUnlocked = userManager.isUserUnlockingOrUnlocked(userId);
1146             if (!unlockingOrUnlocked) {
1147                 continue;
1148             }
1149             Slog.w(TAG, "UNLOCK_USER lost from vold reset, will retry, user:" + userId);
1150             mVold.onUserStarted(userId);
1151             mStoraged.onUserStarted(userId);
1152             mHandler.obtainMessage(H_COMPLETE_UNLOCK_USER, userId, /* arg2 (unusued) */ 0)
1153                     .sendToTarget();
1154         }
1155     }
1156 
1157     // If vold knows that some users have their CE storage unlocked already (which can happen after
1158     // a "userspace reboot"), then add those users to mCeUnlockedUsers.  Do this right away and
1159     // don't wait until PHASE_BOOT_COMPLETED, since the system may unlock users before then.
restoreCeUnlockedUsers()1160     private void restoreCeUnlockedUsers() {
1161         final int[] userIds;
1162         try {
1163             userIds = mVold.getUnlockedUsers();
1164         } catch (Exception e) {
1165             Slog.e(TAG, "Failed to get unlocked users from vold", e);
1166             return;
1167         }
1168         if (!ArrayUtils.isEmpty(userIds)) {
1169             Slog.d(TAG, "CE storage for users " + Arrays.toString(userIds)
1170                     + " is already unlocked");
1171             synchronized (mLock) {
1172                 // Append rather than replace, just in case we're actually
1173                 // reconnecting to vold after it crashed and was restarted, in
1174                 // which case things will be the other way around --- we'll know
1175                 // about the unlocked users but vold won't.
1176                 mCeUnlockedUsers.appendAll(userIds);
1177             }
1178         }
1179     }
1180 
onUserUnlocking(int userId)1181     private void onUserUnlocking(int userId) {
1182         Slog.d(TAG, "onUserUnlocking " + userId);
1183 
1184         if (userId != UserHandle.USER_SYSTEM) {
1185             // Check if this user shares media with another user
1186             try {
1187                 Context userContext = mContext.createPackageContextAsUser("system", 0,
1188                         UserHandle.of(userId));
1189                 UserManager um = userContext.getSystemService(UserManager.class);
1190                 if (um != null && um.isMediaSharedWithParent()) {
1191                     int parentUserId = um.getProfileParent(userId).id;
1192                     mUserSharesMediaWith.put(userId, parentUserId);
1193                     mUserSharesMediaWith.put(parentUserId, userId);
1194                 }
1195             } catch (PackageManager.NameNotFoundException e) {
1196                 Log.e(TAG, "Failed to create user context for user " + userId);
1197             }
1198         }
1199         // We purposefully block here to make sure that user-specific
1200         // staging area is ready so it's ready for zygote-forked apps to
1201         // bind mount against.
1202         try {
1203             mStorageSessionController.onUnlockUser(userId);
1204             mVold.onUserStarted(userId);
1205             mStoraged.onUserStarted(userId);
1206         } catch (Exception e) {
1207             Slog.wtf(TAG, e);
1208         }
1209 
1210         mHandler.obtainMessage(H_COMPLETE_UNLOCK_USER, userId, /* arg2 (unusued) */ 0)
1211                 .sendToTarget();
1212         if (mRemountCurrentUserVolumesOnUnlock && userId == mCurrentUserId) {
1213             maybeRemountVolumes(userId);
1214             mRemountCurrentUserVolumesOnUnlock = false;
1215         }
1216     }
1217 
completeUnlockUser(int userId)1218     private void completeUnlockUser(int userId) {
1219         onKeyguardStateChanged(false);
1220 
1221         // Record user as started so newly mounted volumes kick off events
1222         // correctly, then synthesize events for any already-mounted volumes.
1223         synchronized (mLock) {
1224             for (int unlockedUser : mSystemUnlockedUsers) {
1225                 if (unlockedUser == userId) {
1226                     // This can happen as restoreAllUnlockedUsers can double post the message.
1227                     Log.i(TAG, "completeUnlockUser called for already unlocked user:" + userId);
1228                     return;
1229                 }
1230             }
1231             for (int i = 0; i < mVolumes.size(); i++) {
1232                 final VolumeInfo vol = mVolumes.valueAt(i);
1233                 if (vol.isVisibleForUser(userId) && vol.isMountedReadable()) {
1234                     final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
1235                     mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
1236 
1237                     final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
1238                     mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
1239                 }
1240             }
1241             mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId);
1242         }
1243     }
1244 
extendWatchdogTimeout(String reason)1245     private void extendWatchdogTimeout(String reason) {
1246         Watchdog w = Watchdog.getInstance();
1247         w.pauseWatchingMonitorsFor(SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, reason);
1248         w.pauseWatchingCurrentThreadFor(SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, reason);
1249     }
1250 
onUserStopped(int userId)1251     private void onUserStopped(int userId) {
1252         Slog.d(TAG, "onUserStopped " + userId);
1253 
1254         extendWatchdogTimeout("#onUserStopped might be slow");
1255         try {
1256             mVold.onUserStopped(userId);
1257             mStoraged.onUserStopped(userId);
1258         } catch (Exception e) {
1259             Slog.wtf(TAG, e);
1260         }
1261 
1262         synchronized (mLock) {
1263             mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
1264         }
1265     }
1266 
onUserStopping(int userId)1267     private void onUserStopping(int userId) {
1268         Slog.i(TAG, "onUserStopping " + userId);
1269         try {
1270             mStorageSessionController.onUserStopping(userId);
1271         } catch (Exception e) {
1272             Slog.wtf(TAG, e);
1273         }
1274         PackageMonitor monitor = mPackageMonitorsForUser.removeReturnOld(userId);
1275         if (monitor != null) {
1276             monitor.unregister();
1277         }
1278     }
1279 
maybeRemountVolumes(int userId)1280     private void maybeRemountVolumes(int userId) {
1281         List<VolumeInfo> volumesToRemount = new ArrayList<>();
1282         synchronized (mLock) {
1283             for (int i = 0; i < mVolumes.size(); i++) {
1284                 final VolumeInfo vol = mVolumes.valueAt(i);
1285                 if (!vol.isPrimary() && vol.isMountedWritable() && vol.isVisible()
1286                         && vol.getMountUserId() != mCurrentUserId) {
1287                     // If there's a visible secondary volume mounted,
1288                     // we need to update the currentUserId and remount
1289                     vol.mountUserId = mCurrentUserId;
1290                     volumesToRemount.add(vol);
1291                 }
1292             }
1293         }
1294 
1295         for (VolumeInfo vol : volumesToRemount) {
1296             Slog.i(TAG, "Remounting volume for user: " + userId + ". Volume: " + vol);
1297             mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
1298             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1299         }
1300     }
1301 
1302     /**
1303      * This method checks if the volume is public and the volume is visible and the volume it is
1304      * trying to mount doesn't have the same mount user id as the current user being maintained by
1305      * StorageManagerService and change the mount Id. The checks are same as
1306      * {@link StorageManagerService#maybeRemountVolumes(int)}
1307      * @param VolumeInfo object to consider for changing the mountId
1308      */
updateVolumeMountIdIfRequired(VolumeInfo vol)1309     private void updateVolumeMountIdIfRequired(VolumeInfo vol) {
1310         synchronized (mLock) {
1311             if (!vol.isPrimary() && vol.isVisible() && vol.getMountUserId() != mCurrentUserId) {
1312                 vol.mountUserId = mCurrentUserId;
1313             }
1314         }
1315     }
1316 
1317     /**
1318      * This method informs vold and storaged that the user has stopped and started whenever move
1319      * storage is performed. This ensures that the correct emulated volumes are mounted for the
1320      * users other than the current user. This solves an edge case wherein the correct emulated
1321      * volumes are not mounted, this will cause the media data to be still stored on internal
1322      * storage whereas the data should be stored in the adopted primary storage. This method stops
1323      * the users at vold first which will remove the old volumes which and starts the users at vold
1324      * which will reattach the correct volumes. This does not performs a full reset as full reset
1325      * clears every state from vold and SMS {@link #resetIfRebootedAndConnected} which is expensive
1326      * and causes instability.
1327      */
remountVolumesForRunningUsersOnMove()1328     private void remountVolumesForRunningUsersOnMove() {
1329         // Do not want to hold the lock for long
1330         final List<Integer> unlockedUsers = new ArrayList<>();
1331         synchronized (mLock) {
1332             for (int userId : mSystemUnlockedUsers) {
1333                 if (userId == mCurrentUserId) continue;
1334                 unlockedUsers.add(userId);
1335             }
1336         }
1337         extendWatchdogTimeout("#onUserStopped might be slow");
1338         for (Integer userId : unlockedUsers) {
1339             try {
1340                 mVold.onUserStopped(userId);
1341                 mStoraged.onUserStopped(userId);
1342             } catch (Exception e) {
1343                 Slog.wtf(TAG, e);
1344             }
1345         }
1346         for (Integer userId : unlockedUsers) {
1347             try {
1348                 mVold.onUserStarted(userId);
1349                 mStoraged.onUserStarted(userId);
1350             } catch (Exception e) {
1351                 Slog.wtf(TAG, e);
1352             }
1353         }
1354     }
1355 
supportsBlockCheckpoint()1356     private boolean supportsBlockCheckpoint() throws RemoteException {
1357         enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1358         return mVold.supportsBlockCheckpoint();
1359     }
1360 
prepareUserStorageForMoveInternal(String fromVolumeUuid, String toVolumeUuid, List<UserInfo> users)1361     private void prepareUserStorageForMoveInternal(String fromVolumeUuid, String toVolumeUuid,
1362             List<UserInfo> users) throws Exception {
1363 
1364         final int flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
1365         for (UserInfo user : users) {
1366             prepareUserStorageInternal(fromVolumeUuid, user.id, flags);
1367             prepareUserStorageInternal(toVolumeUuid, user.id, flags);
1368         }
1369     }
1370 
1371     @Override
onAwakeStateChanged(boolean isAwake)1372     public void onAwakeStateChanged(boolean isAwake) {
1373         // Ignored
1374     }
1375 
1376     @Override
onKeyguardStateChanged(boolean isShowing)1377     public void onKeyguardStateChanged(boolean isShowing) {
1378         // Push down current secure keyguard status so that we ignore malicious
1379         // USB devices while locked.
1380         boolean isSecureKeyguardShowing = isShowing
1381                 && mContext.getSystemService(KeyguardManager.class).isDeviceSecure(mCurrentUserId);
1382         if (mSecureKeyguardShowing != isSecureKeyguardShowing) {
1383             mSecureKeyguardShowing = isSecureKeyguardShowing;
1384             mHandler.obtainMessage(H_SECURE_KEYGUARD_STATE_CHANGED, mSecureKeyguardShowing)
1385                     .sendToTarget();
1386         }
1387     }
1388 
runIdleMaintenance(Runnable callback)1389     void runIdleMaintenance(Runnable callback) {
1390         mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
1391     }
1392 
1393     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
1394     // Binder entry point for kicking off an immediate fstrim
1395     @Override
runMaintenance()1396     public void runMaintenance() {
1397         super.runMaintenance_enforcePermission();
1398 
1399         runIdleMaintenance(null);
1400     }
1401 
1402     @Override
lastMaintenance()1403     public long lastMaintenance() {
1404         return mLastMaintenance;
1405     }
1406 
onDaemonConnected()1407     public void onDaemonConnected() {
1408         mDaemonConnected = true;
1409         mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
1410     }
1411 
handleDaemonConnected()1412     private void handleDaemonConnected() {
1413         resetIfBootedAndConnected();
1414     }
1415 
1416     private final IVoldListener mListener = new IVoldListener.Stub() {
1417         @Override
1418         public void onDiskCreated(String diskId, int flags) {
1419             synchronized (mLock) {
1420                 final String value = SystemProperties.get(StorageManager.PROP_ADOPTABLE);
1421                 switch (value) {
1422                     case "force_on":
1423                         flags |= DiskInfo.FLAG_ADOPTABLE;
1424                         break;
1425                     case "force_off":
1426                         flags &= ~DiskInfo.FLAG_ADOPTABLE;
1427                         break;
1428                 }
1429                 mDisks.put(diskId, new DiskInfo(diskId, flags));
1430             }
1431         }
1432 
1433         @Override
1434         public void onDiskScanned(String diskId) {
1435             synchronized (mLock) {
1436                 final DiskInfo disk = mDisks.get(diskId);
1437                 if (disk != null) {
1438                     onDiskScannedLocked(disk);
1439                 }
1440             }
1441         }
1442 
1443         @Override
1444         public void onDiskMetadataChanged(String diskId, long sizeBytes, String label,
1445                 String sysPath) {
1446             synchronized (mLock) {
1447                 final DiskInfo disk = mDisks.get(diskId);
1448                 if (disk != null) {
1449                     disk.size = sizeBytes;
1450                     disk.label = label;
1451                     disk.sysPath = sysPath;
1452                 }
1453             }
1454         }
1455 
1456         @Override
1457         public void onDiskDestroyed(String diskId) {
1458             synchronized (mLock) {
1459                 final DiskInfo disk = mDisks.remove(diskId);
1460                 if (disk != null) {
1461                     mCallbacks.notifyDiskDestroyed(disk);
1462                 }
1463             }
1464         }
1465 
1466         @Override
1467         public void onVolumeCreated(String volId, int type, String diskId, String partGuid,
1468                 int userId) {
1469             synchronized (mLock) {
1470                 final DiskInfo disk = mDisks.get(diskId);
1471                 final VolumeInfo vol = new VolumeInfo(volId, type, disk, partGuid);
1472                 vol.mountUserId = userId;
1473                 mVolumes.put(volId, vol);
1474                 onVolumeCreatedLocked(vol);
1475             }
1476         }
1477 
1478         @Override
1479         public void onVolumeStateChanged(String volId, final int newState, final int userId) {
1480             synchronized (mLock) {
1481                 final VolumeInfo vol = mVolumes.get(volId);
1482                 if (vol != null) {
1483                     final int oldState = vol.state;
1484                     vol.state = newState;
1485                     final VolumeInfo vInfo = new VolumeInfo(vol);
1486                     vInfo.mountUserId = userId;
1487                     final SomeArgs args = SomeArgs.obtain();
1488                     args.arg1 = vInfo;
1489                     args.argi1 = oldState;
1490                     args.argi2 = newState;
1491                     mHandler.obtainMessage(H_VOLUME_STATE_CHANGED, args).sendToTarget();
1492                     onVolumeStateChangedLocked(vInfo, newState);
1493                 }
1494             }
1495         }
1496 
1497         @Override
1498         public void onVolumeMetadataChanged(String volId, String fsType, String fsUuid,
1499                 String fsLabel) {
1500             synchronized (mLock) {
1501                 final VolumeInfo vol = mVolumes.get(volId);
1502                 if (vol != null) {
1503                     vol.fsType = fsType;
1504                     vol.fsUuid = fsUuid;
1505                     vol.fsLabel = fsLabel;
1506                 }
1507             }
1508         }
1509 
1510         @Override
1511         public void onVolumePathChanged(String volId, String path) {
1512             synchronized (mLock) {
1513                 final VolumeInfo vol = mVolumes.get(volId);
1514                 if (vol != null) {
1515                     vol.path = path;
1516                 }
1517             }
1518         }
1519 
1520         @Override
1521         public void onVolumeInternalPathChanged(String volId, String internalPath) {
1522             synchronized (mLock) {
1523                 final VolumeInfo vol = mVolumes.get(volId);
1524                 if (vol != null) {
1525                     vol.internalPath = internalPath;
1526                 }
1527             }
1528         }
1529 
1530         @Override
1531         public void onVolumeDestroyed(String volId) {
1532             VolumeInfo vol = null;
1533             synchronized (mLock) {
1534                 vol = mVolumes.remove(volId);
1535             }
1536 
1537             if (vol != null) {
1538                 mStorageSessionController.onVolumeRemove(vol);
1539                 try {
1540                     if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1541                         mInstaller.onPrivateVolumeRemoved(vol.getFsUuid());
1542                     }
1543                 } catch (Installer.InstallerException e) {
1544                     Slog.i(TAG, "Failed when private volume unmounted " + vol, e);
1545                 }
1546             }
1547         }
1548     };
1549 
1550     @GuardedBy("mLock")
onDiskScannedLocked(DiskInfo disk)1551     private void onDiskScannedLocked(DiskInfo disk) {
1552         int volumeCount = 0;
1553         for (int i = 0; i < mVolumes.size(); i++) {
1554             final VolumeInfo vol = mVolumes.valueAt(i);
1555             if (Objects.equals(disk.id, vol.getDiskId())) {
1556                 volumeCount++;
1557             }
1558         }
1559 
1560         final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
1561         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1562                 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1563         intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
1564         intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
1565         mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
1566 
1567         final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
1568         if (latch != null) {
1569             latch.countDown();
1570         }
1571 
1572         disk.volumeCount = volumeCount;
1573         mCallbacks.notifyDiskScanned(disk, volumeCount);
1574     }
1575 
1576     @GuardedBy("mLock")
onVolumeCreatedLocked(VolumeInfo vol)1577     private void onVolumeCreatedLocked(VolumeInfo vol) {
1578         final ActivityManagerInternal amInternal =
1579                 LocalServices.getService(ActivityManagerInternal.class);
1580 
1581         if (vol.mountUserId >= 0 && !amInternal.isUserRunning(vol.mountUserId, 0)) {
1582             Slog.d(TAG, "Ignoring volume " + vol.getId() + " because user "
1583                     + Integer.toString(vol.mountUserId) + " is no longer running.");
1584             return;
1585         }
1586 
1587         if (vol.type == VolumeInfo.TYPE_EMULATED) {
1588             final Context volumeUserContext = mContext.createContextAsUser(
1589                     UserHandle.of(vol.mountUserId), 0);
1590 
1591             boolean isMediaSharedWithParent =
1592                     (volumeUserContext != null) ? volumeUserContext.getSystemService(
1593                             UserManager.class).isMediaSharedWithParent() : false;
1594 
1595             // For all the users where media is shared with parent, creation of emulated volume
1596             // should not be skipped even if media provider instance is not running in that user
1597             // space
1598             if (!isMediaSharedWithParent
1599                     && !mStorageSessionController.supportsExternalStorage(vol.mountUserId)) {
1600                 Slog.d(TAG, "Ignoring volume " + vol.getId() + " because user "
1601                         + Integer.toString(vol.mountUserId)
1602                         + " does not support external storage.");
1603                 return;
1604             }
1605 
1606             final StorageManager storage = mContext.getSystemService(StorageManager.class);
1607             final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
1608 
1609             if ((Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
1610                     && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id))
1611                     || Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
1612                 Slog.v(TAG, "Found primary storage at " + vol);
1613                 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1614                 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
1615                 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1616             }
1617 
1618         } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
1619             // TODO: only look at first public partition
1620             if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1621                     && vol.disk.isDefaultPrimary()) {
1622                 Slog.v(TAG, "Found primary storage at " + vol);
1623                 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1624                 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
1625             }
1626 
1627             // Adoptable public disks are visible to apps, since they meet
1628             // public API requirement of being in a stable location.
1629             if (vol.disk.isAdoptable()) {
1630                 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
1631             }
1632 
1633             vol.mountUserId = mCurrentUserId;
1634             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1635 
1636         } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1637             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1638 
1639         } else if (vol.type == VolumeInfo.TYPE_STUB) {
1640             if (vol.disk.isStubVisible()) {
1641                 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
1642             } else {
1643                 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_READ;
1644             }
1645             vol.mountUserId = mCurrentUserId;
1646             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1647         } else {
1648             Slog.d(TAG, "Skipping automatic mounting of " + vol);
1649         }
1650     }
1651 
isBroadcastWorthy(VolumeInfo vol)1652     private boolean isBroadcastWorthy(VolumeInfo vol) {
1653         switch (vol.getType()) {
1654             case VolumeInfo.TYPE_PRIVATE:
1655             case VolumeInfo.TYPE_PUBLIC:
1656             case VolumeInfo.TYPE_EMULATED:
1657             case VolumeInfo.TYPE_STUB:
1658                 break;
1659             default:
1660                 return false;
1661         }
1662 
1663         switch (vol.getState()) {
1664             case VolumeInfo.STATE_MOUNTED:
1665             case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1666             case VolumeInfo.STATE_EJECTING:
1667             case VolumeInfo.STATE_UNMOUNTED:
1668             case VolumeInfo.STATE_UNMOUNTABLE:
1669             case VolumeInfo.STATE_BAD_REMOVAL:
1670                 break;
1671             default:
1672                 return false;
1673         }
1674 
1675         return true;
1676     }
1677 
1678     @GuardedBy("mLock")
onVolumeStateChangedLocked(VolumeInfo vol, int newState)1679     private void onVolumeStateChangedLocked(VolumeInfo vol, int newState) {
1680         if (vol.type == VolumeInfo.TYPE_EMULATED) {
1681             if (newState != VolumeInfo.STATE_MOUNTED) {
1682                 mFuseMountedUser.remove(vol.getMountUserId());
1683             } else if (mVoldAppDataIsolationEnabled){
1684                 final int userId = vol.getMountUserId();
1685                 // Async remount app storage so it won't block the main thread.
1686                 new Thread(() -> {
1687 
1688                     // If user 0 has completed unlock, perform a one-time migration of legacy
1689                     // obb data to its new location. This may take time depending on the size of
1690                     // the data to be copied so it's done on the StorageManager worker thread.
1691                     // This needs to be finished before start mounting obb directories.
1692                     if (userId == 0
1693                             && Build.VERSION.DEVICE_INITIAL_SDK_INT < Build.VERSION_CODES.Q) {
1694                         mPmInternal.migrateLegacyObbData();
1695                     }
1696 
1697                     // Add fuse mounted user after migration to prevent ProcessList tries to
1698                     // create obb directory before migration is done.
1699                     synchronized (mLock) {
1700                         mFuseMountedUser.add(userId);
1701                     }
1702 
1703                     Map<Integer, String> pidPkgMap = null;
1704                     // getProcessesWithPendingBindMounts() could fail when a new app process is
1705                     // starting and it's not planning to mount storage dirs in zygote, but it's
1706                     // rare, so we retry 5 times and hope we can get the result successfully.
1707                     for (int i = 0; i < 5; i++) {
1708                         try {
1709                             pidPkgMap = LocalServices.getService(ActivityManagerInternal.class)
1710                                     .getProcessesWithPendingBindMounts(vol.getMountUserId());
1711                             break;
1712                         } catch (IllegalStateException e) {
1713                             Slog.i(TAG, "Some processes are starting, retry");
1714                             // Wait 100ms and retry so hope the pending process is started.
1715                             SystemClock.sleep(100);
1716                         }
1717                     }
1718                     if (pidPkgMap != null) {
1719                         remountAppStorageDirs(pidPkgMap, userId);
1720                     } else {
1721                         Slog.wtf(TAG, "Not able to getStorageNotOptimizedProcesses() after"
1722                                 + " 5 retries");
1723                     }
1724                 }).start();
1725             }
1726         }
1727     }
1728 
onVolumeStateChangedAsync(VolumeInfo vol, int oldState, int newState)1729     private void onVolumeStateChangedAsync(VolumeInfo vol, int oldState, int newState) {
1730         if (newState == VolumeInfo.STATE_MOUNTED) {
1731             // Private volumes can be unmounted and re-mounted even after a user has
1732             // been unlocked; on devices that support encryption keys tied to the filesystem,
1733             // this requires setting up the keys again.
1734             try {
1735                 prepareUserStorageIfNeeded(vol);
1736             } catch (Exception e) {
1737                 // Unusable partition, unmount.
1738                 try {
1739                     mVold.unmount(vol.id);
1740                 } catch (Exception ee) {
1741                     Slog.wtf(TAG, ee);
1742                 }
1743                 return;
1744             }
1745         }
1746 
1747         synchronized (mLock) {
1748             // Remember that we saw this volume so we're ready to accept user
1749             // metadata, or so we can annoy them when a private volume is ejected
1750             if (!TextUtils.isEmpty(vol.fsUuid)) {
1751                 VolumeRecord rec = mRecords.get(vol.fsUuid);
1752                 if (rec == null) {
1753                     rec = new VolumeRecord(vol.type, vol.fsUuid);
1754                     rec.partGuid = vol.partGuid;
1755                     rec.createdMillis = System.currentTimeMillis();
1756                     if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1757                         rec.nickname = vol.disk.getDescription();
1758                     }
1759                     mRecords.put(rec.fsUuid, rec);
1760                 } else {
1761                     // Handle upgrade case where we didn't store partition GUID
1762                     if (TextUtils.isEmpty(rec.partGuid)) {
1763                         rec.partGuid = vol.partGuid;
1764                     }
1765                 }
1766 
1767                 rec.lastSeenMillis = System.currentTimeMillis();
1768                 writeSettingsLocked();
1769             }
1770         }
1771 
1772         // This is a blocking call to Storage Service which needs to process volume state changed
1773         // before notifying other listeners.
1774         // Intentionally called without the mLock to avoid deadlocking from the Storage Service.
1775         try {
1776             mStorageSessionController.notifyVolumeStateChanged(vol);
1777         } catch (ExternalStorageServiceException e) {
1778             Log.e(TAG, "Failed to notify volume state changed to the Storage Service", e);
1779         }
1780         synchronized (mLock) {
1781             mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1782 
1783             // Do not broadcast before boot has completed to avoid launching the
1784             // processes that receive the intent unnecessarily.
1785             if (mBootCompleted && isBroadcastWorthy(vol)) {
1786                 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
1787                 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
1788                 intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
1789                 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
1790                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1791                         | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1792                 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
1793             }
1794 
1795             final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1796             final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
1797 
1798             if (!Objects.equals(oldStateEnv, newStateEnv)) {
1799                 // Kick state changed event towards all started users. Any users
1800                 // started after this point will trigger additional
1801                 // user-specific broadcasts.
1802                 for (int userId : mSystemUnlockedUsers) {
1803                     if (vol.isVisibleForUser(userId)) {
1804                         final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
1805                                 false);
1806                         mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
1807 
1808                         mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1809                                 newStateEnv);
1810                     }
1811                 }
1812             }
1813 
1814             if ((vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_STUB)
1815                     && vol.state == VolumeInfo.STATE_EJECTING) {
1816                 // TODO: this should eventually be handled by new ObbVolume state changes
1817                 /*
1818                  * Some OBBs might have been unmounted when this volume was
1819                  * unmounted, so send a message to the handler to let it know to
1820                  * remove those from the list of mounted OBBS.
1821                  */
1822                 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1823                         OBB_FLUSH_MOUNT_STATE, vol.path));
1824             }
1825             maybeLogMediaMount(vol, newState);
1826         }
1827     }
1828 
notifyCloudMediaProviderChangedAsync( @onNull StorageManagerInternal.CloudProviderChangeListener listener)1829     private void notifyCloudMediaProviderChangedAsync(
1830             @NonNull StorageManagerInternal.CloudProviderChangeListener listener) {
1831         synchronized (mCloudMediaProviders) {
1832             for (int i = mCloudMediaProviders.size() - 1; i >= 0; --i) {
1833                 final int userId = mCloudMediaProviders.keyAt(i);
1834                 final String authority = mCloudMediaProviders.valueAt(i);
1835                 listener.onCloudProviderChanged(userId, authority);
1836             }
1837         }
1838     }
1839 
onCloudMediaProviderChangedAsync( @serIdInt int userId, @Nullable String authority)1840     private void onCloudMediaProviderChangedAsync(
1841             @UserIdInt int userId, @Nullable String authority) {
1842         for (StorageManagerInternal.CloudProviderChangeListener listener :
1843                 mStorageManagerInternal.mCloudProviderChangeListeners) {
1844             listener.onCloudProviderChanged(userId, authority);
1845         }
1846     }
1847 
maybeLogMediaMount(VolumeInfo vol, int newState)1848     private void maybeLogMediaMount(VolumeInfo vol, int newState) {
1849         if (!SecurityLog.isLoggingEnabled()) {
1850             return;
1851         }
1852 
1853         final DiskInfo disk = vol.getDisk();
1854         if (disk == null || (disk.flags & (DiskInfo.FLAG_SD | DiskInfo.FLAG_USB)) == 0) {
1855             return;
1856         }
1857 
1858         // Sometimes there is a newline character.
1859         final String label = disk.label != null ? disk.label.trim() : "";
1860 
1861         if (newState == VolumeInfo.STATE_MOUNTED
1862                 || newState == VolumeInfo.STATE_MOUNTED_READ_ONLY) {
1863             SecurityLog.writeEvent(SecurityLog.TAG_MEDIA_MOUNT, vol.path, label);
1864         } else if (newState == VolumeInfo.STATE_UNMOUNTED
1865                 || newState == VolumeInfo.STATE_BAD_REMOVAL) {
1866             SecurityLog.writeEvent(SecurityLog.TAG_MEDIA_UNMOUNT, vol.path, label);
1867         }
1868     }
1869 
1870     @GuardedBy("mLock")
onMoveStatusLocked(int status)1871     private void onMoveStatusLocked(int status) {
1872         if (mMoveCallback == null) {
1873             Slog.w(TAG, "Odd, status but no move requested");
1874             return;
1875         }
1876 
1877         // TODO: estimate remaining time
1878         try {
1879             mMoveCallback.onStatusChanged(-1, status, -1);
1880         } catch (RemoteException ignored) {
1881         }
1882 
1883         // We've finished copying and we're about to clean up old data, so
1884         // remember that move was successful if we get rebooted
1885         if (status == MOVE_STATUS_COPY_FINISHED) {
1886             Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1887 
1888             mPrimaryStorageUuid = mMoveTargetUuid;
1889             writeSettingsLocked();
1890             mHandler.obtainMessage(H_REMOUNT_VOLUMES_ON_MOVE).sendToTarget();
1891         }
1892 
1893         if (PackageManager.isMoveStatusFinished(status)) {
1894             Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1895 
1896             mMoveCallback = null;
1897             mMoveTargetUuid = null;
1898         }
1899     }
1900 
enforcePermission(String perm)1901     private void enforcePermission(String perm) {
1902         mContext.enforceCallingOrSelfPermission(perm, perm);
1903     }
1904 
1905     /**
1906      * Decide if volume is mountable per device policies.
1907      */
isMountDisallowed(VolumeInfo vol)1908     private boolean isMountDisallowed(VolumeInfo vol) {
1909         UserManager userManager = mContext.getSystemService(UserManager.class);
1910 
1911         boolean isUsbRestricted = false;
1912         if (vol.disk != null && vol.disk.isUsb()) {
1913             isUsbRestricted = userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER,
1914                     Binder.getCallingUserHandle());
1915         }
1916 
1917         boolean isTypeRestricted = false;
1918         if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE
1919                 || vol.type == VolumeInfo.TYPE_STUB) {
1920             isTypeRestricted = userManager
1921                     .hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
1922                     Binder.getCallingUserHandle());
1923         }
1924 
1925         return isUsbRestricted || isTypeRestricted;
1926     }
1927 
enforceAdminUser()1928     private void enforceAdminUser() {
1929         UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1930         final int callingUserId = UserHandle.getCallingUserId();
1931         boolean isAdmin;
1932         final long token = Binder.clearCallingIdentity();
1933         try {
1934             isAdmin = um.getUserInfo(callingUserId).isAdmin();
1935         } finally {
1936             Binder.restoreCallingIdentity(token);
1937         }
1938         if (!isAdmin) {
1939             throw new SecurityException("Only admin users can adopt sd cards");
1940         }
1941     }
1942 
1943     /**
1944      * Constructs a new StorageManagerService instance
1945      *
1946      * @param context  Binder context for this service
1947      */
StorageManagerService(Context context)1948     public StorageManagerService(Context context) {
1949         sSelf = this;
1950         mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
1951                 ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
1952         mContext = context;
1953         mCallbacks = new Callbacks(FgThread.get().getLooper());
1954 
1955         HandlerThread hthread = new HandlerThread(TAG);
1956         hthread.start();
1957         mHandler = new StorageManagerServiceHandler(hthread.getLooper());
1958 
1959         // Add OBB Action Handler to StorageManagerService thread.
1960         mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
1961 
1962         mStorageSessionController = new StorageSessionController(mContext);
1963 
1964         mInstaller = new Installer(mContext);
1965         mInstaller.onStart();
1966 
1967         // Initialize the last-fstrim tracking if necessary
1968         File dataDir = Environment.getDataDirectory();
1969         File systemDir = new File(dataDir, "system");
1970         mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1971         if (!mLastMaintenanceFile.exists()) {
1972             // Not setting mLastMaintenance here means that we will force an
1973             // fstrim during reboot following the OTA that installs this code.
1974             try {
1975                 (new FileOutputStream(mLastMaintenanceFile)).close();
1976             } catch (IOException e) {
1977                 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1978             }
1979         } else {
1980             mLastMaintenance = mLastMaintenanceFile.lastModified();
1981         }
1982 
1983         mSettingsFile = new AtomicFile(
1984                 new File(Environment.getDataSystemDirectory(), "storage.xml"), "storage-settings");
1985         mWriteRecordFile = new AtomicFile(
1986                 new File(Environment.getDataSystemDirectory(), "storage-write-records"));
1987 
1988         sSmartIdleMaintPeriod = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
1989             "smart_idle_maint_period", DEFAULT_SMART_IDLE_MAINT_PERIOD);
1990         if (sSmartIdleMaintPeriod < MIN_SMART_IDLE_MAINT_PERIOD) {
1991             sSmartIdleMaintPeriod = MIN_SMART_IDLE_MAINT_PERIOD;
1992         } else if (sSmartIdleMaintPeriod > MAX_SMART_IDLE_MAINT_PERIOD) {
1993             sSmartIdleMaintPeriod = MAX_SMART_IDLE_MAINT_PERIOD;
1994         }
1995 
1996         mMaxWriteRecords = MAX_PERIOD_WRITE_RECORD / sSmartIdleMaintPeriod;
1997         mStorageWriteRecords = new int[mMaxWriteRecords];
1998 
1999         synchronized (mLock) {
2000             readSettingsLocked();
2001         }
2002 
2003         LocalServices.addService(StorageManagerInternal.class, mStorageManagerInternal);
2004 
2005         final IntentFilter userFilter = new IntentFilter();
2006         userFilter.addAction(Intent.ACTION_USER_ADDED);
2007         userFilter.addAction(Intent.ACTION_USER_REMOVED);
2008         mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
2009 
2010         synchronized (mLock) {
2011             addInternalVolumeLocked();
2012         }
2013 
2014         // Add ourself to the Watchdog monitors if enabled.
2015         if (WATCHDOG_ENABLE) {
2016             Watchdog.getInstance().addMonitor(this);
2017         }
2018     }
2019 
start()2020     private void start() {
2021         connectStoraged();
2022         connectVold();
2023     }
2024 
connectStoraged()2025     private void connectStoraged() {
2026         IBinder binder = ServiceManager.getService("storaged");
2027         if (binder != null) {
2028             try {
2029                 binder.linkToDeath(new DeathRecipient() {
2030                     @Override
2031                     public void binderDied() {
2032                         Slog.w(TAG, "storaged died; reconnecting");
2033                         mStoraged = null;
2034                         connectStoraged();
2035                     }
2036                 }, 0);
2037             } catch (RemoteException e) {
2038                 binder = null;
2039             }
2040         }
2041 
2042         if (binder != null) {
2043             mStoraged = IStoraged.Stub.asInterface(binder);
2044         } else {
2045             Slog.w(TAG, "storaged not found; trying again");
2046         }
2047 
2048         if (mStoraged == null) {
2049             BackgroundThread.getHandler().postDelayed(() -> {
2050                 connectStoraged();
2051             }, DateUtils.SECOND_IN_MILLIS);
2052         } else {
2053             onDaemonConnected();
2054         }
2055     }
2056 
connectVold()2057     private void connectVold() {
2058         IBinder binder = ServiceManager.getService("vold");
2059         if (binder != null) {
2060             try {
2061                 binder.linkToDeath(new DeathRecipient() {
2062                     @Override
2063                     public void binderDied() {
2064                         Slog.w(TAG, "vold died; reconnecting");
2065                         mVold = null;
2066                         connectVold();
2067                     }
2068                 }, 0);
2069             } catch (RemoteException e) {
2070                 binder = null;
2071             }
2072         }
2073 
2074         if (binder != null) {
2075             mVold = IVold.Stub.asInterface(binder);
2076             try {
2077                 mVold.setListener(mListener);
2078             } catch (RemoteException e) {
2079                 mVold = null;
2080                 Slog.w(TAG, "vold listener rejected; trying again", e);
2081             }
2082         } else {
2083             Slog.w(TAG, "vold not found; trying again");
2084         }
2085 
2086         if (mVold == null) {
2087             BackgroundThread.getHandler().postDelayed(() -> {
2088                 connectVold();
2089             }, DateUtils.SECOND_IN_MILLIS);
2090         } else {
2091             restoreCeUnlockedUsers();
2092             onDaemonConnected();
2093         }
2094     }
2095 
servicesReady()2096     private void servicesReady() {
2097         mPmInternal = LocalServices.getService(PackageManagerInternal.class);
2098 
2099         mIPackageManager = IPackageManager.Stub.asInterface(
2100                 ServiceManager.getService("package"));
2101         mIAppOpsService = IAppOpsService.Stub.asInterface(
2102                 ServiceManager.getService(Context.APP_OPS_SERVICE));
2103 
2104         ProviderInfo provider = getProviderInfo(MediaStore.AUTHORITY);
2105         if (provider != null) {
2106             mMediaStoreAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
2107             sMediaStoreAuthorityProcessName = provider.applicationInfo.processName;
2108         }
2109 
2110         provider = getProviderInfo(Downloads.Impl.AUTHORITY);
2111         if (provider != null) {
2112             mDownloadsAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
2113         }
2114 
2115         provider = getProviderInfo(DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY);
2116         if (provider != null) {
2117             mExternalStorageAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
2118         }
2119     }
2120 
getProviderInfo(String authority)2121     private ProviderInfo getProviderInfo(String authority) {
2122         return mPmInternal.resolveContentProvider(
2123                 authority, PackageManager.MATCH_DIRECT_BOOT_AWARE
2124                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
2125                 UserHandle.getUserId(UserHandle.USER_SYSTEM), Process.SYSTEM_UID);
2126     }
2127 
updateLegacyStorageApps(String packageName, int uid, boolean hasLegacy)2128     private void updateLegacyStorageApps(String packageName, int uid, boolean hasLegacy) {
2129         synchronized (mLock) {
2130             if (hasLegacy) {
2131                 Slog.v(TAG, "Package " + packageName + " has legacy storage");
2132                 mUidsWithLegacyExternalStorage.add(uid);
2133             } else {
2134                 // TODO(b/149391976): Handle shared user id. Check if there's any other
2135                 // installed app with legacy external storage before removing
2136                 Slog.v(TAG, "Package " + packageName + " does not have legacy storage");
2137                 mUidsWithLegacyExternalStorage.remove(uid);
2138             }
2139         }
2140     }
2141 
snapshotAndMonitorLegacyStorageAppOp(UserHandle user)2142     private void snapshotAndMonitorLegacyStorageAppOp(UserHandle user) {
2143         int userId = user.getIdentifier();
2144 
2145         // TODO(b/149391976): Use mIAppOpsService.getPackagesForOps instead of iterating below
2146         // It should improve performance but the AppOps method doesn't return any app here :(
2147         // This operation currently takes about ~20ms on a freshly flashed device
2148         for (ApplicationInfo ai : mPmInternal.getInstalledApplications(MATCH_DIRECT_BOOT_AWARE
2149                         | MATCH_DIRECT_BOOT_UNAWARE | MATCH_UNINSTALLED_PACKAGES | MATCH_ANY_USER,
2150                         userId, Process.myUid())) {
2151             try {
2152                 boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE, ai.uid,
2153                         ai.packageName) == MODE_ALLOWED;
2154                 updateLegacyStorageApps(ai.packageName, ai.uid, hasLegacy);
2155             } catch (RemoteException e) {
2156                 Slog.e(TAG, "Failed to check legacy op for package " + ai.packageName, e);
2157             }
2158         }
2159 
2160         if (mPackageMonitorsForUser.get(userId) == null) {
2161             PackageMonitor monitor = new PackageMonitor() {
2162                 @Override
2163                 public void onPackageRemoved(String packageName, int uid) {
2164                     updateLegacyStorageApps(packageName, uid, false);
2165                 }
2166             };
2167             // TODO(b/149391976): Use different handler?
2168             monitor.register(mContext, user, mHandler);
2169             mPackageMonitorsForUser.put(userId, monitor);
2170         } else {
2171             Slog.w(TAG, "PackageMonitor is already registered for: " + userId);
2172         }
2173     }
2174 
systemReady()2175     private void systemReady() {
2176         LocalServices.getService(ActivityTaskManagerInternal.class)
2177                 .registerScreenObserver(this);
2178 
2179         mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
2180     }
2181 
bootCompleted()2182     private void bootCompleted() {
2183         mBootCompleted = true;
2184         mHandler.obtainMessage(H_BOOT_COMPLETED).sendToTarget();
2185     }
2186 
handleBootCompleted()2187     private void handleBootCompleted() {
2188         resetIfBootedAndConnected();
2189     }
2190 
getDefaultPrimaryStorageUuid()2191     private String getDefaultPrimaryStorageUuid() {
2192         if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
2193             return StorageManager.UUID_PRIMARY_PHYSICAL;
2194         } else {
2195             return StorageManager.UUID_PRIVATE_INTERNAL;
2196         }
2197     }
2198 
2199     @GuardedBy("mLock")
readSettingsLocked()2200     private void readSettingsLocked() {
2201         mRecords.clear();
2202         mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
2203 
2204         FileInputStream fis = null;
2205         try {
2206             fis = mSettingsFile.openRead();
2207             final TypedXmlPullParser in = Xml.resolvePullParser(fis);
2208 
2209             int type;
2210             while ((type = in.next()) != END_DOCUMENT) {
2211                 if (type == START_TAG) {
2212                     final String tag = in.getName();
2213                     if (TAG_VOLUMES.equals(tag)) {
2214                         final int version = in.getAttributeInt(null, ATTR_VERSION, VERSION_INIT);
2215                         final boolean primaryPhysical = SystemProperties.getBoolean(
2216                                 StorageManager.PROP_PRIMARY_PHYSICAL, false);
2217                         final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
2218                                 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
2219                         if (validAttr) {
2220                             mPrimaryStorageUuid = readStringAttribute(in,
2221                                     ATTR_PRIMARY_STORAGE_UUID);
2222                         }
2223                     } else if (TAG_VOLUME.equals(tag)) {
2224                         final VolumeRecord rec = readVolumeRecord(in);
2225                         mRecords.put(rec.fsUuid, rec);
2226                     }
2227                 }
2228             }
2229         } catch (FileNotFoundException e) {
2230             // Missing metadata is okay, probably first boot
2231         } catch (IOException e) {
2232             Slog.wtf(TAG, "Failed reading metadata", e);
2233         } catch (XmlPullParserException e) {
2234             Slog.wtf(TAG, "Failed reading metadata", e);
2235         } finally {
2236             IoUtils.closeQuietly(fis);
2237         }
2238     }
2239 
2240     @GuardedBy("mLock")
writeSettingsLocked()2241     private void writeSettingsLocked() {
2242         FileOutputStream fos = null;
2243         try {
2244             fos = mSettingsFile.startWrite();
2245 
2246             TypedXmlSerializer out = Xml.resolveSerializer(fos);
2247             out.startDocument(null, true);
2248             out.startTag(null, TAG_VOLUMES);
2249             out.attributeInt(null, ATTR_VERSION, VERSION_FIX_PRIMARY);
2250             writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
2251             final int size = mRecords.size();
2252             for (int i = 0; i < size; i++) {
2253                 final VolumeRecord rec = mRecords.valueAt(i);
2254                 writeVolumeRecord(out, rec);
2255             }
2256             out.endTag(null, TAG_VOLUMES);
2257             out.endDocument();
2258 
2259             mSettingsFile.finishWrite(fos);
2260         } catch (IOException e) {
2261             if (fos != null) {
2262                 mSettingsFile.failWrite(fos);
2263             }
2264         }
2265     }
2266 
readVolumeRecord(TypedXmlPullParser in)2267     public static VolumeRecord readVolumeRecord(TypedXmlPullParser in)
2268             throws IOException, XmlPullParserException {
2269         final int type = in.getAttributeInt(null, ATTR_TYPE);
2270         final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
2271         final VolumeRecord meta = new VolumeRecord(type, fsUuid);
2272         meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
2273         meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
2274         meta.userFlags = in.getAttributeInt(null, ATTR_USER_FLAGS);
2275         meta.createdMillis = in.getAttributeLong(null, ATTR_CREATED_MILLIS, 0);
2276         meta.lastSeenMillis = in.getAttributeLong(null, ATTR_LAST_SEEN_MILLIS, 0);
2277         meta.lastTrimMillis = in.getAttributeLong(null, ATTR_LAST_TRIM_MILLIS, 0);
2278         meta.lastBenchMillis = in.getAttributeLong(null, ATTR_LAST_BENCH_MILLIS, 0);
2279         return meta;
2280     }
2281 
writeVolumeRecord(TypedXmlSerializer out, VolumeRecord rec)2282     public static void writeVolumeRecord(TypedXmlSerializer out, VolumeRecord rec)
2283             throws IOException {
2284         out.startTag(null, TAG_VOLUME);
2285         out.attributeInt(null, ATTR_TYPE, rec.type);
2286         writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
2287         writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
2288         writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
2289         out.attributeInt(null, ATTR_USER_FLAGS, rec.userFlags);
2290         out.attributeLong(null, ATTR_CREATED_MILLIS, rec.createdMillis);
2291         out.attributeLong(null, ATTR_LAST_SEEN_MILLIS, rec.lastSeenMillis);
2292         out.attributeLong(null, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
2293         out.attributeLong(null, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
2294         out.endTag(null, TAG_VOLUME);
2295     }
2296 
2297     /**
2298      * Exposed API calls below here
2299      */
2300 
2301     @Override
registerListener(IStorageEventListener listener)2302     public void registerListener(IStorageEventListener listener) {
2303         mCallbacks.register(listener);
2304     }
2305 
2306     @Override
unregisterListener(IStorageEventListener listener)2307     public void unregisterListener(IStorageEventListener listener) {
2308         mCallbacks.unregister(listener);
2309     }
2310 
2311     @android.annotation.EnforcePermission(android.Manifest.permission.SHUTDOWN)
2312     @Override
shutdown(final IStorageShutdownObserver observer)2313     public void shutdown(final IStorageShutdownObserver observer) {
2314 
2315         super.shutdown_enforcePermission();
2316 
2317         Slog.i(TAG, "Shutting down");
2318         mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
2319     }
2320 
2321     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
2322     @Override
mount(String volId)2323     public void mount(String volId) {
2324 
2325         super.mount_enforcePermission();
2326 
2327         final VolumeInfo vol = findVolumeByIdOrThrow(volId);
2328         if (isMountDisallowed(vol)) {
2329             throw new SecurityException("Mounting " + volId + " restricted by policy");
2330         }
2331         updateVolumeMountIdIfRequired(vol);
2332         mount(vol);
2333     }
2334 
remountAppStorageDirs(Map<Integer, String> pidPkgMap, int userId)2335     private void remountAppStorageDirs(Map<Integer, String> pidPkgMap, int userId) {
2336         for (Entry<Integer, String> entry : pidPkgMap.entrySet()) {
2337             final int pid = entry.getKey();
2338             final String packageName = entry.getValue();
2339             Slog.i(TAG, "Remounting storage for pid: " + pid);
2340             final String[] sharedPackages =
2341                     mPmInternal.getSharedUserPackagesForPackage(packageName, userId);
2342             final int uid = mPmInternal.getPackageUid(packageName, 0 /* flags */, userId);
2343             final String[] packages =
2344                     sharedPackages.length != 0 ? sharedPackages : new String[]{packageName};
2345             try {
2346                 mVold.remountAppStorageDirs(uid, pid, packages);
2347             } catch (RemoteException e) {
2348                 throw e.rethrowAsRuntimeException();
2349             }
2350         }
2351     }
2352 
mount(VolumeInfo vol)2353     private void mount(VolumeInfo vol) {
2354         try {
2355             // TODO(b/135341433): Remove cautious logging when FUSE is stable
2356             Slog.i(TAG, "Mounting volume " + vol);
2357             extendWatchdogTimeout("#mount might be slow");
2358             mVold.mount(vol.id, vol.mountFlags, vol.mountUserId, new IVoldMountCallback.Stub() {
2359                 @Override
2360                 public boolean onVolumeChecking(FileDescriptor fd, String path,
2361                         String internalPath) {
2362                     vol.path = path;
2363                     vol.internalPath = internalPath;
2364                     ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd);
2365                     try {
2366                         mStorageSessionController.onVolumeMount(pfd, vol);
2367                         return true;
2368                     } catch (ExternalStorageServiceException e) {
2369                         Slog.e(TAG, "Failed to mount volume " + vol, e);
2370 
2371                         int nextResetSeconds = FAILED_MOUNT_RESET_TIMEOUT_SECONDS;
2372                         Slog.i(TAG, "Scheduling reset in " + nextResetSeconds + "s");
2373                         mHandler.removeMessages(H_RESET);
2374                         mHandler.sendMessageDelayed(mHandler.obtainMessage(H_RESET),
2375                                 TimeUnit.SECONDS.toMillis(nextResetSeconds));
2376                         return false;
2377                     } finally {
2378                         try {
2379                             pfd.close();
2380                         } catch (Exception e) {
2381                             Slog.e(TAG, "Failed to close FUSE device fd", e);
2382                         }
2383                     }
2384                 }
2385             });
2386             Slog.i(TAG, "Mounted volume " + vol);
2387         } catch (Exception e) {
2388             Slog.wtf(TAG, e);
2389         }
2390     }
2391 
2392     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
2393     @Override
unmount(String volId)2394     public void unmount(String volId) {
2395 
2396         super.unmount_enforcePermission();
2397 
2398         final VolumeInfo vol = findVolumeByIdOrThrow(volId);
2399         unmount(vol);
2400     }
2401 
unmount(VolumeInfo vol)2402     private void unmount(VolumeInfo vol) {
2403         try {
2404             try {
2405                 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
2406                     mInstaller.onPrivateVolumeRemoved(vol.getFsUuid());
2407                 }
2408             } catch (Installer.InstallerException e) {
2409                 Slog.e(TAG, "Failed unmount mirror data", e);
2410             }
2411             mVold.unmount(vol.id);
2412             mStorageSessionController.onVolumeUnmount(vol);
2413         } catch (Exception e) {
2414             Slog.wtf(TAG, e);
2415         }
2416     }
2417 
2418     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS)
2419     @Override
format(String volId)2420     public void format(String volId) {
2421 
2422         super.format_enforcePermission();
2423 
2424         final VolumeInfo vol = findVolumeByIdOrThrow(volId);
2425         final String fsUuid = vol.fsUuid;
2426         try {
2427             mVold.format(vol.id, "auto");
2428 
2429             // After a successful format above, we should forget about any
2430             // records for the old partition, since it'll never appear again
2431             if (!TextUtils.isEmpty(fsUuid)) {
2432                 forgetVolume(fsUuid);
2433             }
2434         } catch (Exception e) {
2435             Slog.wtf(TAG, e);
2436         }
2437     }
2438 
2439     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS)
2440     @Override
benchmark(String volId, IVoldTaskListener listener)2441     public void benchmark(String volId, IVoldTaskListener listener) {
2442 
2443         super.benchmark_enforcePermission();
2444 
2445         try {
2446             mVold.benchmark(volId, new IVoldTaskListener.Stub() {
2447                 @Override
2448                 public void onStatus(int status, PersistableBundle extras) {
2449                     dispatchOnStatus(listener, status, extras);
2450                 }
2451 
2452                 @Override
2453                 public void onFinished(int status, PersistableBundle extras) {
2454                     dispatchOnFinished(listener, status, extras);
2455 
2456                     final String path = extras.getString("path");
2457                     final String ident = extras.getString("ident");
2458                     final long create = extras.getLong("create");
2459                     final long run = extras.getLong("run");
2460                     final long destroy = extras.getLong("destroy");
2461 
2462                     final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
2463                     dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
2464                             + " " + ident + " " + create + " " + run + " " + destroy);
2465 
2466                     synchronized (mLock) {
2467                         final VolumeRecord rec = findRecordForPath(path);
2468                         if (rec != null) {
2469                             rec.lastBenchMillis = System.currentTimeMillis();
2470                             writeSettingsLocked();
2471                         }
2472                     }
2473                 }
2474             });
2475         } catch (RemoteException e) {
2476             throw e.rethrowAsRuntimeException();
2477         }
2478     }
2479 
2480     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS)
2481     @Override
partitionPublic(String diskId)2482     public void partitionPublic(String diskId) {
2483         super.partitionPublic_enforcePermission();
2484 
2485         final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
2486 
2487         extendWatchdogTimeout("#partition might be slow");
2488         try {
2489             mVold.partition(diskId, IVold.PARTITION_TYPE_PUBLIC, -1);
2490             waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
2491         } catch (Exception e) {
2492             Slog.wtf(TAG, e);
2493         }
2494     }
2495 
2496     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS)
2497     @Override
partitionPrivate(String diskId)2498     public void partitionPrivate(String diskId) {
2499         super.partitionPrivate_enforcePermission();
2500 
2501         enforceAdminUser();
2502 
2503         final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
2504 
2505         extendWatchdogTimeout("#partition might be slow");
2506         try {
2507             mVold.partition(diskId, IVold.PARTITION_TYPE_PRIVATE, -1);
2508             waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
2509         } catch (Exception e) {
2510             Slog.wtf(TAG, e);
2511         }
2512     }
2513 
2514     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS)
2515     @Override
partitionMixed(String diskId, int ratio)2516     public void partitionMixed(String diskId, int ratio) {
2517         super.partitionMixed_enforcePermission();
2518 
2519         enforceAdminUser();
2520 
2521         final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
2522 
2523         extendWatchdogTimeout("#partition might be slow");
2524         try {
2525             mVold.partition(diskId, IVold.PARTITION_TYPE_MIXED, ratio);
2526             waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
2527         } catch (Exception e) {
2528             Slog.wtf(TAG, e);
2529         }
2530     }
2531 
2532     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
2533     @Override
setVolumeNickname(String fsUuid, String nickname)2534     public void setVolumeNickname(String fsUuid, String nickname) {
2535 
2536         super.setVolumeNickname_enforcePermission();
2537 
2538         Objects.requireNonNull(fsUuid);
2539         synchronized (mLock) {
2540             final VolumeRecord rec = mRecords.get(fsUuid);
2541             rec.nickname = nickname;
2542             mCallbacks.notifyVolumeRecordChanged(rec);
2543             writeSettingsLocked();
2544         }
2545     }
2546 
2547     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
2548     @Override
setVolumeUserFlags(String fsUuid, int flags, int mask)2549     public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
2550 
2551         super.setVolumeUserFlags_enforcePermission();
2552 
2553         Objects.requireNonNull(fsUuid);
2554         synchronized (mLock) {
2555             final VolumeRecord rec = mRecords.get(fsUuid);
2556             rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
2557             mCallbacks.notifyVolumeRecordChanged(rec);
2558             writeSettingsLocked();
2559         }
2560     }
2561 
2562     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
2563     @Override
forgetVolume(String fsUuid)2564     public void forgetVolume(String fsUuid) {
2565 
2566         super.forgetVolume_enforcePermission();
2567 
2568         Objects.requireNonNull(fsUuid);
2569 
2570         synchronized (mLock) {
2571             final VolumeRecord rec = mRecords.remove(fsUuid);
2572             if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
2573                 mHandler.obtainMessage(H_PARTITION_FORGET, rec).sendToTarget();
2574             }
2575             mCallbacks.notifyVolumeForgotten(fsUuid);
2576 
2577             // If this had been primary storage, revert back to internal and
2578             // reset vold so we bind into new volume into place.
2579             if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
2580                 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
2581                 mHandler.obtainMessage(H_RESET).sendToTarget();
2582             }
2583 
2584             writeSettingsLocked();
2585         }
2586     }
2587 
2588     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
2589     @Override
forgetAllVolumes()2590     public void forgetAllVolumes() {
2591 
2592         super.forgetAllVolumes_enforcePermission();
2593 
2594         synchronized (mLock) {
2595             for (int i = 0; i < mRecords.size(); i++) {
2596                 final String fsUuid = mRecords.keyAt(i);
2597                 final VolumeRecord rec = mRecords.valueAt(i);
2598                 if (!TextUtils.isEmpty(rec.partGuid)) {
2599                     mHandler.obtainMessage(H_PARTITION_FORGET, rec).sendToTarget();
2600                 }
2601                 mCallbacks.notifyVolumeForgotten(fsUuid);
2602             }
2603             mRecords.clear();
2604 
2605             if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
2606                 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
2607             }
2608 
2609             writeSettingsLocked();
2610             mHandler.obtainMessage(H_RESET).sendToTarget();
2611         }
2612     }
2613 
forgetPartition(String partGuid, String fsUuid)2614     private void forgetPartition(String partGuid, String fsUuid) {
2615         try {
2616             mVold.forgetPartition(partGuid, fsUuid);
2617         } catch (Exception e) {
2618             Slog.wtf(TAG, e);
2619         }
2620     }
2621 
2622     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS)
2623     @Override
fstrim(int flags, IVoldTaskListener listener)2624     public void fstrim(int flags, IVoldTaskListener listener) {
2625 
2626         super.fstrim_enforcePermission();
2627 
2628         try {
2629             // Block based checkpoint process runs fstrim. So, if checkpoint is in progress
2630             // (first boot after OTA), We skip idle maintenance and make sure the last
2631             // fstrim time is still updated. If file based checkpoints are used, we run
2632             // idle maintenance (GC + fstrim) regardless of checkpoint status.
2633             if (!needsCheckpoint() || !supportsBlockCheckpoint()) {
2634                 mVold.fstrim(flags, new IVoldTaskListener.Stub() {
2635                     @Override
2636                     public void onStatus(int status, PersistableBundle extras) {
2637                         dispatchOnStatus(listener, status, extras);
2638 
2639                         // Ignore trim failures
2640                         if (status != 0) return;
2641 
2642                         final String path = extras.getString("path");
2643                         final long bytes = extras.getLong("bytes");
2644                         final long time = extras.getLong("time");
2645 
2646                         final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
2647                         dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path) + " " + bytes + " " + time);
2648 
2649                         synchronized (mLock) {
2650                             final VolumeRecord rec = findRecordForPath(path);
2651                             if (rec != null) {
2652                                 rec.lastTrimMillis = System.currentTimeMillis();
2653                                 writeSettingsLocked();
2654                             }
2655                         }
2656                     }
2657 
2658                     @Override
2659                     public void onFinished(int status, PersistableBundle extras) {
2660                         dispatchOnFinished(listener, status, extras);
2661 
2662                         // TODO: benchmark when desired
2663                     }
2664                 });
2665             } else {
2666                 Slog.i(TAG, "Skipping fstrim - block based checkpoint in progress");
2667             }
2668         } catch (RemoteException e) {
2669             throw e.rethrowAsRuntimeException();
2670         }
2671     }
2672 
runIdleMaint(Runnable callback)2673     void runIdleMaint(Runnable callback) {
2674         enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
2675 
2676         try {
2677             // Block based checkpoint process runs fstrim. So, if checkpoint is in progress
2678             // (first boot after OTA), We skip idle maintenance and make sure the last
2679             // fstrim time is still updated. If file based checkpoints are used, we run
2680             // idle maintenance (GC + fstrim) regardless of checkpoint status.
2681             if (!needsCheckpoint() || !supportsBlockCheckpoint()) {
2682                 mVold.runIdleMaint(mNeedGC, new IVoldTaskListener.Stub() {
2683                     @Override
2684                     public void onStatus(int status, PersistableBundle extras) {
2685                         // Not currently used
2686                     }
2687                     @Override
2688                     public void onFinished(int status, PersistableBundle extras) {
2689                         if (callback != null) {
2690                             BackgroundThread.getHandler().post(callback);
2691                         }
2692                     }
2693                 });
2694             } else {
2695                 Slog.i(TAG, "Skipping idle maintenance - block based checkpoint in progress");
2696             }
2697         } catch (Exception e) {
2698             Slog.wtf(TAG, e);
2699         }
2700     }
2701 
2702     @Override
runIdleMaintenance()2703     public void runIdleMaintenance() {
2704         runIdleMaint(null);
2705     }
2706 
abortIdleMaint(Runnable callback)2707     void abortIdleMaint(Runnable callback) {
2708         enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
2709 
2710         try {
2711             mVold.abortIdleMaint(new IVoldTaskListener.Stub() {
2712                 @Override
2713                 public void onStatus(int status, PersistableBundle extras) {
2714                     // Not currently used
2715                 }
2716                 @Override
2717                 public void onFinished(int status, PersistableBundle extras) {
2718                     if (callback != null) {
2719                         BackgroundThread.getHandler().post(callback);
2720                     }
2721                 }
2722             });
2723         } catch (Exception e) {
2724             Slog.wtf(TAG, e);
2725         }
2726     }
2727 
2728     @Override
abortIdleMaintenance()2729     public void abortIdleMaintenance() {
2730         abortIdleMaint(null);
2731     }
2732 
prepareSmartIdleMaint()2733     private boolean prepareSmartIdleMaint() {
2734         /**
2735          * We can choose whether going with a new storage smart idle maintenance job
2736          * or falling back to the traditional way using DeviceConfig
2737          */
2738         boolean smartIdleMaintEnabled = DeviceConfig.getBoolean(
2739             DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
2740             "smart_idle_maint_enabled",
2741             DEFAULT_SMART_IDLE_MAINT_ENABLED);
2742         if (smartIdleMaintEnabled) {
2743             mLifetimePercentThreshold = DeviceConfig.getInt(
2744                 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
2745                 "lifetime_threshold", DEFAULT_LIFETIME_PERCENT_THRESHOLD);
2746             mMinSegmentsThreshold = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
2747                 "min_segments_threshold", DEFAULT_MIN_SEGMENTS_THRESHOLD);
2748             mDirtyReclaimRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
2749                 "dirty_reclaim_rate", DEFAULT_DIRTY_RECLAIM_RATE);
2750             mSegmentReclaimWeight = DeviceConfig.getFloat(
2751                 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
2752                 "segment_reclaim_weight", DEFAULT_SEGMENT_RECLAIM_WEIGHT);
2753             mLowBatteryLevel = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
2754                 "low_battery_level", DEFAULT_LOW_BATTERY_LEVEL);
2755             mChargingRequired = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
2756                 "charging_required", DEFAULT_CHARGING_REQUIRED);
2757             mMinGCSleepTime = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
2758                 "min_gc_sleeptime", DEFAULT_MIN_GC_SLEEPTIME);
2759             mTargetDirtyRatio = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
2760                 "target_dirty_ratio", DEFAULT_TARGET_DIRTY_RATIO);
2761 
2762             // If we use the smart idle maintenance, we need to turn off GC in the traditional idle
2763             // maintenance to avoid the conflict
2764             mNeedGC = false;
2765 
2766             loadStorageWriteRecords();
2767             try {
2768                 mVold.refreshLatestWrite();
2769             } catch (Exception e) {
2770                 Slog.wtf(TAG, e);
2771             }
2772             refreshLifetimeConstraint();
2773         }
2774         return smartIdleMaintEnabled;
2775     }
2776 
2777     // Return whether storage lifetime exceeds the threshold
isPassedLifetimeThresh()2778     public boolean isPassedLifetimeThresh() {
2779         return mPassedLifetimeThresh;
2780     }
2781 
loadStorageWriteRecords()2782     private void loadStorageWriteRecords() {
2783         FileInputStream fis = null;
2784 
2785         try {
2786             fis = mWriteRecordFile.openRead();
2787             ObjectInputStream ois = new ObjectInputStream(fis);
2788 
2789             int periodValue = ois.readInt();
2790             if (periodValue == sSmartIdleMaintPeriod) {
2791                 mStorageWriteRecords = (int[]) ois.readObject();
2792             }
2793         } catch (FileNotFoundException e) {
2794             // Missing data is okay, probably first boot
2795         } catch (Exception e) {
2796             Slog.wtf(TAG, "Failed reading write records", e);
2797         } finally {
2798             IoUtils.closeQuietly(fis);
2799         }
2800     }
2801 
getAverageWriteAmount()2802     private int getAverageWriteAmount() {
2803         return Arrays.stream(mStorageWriteRecords).sum() / mMaxWriteRecords;
2804     }
2805 
updateStorageWriteRecords(int latestWrite)2806     private void updateStorageWriteRecords(int latestWrite) {
2807         FileOutputStream fos = null;
2808 
2809         System.arraycopy(mStorageWriteRecords, 0, mStorageWriteRecords, 1,
2810                      mMaxWriteRecords - 1);
2811         mStorageWriteRecords[0] = latestWrite;
2812         try {
2813             fos = mWriteRecordFile.startWrite();
2814             ObjectOutputStream oos = new ObjectOutputStream(fos);
2815 
2816             oos.writeInt(sSmartIdleMaintPeriod);
2817             oos.writeObject(mStorageWriteRecords);
2818             mWriteRecordFile.finishWrite(fos);
2819         } catch (IOException e) {
2820             if (fos != null) {
2821                 mWriteRecordFile.failWrite(fos);
2822             }
2823         }
2824     }
2825 
checkChargeStatus()2826     private boolean checkChargeStatus() {
2827         IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
2828         Intent batteryStatus = mContext.registerReceiver(null, ifilter);
2829 
2830         if (mChargingRequired) {
2831             int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
2832             if (status != BatteryManager.BATTERY_STATUS_CHARGING &&
2833                 status != BatteryManager.BATTERY_STATUS_FULL) {
2834                 Slog.w(TAG, "Battery is not being charged");
2835                 return false;
2836             }
2837         }
2838 
2839         int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
2840         int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
2841         float chargePercent = level * 100f / (float)scale;
2842 
2843         if (chargePercent < mLowBatteryLevel) {
2844             Slog.w(TAG, "Battery level is " + chargePercent + ", which is lower than threshold: " +
2845                         mLowBatteryLevel);
2846             return false;
2847         }
2848         return true;
2849     }
2850 
refreshLifetimeConstraint()2851     private boolean refreshLifetimeConstraint() {
2852         int storageLifeTime = 0;
2853 
2854         try {
2855             storageLifeTime = mVold.getStorageLifeTime();
2856         } catch (Exception e) {
2857             Slog.wtf(TAG, e);
2858             return false;
2859         }
2860 
2861         if (storageLifeTime == -1) {
2862             Slog.w(TAG, "Failed to get storage lifetime");
2863             return false;
2864         } else if (storageLifeTime > mLifetimePercentThreshold) {
2865             Slog.w(TAG, "Ended smart idle maintenance, because of lifetime(" + storageLifeTime +
2866                         ")" + ", lifetime threshold(" + mLifetimePercentThreshold + ")");
2867             mPassedLifetimeThresh = true;
2868             return false;
2869         }
2870         Slog.i(TAG, "Storage lifetime: " + storageLifeTime);
2871         return true;
2872     }
2873 
runSmartIdleMaint(Runnable callback)2874     synchronized void runSmartIdleMaint(Runnable callback) {
2875         enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
2876 
2877         try {
2878             int avgWriteAmount = 0;
2879             int targetDirtyRatio = mTargetDirtyRatio;
2880             int latestWrite = mVold.getWriteAmount();
2881             if (latestWrite == -1) {
2882                 Slog.w(TAG, "Failed to get storage write record");
2883                 return;
2884             }
2885 
2886             updateStorageWriteRecords(latestWrite);
2887 
2888             // Block based checkpoint process runs fstrim. So, if checkpoint is in progress
2889             // (first boot after OTA), We skip the smart idle maintenance
2890             if (!needsCheckpoint() || !supportsBlockCheckpoint()) {
2891                 if (!refreshLifetimeConstraint() || !checkChargeStatus()) {
2892                     Slog.i(TAG, "Turn off gc_urgent based on checking lifetime and charge status");
2893                     targetDirtyRatio = 100;
2894                 } else {
2895                     avgWriteAmount = getAverageWriteAmount();
2896                 }
2897 
2898                 Slog.i(TAG, "Set smart idle maintenance: " + "latest write amount: " +
2899                             latestWrite + ", average write amount: " + avgWriteAmount +
2900                             ", min segment threshold: " + mMinSegmentsThreshold +
2901                             ", dirty reclaim rate: " + mDirtyReclaimRate +
2902                             ", segment reclaim weight: " + mSegmentReclaimWeight +
2903                             ", period(min): " + sSmartIdleMaintPeriod +
2904                             ", min gc sleep time(ms): " + mMinGCSleepTime +
2905                             ", target dirty ratio: " + targetDirtyRatio);
2906                 mVold.setGCUrgentPace(avgWriteAmount, mMinSegmentsThreshold, mDirtyReclaimRate,
2907                                       mSegmentReclaimWeight, sSmartIdleMaintPeriod,
2908                                       mMinGCSleepTime, targetDirtyRatio);
2909             } else {
2910                 Slog.i(TAG, "Skipping smart idle maintenance - block based checkpoint in progress");
2911             }
2912         } catch (Exception e) {
2913             Slog.wtf(TAG, e);
2914         } finally {
2915             if (callback != null) {
2916                 callback.run();
2917             }
2918         }
2919     }
2920 
2921     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
2922     @Override
setDebugFlags(int flags, int mask)2923     public void setDebugFlags(int flags, int mask) {
2924 
2925         super.setDebugFlags_enforcePermission();
2926 
2927         if ((mask & (StorageManager.DEBUG_ADOPTABLE_FORCE_ON
2928                 | StorageManager.DEBUG_ADOPTABLE_FORCE_OFF)) != 0) {
2929             final String value;
2930             if ((flags & StorageManager.DEBUG_ADOPTABLE_FORCE_ON) != 0) {
2931                 value = "force_on";
2932             } else if ((flags & StorageManager.DEBUG_ADOPTABLE_FORCE_OFF) != 0) {
2933                 value = "force_off";
2934             } else {
2935                 value = "";
2936             }
2937 
2938             final long token = Binder.clearCallingIdentity();
2939             try {
2940                 SystemProperties.set(StorageManager.PROP_ADOPTABLE, value);
2941 
2942                 // Reset storage to kick new setting into place
2943                 mHandler.obtainMessage(H_RESET).sendToTarget();
2944             } finally {
2945                 Binder.restoreCallingIdentity(token);
2946             }
2947         }
2948 
2949         if ((mask & (StorageManager.DEBUG_SDCARDFS_FORCE_ON
2950                 | StorageManager.DEBUG_SDCARDFS_FORCE_OFF)) != 0) {
2951             final String value;
2952             if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_ON) != 0) {
2953                 value = "force_on";
2954             } else if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_OFF) != 0) {
2955                 value = "force_off";
2956             } else {
2957                 value = "";
2958             }
2959 
2960             final long token = Binder.clearCallingIdentity();
2961             try {
2962                 SystemProperties.set(StorageManager.PROP_SDCARDFS, value);
2963 
2964                 // Reset storage to kick new setting into place
2965                 mHandler.obtainMessage(H_RESET).sendToTarget();
2966             } finally {
2967                 Binder.restoreCallingIdentity(token);
2968             }
2969         }
2970 
2971         if ((mask & StorageManager.DEBUG_VIRTUAL_DISK) != 0) {
2972             final boolean enabled = (flags & StorageManager.DEBUG_VIRTUAL_DISK) != 0;
2973 
2974             final long token = Binder.clearCallingIdentity();
2975             try {
2976                 SystemProperties.set(StorageManager.PROP_VIRTUAL_DISK, Boolean.toString(enabled));
2977 
2978                 // Reset storage to kick new setting into place
2979                 mHandler.obtainMessage(H_RESET).sendToTarget();
2980             } finally {
2981                 Binder.restoreCallingIdentity(token);
2982             }
2983         }
2984     }
2985 
2986     @Override
getPrimaryStorageUuid()2987     public String getPrimaryStorageUuid() {
2988         synchronized (mLock) {
2989             return mPrimaryStorageUuid;
2990         }
2991     }
2992 
2993     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
2994     @Override
setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)2995     public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
2996 
2997         super.setPrimaryStorageUuid_enforcePermission();
2998 
2999         final VolumeInfo from;
3000         final VolumeInfo to;
3001         final List<UserInfo> users;
3002 
3003         synchronized (mLock) {
3004             if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
3005                 throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
3006             }
3007 
3008             if (mMoveCallback != null) {
3009                 throw new IllegalStateException("Move already in progress");
3010             }
3011             mMoveCallback = callback;
3012             mMoveTargetUuid = volumeUuid;
3013 
3014             // We need all the users unlocked to move their primary storage
3015             users = mContext.getSystemService(UserManager.class).getUsers();
3016             for (UserInfo user : users) {
3017                 if (StorageManager.isFileEncrypted() && !isCeStorageUnlocked(user.id)) {
3018                     Slog.w(TAG, "Failing move due to locked user " + user.id);
3019                     onMoveStatusLocked(PackageManager.MOVE_FAILED_LOCKED_USER);
3020                     return;
3021                 }
3022             }
3023 
3024             // When moving to/from primary physical volume, we probably just nuked
3025             // the current storage location, so we have nothing to move.
3026             if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
3027                     || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
3028                 Slog.d(TAG, "Skipping move to/from primary physical");
3029                 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
3030                 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
3031                 mHandler.obtainMessage(H_RESET).sendToTarget();
3032                 return;
3033 
3034             } else {
3035                 int currentUserId = mCurrentUserId;
3036                 from = findStorageForUuidAsUser(mPrimaryStorageUuid, currentUserId);
3037                 to = findStorageForUuidAsUser(volumeUuid, currentUserId);
3038 
3039                 if (from == null) {
3040                     Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
3041                     onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
3042                     return;
3043                 } else if (to == null) {
3044                     Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid);
3045                     onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
3046                     return;
3047                 }
3048             }
3049         }
3050 
3051         // Prepare the storage before move, this is required to unlock adoptable storage (as the
3052         // keys are tied to prepare user data step) & also is required for the destination files to
3053         // end up with the correct SELinux labels and encryption policies for directories
3054         try {
3055             prepareUserStorageForMoveInternal(mPrimaryStorageUuid, volumeUuid, users);
3056         } catch (Exception e) {
3057             Slog.w(TAG, "Failing move due to failure on prepare user data", e);
3058             synchronized (mLock) {
3059                 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
3060             }
3061             return;
3062         }
3063 
3064         try {
3065             mVold.moveStorage(from.id, to.id, new IVoldTaskListener.Stub() {
3066                 @Override
3067                 public void onStatus(int status, PersistableBundle extras) {
3068                     synchronized (mLock) {
3069                         onMoveStatusLocked(status);
3070                     }
3071                 }
3072 
3073                 @Override
3074                 public void onFinished(int status, PersistableBundle extras) {
3075                     // Not currently used
3076                 }
3077             });
3078         } catch (Exception e) {
3079             Slog.wtf(TAG, e);
3080         }
3081     }
3082 
warnOnNotMounted()3083     private void warnOnNotMounted() {
3084         synchronized (mLock) {
3085             for (int i = 0; i < mVolumes.size(); i++) {
3086                 final VolumeInfo vol = mVolumes.valueAt(i);
3087                 if (vol.isPrimary() && vol.isMountedWritable()) {
3088                     // Cool beans, we have a mounted primary volume
3089                     return;
3090                 }
3091             }
3092         }
3093 
3094         Slog.w(TAG, "No primary storage mounted!");
3095     }
3096 
isUidOwnerOfPackageOrSystem(String packageName, int callerUid)3097     private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
3098         if (callerUid == android.os.Process.SYSTEM_UID) {
3099             return true;
3100         }
3101 
3102         return mPmInternal.isSameApp(packageName, callerUid, UserHandle.getUserId(callerUid));
3103     }
3104 
3105     @Override
getMountedObbPath(String rawPath)3106     public String getMountedObbPath(String rawPath) {
3107         Objects.requireNonNull(rawPath, "rawPath cannot be null");
3108 
3109         warnOnNotMounted();
3110 
3111         final ObbState state;
3112         synchronized (mObbMounts) {
3113             state = mObbPathToStateMap.get(rawPath);
3114         }
3115         if (state == null) {
3116             Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
3117             return null;
3118         }
3119 
3120         return findVolumeByIdOrThrow(state.volId).getPath().getAbsolutePath();
3121     }
3122 
3123     @Override
isObbMounted(String rawPath)3124     public boolean isObbMounted(String rawPath) {
3125         Objects.requireNonNull(rawPath, "rawPath cannot be null");
3126         synchronized (mObbMounts) {
3127             return mObbPathToStateMap.containsKey(rawPath);
3128         }
3129     }
3130 
3131     @Override
mountObb(String rawPath, String canonicalPath, IObbActionListener token, int nonce, ObbInfo obbInfo)3132     public void mountObb(String rawPath, String canonicalPath, IObbActionListener token,
3133             int nonce, ObbInfo obbInfo) {
3134         Objects.requireNonNull(rawPath, "rawPath cannot be null");
3135         Objects.requireNonNull(canonicalPath, "canonicalPath cannot be null");
3136         Objects.requireNonNull(token, "token cannot be null");
3137         Objects.requireNonNull(obbInfo, "obbIfno cannot be null");
3138 
3139         final int callingUid = Binder.getCallingUid();
3140         final ObbState obbState = new ObbState(rawPath, canonicalPath,
3141                 callingUid, token, nonce, null);
3142         final ObbAction action = new MountObbAction(obbState, callingUid, obbInfo);
3143         mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
3144 
3145         if (DEBUG_OBB)
3146             Slog.i(TAG, "Send to OBB handler: " + action.toString());
3147     }
3148 
3149     @Override
unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce)3150     public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
3151         Objects.requireNonNull(rawPath, "rawPath cannot be null");
3152 
3153         final ObbState existingState;
3154         synchronized (mObbMounts) {
3155             existingState = mObbPathToStateMap.get(rawPath);
3156         }
3157 
3158         if (existingState != null) {
3159             // TODO: separate state object from request data
3160             final int callingUid = Binder.getCallingUid();
3161             final ObbState newState = new ObbState(rawPath, existingState.canonicalPath,
3162                     callingUid, token, nonce, existingState.volId);
3163             final ObbAction action = new UnmountObbAction(newState, force);
3164             mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
3165 
3166             if (DEBUG_OBB)
3167                 Slog.i(TAG, "Send to OBB handler: " + action.toString());
3168         } else {
3169             Slog.w(TAG, "Unknown OBB mount at " + rawPath);
3170         }
3171     }
3172 
3173     /**
3174      * Check whether the device supports filesystem checkpointing.
3175      *
3176      * @return true if the device supports filesystem checkpointing, false otherwise.
3177      */
3178     @Override
supportsCheckpoint()3179     public boolean supportsCheckpoint() throws RemoteException {
3180         return mVold.supportsCheckpoint();
3181     }
3182 
3183     /**
3184      * Signal that checkpointing partitions should start a checkpoint on the next boot.
3185      *
3186      * @param numTries Number of times to try booting in checkpoint mode, before we will boot
3187      *                 non-checkpoint mode and commit all changes immediately. Callers are
3188      *                 responsible for ensuring that boot is safe (eg, by rolling back updates).
3189      */
3190     @Override
startCheckpoint(int numTries)3191     public void startCheckpoint(int numTries) throws RemoteException {
3192         // Only the root, system_server and shell processes are permitted to start checkpoints
3193         final int callingUid = Binder.getCallingUid();
3194         if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID
3195                 && callingUid != Process.SHELL_UID) {
3196             throw new SecurityException("no permission to start filesystem checkpoint");
3197         }
3198 
3199         mVold.startCheckpoint(numTries);
3200     }
3201 
3202     /**
3203      * Signal that checkpointing partitions should commit changes
3204      */
3205     @Override
commitChanges()3206     public void commitChanges() throws RemoteException {
3207         // Only the system process is permitted to commit checkpoints
3208         if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
3209             throw new SecurityException("no permission to commit checkpoint changes");
3210         }
3211 
3212         mVold.commitChanges();
3213     }
3214 
3215     @android.annotation.EnforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS)
3216     /**
3217      * Check if we should be mounting with checkpointing or are checkpointing now
3218      */
3219     @Override
needsCheckpoint()3220     public boolean needsCheckpoint() throws RemoteException {
3221         super.needsCheckpoint_enforcePermission();
3222 
3223         return mVold.needsCheckpoint();
3224     }
3225 
3226     /**
3227      * Abort the current set of changes and either try again, or abort entirely
3228      */
3229     @Override
abortChanges(String message, boolean retry)3230     public void abortChanges(String message, boolean retry) throws RemoteException {
3231         // Only the system process is permitted to abort checkpoints
3232         if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
3233             throw new SecurityException("no permission to commit checkpoint changes");
3234         }
3235 
3236         mVold.abortChanges(message, retry);
3237     }
3238 
3239     @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL)
3240     @Override
createUserStorageKeys(int userId, boolean ephemeral)3241     public void createUserStorageKeys(int userId, boolean ephemeral) {
3242 
3243         super.createUserStorageKeys_enforcePermission();
3244 
3245         try {
3246             mVold.createUserStorageKeys(userId, ephemeral);
3247             // Since the user's CE key was just created, the user's CE storage is now unlocked.
3248             synchronized (mLock) {
3249                 mCeUnlockedUsers.append(userId);
3250             }
3251         } catch (Exception e) {
3252             Slog.wtf(TAG, e);
3253         }
3254     }
3255 
3256     @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL)
3257     @Override
destroyUserStorageKeys(int userId)3258     public void destroyUserStorageKeys(int userId) {
3259 
3260         super.destroyUserStorageKeys_enforcePermission();
3261 
3262         try {
3263             mVold.destroyUserStorageKeys(userId);
3264             // Since the user's CE key was just destroyed, the user's CE storage is now locked.
3265             synchronized (mLock) {
3266                 mCeUnlockedUsers.remove(userId);
3267             }
3268         } catch (Exception e) {
3269             Slog.wtf(TAG, e);
3270         }
3271     }
3272 
3273     /* Only for use by LockSettingsService */
3274     @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL)
3275     @Override
setCeStorageProtection(@serIdInt int userId, byte[] secret)3276     public void setCeStorageProtection(@UserIdInt int userId, byte[] secret)
3277             throws RemoteException {
3278         super.setCeStorageProtection_enforcePermission();
3279 
3280         mVold.setCeStorageProtection(userId, secret);
3281     }
3282 
3283     /* Only for use by LockSettingsService */
3284     @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL)
3285     @Override
unlockCeStorage(@serIdInt int userId, byte[] secret)3286     public void unlockCeStorage(@UserIdInt int userId, byte[] secret) throws RemoteException {
3287         super.unlockCeStorage_enforcePermission();
3288 
3289         if (StorageManager.isFileEncrypted()) {
3290             mVold.unlockCeStorage(userId, secret);
3291         }
3292         synchronized (mLock) {
3293             mCeUnlockedUsers.append(userId);
3294         }
3295     }
3296 
3297     @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL)
3298     @Override
lockCeStorage(int userId)3299     public void lockCeStorage(int userId) {
3300         super.lockCeStorage_enforcePermission();
3301 
3302         // Never lock the CE storage of a headless system user.
3303         if (userId == UserHandle.USER_SYSTEM
3304                 && UserManager.isHeadlessSystemUserMode()) {
3305             throw new IllegalArgumentException("Headless system user data cannot be locked..");
3306         }
3307 
3308         if (!isCeStorageUnlocked(userId)) {
3309             Slog.d(TAG, "User " + userId + "'s CE storage is already locked");
3310             return;
3311         }
3312 
3313         try {
3314             mVold.lockCeStorage(userId);
3315         } catch (Exception e) {
3316             Slog.wtf(TAG, e);
3317             return;
3318         }
3319 
3320         synchronized (mLock) {
3321             mCeUnlockedUsers.remove(userId);
3322         }
3323         if (android.os.Flags.allowPrivateProfile()
3324                 && android.multiuser.Flags.enablePrivateSpaceFeatures()
3325                 && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) {
3326             dispatchCeStorageLockedEvent(userId);
3327         }
3328     }
3329 
3330     @Override
isCeStorageUnlocked(int userId)3331     public boolean isCeStorageUnlocked(int userId) {
3332         synchronized (mLock) {
3333             return mCeUnlockedUsers.contains(userId);
3334         }
3335     }
3336 
isSystemUnlocked(int userId)3337     private boolean isSystemUnlocked(int userId) {
3338         synchronized (mLock) {
3339             return ArrayUtils.contains(mSystemUnlockedUsers, userId);
3340         }
3341     }
3342 
prepareUserStorageIfNeeded(VolumeInfo vol)3343     private void prepareUserStorageIfNeeded(VolumeInfo vol) throws Exception {
3344         if (vol.type != VolumeInfo.TYPE_PRIVATE) {
3345             return;
3346         }
3347 
3348         final UserManager um = mContext.getSystemService(UserManager.class);
3349         final UserManagerInternal umInternal =
3350                 LocalServices.getService(UserManagerInternal.class);
3351 
3352         for (UserInfo user : um.getUsers()) {
3353             final int flags;
3354             if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
3355                 flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
3356             } else if (umInternal.isUserRunning(user.id)) {
3357                 flags = StorageManager.FLAG_STORAGE_DE;
3358             } else {
3359                 continue;
3360             }
3361 
3362             prepareUserStorageInternal(vol.fsUuid, user.id, flags);
3363         }
3364     }
3365 
3366     @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL)
3367     @Override
prepareUserStorage(String volumeUuid, int userId, int flags)3368     public void prepareUserStorage(String volumeUuid, int userId, int flags) {
3369 
3370         super.prepareUserStorage_enforcePermission();
3371 
3372         try {
3373             prepareUserStorageInternal(volumeUuid, userId, flags);
3374         } catch (Exception e) {
3375             throw new RuntimeException(e);
3376         }
3377     }
3378 
prepareUserStorageInternal(String volumeUuid, int userId, int flags)3379     private void prepareUserStorageInternal(String volumeUuid, int userId, int flags)
3380             throws Exception {
3381         try {
3382             mVold.prepareUserStorage(volumeUuid, userId, flags);
3383             // After preparing user storage, we should check if we should mount data mirror again,
3384             // and we do it for user 0 only as we only need to do once for all users.
3385             if (volumeUuid != null) {
3386                 final StorageManager storage = mContext.getSystemService(StorageManager.class);
3387                 VolumeInfo info = storage.findVolumeByUuid(volumeUuid);
3388                 if (info != null && userId == 0 && info.type == VolumeInfo.TYPE_PRIVATE) {
3389                     mInstaller.tryMountDataMirror(volumeUuid);
3390                 }
3391             }
3392         } catch (Exception e) {
3393             EventLog.writeEvent(0x534e4554, "224585613", -1, "");
3394             Slog.wtf(TAG, e);
3395             // Make sure to re-throw this exception; we must not ignore failure
3396             // to prepare the user storage as it could indicate that encryption
3397             // wasn't successfully set up.
3398             //
3399             // Very unfortunately, these errors need to be ignored for broken
3400             // users that already existed on-disk from older Android versions.
3401             UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class);
3402             if (umInternal.shouldIgnorePrepareStorageErrors(userId)) {
3403                 Slog.wtf(TAG, "ignoring error preparing storage for existing user " + userId
3404                         + "; device may be insecure!");
3405                 return;
3406             }
3407             throw e;
3408         }
3409     }
3410 
3411     @android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL)
3412     @Override
destroyUserStorage(String volumeUuid, int userId, int flags)3413     public void destroyUserStorage(String volumeUuid, int userId, int flags) {
3414 
3415         super.destroyUserStorage_enforcePermission();
3416 
3417         try {
3418             mVold.destroyUserStorage(volumeUuid, userId, flags);
3419         } catch (Exception e) {
3420             Slog.wtf(TAG, e);
3421         }
3422     }
3423 
3424     @Override
fixupAppDir(String path)3425     public void fixupAppDir(String path) {
3426         final Matcher matcher = KNOWN_APP_DIR_PATHS.matcher(path);
3427         if (matcher.matches()) {
3428             if (matcher.group(2) == null) {
3429                 Log.e(TAG, "Asked to fixup an app dir without a userId: " + path);
3430                 return;
3431             }
3432             try {
3433                 int userId = Integer.parseInt(matcher.group(2));
3434                 String packageName = matcher.group(3);
3435                 int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, userId);
3436                 try {
3437                     mVold.fixupAppDir(path + "/", uid);
3438                 } catch (RemoteException | ServiceSpecificException e) {
3439                     Log.e(TAG, "Failed to fixup app dir for " + packageName, e);
3440                 }
3441             } catch (NumberFormatException e) {
3442                 Log.e(TAG, "Invalid userId in path: " + path, e);
3443             } catch (PackageManager.NameNotFoundException e) {
3444                 Log.e(TAG, "Couldn't find package to fixup app dir " + path, e);
3445             }
3446         } else {
3447             Log.e(TAG, "Path " + path + " is not a valid application-specific directory");
3448         }
3449     }
3450 
3451     /*
3452      * Disable storage's app data isolation for testing.
3453      */
3454     @Override
disableAppDataIsolation(String pkgName, int pid, int userId)3455     public void disableAppDataIsolation(String pkgName, int pid, int userId) {
3456         final int callingUid = Binder.getCallingUid();
3457         if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) {
3458             throw new SecurityException("no permission to enable app visibility");
3459         }
3460         final String[] sharedPackages =
3461                 mPmInternal.getSharedUserPackagesForPackage(pkgName, userId);
3462         final int uid = mPmInternal.getPackageUid(pkgName, 0, userId);
3463         final String[] packages =
3464                 sharedPackages.length != 0 ? sharedPackages : new String[]{pkgName};
3465         try {
3466             mVold.unmountAppStorageDirs(uid, pid, packages);
3467         } catch (RemoteException e) {
3468             throw e.rethrowAsRuntimeException();
3469         }
3470     }
3471 
3472     /**
3473      * Returns PendingIntent which can be used by Apps with MANAGE_EXTERNAL_STORAGE permission
3474      * to launch the manageSpaceActivity of the App specified by packageName.
3475      */
3476     @Override
3477     @Nullable
getManageSpaceActivityIntent( @onNull String packageName, int requestCode)3478     public PendingIntent getManageSpaceActivityIntent(
3479             @NonNull String packageName, int requestCode) {
3480         // Only Apps with MANAGE_EXTERNAL_STORAGE permission which have package visibility for
3481         // packageName should be able to call this API.
3482         int originalUid = Binder.getCallingUidOrThrow();
3483         try {
3484             // Get package name for calling app and verify it has MANAGE_EXTERNAL_STORAGE permission
3485             final String[] packagesFromUid = mIPackageManager.getPackagesForUid(originalUid);
3486             if (packagesFromUid == null) {
3487                 throw new SecurityException("Unknown uid " + originalUid);
3488             }
3489             // Checking first entry in packagesFromUid is enough as using "sharedUserId"
3490             // mechanism is rare and discouraged. Also, Apps that share same UID share the same
3491             // permissions.
3492             if (!mStorageManagerInternal.hasExternalStorageAccess(originalUid,
3493                     packagesFromUid[0])) {
3494                 throw new SecurityException("Only File Manager Apps permitted");
3495             }
3496         } catch (RemoteException re) {
3497             throw new SecurityException("Unknown uid " + originalUid, re);
3498         }
3499 
3500         ApplicationInfo appInfo;
3501         try {
3502             appInfo = mIPackageManager.getApplicationInfo(packageName, 0,
3503                     UserHandle.getUserId(originalUid));
3504             if (appInfo == null) {
3505                 throw new IllegalArgumentException(
3506                         "Invalid packageName");
3507             }
3508             if (appInfo.manageSpaceActivityName == null) {
3509                 Log.i(TAG, packageName + " doesn't have a manageSpaceActivity");
3510                 return null;
3511             }
3512         } catch (RemoteException e) {
3513             throw new SecurityException("Only File Manager Apps permitted");
3514         }
3515 
3516         // We want to call the manageSpaceActivity as a SystemService and clear identity
3517         // of the calling App
3518         final long token = Binder.clearCallingIdentity();
3519         try {
3520             Context targetAppContext = mContext.createPackageContext(packageName, 0);
3521             Intent intent = new Intent(Intent.ACTION_DEFAULT);
3522             intent.setClassName(packageName,
3523                     appInfo.manageSpaceActivityName);
3524             intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
3525 
3526             final ActivityOptions options = ActivityOptions.makeBasic()
3527                     .setPendingIntentCreatorBackgroundActivityStartMode(
3528                             ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED);
3529 
3530             PendingIntent activity = PendingIntent.getActivity(targetAppContext, requestCode,
3531                     intent,
3532                     FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE, options.toBundle());
3533             return activity;
3534         } catch (PackageManager.NameNotFoundException e) {
3535             throw new IllegalArgumentException(
3536                     "packageName not found");
3537         } finally {
3538             Binder.restoreCallingIdentity(token);
3539         }
3540     }
3541 
3542     @Override
notifyAppIoBlocked(String volumeUuid, int uid, int tid, int reason)3543     public void notifyAppIoBlocked(String volumeUuid, int uid, int tid, int reason) {
3544         enforceExternalStorageService();
3545 
3546         mStorageSessionController.notifyAppIoBlocked(volumeUuid, uid, tid, reason);
3547     }
3548 
3549     @Override
notifyAppIoResumed(String volumeUuid, int uid, int tid, int reason)3550     public void notifyAppIoResumed(String volumeUuid, int uid, int tid, int reason) {
3551         enforceExternalStorageService();
3552 
3553         mStorageSessionController.notifyAppIoResumed(volumeUuid, uid, tid, reason);
3554     }
3555 
3556     @Override
isAppIoBlocked(String volumeUuid, int uid, int tid, @StorageManager.AppIoBlockedReason int reason)3557     public boolean isAppIoBlocked(String volumeUuid, int uid, int tid,
3558             @StorageManager.AppIoBlockedReason int reason) {
3559         return isAppIoBlocked(uid);
3560     }
3561 
isAppIoBlocked(int uid)3562     private boolean isAppIoBlocked(int uid) {
3563         return mStorageSessionController.isAppIoBlocked(uid);
3564     }
3565 
3566     @Override
setCloudMediaProvider(@ullable String authority)3567     public void setCloudMediaProvider(@Nullable String authority) {
3568         enforceExternalStorageService();
3569 
3570         final int userId = UserHandle.getUserId(Binder.getCallingUid());
3571         synchronized (mCloudMediaProviders) {
3572             final String oldAuthority = mCloudMediaProviders.get(userId);
3573             if (!Objects.equals(authority, oldAuthority)) {
3574                 mCloudMediaProviders.put(userId, authority);
3575                 mHandler.obtainMessage(H_CLOUD_MEDIA_PROVIDER_CHANGED, userId, 0, authority)
3576                         .sendToTarget();
3577             }
3578         }
3579     }
3580 
3581     @Override
3582     @Nullable
getCloudMediaProvider()3583     public String getCloudMediaProvider() {
3584         final int callingUid = Binder.getCallingUid();
3585         final int userId = UserHandle.getUserId(callingUid);
3586         final String authority;
3587         synchronized (mCloudMediaProviders) {
3588             authority = mCloudMediaProviders.get(userId);
3589         }
3590         if (authority == null) {
3591             return null;
3592         }
3593         final ProviderInfo pi = mPmInternal.resolveContentProvider(
3594                 authority, 0, userId, callingUid);
3595         if (pi == null
3596                 || mPmInternal.filterAppAccess(pi.packageName, callingUid, userId)) {
3597             return null;
3598         }
3599         return authority;
3600     }
3601 
3602     @Override
getInternalStorageBlockDeviceSize()3603     public long getInternalStorageBlockDeviceSize() throws RemoteException {
3604         if (mInternalStorageSize == 0) {
3605             mInternalStorageSize = mVold.getStorageSize();
3606         }
3607 
3608         return mInternalStorageSize;
3609     }
3610 
3611     @EnforcePermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
3612     @Override
getInternalStorageRemainingLifetime()3613     public int getInternalStorageRemainingLifetime() throws RemoteException {
3614         super.getInternalStorageRemainingLifetime_enforcePermission();
3615         return mVold.getStorageRemainingLifetime();
3616     }
3617 
3618     /**
3619      * Enforces that the caller is the {@link ExternalStorageService}
3620      *
3621      * @throws SecurityException if the caller doesn't have the
3622      * {@link android.Manifest.permission.WRITE_MEDIA_STORAGE} permission or is not the
3623      * {@link ExternalStorageService}
3624      */
enforceExternalStorageService()3625     private void enforceExternalStorageService() {
3626         enforcePermission(android.Manifest.permission.WRITE_MEDIA_STORAGE);
3627         int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
3628         if (callingAppId != mMediaStoreAuthorityAppId) {
3629             throw new SecurityException("Only the ExternalStorageService is permitted");
3630         }
3631     }
3632 
3633     /** Not thread safe */
3634     class AppFuseMountScope extends AppFuseBridge.MountScope {
3635         private boolean mMounted = false;
3636 
AppFuseMountScope(int uid, int mountId)3637         public AppFuseMountScope(int uid, int mountId) {
3638             super(uid, mountId);
3639         }
3640 
3641         @Override
open()3642         public ParcelFileDescriptor open() throws AppFuseMountException {
3643             extendWatchdogTimeout("#open might be slow");
3644             try {
3645                 final FileDescriptor fd = mVold.mountAppFuse(uid, mountId);
3646                 mMounted = true;
3647                 return new ParcelFileDescriptor(fd);
3648             } catch (Exception e) {
3649                 throw new AppFuseMountException("Failed to mount", e);
3650             }
3651         }
3652 
3653         @Override
openFile(int mountId, int fileId, int flags)3654         public ParcelFileDescriptor openFile(int mountId, int fileId, int flags)
3655                 throws AppFuseMountException {
3656             extendWatchdogTimeout("#openFile might be slow");
3657             try {
3658                 return new ParcelFileDescriptor(
3659                         mVold.openAppFuseFile(uid, mountId, fileId, flags));
3660             } catch (Exception e) {
3661                 throw new AppFuseMountException("Failed to open", e);
3662             }
3663         }
3664 
3665         @Override
close()3666         public void close() throws Exception {
3667             extendWatchdogTimeout("#close might be slow");
3668             if (mMounted) {
3669                 BackgroundThread.getHandler().post(() -> {
3670                     try {
3671                         // We need to run the unmount on a separate thread to
3672                         // prevent a possible deadlock, where:
3673                         // 1. AppFuseThread (this thread) tries to call into vold
3674                         // 2. the vold lock is held by another thread, which called:
3675                         //    mVold.openAppFuseFile()
3676                         //    as part of that call, vold calls open() on the
3677                         //    underlying file, which is a call that needs to be
3678                         //    handled by the AppFuseThread, which is stuck waiting
3679                         //    for the vold lock (see 1.)
3680                         // It is safe to do the unmount asynchronously, because the mount
3681                         // path we use is never reused during the current boot cycle;
3682                         // see mNextAppFuseName. Also,we have anyway stopped serving
3683                         // requests at this point.
3684                         mVold.unmountAppFuse(uid, mountId);
3685                     } catch (RemoteException e) {
3686                         throw e.rethrowAsRuntimeException();
3687                     }
3688                 });
3689                 mMounted = false;
3690             }
3691         }
3692     }
3693 
3694     @Override
mountProxyFileDescriptorBridge()3695     public @Nullable AppFuseMount mountProxyFileDescriptorBridge() {
3696         Slog.v(TAG, "mountProxyFileDescriptorBridge");
3697         final int uid = Binder.getCallingUid();
3698 
3699         while (true) {
3700             synchronized (mAppFuseLock) {
3701                 boolean newlyCreated = false;
3702                 if (mAppFuseBridge == null) {
3703                     mAppFuseBridge = new AppFuseBridge();
3704                     new Thread(mAppFuseBridge, AppFuseBridge.TAG).start();
3705                     newlyCreated = true;
3706                 }
3707                 try {
3708                     final int name = mNextAppFuseName++;
3709                     try {
3710                         return new AppFuseMount(
3711                             name, mAppFuseBridge.addBridge(new AppFuseMountScope(uid, name)));
3712                     } catch (FuseUnavailableMountException e) {
3713                         if (newlyCreated) {
3714                             // If newly created bridge fails, it's a real error.
3715                             Slog.e(TAG, "", e);
3716                             return null;
3717                         }
3718                         // It seems the thread of mAppFuseBridge has already been terminated.
3719                         mAppFuseBridge = null;
3720                     }
3721                 } catch (AppFuseMountException e) {
3722                     throw e.rethrowAsParcelableException();
3723                 }
3724             }
3725         }
3726     }
3727 
3728     @Override
openProxyFileDescriptor( int mountId, int fileId, int mode)3729     public @Nullable ParcelFileDescriptor openProxyFileDescriptor(
3730             int mountId, int fileId, int mode) {
3731         Slog.v(TAG, "mountProxyFileDescriptor");
3732 
3733         // We only support a narrow set of incoming mode flags
3734         mode &= MODE_READ_WRITE;
3735 
3736         try {
3737             synchronized (mAppFuseLock) {
3738                 if (mAppFuseBridge == null) {
3739                     Slog.e(TAG, "FuseBridge has not been created");
3740                     return null;
3741                 }
3742                 return mAppFuseBridge.openFile(mountId, fileId, mode);
3743             }
3744         } catch (FuseUnavailableMountException | InterruptedException error) {
3745             Slog.v(TAG, "The mount point has already been invalid", error);
3746             return null;
3747         }
3748     }
3749 
3750     @Override
mkdirs(String callingPkg, String appPath)3751     public void mkdirs(String callingPkg, String appPath) {
3752         final int callingUid = Binder.getCallingUid();
3753         final int userId = UserHandle.getUserId(callingUid);
3754         final String propertyName = "sys.user." + userId + ".ce_available";
3755 
3756         // Ignore requests to create directories while CE storage is locked
3757         if (!isCeStorageUnlocked(userId)) {
3758             throw new IllegalStateException("Failed to prepare " + appPath);
3759         }
3760 
3761         // Ignore requests to create directories if CE storage is not available
3762         if ((userId == UserHandle.USER_SYSTEM)
3763                 && !SystemProperties.getBoolean(propertyName, false)) {
3764             throw new IllegalStateException("Failed to prepare " + appPath);
3765         }
3766 
3767         // Validate that reported package name belongs to caller
3768         final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
3769                 Context.APP_OPS_SERVICE);
3770         appOps.checkPackage(callingUid, callingPkg);
3771 
3772         try {
3773             final PackageManager.Property noAppStorageProp = mContext.getPackageManager()
3774                     .getPropertyAsUser(PackageManager.PROPERTY_NO_APP_DATA_STORAGE, callingPkg,
3775                             null /* className */, userId);
3776             if (noAppStorageProp != null && noAppStorageProp.getBoolean()) {
3777                 throw new SecurityException(callingPkg + " should not have " + appPath);
3778             }
3779         } catch (PackageManager.NameNotFoundException ignore) {
3780             // Property not found
3781         }
3782 
3783         File appFile = null;
3784         try {
3785             appFile = new File(appPath).getCanonicalFile();
3786         } catch (IOException e) {
3787             throw new IllegalStateException("Failed to resolve " + appPath + ": " + e);
3788         }
3789 
3790         appPath = appFile.getAbsolutePath();
3791         if (!appPath.endsWith("/")) {
3792             appPath = appPath + "/";
3793         }
3794         // Ensure that the path we're asked to create is a known application directory
3795         // path.
3796         final Matcher matcher = KNOWN_APP_DIR_PATHS.matcher(appPath);
3797         if (matcher.matches()) {
3798             // And that the package dir matches the calling package
3799             if (!matcher.group(3).equals(callingPkg)) {
3800                 throw new SecurityException("Invalid mkdirs path: " + appFile
3801                         + " does not contain calling package " + callingPkg);
3802             }
3803             // And that the user id part of the path (if any) matches the calling user id,
3804             // or if for a public volume (no user id), the user matches the current user
3805             if ((matcher.group(2) != null && !matcher.group(2).equals(Integer.toString(userId)))
3806                     || (matcher.group(2) == null && userId != mCurrentUserId)) {
3807                 throw new SecurityException("Invalid mkdirs path: " + appFile
3808                         + " does not match calling user id " + userId);
3809             }
3810             try {
3811                 mVold.setupAppDir(appPath, callingUid);
3812             } catch (RemoteException e) {
3813                 throw new IllegalStateException("Failed to prepare " + appPath + ": " + e);
3814             }
3815 
3816             return;
3817         }
3818         throw new SecurityException("Invalid mkdirs path: " + appFile
3819                 + " is not a known app path.");
3820     }
3821 
3822     @Override
getVolumeList(int userId, String callingPackage, int flags)3823     public StorageVolume[] getVolumeList(int userId, String callingPackage, int flags) {
3824         final int callingUid = Binder.getCallingUid();
3825         final int callingUserId = UserHandle.getUserId(callingUid);
3826 
3827         if (!isUidOwnerOfPackageOrSystem(callingPackage, callingUid)) {
3828             throw new SecurityException("callingPackage does not match UID");
3829         }
3830         if (callingUserId != userId) {
3831             // Callers can ask for volumes of different users, but only with the correct permissions
3832             mContext.enforceCallingOrSelfPermission(
3833                     android.Manifest.permission.INTERACT_ACROSS_USERS,
3834                     "Need INTERACT_ACROSS_USERS to get volumes for another user");
3835         }
3836 
3837         final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
3838         final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0;
3839         final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0;
3840         final boolean includeRecent = (flags & StorageManager.FLAG_INCLUDE_RECENT) != 0;
3841         final boolean includeSharedProfile =
3842                 (flags & StorageManager.FLAG_INCLUDE_SHARED_PROFILE) != 0;
3843 
3844         // When the caller is the app actually hosting external storage, we
3845         // should never attempt to augment the actual storage volume state,
3846         // otherwise we risk confusing it with race conditions as users go
3847         // through various unlocked states
3848         final boolean callerIsMediaStore = UserHandle.isSameApp(callingUid,
3849                 mMediaStoreAuthorityAppId);
3850 
3851         // Only Apps with MANAGE_EXTERNAL_STORAGE should call the API with includeSharedProfile
3852         if (includeSharedProfile) {
3853             try {
3854                 // Get package name for calling app and
3855                 // verify it has MANAGE_EXTERNAL_STORAGE permission
3856                 final String[] packagesFromUid = mIPackageManager.getPackagesForUid(callingUid);
3857                 if (packagesFromUid == null) {
3858                     throw new SecurityException("Unknown uid " + callingUid);
3859                 }
3860                 // Checking first entry in packagesFromUid is enough as using "sharedUserId"
3861                 // mechanism is rare and discouraged. Also, Apps that share same UID share the same
3862                 // permissions.
3863                 // Allowing Media Provider is an exception, Media Provider process should be allowed
3864                 // to query users across profiles, even without MANAGE_EXTERNAL_STORAGE access.
3865                 // Note that ordinarily Media provider process has the above permission, but if they
3866                 // are revoked, Storage Volume(s) should still be returned.
3867                 if (!callerIsMediaStore
3868                         && !mStorageManagerInternal.hasExternalStorageAccess(callingUid,
3869                                 packagesFromUid[0])) {
3870                     throw new SecurityException("Only File Manager Apps permitted");
3871                 }
3872             } catch (RemoteException re) {
3873                 throw new SecurityException("Unknown uid " + callingUid, re);
3874             }
3875         }
3876 
3877         // Report all volumes as unmounted until we've recorded that user 0 has unlocked. There
3878         // are no guarantees that callers will see a consistent view of the volume before that
3879         // point
3880         final boolean systemUserUnlocked = isSystemUnlocked(UserHandle.USER_SYSTEM);
3881 
3882         final boolean userIsDemo;
3883         final boolean storagePermission;
3884         final boolean ceStorageUnlocked;
3885         final long token = Binder.clearCallingIdentity();
3886         try {
3887             userIsDemo = LocalServices.getService(UserManagerInternal.class)
3888                     .getUserInfo(userId).isDemo();
3889             storagePermission = mStorageManagerInternal.hasExternalStorage(callingUid,
3890                     callingPackage);
3891             ceStorageUnlocked = isCeStorageUnlocked(userId);
3892         } finally {
3893             Binder.restoreCallingIdentity(token);
3894         }
3895 
3896         boolean foundPrimary = false;
3897 
3898         final ArrayList<StorageVolume> res = new ArrayList<>();
3899         final ArraySet<String> resUuids = new ArraySet<>();
3900         final int userIdSharingMedia = mUserSharesMediaWith.get(userId, -1);
3901         synchronized (mLock) {
3902             for (int i = 0; i < mVolumes.size(); i++) {
3903                 final String volId = mVolumes.keyAt(i);
3904                 final VolumeInfo vol = mVolumes.valueAt(i);
3905                 switch (vol.getType()) {
3906                     case VolumeInfo.TYPE_PUBLIC:
3907                     case VolumeInfo.TYPE_STUB:
3908                         break;
3909                     case VolumeInfo.TYPE_EMULATED:
3910                         if (vol.getMountUserId() == userId) {
3911                             break;
3912                         }
3913                         if (includeSharedProfile && vol.getMountUserId() == userIdSharingMedia) {
3914                             // If the volume belongs to a user we share media with,
3915                             // return it too.
3916                             break;
3917                         }
3918                         // Skip if emulated volume not for userId
3919                         continue;
3920                     default:
3921                         continue;
3922                 }
3923 
3924                 boolean match = false;
3925                 if (forWrite) {
3926                     match = vol.isVisibleForWrite(userId)
3927                             || (includeSharedProfile && vol.isVisibleForWrite(userIdSharingMedia));
3928                 } else {
3929                     // Return both read only and write only volumes. When includeSharedProfile is
3930                     // true, all the volumes of userIdSharingMedia should be returned when queried
3931                     // from the user it shares media with
3932                     // Public Volumes will be also be returned if visible to the
3933                     // userIdSharingMedia with.
3934                     match = vol.isVisibleForUser(userId)
3935                             || (!vol.isVisible() && includeInvisible && vol.getPath() != null)
3936                             || (vol.getType() == VolumeInfo.TYPE_PUBLIC
3937                                     && vol.isVisibleForUser(userIdSharingMedia))
3938                             || (includeSharedProfile && vol.isVisibleForUser(userIdSharingMedia));
3939                 }
3940                 if (!match) continue;
3941 
3942                 boolean reportUnmounted = false;
3943                 if (callerIsMediaStore) {
3944                     // When the caller is the app actually hosting external storage, we
3945                     // should never attempt to augment the actual storage volume state,
3946                     // otherwise we risk confusing it with race conditions as users go
3947                     // through various unlocked states
3948                 } else if (!systemUserUnlocked) {
3949                     reportUnmounted = true;
3950                     Slog.w(TAG, "Reporting " + volId + " unmounted due to system locked");
3951                 } else if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !ceStorageUnlocked) {
3952                     reportUnmounted = true;
3953                     Slog.w(TAG, "Reporting " + volId + "unmounted due to " + userId + " locked");
3954                 } else if (!storagePermission && !realState) {
3955                     Slog.w(TAG, "Reporting " + volId + "unmounted due to missing permissions");
3956                     reportUnmounted = true;
3957                 }
3958 
3959                 int volUserId = userId;
3960                 if (volUserId != vol.getMountUserId() && vol.getMountUserId() >= 0) {
3961                     volUserId = vol.getMountUserId();
3962                 }
3963                 final StorageVolume userVol = vol.buildStorageVolume(mContext, volUserId,
3964                         reportUnmounted);
3965                 if (vol.isPrimary() && vol.getMountUserId() == userId) {
3966                     res.add(0, userVol);
3967                     foundPrimary = true;
3968                 } else {
3969                     res.add(userVol);
3970                 }
3971                 resUuids.add(userVol.getUuid());
3972             }
3973 
3974             if (includeRecent) {
3975                 final long lastWeek = System.currentTimeMillis() - DateUtils.WEEK_IN_MILLIS;
3976                 for (int i = 0; i < mRecords.size(); i++) {
3977                     final VolumeRecord rec = mRecords.valueAt(i);
3978 
3979                     // Skip if we've already included it above
3980                     if (resUuids.contains(rec.fsUuid)) continue;
3981 
3982                     // Treat as recent if mounted within the last week
3983                     if (rec.lastSeenMillis > 0 && rec.lastSeenMillis >= lastWeek) {
3984                         final StorageVolume userVol = rec.buildStorageVolume(mContext);
3985                         res.add(userVol);
3986                         resUuids.add(userVol.getUuid());
3987                     }
3988                 }
3989             }
3990         }
3991 
3992         // Synthesize a volume for preloaded media under demo users, so that
3993         // it's scanned into MediaStore
3994         if (userIsDemo) {
3995             final String id = "demo";
3996             final File path = Environment.getDataPreloadsMediaDirectory();
3997             final boolean primary = false;
3998             final boolean removable = false;
3999             final boolean emulated = true;
4000             final boolean externallyManaged = false;
4001             final boolean allowMassStorage = false;
4002             final long maxFileSize = 0;
4003             final UserHandle user = new UserHandle(userId);
4004             final String envState = Environment.MEDIA_MOUNTED_READ_ONLY;
4005             final String description = mContext.getString(android.R.string.unknownName);
4006 
4007             res.add(new StorageVolume(id, path, path, description, primary, removable, emulated,
4008                     externallyManaged, allowMassStorage, maxFileSize, user, null /*uuid */, id,
4009                     envState));
4010         }
4011 
4012         if (!foundPrimary) {
4013             Slog.w(TAG, "No primary storage defined yet; hacking together a stub");
4014 
4015             final boolean primaryPhysical = SystemProperties.getBoolean(
4016                     StorageManager.PROP_PRIMARY_PHYSICAL, false);
4017 
4018             final String id = "stub_primary";
4019             final File path = Environment.getLegacyExternalStorageDirectory();
4020             final String description = mContext.getString(android.R.string.unknownName);
4021             final boolean primary = true;
4022             final boolean removable = primaryPhysical;
4023             final boolean emulated = !primaryPhysical;
4024             final boolean externallyManaged = false;
4025             final boolean allowMassStorage = false;
4026             final long maxFileSize = 0L;
4027             final UserHandle owner = new UserHandle(userId);
4028             final String fsUuid = null;
4029             final UUID uuid = null;
4030             final String state = Environment.MEDIA_REMOVED;
4031 
4032             res.add(0, new StorageVolume(id, path, path,
4033                     description, primary, removable, emulated, externallyManaged,
4034                     allowMassStorage, maxFileSize, owner, uuid, fsUuid, state));
4035         }
4036 
4037         return res.toArray(new StorageVolume[res.size()]);
4038     }
4039 
4040     @Override
getDisks()4041     public DiskInfo[] getDisks() {
4042         synchronized (mLock) {
4043             final DiskInfo[] res = new DiskInfo[mDisks.size()];
4044             for (int i = 0; i < mDisks.size(); i++) {
4045                 res[i] = mDisks.valueAt(i);
4046             }
4047             return res;
4048         }
4049     }
4050 
4051     @Override
getVolumes(int flags)4052     public VolumeInfo[] getVolumes(int flags) {
4053         synchronized (mLock) {
4054             final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
4055             for (int i = 0; i < mVolumes.size(); i++) {
4056                 res[i] = mVolumes.valueAt(i);
4057             }
4058             return res;
4059         }
4060     }
4061 
4062     @Override
getVolumeRecords(int flags)4063     public VolumeRecord[] getVolumeRecords(int flags) {
4064         synchronized (mLock) {
4065             final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
4066             for (int i = 0; i < mRecords.size(); i++) {
4067                 res[i] = mRecords.valueAt(i);
4068             }
4069             return res;
4070         }
4071     }
4072 
4073     @Override
getCacheQuotaBytes(String volumeUuid, int uid)4074     public long getCacheQuotaBytes(String volumeUuid, int uid) {
4075         if (uid != Binder.getCallingUid()) {
4076             mContext.enforceCallingPermission(android.Manifest.permission.STORAGE_INTERNAL, TAG);
4077         }
4078         final long token = Binder.clearCallingIdentity();
4079         try {
4080             final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class);
4081             return stats.getCacheQuotaBytes(volumeUuid, uid);
4082         } finally {
4083             Binder.restoreCallingIdentity(token);
4084         }
4085     }
4086 
4087     @Override
getCacheSizeBytes(String volumeUuid, int uid)4088     public long getCacheSizeBytes(String volumeUuid, int uid) {
4089         if (uid != Binder.getCallingUid()) {
4090             mContext.enforceCallingPermission(android.Manifest.permission.STORAGE_INTERNAL, TAG);
4091         }
4092         final long token = Binder.clearCallingIdentity();
4093         try {
4094             return mContext.getSystemService(StorageStatsManager.class)
4095                     .queryStatsForUid(volumeUuid, uid).getCacheBytes();
4096         } catch (IOException e) {
4097             throw new ParcelableException(e);
4098         } finally {
4099             Binder.restoreCallingIdentity(token);
4100         }
4101     }
4102 
adjustAllocateFlags(int flags, int callingUid, String callingPackage)4103     private int adjustAllocateFlags(int flags, int callingUid, String callingPackage) {
4104         // Require permission to allocate aggressively
4105         if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
4106             mContext.enforceCallingOrSelfPermission(
4107                     android.Manifest.permission.ALLOCATE_AGGRESSIVE, TAG);
4108         }
4109 
4110         // Apps normally can't directly defy reserved space
4111         flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED;
4112         flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED;
4113 
4114         // However, if app is actively using the camera, then we're willing to
4115         // clear up to half of the reserved cache space, since the user might be
4116         // trying to capture an important memory.
4117         final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
4118         final long token = Binder.clearCallingIdentity();
4119         try {
4120             if (appOps.isOperationActive(AppOpsManager.OP_CAMERA, callingUid, callingPackage)) {
4121                 Slog.d(TAG, "UID " + callingUid + " is actively using camera;"
4122                         + " letting them defy reserved cached data");
4123                 flags |= StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED;
4124             }
4125         } finally {
4126             Binder.restoreCallingIdentity(token);
4127         }
4128 
4129         return flags;
4130     }
4131 
4132     @Override
getAllocatableBytes(String volumeUuid, int flags, String callingPackage)4133     public long getAllocatableBytes(String volumeUuid, int flags, String callingPackage) {
4134         flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);
4135 
4136         final StorageManager storage = mContext.getSystemService(StorageManager.class);
4137         final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class);
4138         final long token = Binder.clearCallingIdentity();
4139         try {
4140             // In general, apps can allocate as much space as they want, except
4141             // we never let them eat into either the minimum cache space or into
4142             // the low disk warning space. To avoid user confusion, this logic
4143             // should be kept in sync with getFreeBytes().
4144             final File path = storage.findPathForUuid(volumeUuid);
4145 
4146             long usable = 0;
4147             long lowReserved = 0;
4148             long fullReserved = 0;
4149             long cacheClearable = 0;
4150 
4151             if ((flags & StorageManager.FLAG_ALLOCATE_CACHE_ONLY) == 0) {
4152                 usable = path.getUsableSpace();
4153                 lowReserved = storage.getStorageLowBytes(path);
4154                 fullReserved = storage.getStorageFullBytes(path);
4155             }
4156 
4157             if ((flags & StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY) == 0
4158                     && stats.isQuotaSupported(volumeUuid)) {
4159                 final long cacheTotal = stats.getCacheBytes(volumeUuid);
4160                 final long cacheReserved = storage.getStorageCacheBytes(path, flags);
4161                 cacheClearable = Math.max(0, cacheTotal - cacheReserved);
4162             }
4163 
4164             if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
4165                 return Math.max(0, (usable + cacheClearable) - fullReserved);
4166             } else {
4167                 return Math.max(0, (usable + cacheClearable) - lowReserved);
4168             }
4169         } catch (IOException e) {
4170             throw new ParcelableException(e);
4171         } finally {
4172             Binder.restoreCallingIdentity(token);
4173         }
4174     }
4175 
4176     @Override
allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage)4177     public void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) {
4178         flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);
4179 
4180         final long allocatableBytes = getAllocatableBytes(volumeUuid,
4181                 flags | StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY, callingPackage);
4182         if (bytes > allocatableBytes) {
4183             // If we don't have room without taking cache into account, check to see if we'd have
4184             // room if we included freeable cache space.
4185             final long cacheClearable = getAllocatableBytes(volumeUuid,
4186                     flags | StorageManager.FLAG_ALLOCATE_CACHE_ONLY, callingPackage);
4187             if (bytes > allocatableBytes + cacheClearable) {
4188                 throw new ParcelableException(new IOException("Failed to allocate " + bytes
4189                     + " because only " + (allocatableBytes + cacheClearable) + " allocatable"));
4190             }
4191         }
4192 
4193         final StorageManager storage = mContext.getSystemService(StorageManager.class);
4194         final long token = Binder.clearCallingIdentity();
4195         try {
4196             // Free up enough disk space to satisfy both the requested allocation
4197             // and our low disk warning space.
4198             final File path = storage.findPathForUuid(volumeUuid);
4199             if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
4200                 bytes += storage.getStorageFullBytes(path);
4201             } else {
4202                 bytes += storage.getStorageLowBytes(path);
4203             }
4204 
4205             mPmInternal.freeStorage(volumeUuid, bytes, flags);
4206         } catch (IOException e) {
4207             throw new ParcelableException(e);
4208         } finally {
4209             Binder.restoreCallingIdentity(token);
4210         }
4211     }
4212 
addObbStateLocked(ObbState obbState)4213     private void addObbStateLocked(ObbState obbState) throws RemoteException {
4214         final IBinder binder = obbState.getBinder();
4215         List<ObbState> obbStates = mObbMounts.get(binder);
4216 
4217         if (obbStates == null) {
4218             obbStates = new ArrayList<ObbState>();
4219             mObbMounts.put(binder, obbStates);
4220         } else {
4221             for (final ObbState o : obbStates) {
4222                 if (o.rawPath.equals(obbState.rawPath)) {
4223                     throw new IllegalStateException("Attempt to add ObbState twice. "
4224                             + "This indicates an error in the StorageManagerService logic.");
4225                 }
4226             }
4227         }
4228 
4229         obbStates.add(obbState);
4230         try {
4231             obbState.link();
4232         } catch (RemoteException e) {
4233             /*
4234              * The binder died before we could link it, so clean up our state
4235              * and return failure.
4236              */
4237             obbStates.remove(obbState);
4238             if (obbStates.isEmpty()) {
4239                 mObbMounts.remove(binder);
4240             }
4241 
4242             // Rethrow the error so mountObb can get it
4243             throw e;
4244         }
4245 
4246         mObbPathToStateMap.put(obbState.rawPath, obbState);
4247     }
4248 
removeObbStateLocked(ObbState obbState)4249     private void removeObbStateLocked(ObbState obbState) {
4250         final IBinder binder = obbState.getBinder();
4251         final List<ObbState> obbStates = mObbMounts.get(binder);
4252         if (obbStates != null) {
4253             if (obbStates.remove(obbState)) {
4254                 obbState.unlink();
4255             }
4256             if (obbStates.isEmpty()) {
4257                 mObbMounts.remove(binder);
4258             }
4259         }
4260 
4261         mObbPathToStateMap.remove(obbState.rawPath);
4262     }
4263 
4264     private class ObbActionHandler extends Handler {
4265 
ObbActionHandler(Looper l)4266         ObbActionHandler(Looper l) {
4267             super(l);
4268         }
4269 
4270         @Override
handleMessage(Message msg)4271         public void handleMessage(Message msg) {
4272             switch (msg.what) {
4273                 case OBB_RUN_ACTION: {
4274                     final ObbAction action = (ObbAction) msg.obj;
4275 
4276                     if (DEBUG_OBB)
4277                         Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
4278 
4279                     action.execute(this);
4280                     break;
4281                 }
4282                 case OBB_FLUSH_MOUNT_STATE: {
4283                     final String path = (String) msg.obj;
4284 
4285                     if (DEBUG_OBB)
4286                         Slog.i(TAG, "Flushing all OBB state for path " + path);
4287 
4288                     synchronized (mObbMounts) {
4289                         final List<ObbState> obbStatesToRemove = new ArrayList<>();
4290 
4291                         final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
4292                         while (i.hasNext()) {
4293                             final ObbState state = i.next();
4294 
4295                             /*
4296                              * If this entry's source file is in the volume path
4297                              * that got unmounted, remove it because it's no
4298                              * longer valid.
4299                              */
4300                             if (state.canonicalPath.startsWith(path)) {
4301                                 obbStatesToRemove.add(state);
4302                             }
4303                         }
4304 
4305                         for (final ObbState obbState : obbStatesToRemove) {
4306                             if (DEBUG_OBB)
4307                                 Slog.i(TAG, "Removing state for " + obbState.rawPath);
4308 
4309                             removeObbStateLocked(obbState);
4310 
4311                             try {
4312                                 obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
4313                                         OnObbStateChangeListener.UNMOUNTED);
4314                             } catch (RemoteException e) {
4315                                 Slog.i(TAG, "Couldn't send unmount notification for  OBB: "
4316                                         + obbState.rawPath);
4317                             }
4318                         }
4319                     }
4320                     break;
4321                 }
4322             }
4323         }
4324     }
4325 
4326     private static class ObbException extends Exception {
4327         public final int status;
4328 
ObbException(int status, String message)4329         public ObbException(int status, String message) {
4330             super(message);
4331             this.status = status;
4332         }
4333 
ObbException(int status, Throwable cause)4334         public ObbException(int status, Throwable cause) {
4335             super(cause.getMessage(), cause);
4336             this.status = status;
4337         }
4338     }
4339 
4340     private static abstract class ObbAction {
4341 
4342         ObbState mObbState;
4343 
ObbAction(ObbState obbState)4344         ObbAction(ObbState obbState) {
4345             mObbState = obbState;
4346         }
4347 
execute(ObbActionHandler handler)4348         public void execute(ObbActionHandler handler) {
4349             try {
4350                 if (DEBUG_OBB)
4351                     Slog.i(TAG, "Starting to execute action: " + toString());
4352                 handleExecute();
4353             } catch (ObbException e) {
4354                 notifyObbStateChange(e);
4355             }
4356         }
4357 
handleExecute()4358         abstract void handleExecute() throws ObbException;
4359 
notifyObbStateChange(ObbException e)4360         protected void notifyObbStateChange(ObbException e) {
4361             Slog.w(TAG, e);
4362             notifyObbStateChange(e.status);
4363         }
4364 
notifyObbStateChange(int status)4365         protected void notifyObbStateChange(int status) {
4366             if (mObbState == null || mObbState.token == null) {
4367                 return;
4368             }
4369 
4370             try {
4371                 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
4372             } catch (RemoteException e) {
4373                 Slog.w(TAG, "StorageEventListener went away while calling onObbStateChanged");
4374             }
4375         }
4376     }
4377 
4378     class MountObbAction extends ObbAction {
4379         private final int mCallingUid;
4380         private ObbInfo mObbInfo;
4381 
MountObbAction(ObbState obbState, int callingUid, ObbInfo obbInfo)4382         MountObbAction(ObbState obbState, int callingUid, ObbInfo obbInfo) {
4383             super(obbState);
4384             mCallingUid = callingUid;
4385             mObbInfo = obbInfo;
4386         }
4387 
4388         @Override
handleExecute()4389         public void handleExecute() throws ObbException {
4390             warnOnNotMounted();
4391 
4392             if (!isUidOwnerOfPackageOrSystem(mObbInfo.packageName, mCallingUid)) {
4393                 throw new ObbException(ERROR_PERMISSION_DENIED, "Denied attempt to mount OBB "
4394                         + mObbInfo.filename + " which is owned by " + mObbInfo.packageName);
4395             }
4396 
4397             final boolean isMounted;
4398             synchronized (mObbMounts) {
4399                 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
4400             }
4401             if (isMounted) {
4402                 throw new ObbException(ERROR_ALREADY_MOUNTED,
4403                         "Attempt to mount OBB which is already mounted: " + mObbInfo.filename);
4404             }
4405 
4406             try {
4407                 mObbState.volId = mVold.createObb(mObbState.canonicalPath, mObbState.ownerGid);
4408                 mVold.mount(mObbState.volId, 0, -1, null);
4409 
4410                 if (DEBUG_OBB)
4411                     Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
4412 
4413                 synchronized (mObbMounts) {
4414                     addObbStateLocked(mObbState);
4415                 }
4416 
4417                 notifyObbStateChange(MOUNTED);
4418             } catch (Exception e) {
4419                 throw new ObbException(ERROR_COULD_NOT_MOUNT, e);
4420             }
4421         }
4422 
4423         @Override
toString()4424         public String toString() {
4425             StringBuilder sb = new StringBuilder();
4426             sb.append("MountObbAction{");
4427             sb.append(mObbState);
4428             sb.append('}');
4429             return sb.toString();
4430         }
4431     }
4432 
4433     class UnmountObbAction extends ObbAction {
4434         private final boolean mForceUnmount;
4435 
UnmountObbAction(ObbState obbState, boolean force)4436         UnmountObbAction(ObbState obbState, boolean force) {
4437             super(obbState);
4438             mForceUnmount = force;
4439         }
4440 
4441         @Override
handleExecute()4442         public void handleExecute() throws ObbException {
4443             warnOnNotMounted();
4444 
4445             final ObbState existingState;
4446             synchronized (mObbMounts) {
4447                 existingState = mObbPathToStateMap.get(mObbState.rawPath);
4448             }
4449 
4450             if (existingState == null) {
4451                 throw new ObbException(ERROR_NOT_MOUNTED, "Missing existingState");
4452             }
4453 
4454             if (existingState.ownerGid != mObbState.ownerGid) {
4455                 notifyObbStateChange(new ObbException(ERROR_PERMISSION_DENIED,
4456                         "Permission denied to unmount OBB " + existingState.rawPath
4457                                 + " (owned by GID " + existingState.ownerGid + ")"));
4458                 return;
4459             }
4460 
4461             try {
4462                 mVold.unmount(mObbState.volId);
4463                 mVold.destroyObb(mObbState.volId);
4464                 mObbState.volId = null;
4465 
4466                 synchronized (mObbMounts) {
4467                     removeObbStateLocked(existingState);
4468                 }
4469 
4470                 notifyObbStateChange(UNMOUNTED);
4471             } catch (Exception e) {
4472                 throw new ObbException(ERROR_COULD_NOT_UNMOUNT, e);
4473             }
4474         }
4475 
4476         @Override
toString()4477         public String toString() {
4478             StringBuilder sb = new StringBuilder();
4479             sb.append("UnmountObbAction{");
4480             sb.append(mObbState);
4481             sb.append(",force=");
4482             sb.append(mForceUnmount);
4483             sb.append('}');
4484             return sb.toString();
4485         }
4486     }
4487 
dispatchOnStatus(IVoldTaskListener listener, int status, PersistableBundle extras)4488     private void dispatchOnStatus(IVoldTaskListener listener, int status,
4489             PersistableBundle extras) {
4490         if (listener != null) {
4491             try {
4492                 listener.onStatus(status, extras);
4493             } catch (RemoteException ignored) {
4494             }
4495         }
4496     }
4497 
dispatchOnFinished(IVoldTaskListener listener, int status, PersistableBundle extras)4498     private void dispatchOnFinished(IVoldTaskListener listener, int status,
4499             PersistableBundle extras) {
4500         if (listener != null) {
4501             try {
4502                 listener.onFinished(status, extras);
4503             } catch (RemoteException ignored) {
4504             }
4505         }
4506     }
4507 
4508     @android.annotation.EnforcePermission(android.Manifest.permission.WRITE_MEDIA_STORAGE)
4509     @Override
getExternalStorageMountMode(int uid, String packageName)4510     public int getExternalStorageMountMode(int uid, String packageName) {
4511         super.getExternalStorageMountMode_enforcePermission();
4512 
4513         return mStorageManagerInternal.getExternalStorageMountMode(uid, packageName);
4514     }
4515 
getMountModeInternal(int uid, String packageName)4516     private int getMountModeInternal(int uid, String packageName) {
4517         try {
4518             // Get some easy cases out of the way first
4519             if (Process.isIsolated(uid) || Process.isSdkSandboxUid(uid)) {
4520                 return StorageManager.MOUNT_MODE_EXTERNAL_NONE;
4521             }
4522 
4523             final String[] packagesForUid = mIPackageManager.getPackagesForUid(uid);
4524             if (ArrayUtils.isEmpty(packagesForUid)) {
4525                 // It's possible the package got uninstalled already, so just ignore.
4526                 return StorageManager.MOUNT_MODE_EXTERNAL_NONE;
4527             }
4528             if (packageName == null) {
4529                 packageName = packagesForUid[0];
4530             }
4531 
4532             final long token = Binder.clearCallingIdentity();
4533             try {
4534                 if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
4535                     return StorageManager.MOUNT_MODE_EXTERNAL_NONE;
4536                 }
4537             } finally {
4538                 Binder.restoreCallingIdentity(token);
4539             }
4540 
4541             if (mStorageManagerInternal.isExternalStorageService(uid)) {
4542                 // Determine if caller requires pass_through mount; note that we do this for
4543                 // all processes that share a UID with MediaProvider; but this is fine, since
4544                 // those processes anyway share the same rights as MediaProvider.
4545                 return StorageManager.MOUNT_MODE_EXTERNAL_PASS_THROUGH;
4546             }
4547 
4548             if ((mDownloadsAuthorityAppId == UserHandle.getAppId(uid)
4549                     || mExternalStorageAuthorityAppId == UserHandle.getAppId(uid))) {
4550                 // DownloadManager can write in app-private directories on behalf of apps;
4551                 // give it write access to Android/
4552                 // ExternalStorageProvider can access Android/{data,obb} dirs in managed mode
4553                 return StorageManager.MOUNT_MODE_EXTERNAL_ANDROID_WRITABLE;
4554             }
4555 
4556             final boolean hasMtp = mIPackageManager.checkUidPermission(ACCESS_MTP, uid) ==
4557                     PERMISSION_GRANTED;
4558             if (hasMtp) {
4559                 ApplicationInfo ai = mIPackageManager.getApplicationInfo(packageName,
4560                         0, UserHandle.getUserId(uid));
4561                 if (ai != null && ai.isSignedWithPlatformKey()) {
4562                     // Platform processes hosting the MTP server should be able to write in Android/
4563                     return StorageManager.MOUNT_MODE_EXTERNAL_ANDROID_WRITABLE;
4564                 }
4565             }
4566 
4567             // We're only willing to give out installer access if they hold
4568             // runtime permission; this is a firm CDD requirement
4569             final boolean hasInstall = mIPackageManager.checkUidPermission(INSTALL_PACKAGES,
4570                     uid) == PERMISSION_GRANTED;
4571             boolean hasInstallOp = false;
4572             // OP_REQUEST_INSTALL_PACKAGES is granted/denied per package but vold can't
4573             // update mountpoints of a specific package. So, check the appop for all packages
4574             // sharing the uid and allow same level of storage access for all packages even if
4575             // one of the packages has the appop granted.
4576             for (String uidPackageName : packagesForUid) {
4577                 if (mIAppOpsService.checkOperation(
4578                         OP_REQUEST_INSTALL_PACKAGES, uid, uidPackageName) == MODE_ALLOWED) {
4579                     hasInstallOp = true;
4580                     break;
4581                 }
4582             }
4583             if (hasInstall || hasInstallOp) {
4584                 return StorageManager.MOUNT_MODE_EXTERNAL_INSTALLER;
4585             }
4586             return StorageManager.MOUNT_MODE_EXTERNAL_DEFAULT;
4587         } catch (RemoteException e) {
4588             // Should not happen
4589         }
4590         return StorageManager.MOUNT_MODE_EXTERNAL_NONE;
4591     }
4592 
4593     @VisibleForTesting
getCeStorageEventCallbacks()4594     CopyOnWriteArrayList<ICeStorageLockEventListener> getCeStorageEventCallbacks() {
4595         return mCeStorageEventCallbacks;
4596     }
4597 
4598     @VisibleForTesting
dispatchCeStorageLockedEvent(int userId)4599     void dispatchCeStorageLockedEvent(int userId) {
4600         for (ICeStorageLockEventListener listener: mCeStorageEventCallbacks) {
4601             listener.onStorageLocked(userId);
4602         }
4603     }
4604 
4605     private static class Callbacks extends Handler {
4606         private static final int MSG_STORAGE_STATE_CHANGED = 1;
4607         private static final int MSG_VOLUME_STATE_CHANGED = 2;
4608         private static final int MSG_VOLUME_RECORD_CHANGED = 3;
4609         private static final int MSG_VOLUME_FORGOTTEN = 4;
4610         private static final int MSG_DISK_SCANNED = 5;
4611         private static final int MSG_DISK_DESTROYED = 6;
4612 
4613         private final RemoteCallbackList<IStorageEventListener>
4614                 mCallbacks = new RemoteCallbackList<>();
4615 
Callbacks(Looper looper)4616         public Callbacks(Looper looper) {
4617             super(looper);
4618         }
4619 
register(IStorageEventListener callback)4620         public void register(IStorageEventListener callback) {
4621             mCallbacks.register(callback);
4622         }
4623 
unregister(IStorageEventListener callback)4624         public void unregister(IStorageEventListener callback) {
4625             mCallbacks.unregister(callback);
4626         }
4627 
4628         @Override
handleMessage(Message msg)4629         public void handleMessage(Message msg) {
4630             final SomeArgs args = (SomeArgs) msg.obj;
4631             final int n = mCallbacks.beginBroadcast();
4632             for (int i = 0; i < n; i++) {
4633                 final IStorageEventListener callback = mCallbacks.getBroadcastItem(i);
4634                 try {
4635                     invokeCallback(callback, msg.what, args);
4636                 } catch (RemoteException ignored) {
4637                 }
4638             }
4639             mCallbacks.finishBroadcast();
4640             args.recycle();
4641         }
4642 
invokeCallback(IStorageEventListener callback, int what, SomeArgs args)4643         private void invokeCallback(IStorageEventListener callback, int what, SomeArgs args)
4644                 throws RemoteException {
4645             switch (what) {
4646                 case MSG_STORAGE_STATE_CHANGED: {
4647                     callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
4648                             (String) args.arg3);
4649                     break;
4650                 }
4651                 case MSG_VOLUME_STATE_CHANGED: {
4652                     callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
4653                     break;
4654                 }
4655                 case MSG_VOLUME_RECORD_CHANGED: {
4656                     callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
4657                     break;
4658                 }
4659                 case MSG_VOLUME_FORGOTTEN: {
4660                     callback.onVolumeForgotten((String) args.arg1);
4661                     break;
4662                 }
4663                 case MSG_DISK_SCANNED: {
4664                     callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
4665                     break;
4666                 }
4667                 case MSG_DISK_DESTROYED: {
4668                     callback.onDiskDestroyed((DiskInfo) args.arg1);
4669                     break;
4670                 }
4671             }
4672         }
4673 
notifyStorageStateChanged(String path, String oldState, String newState)4674         private void notifyStorageStateChanged(String path, String oldState, String newState) {
4675             final SomeArgs args = SomeArgs.obtain();
4676             args.arg1 = path;
4677             args.arg2 = oldState;
4678             args.arg3 = newState;
4679             obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
4680         }
4681 
notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState)4682         private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
4683             final SomeArgs args = SomeArgs.obtain();
4684             args.arg1 = vol.clone();
4685             args.argi2 = oldState;
4686             args.argi3 = newState;
4687             obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
4688         }
4689 
notifyVolumeRecordChanged(VolumeRecord rec)4690         private void notifyVolumeRecordChanged(VolumeRecord rec) {
4691             final SomeArgs args = SomeArgs.obtain();
4692             args.arg1 = rec.clone();
4693             obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
4694         }
4695 
notifyVolumeForgotten(String fsUuid)4696         private void notifyVolumeForgotten(String fsUuid) {
4697             final SomeArgs args = SomeArgs.obtain();
4698             args.arg1 = fsUuid;
4699             obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
4700         }
4701 
notifyDiskScanned(DiskInfo disk, int volumeCount)4702         private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
4703             final SomeArgs args = SomeArgs.obtain();
4704             args.arg1 = disk.clone();
4705             args.argi2 = volumeCount;
4706             obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
4707         }
4708 
notifyDiskDestroyed(DiskInfo disk)4709         private void notifyDiskDestroyed(DiskInfo disk) {
4710             final SomeArgs args = SomeArgs.obtain();
4711             args.arg1 = disk.clone();
4712             obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
4713         }
4714     }
4715 
4716     @Override
dump(FileDescriptor fd, PrintWriter writer, String[] args)4717     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
4718         if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
4719 
4720         final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ", 160);
4721         synchronized (mLock) {
4722             pw.println("Disks:");
4723             pw.increaseIndent();
4724             for (int i = 0; i < mDisks.size(); i++) {
4725                 final DiskInfo disk = mDisks.valueAt(i);
4726                 disk.dump(pw);
4727             }
4728             pw.decreaseIndent();
4729 
4730             pw.println();
4731             pw.println("Volumes:");
4732             pw.increaseIndent();
4733             for (int i = 0; i < mVolumes.size(); i++) {
4734                 final VolumeInfo vol = mVolumes.valueAt(i);
4735                 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
4736                 vol.dump(pw);
4737             }
4738             pw.decreaseIndent();
4739 
4740             pw.println();
4741             pw.println("Records:");
4742             pw.increaseIndent();
4743             for (int i = 0; i < mRecords.size(); i++) {
4744                 final VolumeRecord note = mRecords.valueAt(i);
4745                 note.dump(pw);
4746             }
4747             pw.decreaseIndent();
4748 
4749             pw.println();
4750             pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
4751 
4752             pw.println();
4753             final Pair<String, Long> pair = StorageManager.getPrimaryStoragePathAndSize();
4754             if (pair == null) {
4755                 pw.println("Internal storage total size: N/A");
4756             } else {
4757                 pw.print("Internal storage (");
4758                 pw.print(pair.first);
4759                 pw.print(") total size: ");
4760                 pw.print(pair.second);
4761                 pw.print(" (");
4762                 pw.print(pair.second / DataUnit.MEBIBYTES.toBytes(1L));
4763                 pw.println(" MiB)");
4764             }
4765 
4766             pw.println();
4767             pw.println("CE unlocked users: " + mCeUnlockedUsers);
4768             pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
4769         }
4770 
4771         synchronized (mObbMounts) {
4772             pw.println();
4773             pw.println("mObbMounts:");
4774             pw.increaseIndent();
4775             final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
4776                     .iterator();
4777             while (binders.hasNext()) {
4778                 Entry<IBinder, List<ObbState>> e = binders.next();
4779                 pw.println(e.getKey() + ":");
4780                 pw.increaseIndent();
4781                 final List<ObbState> obbStates = e.getValue();
4782                 for (final ObbState obbState : obbStates) {
4783                     pw.println(obbState);
4784                 }
4785                 pw.decreaseIndent();
4786             }
4787             pw.decreaseIndent();
4788 
4789             pw.println();
4790             pw.println("mObbPathToStateMap:");
4791             pw.increaseIndent();
4792             final Iterator<Entry<String, ObbState>> maps =
4793                     mObbPathToStateMap.entrySet().iterator();
4794             while (maps.hasNext()) {
4795                 final Entry<String, ObbState> e = maps.next();
4796                 pw.print(e.getKey());
4797                 pw.print(" -> ");
4798                 pw.println(e.getValue());
4799             }
4800             pw.decreaseIndent();
4801         }
4802 
4803         synchronized (mCloudMediaProviders) {
4804             pw.println();
4805             pw.print("Media cloud providers: ");
4806             pw.println(mCloudMediaProviders);
4807         }
4808 
4809         pw.println();
4810         pw.print("Last maintenance: ");
4811         pw.println(TimeUtils.formatForLogging(mLastMaintenance));
4812     }
4813 
4814     /** {@inheritDoc} */
4815     @Override
monitor()4816     public void monitor() {
4817         try {
4818             mVold.monitor();
4819         } catch (Exception e) {
4820             Slog.wtf(TAG, e);
4821         }
4822     }
4823 
4824     private final class StorageManagerInternalImpl extends StorageManagerInternal {
4825         @GuardedBy("mResetListeners")
4826         private final List<StorageManagerInternal.ResetListener> mResetListeners =
4827                 new ArrayList<>();
4828 
4829         private final CopyOnWriteArraySet<StorageManagerInternal.CloudProviderChangeListener>
4830                 mCloudProviderChangeListeners = new CopyOnWriteArraySet<>();
4831 
4832         @Override
isFuseMounted(int userId)4833         public boolean isFuseMounted(int userId) {
4834             synchronized (mLock) {
4835                 return mFuseMountedUser.contains(userId);
4836             }
4837         }
4838 
4839         /**
4840          * Check if fuse is running in target user, if it's running then setup its storage dirs.
4841          * Return true if storage dirs are mounted.
4842          */
4843         @Override
prepareStorageDirs(int userId, Set<String> packageList, String processName)4844         public boolean prepareStorageDirs(int userId, Set<String> packageList,
4845                 String processName) {
4846             synchronized (mLock) {
4847                 if (!mFuseMountedUser.contains(userId)) {
4848                     Slog.w(TAG, "User " + userId + " is not unlocked yet so skip mounting obb");
4849                     return false;
4850                 }
4851             }
4852             try {
4853                 final IVold vold = IVold.Stub.asInterface(
4854                         ServiceManager.getServiceOrThrow("vold"));
4855                 for (String pkg : packageList) {
4856                     final String packageObbDir =
4857                             String.format(Locale.US, "/storage/emulated/%d/Android/obb/%s/",
4858                                     userId, pkg);
4859                     final String packageDataDir =
4860                             String.format(Locale.US, "/storage/emulated/%d/Android/data/%s/",
4861                                     userId, pkg);
4862 
4863                     // Create package obb and data dir if it doesn't exist.
4864                     int appUid = UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid());
4865                     vold.ensureAppDirsCreated(new String[] {packageObbDir, packageDataDir}, appUid);
4866                 }
4867             } catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
4868                 Slog.e(TAG, "Unable to create obb and data directories for " + processName,e);
4869                 return false;
4870             }
4871             return true;
4872         }
4873 
4874         @Override
getExternalStorageMountMode(int uid, String packageName)4875         public int getExternalStorageMountMode(int uid, String packageName) {
4876             final int mode = getMountModeInternal(uid, packageName);
4877             if (LOCAL_LOGV) {
4878                 Slog.v(TAG, "Resolved mode " + mode + " for " + packageName + "/"
4879                         + UserHandle.formatUid(uid));
4880             }
4881             return mode;
4882         }
4883 
4884         @Override
hasExternalStorageAccess(int uid, String packageName)4885         public boolean hasExternalStorageAccess(int uid, String packageName) {
4886             try {
4887                 final int opMode = mIAppOpsService.checkOperation(
4888                         OP_MANAGE_EXTERNAL_STORAGE, uid, packageName);
4889                 if (opMode == AppOpsManager.MODE_DEFAULT) {
4890                     return mIPackageManager.checkUidPermission(
4891                             MANAGE_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED;
4892                 }
4893 
4894                 return opMode == AppOpsManager.MODE_ALLOWED;
4895             } catch (RemoteException e) {
4896                 Slog.w("Failed to check MANAGE_EXTERNAL_STORAGE access for " + packageName, e);
4897             }
4898             return false;
4899         }
4900 
4901         @Override
addResetListener(StorageManagerInternal.ResetListener listener)4902         public void addResetListener(StorageManagerInternal.ResetListener listener) {
4903             synchronized (mResetListeners) {
4904                 mResetListeners.add(listener);
4905             }
4906         }
4907 
onReset(IVold vold)4908         public void onReset(IVold vold) {
4909             synchronized (mResetListeners) {
4910                 for (StorageManagerInternal.ResetListener listener : mResetListeners) {
4911                     listener.onReset(vold);
4912                 }
4913             }
4914         }
4915 
4916         @Override
resetUser(int userId)4917         public void resetUser(int userId) {
4918             // TODO(b/145931219): ideally, we only reset storage for the user in question,
4919             // but for now, reset everything.
4920             mHandler.obtainMessage(H_RESET).sendToTarget();
4921         }
4922 
4923         @Override
hasLegacyExternalStorage(int uid)4924         public boolean hasLegacyExternalStorage(int uid) {
4925             synchronized (mLock) {
4926                 return mUidsWithLegacyExternalStorage.contains(uid);
4927             }
4928         }
4929 
4930         @Override
prepareAppDataAfterInstall(String packageName, int uid)4931         public void prepareAppDataAfterInstall(String packageName, int uid) {
4932             int userId = UserHandle.getUserId(uid);
4933             final Environment.UserEnvironment userEnv = new Environment.UserEnvironment(userId);
4934 
4935             // The installer may have downloaded OBBs for this newly installed application;
4936             // make sure the OBB dir for the application is setup correctly, if it exists.
4937             File[] packageObbDirs = userEnv.buildExternalStorageAppObbDirs(packageName);
4938             for (File packageObbDir : packageObbDirs) {
4939                 if (packageObbDir.getPath().startsWith(
4940                                 Environment.getDataPreloadsMediaDirectory().getPath())) {
4941                     Slog.i(TAG, "Skipping app data preparation for " + packageObbDir);
4942                     continue;
4943                 }
4944                 try {
4945                     mVold.fixupAppDir(packageObbDir.getCanonicalPath() + "/", uid);
4946                 } catch (IOException e) {
4947                     Log.e(TAG, "Failed to get canonical path for " + packageName);
4948                 } catch (RemoteException | ServiceSpecificException e) {
4949                     // TODO(b/149975102) there is a known case where this fails, when a new
4950                     // user is setup and we try to fixup app dirs for some existing apps.
4951                     // For now catch the exception and don't crash.
4952                     Log.e(TAG, "Failed to fixup app dir for " + packageName, e);
4953                 }
4954             }
4955         }
4956 
4957         @Override
isExternalStorageService(int uid)4958         public boolean isExternalStorageService(int uid) {
4959             return mMediaStoreAuthorityAppId == UserHandle.getAppId(uid);
4960         }
4961 
4962         @Override
freeCache(String volumeUuid, long freeBytes)4963         public void freeCache(String volumeUuid, long freeBytes) {
4964             try {
4965                 mStorageSessionController.freeCache(volumeUuid, freeBytes);
4966             } catch (ExternalStorageServiceException e) {
4967                 Log.e(TAG, "Failed to free cache of vol : " + volumeUuid, e);
4968             }
4969         }
4970 
hasExternalStorage(int uid, String packageName)4971         public boolean hasExternalStorage(int uid, String packageName) {
4972             // No need to check for system uid. This avoids a deadlock between
4973             // PackageManagerService and AppOpsService.
4974             if (uid == Process.SYSTEM_UID) {
4975                 return true;
4976             }
4977 
4978             return getExternalStorageMountMode(uid, packageName)
4979                     != StorageManager.MOUNT_MODE_EXTERNAL_NONE;
4980         }
4981 
killAppForOpChange(int code, int uid)4982         private void killAppForOpChange(int code, int uid) {
4983             final IActivityManager am = ActivityManager.getService();
4984             try {
4985                 am.killUid(UserHandle.getAppId(uid), UserHandle.USER_ALL,
4986                         AppOpsManager.opToName(code) + " changed.");
4987             } catch (RemoteException e) {
4988             }
4989         }
4990 
onAppOpsChanged(int code, int uid, @Nullable String packageName, int mode, int previousMode)4991         public void onAppOpsChanged(int code, int uid, @Nullable String packageName, int mode,
4992                 int previousMode) {
4993             final long token = Binder.clearCallingIdentity();
4994             try {
4995                 // When using FUSE, we may need to kill the app if the op changes
4996                 switch(code) {
4997                     case OP_REQUEST_INSTALL_PACKAGES:
4998                         // In R, we used to kill the app here if it transitioned to/from
4999                         // MODE_ALLOWED, to make sure the app had the correct (writable) OBB
5000                         // view. But the majority of apps don't handle OBBs anyway, and for those
5001                         // that do, they can restart themselves. Therefore, starting from S,
5002                         // only kill the app when it transitions away from MODE_ALLOWED (eg,
5003                         // when the permission is taken away).
5004                         if (previousMode == MODE_ALLOWED && mode != MODE_ALLOWED) {
5005                             killAppForOpChange(code, uid);
5006                         }
5007                         return;
5008                     case OP_MANAGE_EXTERNAL_STORAGE:
5009                         if (mode != MODE_ALLOWED) {
5010                             // Only kill if op is denied, to lose external_storage gid
5011                             // Killing when op is granted to pickup the gid automatically,
5012                             // results in a bad UX, especially since the gid only gives access
5013                             // to unreliable volumes, USB OTGs that are rarely mounted. The app
5014                             // will get the external_storage gid on next organic restart.
5015                             killAppForOpChange(code, uid);
5016                         }
5017                         return;
5018                     case OP_LEGACY_STORAGE:
5019                         updateLegacyStorageApps(packageName, uid, mode == MODE_ALLOWED);
5020                         return;
5021                 }
5022             } finally {
5023                 Binder.restoreCallingIdentity(token);
5024             }
5025         }
5026 
5027         @Override
getPrimaryVolumeIds()5028         public List<String> getPrimaryVolumeIds() {
5029             final List<String> primaryVolumeIds = new ArrayList<>();
5030             synchronized (mLock) {
5031                 for (int i = 0; i < mVolumes.size(); i++) {
5032                     final VolumeInfo vol = mVolumes.valueAt(i);
5033                     if (vol.isPrimary()) {
5034                         primaryVolumeIds.add(vol.getId());
5035                     }
5036                 }
5037             }
5038             return primaryVolumeIds;
5039         }
5040 
5041         @Override
markCeStoragePrepared(int userId)5042         public void markCeStoragePrepared(int userId) {
5043             synchronized (mLock) {
5044                 mCeStoragePreparedUsers.add(userId);
5045             }
5046         }
5047 
5048         @Override
isCeStoragePrepared(int userId)5049         public boolean isCeStoragePrepared(int userId) {
5050             synchronized (mLock) {
5051                 return mCeStoragePreparedUsers.contains(userId);
5052             }
5053         }
5054 
5055         @Override
registerCloudProviderChangeListener( @onNull StorageManagerInternal.CloudProviderChangeListener listener)5056         public void registerCloudProviderChangeListener(
5057                 @NonNull StorageManagerInternal.CloudProviderChangeListener listener) {
5058             mCloudProviderChangeListeners.add(listener);
5059             mHandler.obtainMessage(H_CLOUD_MEDIA_PROVIDER_CHANGED, listener).sendToTarget();
5060         }
5061 
5062         @Override
prepareUserStorageForMove(String fromVolumeUuid, String toVolumeUuid, List<UserInfo> users)5063         public void prepareUserStorageForMove(String fromVolumeUuid, String toVolumeUuid,
5064                 List<UserInfo> users) {
5065             try {
5066                 prepareUserStorageForMoveInternal(fromVolumeUuid, toVolumeUuid, users);
5067             } catch (Exception e) {
5068                 throw new RuntimeException(e);
5069             }
5070         }
5071 
5072         @Override
createFsveritySetupAuthToken(ParcelFileDescriptor authFd, int uid)5073         public IFsveritySetupAuthToken createFsveritySetupAuthToken(ParcelFileDescriptor authFd,
5074                 int uid) throws IOException {
5075             try {
5076                 return mInstaller.createFsveritySetupAuthToken(authFd, uid);
5077             } catch (Installer.InstallerException e) {
5078                 throw new IOException(e);
5079             }
5080         }
5081 
5082         @Override
enableFsverity(IFsveritySetupAuthToken authToken, String filePath, String packageName)5083         public int enableFsverity(IFsveritySetupAuthToken authToken, String filePath,
5084                 String packageName) throws IOException {
5085             try {
5086                 return mInstaller.enableFsverity(authToken, filePath, packageName);
5087             } catch (Installer.InstallerException e) {
5088                 throw new IOException(e);
5089             }
5090         }
5091 
5092         @Override
registerStorageLockEventListener( @onNull ICeStorageLockEventListener listener)5093         public void registerStorageLockEventListener(
5094                 @NonNull ICeStorageLockEventListener listener) {
5095             boolean registered = mCeStorageEventCallbacks.add(listener);
5096             if (!registered) {
5097                 Slog.w(TAG, "Failed to register listener: " + listener);
5098             }
5099         }
5100 
5101         @Override
unregisterStorageLockEventListener( @onNull ICeStorageLockEventListener listener)5102         public void unregisterStorageLockEventListener(
5103                 @NonNull ICeStorageLockEventListener listener) {
5104             boolean unregistered = mCeStorageEventCallbacks.remove(listener);
5105             if (!unregistered) {
5106                 Slog.w(TAG, "Unregistering " + listener + " that was not registered");
5107             }
5108         }
5109     }
5110 }
5111