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