Loading core/java/android/os/storage/ICeStorageLockEventListener.java 0 → 100644 +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); } core/java/android/os/storage/StorageManagerInternal.java +16 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } services/core/java/com/android/server/StorageManagerService.java +41 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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, Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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"); } } } } services/core/java/com/android/server/TEST_MAPPING +9 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,15 @@ ], "file_patterns": ["SensitiveContentProtectionManagerService\\.java"] }, { "name": "FrameworksMockingServicesTests", "options": [ { "include-filter": "com.android.server.StorageManagerServiceTest" } ], "file_patterns": ["StorageManagerService\\.java"] }, { "name": "FrameworksServicesTests", "options": [ Loading services/core/java/com/android/server/locksettings/LockSettingsService.java +35 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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()); Loading Loading @@ -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<>(); Loading Loading @@ -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 Loading
core/java/android/os/storage/ICeStorageLockEventListener.java 0 → 100644 +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); }
core/java/android/os/storage/StorageManagerInternal.java +16 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); }
services/core/java/com/android/server/StorageManagerService.java +41 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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, Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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"); } } } }
services/core/java/com/android/server/TEST_MAPPING +9 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,15 @@ ], "file_patterns": ["SensitiveContentProtectionManagerService\\.java"] }, { "name": "FrameworksMockingServicesTests", "options": [ { "include-filter": "com.android.server.StorageManagerServiceTest" } ], "file_patterns": ["StorageManagerService\\.java"] }, { "name": "FrameworksServicesTests", "options": [ Loading
services/core/java/com/android/server/locksettings/LockSettingsService.java +35 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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()); Loading Loading @@ -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<>(); Loading Loading @@ -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