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

Commit a5b0a911 authored by Jigar Thakkar's avatar Jigar Thakkar Committed by Android (Google) Code Review
Browse files

Merge "Enforce strong auth for private profile on storage lock events" into main

parents a2aed46d f27ffc65
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