Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 23465f56 authored by Zimuzo Ezeozue's avatar Zimuzo Ezeozue Committed by Android (Google) Code Review
Browse files

Merge "Fix multi-user and multi-storage with FUSE"

parents 3d2b00f3 17be6f99
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -779,7 +779,12 @@ public class StorageManager {
    /** {@hide} */
    public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
        if (emulatedVol != null) {
            return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
            String id = emulatedVol.getId();
            int idx = id.indexOf(";");
            if (idx != -1) {
                id = id.substring(0, idx);
            }
            return findVolumeById(id.replace("emulated", "private"));
        } else {
            return null;
        }
@@ -789,7 +794,8 @@ public class StorageManager {
    @UnsupportedAppUsage
    public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) {
        if (privateVol != null) {
            return findVolumeById(privateVol.getId().replace("private", "emulated"));
            return findVolumeById(privateVol.getId().replace("private", "emulated") + ";"
                    + mContext.getUserId());
        } else {
            return null;
        }
+14 −7
Original line number Diff line number Diff line
@@ -266,7 +266,7 @@ public class VolumeInfo implements Parcelable {

    @UnsupportedAppUsage
    public @Nullable String getDescription() {
        if (ID_PRIVATE_INTERNAL.equals(id) || ID_EMULATED_INTERNAL.equals(id)) {
        if (ID_PRIVATE_INTERNAL.equals(id) || id.startsWith(ID_EMULATED_INTERNAL + ";")) {
            return Resources.getSystem().getString(com.android.internal.R.string.storage_internal);
        } else if (!TextUtils.isEmpty(fsLabel)) {
            return fsLabel;
@@ -301,13 +301,20 @@ public class VolumeInfo implements Parcelable {
    }

    public boolean isVisibleForUser(int userId) {
        if ((type == TYPE_PUBLIC || type == TYPE_STUB) && mountUserId == userId) {
            return isVisible();
        } else if (type == TYPE_EMULATED) {
        if ((type == TYPE_PUBLIC || type == TYPE_STUB || type == TYPE_EMULATED)
                && mountUserId == userId) {
            return isVisible();
        } else {
        }
        return false;
    }

    /**
     * Returns {@code true} if this volume is the primary emulated volume for {@code userId},
     * {@code false} otherwise.
     */
    @UnsupportedAppUsage
    public boolean isPrimaryEmulatedForUser(int userId) {
        return id.equals(ID_EMULATED_INTERNAL + ";" + userId);
    }

    public boolean isVisibleForRead(int userId) {
@@ -390,7 +397,7 @@ public class VolumeInfo implements Parcelable {
                derivedFsUuid = privateVol.fsUuid;
            }

            if (ID_EMULATED_INTERNAL.equals(id)) {
            if (isPrimaryEmulatedForUser(userId)) {
                removable = false;
            } else {
                removable = true;
+2 −2
Original line number Diff line number Diff line
@@ -162,12 +162,12 @@ public class ExternalStorageProvider extends FileSystemProvider {
            final String title;
            final UUID storageUuid;
            if (volume.getType() == VolumeInfo.TYPE_EMULATED) {
                // We currently only support a single emulated volume mounted at
                // We currently only support a single emulated volume per user mounted at
                // a time, and it's always considered the primary
                if (DEBUG) Log.d(TAG, "Found primary volume: " + volume);
                rootId = ROOT_ID_PRIMARY_EMULATED;

                if (VolumeInfo.ID_EMULATED_INTERNAL.equals(volume.getId())) {
                if (volume.isPrimaryEmulatedForUser(userId)) {
                    // This is basically the user's primary device storage.
                    // Use device name for the volume since this is likely same thing
                    // the user sees when they mount their phone on another device.
+102 −36
Original line number Diff line number Diff line
@@ -141,6 +141,7 @@ import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.storage.AppFuseBridge;
import com.android.server.storage.StorageSessionController;
import com.android.server.storage.StorageSessionController.ExternalStorageServiceException;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal.ScreenObserver;

@@ -196,9 +197,6 @@ class StorageManagerService extends IStorageManager.Stub
    private static final String ZRAM_ENABLED_PROPERTY =
            "persist.sys.zram_enabled";

    private static final boolean IS_FUSE_ENABLED =
            SystemProperties.getBoolean(StorageManager.PROP_FUSE, false);

    private static final boolean ENABLE_ISOLATED_STORAGE = StorageManager.hasIsolatedStorage();

    /**
@@ -350,6 +348,10 @@ class StorageManagerService extends IStorageManager.Stub
    @GuardedBy("mLock")
    private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();

    /** Map from volume ID to latches */
    @GuardedBy("mLock")
    private ArrayMap<String, CountDownLatch> mFuseVolumeReadyLatches = new ArrayMap<>();

    @GuardedBy("mLock")
    private IPackageMoveObserver mMoveCallback;
    @GuardedBy("mLock")
@@ -419,7 +421,7 @@ class StorageManagerService extends IStorageManager.Stub
    private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
        final StorageManager storage = mContext.getSystemService(StorageManager.class);
        if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
            return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
            return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL + ";" + 0);
        } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
            return storage.getPrimaryPhysicalVolume();
        } else {
@@ -462,6 +464,17 @@ class StorageManagerService extends IStorageManager.Stub
        }
    }

    private CountDownLatch findOrCreateFuseVolumeReadyLatch(String volId) {
        synchronized (mLock) {
            CountDownLatch latch = mFuseVolumeReadyLatches.get(volId);
            if (latch == null) {
                latch = new CountDownLatch(1);
                mFuseVolumeReadyLatches.put(volId, latch);
            }
            return latch;
        }
    }

    /** List of crypto types.
      * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
      * corresponding commands in CommandListener.cpp */
@@ -514,6 +527,8 @@ class StorageManagerService extends IStorageManager.Stub
    // Not guarded by a lock.
    private final StorageSessionController mStorageSessionController;

    private final boolean mIsFuseEnabled;

    class ObbState implements IBinder.DeathRecipient {
        public ObbState(String rawPath, String canonicalPath, int callingUid,
                IObbActionListener token, int nonce, String volId) {
@@ -597,6 +612,7 @@ class StorageManagerService extends IStorageManager.Stub
    private static final int H_ABORT_IDLE_MAINT = 12;
    private static final int H_BOOT_COMPLETED = 13;
    private static final int H_COMPLETE_UNLOCK_USER = 14;
    private static final int H_VOLUME_READY = 15;

    class StorageManagerServiceHandler extends Handler {
        public StorageManagerServiceHandler(Looper looper) {
@@ -657,6 +673,22 @@ class StorageManagerService extends IStorageManager.Stub
                    }
                    break;
                }
                case H_VOLUME_READY: {
                    final VolumeInfo vol = (VolumeInfo) msg.obj;
                    try {
                        mStorageSessionController.onVolumeReady(vol);

                        synchronized (mLock) {
                            CountDownLatch latch = mFuseVolumeReadyLatches.remove(vol.id);
                            if (latch != null) {
                                latch.countDown();
                            }
                        }
                    } catch (IllegalStateException | ExternalStorageServiceException e) {
                        Slog.i(TAG, "Failed to initialise volume " + vol, e);
                    }
                    break;
                }
                case H_VOLUME_MOUNT: {
                    final VolumeInfo vol = (VolumeInfo) msg.obj;
                    if (isMountDisallowed(vol)) {
@@ -664,19 +696,12 @@ class StorageManagerService extends IStorageManager.Stub
                        break;
                    }

                    // TODO(b/135341433): Remove paranoid logging when FUSE is stable
                    Slog.i(TAG, "Mounting volume " + vol);
                    // TODO(b/135341433): Update to use new vold API that gets or mounts fuse fd
                    // Ensure that we can pass user of a volume to the new API
                    mStorageSessionController.onVolumeMounted(mCurrentUserId, mount(vol), vol);
                    Slog.i(TAG, "Mounted volume " + vol);

                    mount(vol);
                    break;
                }
                case H_VOLUME_UNMOUNT: {
                    final VolumeInfo vol = (VolumeInfo) msg.obj;
                    unmount(vol);
                    mStorageSessionController.onVolumeUnmounted(mCurrentUserId, vol);
                    break;
                }
                case H_VOLUME_BROADCAST: {
@@ -757,7 +782,6 @@ class StorageManagerService extends IStorageManager.Stub
                        }
                    }
                    mVold.onUserRemoved(userId);
                    mStorageSessionController.onUserRemoved(userId);
                }
            } catch (Exception e) {
                Slog.wtf(TAG, e);
@@ -978,7 +1002,12 @@ class StorageManagerService extends IStorageManager.Stub
                + ", mDaemonConnected=" + mDaemonConnected);
        if (mBootCompleted && mDaemonConnected) {
            final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();

            if (mIsFuseEnabled) {
                mStorageSessionController.onReset(mVold, mHandler);
            } else {
                killMediaProvider(users);
            }

            final int[] systemUnlockedUsers;
            synchronized (mLock) {
@@ -992,7 +1021,7 @@ class StorageManagerService extends IStorageManager.Stub

            try {
                // TODO(b/135341433): Remove paranoid logging when FUSE is stable
                Slog.i(TAG, "Resetting vold");
                Slog.i(TAG, "Resetting vold...");
                mVold.reset();
                Slog.i(TAG, "Reset vold");

@@ -1019,7 +1048,7 @@ class StorageManagerService extends IStorageManager.Stub
        // staging area is ready so it's ready for zygote-forked apps to
        // bind mount against.
        try {
            mStorageSessionController.onUserStarted(userId);
            mStorageSessionController.onUnlockUser(userId);
            mVold.onUserStarted(userId);
            mStoraged.onUserStarted(userId);
        } catch (Exception e) {
@@ -1201,10 +1230,12 @@ class StorageManagerService extends IStorageManager.Stub
        }

        @Override
        public void onVolumeCreated(String volId, int type, String diskId, String partGuid) {
        public void onVolumeCreated(String volId, int type, String diskId, String partGuid,
                int userId) {
            synchronized (mLock) {
                final DiskInfo disk = mDisks.get(diskId);
                final VolumeInfo vol = new VolumeInfo(volId, type, disk, partGuid);
                vol.mountUserId = userId;
                mVolumes.put(volId, vol);
                onVolumeCreatedLocked(vol);
            }
@@ -1258,8 +1289,13 @@ class StorageManagerService extends IStorageManager.Stub

        @Override
        public void onVolumeDestroyed(String volId) {
            VolumeInfo vol = null;
            synchronized (mLock) {
                mVolumes.remove(volId);
                vol = mVolumes.remove(volId);
            }

            if (vol != null) {
                mStorageSessionController.onVolumeRemove(vol);
            }
        }
    };
@@ -1395,6 +1431,13 @@ class StorageManagerService extends IStorageManager.Stub
            writeSettingsLocked();
        }

        if (mIsFuseEnabled && newState == VolumeInfo.STATE_MOUNTED
                && (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_EMULATED)) {
            Slog.i(TAG, "Initialising volume " + vol + " ...");
            // TODO(b/144275217): Delay broadcasts till mount is really ready
            mHandler.obtainMessage(H_VOLUME_READY, vol).sendToTarget();
        }

        mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);

        // Do not broadcast before boot has completed to avoid launching the
@@ -1546,13 +1589,12 @@ class StorageManagerService extends IStorageManager.Stub
        // Snapshot feature flag used for this boot
        SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
                SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));

        SystemProperties.set(StorageManager.PROP_FUSE_SNAPSHOT, Boolean.toString(
                SystemProperties.getBoolean(StorageManager.PROP_FUSE, false)));

        mIsFuseEnabled = SystemProperties.getBoolean(StorageManager.PROP_FUSE_SNAPSHOT, false);
        mContext = context;
        mResolver = mContext.getContentResolver();

        mCallbacks = new Callbacks(FgThread.get().getLooper());
        mLockPatternUtils = new LockPatternUtils(mContext);

@@ -1563,11 +1605,7 @@ class StorageManagerService extends IStorageManager.Stub
        // Add OBB Action Handler to StorageManagerService thread.
        mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());

        mStorageSessionController = new StorageSessionController(mContext,
                userId -> {
                    Slog.i(TAG, "Storage session ended for user: " + userId + ". Resetting...");
                    mHandler.obtainMessage(H_RESET).sendToTarget();
                });
        mStorageSessionController = new StorageSessionController(mContext, mIsFuseEnabled);

        // Initialize the last-fstrim tracking if necessary
        File dataDir = Environment.getDataDirectory();
@@ -1873,21 +1911,36 @@ class StorageManagerService extends IStorageManager.Stub
        if (isMountDisallowed(vol)) {
            throw new SecurityException("Mounting " + volId + " restricted by policy");
        }

        CountDownLatch latch = null;
        if (mIsFuseEnabled && StorageSessionController.isEmulatedOrPublic(vol)) {
            latch = findOrCreateFuseVolumeReadyLatch(volId);
        }

        mount(vol);

        if (latch != null) {
            try {
                waitForLatch(latch, "mount " + volId, 3 * DateUtils.MINUTE_IN_MILLIS);
            } catch (TimeoutException e) {
                Slog.wtf(TAG, e);
            } finally {
                synchronized (mLock) {
                    mFuseVolumeReadyLatches.remove(volId);
                }
            }
        }
    }

    private FileDescriptor mount(VolumeInfo vol) {
    private void mount(VolumeInfo vol) {
        try {
            // TODO(b/135341433): Now, emulated (and private?) volumes are shared across users
            // This means the mountUserId on such volumes is USER_NULL. This breaks fuse which
            // requires a valid user to mount a volume. Create individual volumes per user in vold
            // and remove this property check
            int userId = SystemProperties.getBoolean(StorageManager.PROP_FUSE_SNAPSHOT, false)
                    ? mCurrentUserId : vol.mountUserId;
            return mVold.mount(vol.id, vol.mountFlags, userId);
            // TODO(b/135341433): Remove paranoid logging when FUSE is stable
            Slog.i(TAG, "Mounting volume " + vol);
            FileDescriptor fd = mVold.mount(vol.id, vol.mountFlags, vol.mountUserId);
            Slog.i(TAG, "Mounted volume " + vol);
            mStorageSessionController.onVolumeMount(fd, vol);
        } catch (Exception e) {
            Slog.wtf(TAG, e);
            return null;
        }
    }

@@ -1902,6 +1955,7 @@ class StorageManagerService extends IStorageManager.Stub
    private void unmount(VolumeInfo vol) {
        try {
            mVold.unmount(vol.id);
            mStorageSessionController.onVolumeUnmount(vol);
        } catch (Exception e) {
            Slog.wtf(TAG, e);
        }
@@ -3040,6 +3094,14 @@ class StorageManagerService extends IStorageManager.Stub

    @Override
    public void mkdirs(String callingPkg, String appPath) {
        if (mIsFuseEnabled) {
            // TODO(b/144332951): Calling into Vold is risky because the FUSE daemon can go down
            // anytime and Vold will hang forever. We should either remove this call
            // or at least call into the FUSE daemon to mkdir instead
            Slog.w(TAG, "Not making dir for package " + callingPkg + " with path " + appPath);
            return;
        }

        final int callingUid = Binder.getCallingUid();
        final int userId = UserHandle.getUserId(callingUid);
        final UserEnvironment userEnv = new UserEnvironment(userId);
@@ -3121,8 +3183,12 @@ class StorageManagerService extends IStorageManager.Stub
                switch (vol.getType()) {
                    case VolumeInfo.TYPE_PUBLIC:
                    case VolumeInfo.TYPE_STUB:
                        break;
                    case VolumeInfo.TYPE_EMULATED:
                        if (vol.getMountUserId() == userId) {
                            break;
                        }
                        // Skip if emulated volume not for userId
                    default:
                        continue;
                }
@@ -3711,7 +3777,7 @@ class StorageManagerService extends IStorageManager.Stub
                return Zygote.MOUNT_EXTERNAL_NONE;
            }

            if (IS_FUSE_ENABLED && packageName.equals(mMediaStoreAuthorityPackageName)) {
            if (mIsFuseEnabled && packageName.equals(mMediaStoreAuthorityPackageName)) {
                // Determine if caller requires pass_through mount
                return Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
            }
+294 −89

File changed.

Preview size limit exceeded, changes collapsed.

Loading