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

Commit f27ffc65 authored by Jigar Thakkar's avatar Jigar Thakkar
Browse files

Enforce strong auth for private profile on storage lock events

Currently, strong auth requirements are only enforced on reboots for
private profile users. For all other users, the strong auth requirements
are also enforced on all user stops as additionally.

With this change, we expose storage manager callbacks to system services
whenever the ce storage for a user is locked. We also enable
LockSettingsService to register for this callback and ensure private
profile strong auth requirements are enforced when the CE storage of
the private profile user is locked. For all other users, the strong auth
requirements will still be changed only on user stops.

Bug: 319142556
Test: atest StorageManagerServiceTest. Also tested manually by
installing private space and making changes to ensure the storage gets
locked whenever the private space is locked.
Flag: android.multiuser.enable_biometrics_to_unlock_private_space
Ignore-AOSP-First: The change depends on internal flags

Change-Id: I5db6d9f5699117b0c0422269c560eb0723b4d809
parent 8fd912f6
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os.storage;


/**
 * Callback class for receiving CE storage lock events from StorageManagerService.
 * @hide
 */
public interface ICeStorageLockEventListener {

    /**
     * Called when the CE storage corresponding to the userId is locked
     */
    void onStorageLocked(int userId);
}
+16 −0
Original line number Diff line number Diff line
@@ -16,10 +16,12 @@

package android.os.storage;

import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.UserInfo;
import android.multiuser.Flags;
import android.os.IInstalld;
import android.os.IVold;
import android.os.ParcelFileDescriptor;
@@ -201,4 +203,18 @@ public abstract class StorageManagerInternal {
     */
    public abstract int enableFsverity(IInstalld.IFsveritySetupAuthToken authToken, String filePath,
            String packageName) throws IOException;

    /**
     * Registers a {@link ICeStorageLockEventListener} for receiving CE storage lock events.
     */
    @FlaggedApi(Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE)
    public abstract void registerStorageLockEventListener(
            @NonNull ICeStorageLockEventListener listener);

    /**
     * Unregisters the {@link ICeStorageLockEventListener} which was registered previously
     */
    @FlaggedApi(Flags.FLAG_ENABLE_BIOMETRICS_TO_UNLOCK_PRIVATE_SPACE)
    public abstract void unregisterStorageLockEventListener(
            @NonNull ICeStorageLockEventListener listener);
}
+41 −0
Original line number Diff line number Diff line
@@ -107,6 +107,7 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.DiskInfo;
import android.os.storage.ICeStorageLockEventListener;
import android.os.storage.IObbActionListener;
import android.os.storage.IStorageEventListener;
import android.os.storage.IStorageManager;
@@ -139,6 +140,7 @@ import android.util.TimeUtils;
import android.util.Xml;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.AppFuseMount;
@@ -185,6 +187,7 @@ import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -602,6 +605,9 @@ class StorageManagerService extends IStorageManager.Stub
    // Not guarded by lock, always used on the ActivityManager thread
    private final SparseArray<PackageMonitor> mPackageMonitorsForUser = new SparseArray<>();

    /** List of listeners registered for ce storage callbacks */
    private final CopyOnWriteArrayList<ICeStorageLockEventListener>
            mCeStorageEventCallbacks = new CopyOnWriteArrayList<>();

    class ObbState implements IBinder.DeathRecipient {
        public ObbState(String rawPath, String canonicalPath, int callingUid,
@@ -3315,6 +3321,11 @@ class StorageManagerService extends IStorageManager.Stub
        synchronized (mLock) {
            mCeUnlockedUsers.remove(userId);
        }
        if (android.os.Flags.allowPrivateProfile()
                && android.multiuser.Flags.enablePrivateSpaceFeatures()
                && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) {
            dispatchCeStorageLockedEvent(userId);
        }
    }

    @Override
@@ -4580,6 +4591,18 @@ class StorageManagerService extends IStorageManager.Stub
        return StorageManager.MOUNT_MODE_EXTERNAL_NONE;
    }

    @VisibleForTesting
    CopyOnWriteArrayList<ICeStorageLockEventListener> getCeStorageEventCallbacks() {
        return mCeStorageEventCallbacks;
    }

    @VisibleForTesting
    void dispatchCeStorageLockedEvent(int userId) {
        for (ICeStorageLockEventListener listener: mCeStorageEventCallbacks) {
            listener.onStorageLocked(userId);
        }
    }

    private static class Callbacks extends Handler {
        private static final int MSG_STORAGE_STATE_CHANGED = 1;
        private static final int MSG_VOLUME_STATE_CHANGED = 2;
@@ -5066,5 +5089,23 @@ class StorageManagerService extends IStorageManager.Stub
                throw new IOException(e);
            }
        }

        @Override
        public void registerStorageLockEventListener(
                @NonNull ICeStorageLockEventListener listener) {
            boolean registered = mCeStorageEventCallbacks.add(listener);
            if (!registered) {
                Slog.w(TAG, "Failed to register listener: " + listener);
            }
        }

        @Override
        public void unregisterStorageLockEventListener(
                @NonNull ICeStorageLockEventListener listener) {
            boolean unregistered = mCeStorageEventCallbacks.remove(listener);
            if (!unregistered) {
                Slog.w(TAG, "Unregistering " + listener + " that was not registered");
            }
        }
    }
}
+9 −0
Original line number Diff line number Diff line
@@ -73,6 +73,15 @@
            ],
            "file_patterns": ["SensitiveContentProtectionManagerService\\.java"]
        },
        {
            "name": "FrameworksMockingServicesTests",
            "options": [
                {
                    "include-filter": "com.android.server.StorageManagerServiceTest"
                }
            ],
            "file_patterns": ["StorageManagerService\\.java"]
        },
        {
            "name": "FrameworksServicesTests",
            "options": [
+35 −0
Original line number Diff line number Diff line
@@ -102,8 +102,10 @@ import android.os.ShellCallback;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.ICeStorageLockEventListener;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.security.AndroidKeyStoreMaintenance;
@@ -338,6 +340,8 @@ public class LockSettingsService extends ILockSettings.Stub {
    private final CopyOnWriteArrayList<LockSettingsStateListener> mLockSettingsStateListeners =
            new CopyOnWriteArrayList<>();

    private final StorageManagerInternal mStorageManagerInternal;

    // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
    // devices. The most basic of these is to show/hide notifications about missing features until
    // the user unlocks the account and credential-encrypted storage is available.
@@ -577,6 +581,10 @@ public class LockSettingsService extends ILockSettings.Stub {
            return null;
        }

        public StorageManagerInternal getStorageManagerInternal() {
            return LocalServices.getService(StorageManagerInternal.class);
        }

        public SyntheticPasswordManager getSyntheticPasswordManager(LockSettingsStorage storage) {
            return new SyntheticPasswordManager(getContext(), storage, getUserManager(),
                    new PasswordSlotManager());
@@ -672,6 +680,7 @@ public class LockSettingsService extends ILockSettings.Stub {
        mNotificationManager = injector.getNotificationManager();
        mUserManager = injector.getUserManager();
        mStorageManager = injector.getStorageManager();
        mStorageManagerInternal = injector.getStorageManagerInternal();
        mStrongAuthTracker = injector.getStrongAuthTracker();
        mStrongAuthTracker.register(mStrongAuth);
        mGatekeeperPasswords = new LongSparseArray<>();
@@ -925,7 +934,33 @@ public class LockSettingsService extends ILockSettings.Stub {
        mStorage.prefetchUser(UserHandle.USER_SYSTEM);
        mBiometricDeferredQueue.systemReady(mInjector.getFingerprintManager(),
                mInjector.getFaceManager(), mInjector.getBiometricManager());
        if (android.os.Flags.allowPrivateProfile()
                && android.multiuser.Flags.enablePrivateSpaceFeatures()
                && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) {
            mStorageManagerInternal.registerStorageLockEventListener(mCeStorageLockEventListener);
        }
    }

    private final ICeStorageLockEventListener mCeStorageLockEventListener =
            new ICeStorageLockEventListener() {
                @Override
                public void onStorageLocked(int userId) {
                    Slog.i(TAG, "Storage lock event received for " + userId);
                    if (android.os.Flags.allowPrivateProfile()
                            && android.multiuser.Flags.enablePrivateSpaceFeatures()
                            && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) {
                        mHandler.post(() -> {
                            UserProperties userProperties =
                                    mUserManager.getUserProperties(UserHandle.of(userId));
                            if (userProperties != null
                                    && userProperties.getAllowStoppingUserWithDelayedLocking()) {
                                int strongAuthRequired = LockPatternUtils.StrongAuthTracker
                                        .getDefaultFlags(mContext);
                                requireStrongAuth(strongAuthRequired, userId);
                            }
                        });
                    }
                }};

    private void loadEscrowData() {
        mRebootEscrowManager.loadRebootEscrowDataIfAvailable(mHandler);
Loading