diff options
8 files changed, 288 insertions, 59 deletions
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index d359a9050a0f..3cff91597939 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -1149,6 +1149,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu /** * Sets the serial number used for the certificate of the generated key pair. + * To ensure compatibility with devices and certificate parsers, the value + * should be 20 bytes or shorter (see RFC 5280 section 4.1.2.2). * * <p>By default, the serial number is {@code 1}. */ diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java index 7fcef9c90812..c0b354cc69d9 100644 --- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java +++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java @@ -2373,7 +2373,7 @@ public class CameraExtensionsProxyService extends Service { public Plane[] getPlanes() { throwISEIfImageIsInvalid(); if (mPlanes == null) { - int fenceFd = mParcelImage.fence != null ? mParcelImage.fence.getFd() : -1; + int fenceFd = mParcelImage.fence != null ? mParcelImage.fence.detachFd() : -1; mGraphicBuffer = GraphicBuffer.createFromHardwareBuffer(mParcelImage.buffer); mPlanes = ImageReader.initializeImagePlanes(mParcelImage.planeCount, mGraphicBuffer, fenceFd, mParcelImage.format, mParcelImage.timestamp, diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index 966478e33c73..a61925732256 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -138,12 +138,6 @@ public class PackageWatchdog { static final long DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS = TimeUnit.MINUTES.toMillis(10); - // Time needed to apply mitigation - private static final String MITIGATION_WINDOW_MS = - "persist.device_config.configuration.mitigation_window_ms"; - @VisibleForTesting - static final long DEFAULT_MITIGATION_WINDOW_MS = TimeUnit.SECONDS.toMillis(5); - // Threshold level at which or above user might experience significant disruption. private static final String MAJOR_USER_IMPACT_LEVEL_THRESHOLD = "persist.device_config.configuration.major_user_impact_level_threshold"; @@ -216,9 +210,6 @@ public class PackageWatchdog { @GuardedBy("mLock") private boolean mSyncRequired = false; - @GuardedBy("mLock") - private long mLastMitigation = -1000000; - @FunctionalInterface @VisibleForTesting interface SystemClock { @@ -409,16 +400,6 @@ public class PackageWatchdog { Slog.w(TAG, "Could not resolve a list of failing packages"); return; } - synchronized (mLock) { - final long now = mSystemClock.uptimeMillis(); - if (Flags.recoverabilityDetection()) { - if (now >= mLastMitigation - && (now - mLastMitigation) < getMitigationWindowMs()) { - Slog.i(TAG, "Skipping onPackageFailure mitigation"); - return; - } - } - } mLongTaskHandler.post(() -> { synchronized (mLock) { if (mAllObservers.isEmpty()) { @@ -519,17 +500,10 @@ public class PackageWatchdog { int currentObserverImpact, int mitigationCount) { if (currentObserverImpact < getUserImpactLevelLimit()) { - synchronized (mLock) { - mLastMitigation = mSystemClock.uptimeMillis(); - } currentObserverToNotify.execute(versionedPackage, failureReason, mitigationCount); } } - private long getMitigationWindowMs() { - return SystemProperties.getLong(MITIGATION_WINDOW_MS, DEFAULT_MITIGATION_WINDOW_MS); - } - /** * Called when the system server boots. If the system server is detected to be in a boot loop, diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 54fb65c4e799..1ad0abf45f55 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -581,7 +581,7 @@ public class LockSettingsService extends ILockSettings.Stub { public RebootEscrowManager getRebootEscrowManager(RebootEscrowManager.Callbacks callbacks, LockSettingsStorage storage) { return new RebootEscrowManager(mContext, callbacks, storage, - getHandler(getServiceThread())); + getHandler(getServiceThread()), getUserManagerInternal()); } public int binderGetCallingUid() { diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java index e1cd2c585146..d0b8990e37c4 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java @@ -51,16 +51,20 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.widget.RebootEscrowListener; +import com.android.server.pm.UserManagerInternal; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.Set; import javax.crypto.SecretKey; @@ -138,6 +142,7 @@ class RebootEscrowManager { ERROR_KEYSTORE_FAILURE, ERROR_NO_NETWORK, ERROR_TIMEOUT_EXHAUSTED, + ERROR_NO_REBOOT_ESCROW_DATA, }) @Retention(RetentionPolicy.SOURCE) @interface RebootEscrowErrorCode { @@ -153,6 +158,7 @@ class RebootEscrowManager { static final int ERROR_KEYSTORE_FAILURE = 7; static final int ERROR_NO_NETWORK = 8; static final int ERROR_TIMEOUT_EXHAUSTED = 9; + static final int ERROR_NO_REBOOT_ESCROW_DATA = 10; private @RebootEscrowErrorCode int mLoadEscrowDataErrorCode = ERROR_NONE; @@ -222,11 +228,16 @@ class RebootEscrowManager { private final RebootEscrowKeyStoreManager mKeyStoreManager; private final LockSettingsStorage mStorage; private RebootEscrowProviderInterface mRebootEscrowProvider; + private final UserManagerInternal mUserManagerInternal; - Injector(Context context, LockSettingsStorage storage) { + Injector( + Context context, + LockSettingsStorage storage, + UserManagerInternal userManagerInternal) { mContext = context; mStorage = storage; mKeyStoreManager = new RebootEscrowKeyStoreManager(); + mUserManagerInternal = userManagerInternal; } private RebootEscrowProviderInterface createRebootEscrowProvider() { @@ -326,6 +337,10 @@ class RebootEscrowManager { return (UserManager) mContext.getSystemService(Context.USER_SERVICE); } + public UserManagerInternal getUserManagerInternal() { + return mUserManagerInternal; + } + public RebootEscrowKeyStoreManager getKeyStoreManager() { return mKeyStoreManager; } @@ -402,8 +417,8 @@ class RebootEscrowManager { } RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage, - Handler handler) { - this(new Injector(context, storage), callbacks, storage, handler); + Handler handler, UserManagerInternal userManagerInternal) { + this(new Injector(context, storage, userManagerInternal), callbacks, storage, handler); } @VisibleForTesting @@ -451,18 +466,50 @@ class RebootEscrowManager { onEscrowRestoreComplete(false, attemptCount, retryHandler); } - void loadRebootEscrowDataIfAvailable(Handler retryHandler) { - List<UserInfo> users = mUserManager.getUsers(); + private List<UserInfo> getUsersToUnlock(List<UserInfo> users) { + // System user must be unlocked to unlock any other user + if (mCallbacks.isUserSecure(USER_SYSTEM) && !mStorage.hasRebootEscrow(USER_SYSTEM)) { + Slog.i(TAG, "No reboot escrow data found for system user"); + return Collections.emptyList(); + } + + Set<Integer> noEscrowDataUsers = new HashSet<>(); + for (UserInfo user : users) { + if (mCallbacks.isUserSecure(user.id) + && !mStorage.hasRebootEscrow(user.id)) { + Slog.d(TAG, "No reboot escrow data found for user " + user); + noEscrowDataUsers.add(user.id); + } + } + List<UserInfo> rebootEscrowUsers = new ArrayList<>(); for (UserInfo user : users) { - if (mCallbacks.isUserSecure(user.id) && mStorage.hasRebootEscrow(user.id)) { - rebootEscrowUsers.add(user); + // No lskf, no need to unlock. + if (!mCallbacks.isUserSecure(user.id)) { + continue; + } + // Don't unlock if user or user's parent does not have reboot data + int userId = user.id; + if (noEscrowDataUsers.contains(userId) + || noEscrowDataUsers.contains( + mInjector.getUserManagerInternal().getProfileParentId(userId))) { + continue; } + rebootEscrowUsers.add(user); } + return rebootEscrowUsers; + } + + void loadRebootEscrowDataIfAvailable(Handler retryHandler) { + List<UserInfo> users = mUserManager.getUsers(); + List<UserInfo> rebootEscrowUsers = getUsersToUnlock(users); if (rebootEscrowUsers.isEmpty()) { Slog.i(TAG, "No reboot escrow data found for users," + " skipping loading escrow data"); + setLoadEscrowDataErrorCode(ERROR_NO_REBOOT_ESCROW_DATA, retryHandler); + reportMetricOnRestoreComplete( + /* success= */ false, /* attemptCount= */ 1, retryHandler); clearMetricsStorage(); return; } diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index c8bcc5128c3a..e753ce845ddc 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -926,7 +926,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba } Slog.i(TAG, "Enabling rollback for install of " + packageName + ", session:" + session.sessionId - + ", rollbackDataPolicy=" + rollbackDataPolicy); + + ", rollbackDataPolicy=" + rollbackDataPolicy + + ", rollbackId:" + rollback.info.getRollbackId() + + ", originalSessionId:" + rollback.getOriginalSessionId()); final String installerPackageName = session.getInstallerPackageName(); if (!enableRollbackAllowed(installerPackageName, packageName)) { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java index 64e62369f955..17b499e112bc 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java @@ -19,6 +19,7 @@ package com.android.server.locksettings; import static android.content.pm.UserInfo.FLAG_FULL; import static android.content.pm.UserInfo.FLAG_PRIMARY; import static android.content.pm.UserInfo.FLAG_PROFILE; +import static android.content.pm.UserInfo.NO_PROFILE_GROUP_ID; import static android.os.UserHandle.USER_SYSTEM; import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY; @@ -32,6 +33,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyByte; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; @@ -65,6 +67,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.widget.RebootEscrowListener; import com.android.server.locksettings.ResumeOnRebootServiceProvider.ResumeOnRebootServiceConnection; +import com.android.server.pm.UserManagerInternal; import org.junit.Before; import org.junit.Test; @@ -107,6 +110,7 @@ public class RebootEscrowManagerTests { private Context mContext; private UserManager mUserManager; + private UserManagerInternal mUserManagerInternal; private RebootEscrowManager.Callbacks mCallbacks; private IRebootEscrow mRebootEscrow; private ResumeOnRebootServiceConnection mServiceConnection; @@ -126,13 +130,15 @@ public class RebootEscrowManagerTests { long getCurrentTimeMillis(); void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount, - int escrowDurationInSeconds, int vbmetaDigestStatus, int durationSinceBootComplete); + int escrowDurationInSeconds, int vbmetaDigestStatus, + int durationSinceBootComplete); } static class MockInjector extends RebootEscrowManager.Injector { private final IRebootEscrow mRebootEscrow; private final RebootEscrowProviderInterface mDefaultRebootEscrowProvider; private final UserManager mUserManager; + private final UserManagerInternal mUserManagerInternal; private final MockableRebootEscrowInjected mInjected; private final RebootEscrowKeyStoreManager mKeyStoreManager; private boolean mServerBased; @@ -141,12 +147,16 @@ public class RebootEscrowManagerTests { private Consumer<ConnectivityManager.NetworkCallback> mNetworkConsumer; private boolean mWaitForInternet; - MockInjector(Context context, UserManager userManager, + MockInjector( + Context context, + UserManager userManager, + UserManagerInternal userManagerInternal, IRebootEscrow rebootEscrow, RebootEscrowKeyStoreManager keyStoreManager, LockSettingsStorageTestable storage, MockableRebootEscrowInjected injected) { - super(context, storage); + // TODO: change this + super(context, storage, userManagerInternal); mRebootEscrow = rebootEscrow; mServerBased = false; mWaitForInternet = false; @@ -159,16 +169,20 @@ public class RebootEscrowManagerTests { }; mDefaultRebootEscrowProvider = new RebootEscrowProviderHalImpl(halInjector); mUserManager = userManager; + mUserManagerInternal = userManagerInternal; mKeyStoreManager = keyStoreManager; mInjected = injected; } - MockInjector(Context context, UserManager userManager, + MockInjector( + Context context, + UserManager userManager, + UserManagerInternal userManagerInternal, ResumeOnRebootServiceConnection serviceConnection, RebootEscrowKeyStoreManager keyStoreManager, LockSettingsStorageTestable storage, MockableRebootEscrowInjected injected) { - super(context, storage); + super(context, storage, userManagerInternal); mRebootEscrow = null; mServerBased = true; mWaitForInternet = false; @@ -187,6 +201,7 @@ public class RebootEscrowManagerTests { mDefaultRebootEscrowProvider = new RebootEscrowProviderServerBasedImpl( storage, injector); mUserManager = userManager; + mUserManagerInternal = userManagerInternal; mKeyStoreManager = keyStoreManager; mInjected = injected; } @@ -202,6 +217,11 @@ public class RebootEscrowManagerTests { } @Override + public UserManagerInternal getUserManagerInternal() { + return mUserManagerInternal; + } + + @Override public boolean serverBasedResumeOnReboot() { return mServerBased; } @@ -289,8 +309,8 @@ public class RebootEscrowManagerTests { @Override public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount, - int escrowDurationInSeconds, int vbmetaDigestStatus, - int durationSinceBootComplete) { + int escrowDurationInSeconds, int vbmetaDigestStatus, + int durationSinceBootComplete) { mInjected.reportMetric(success, errorCode, serviceType, attemptCount, escrowDurationInSeconds, vbmetaDigestStatus, durationSinceBootComplete); @@ -301,6 +321,7 @@ public class RebootEscrowManagerTests { public void setUp_baseServices() throws Exception { mContext = new ContextWrapper(InstrumentationRegistry.getContext()); mUserManager = mock(UserManager.class); + mUserManagerInternal = mock(UserManagerInternal.class); mCallbacks = mock(RebootEscrowManager.Callbacks.class); mRebootEscrow = mock(IRebootEscrow.class); mServiceConnection = mock(ResumeOnRebootServiceConnection.class); @@ -314,28 +335,43 @@ public class RebootEscrowManagerTests { new File(InstrumentationRegistry.getContext().getFilesDir(), "locksettings")); ArrayList<UserInfo> users = new ArrayList<>(); - users.add(new UserInfo(PRIMARY_USER_ID, "primary", FLAG_PRIMARY)); - users.add(new UserInfo(WORK_PROFILE_USER_ID, "work", FLAG_PROFILE)); - users.add(new UserInfo(NONSECURE_SECONDARY_USER_ID, "non-secure", FLAG_FULL)); - users.add(new UserInfo(SECURE_SECONDARY_USER_ID, "secure", FLAG_FULL)); + users.add(createUser(PRIMARY_USER_ID, "primary", FLAG_PRIMARY, PRIMARY_USER_ID)); + users.add(createUser(WORK_PROFILE_USER_ID, "work", FLAG_PROFILE, PRIMARY_USER_ID)); + users.add( + createUser( + NONSECURE_SECONDARY_USER_ID, "non-secure", FLAG_FULL, NO_PROFILE_GROUP_ID)); + users.add(createUser(SECURE_SECONDARY_USER_ID, "secure", FLAG_FULL, NO_PROFILE_GROUP_ID)); when(mUserManager.getUsers()).thenReturn(users); when(mCallbacks.isUserSecure(PRIMARY_USER_ID)).thenReturn(true); when(mCallbacks.isUserSecure(WORK_PROFILE_USER_ID)).thenReturn(true); when(mCallbacks.isUserSecure(NONSECURE_SECONDARY_USER_ID)).thenReturn(false); when(mCallbacks.isUserSecure(SECURE_SECONDARY_USER_ID)).thenReturn(true); mInjected = mock(MockableRebootEscrowInjected.class); - mMockInjector = new MockInjector(mContext, mUserManager, mRebootEscrow, - mKeyStoreManager, mStorage, mInjected); + mMockInjector = + new MockInjector( + mContext, + mUserManager, + mUserManagerInternal, + mRebootEscrow, + mKeyStoreManager, + mStorage, + mInjected); HandlerThread thread = new HandlerThread("RebootEscrowManagerTest"); thread.start(); mHandler = new Handler(thread.getLooper()); mService = new RebootEscrowManager(mMockInjector, mCallbacks, mStorage, mHandler); - } private void setServerBasedRebootEscrowProvider() throws Exception { - mMockInjector = new MockInjector(mContext, mUserManager, mServiceConnection, - mKeyStoreManager, mStorage, mInjected); + mMockInjector = + new MockInjector( + mContext, + mUserManager, + mUserManagerInternal, + mServiceConnection, + mKeyStoreManager, + mStorage, + mInjected); mService = new RebootEscrowManager(mMockInjector, mCallbacks, mStorage, mHandler); } @@ -352,6 +388,12 @@ public class RebootEscrowManagerTests { waitForHandler(); } + private UserInfo createUser(int id, String name, int flag, int profileGroupId) { + UserInfo user = new UserInfo(id, name, flag); + when(mUserManagerInternal.getProfileParentId(eq(id))).thenReturn(profileGroupId); + return user; + } + @Test public void prepareRebootEscrow_Success() throws Exception { RebootEscrowListener mockListener = mock(RebootEscrowListener.class); @@ -559,6 +601,172 @@ public class RebootEscrowManagerTests { } @Test + public void loadRebootEscrowDataIfAvailable_noDataPrimaryUser_Failure() throws Exception { + setServerBasedRebootEscrowProvider(); + RebootEscrowListener mockListener = mock(RebootEscrowListener.class); + mService.setRebootEscrowListener(mockListener); + mService.prepareRebootEscrow(); + + clearInvocations(mServiceConnection); + + // escrow secondary user, don't escrow primary user + callToRebootEscrowIfNeededAndWait(SECURE_SECONDARY_USER_ID); + verify(mockListener).onPreparedForReboot(eq(true)); + verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); + + when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong())) + .thenAnswer(invocation -> invocation.getArgument(0)); + assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded()); + verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong()); + + assertTrue(mStorage.hasRebootEscrow(SECURE_SECONDARY_USER_ID)); + assertFalse(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); + assertTrue(mStorage.hasRebootEscrowServerBlob()); + + // pretend reboot happens here + when(mInjected.getBootCount()).thenReturn(1); + ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); + ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class); + doNothing() + .when(mInjected) + .reportMetric( + metricsSuccessCaptor.capture(), + metricsErrorCodeCaptor.capture(), + eq(2) /* Server based */, + eq(1) /* attempt count */, + anyInt(), + eq(0) /* vbmeta status */, + anyInt()); + mService.loadRebootEscrowDataIfAvailable(null); + verify(mServiceConnection, never()).unwrap(any(), anyLong()); + verify(mCallbacks, never()).onRebootEscrowRestored(anyByte(), any(), anyInt()); + assertFalse(metricsSuccessCaptor.getValue()); + assertEquals( + Integer.valueOf(RebootEscrowManager.ERROR_NO_REBOOT_ESCROW_DATA), + metricsErrorCodeCaptor.getValue()); + } + + @Test + public void loadRebootEscrowDataIfAvailable_noDataSecondaryUser_Success() throws Exception { + setServerBasedRebootEscrowProvider(); + RebootEscrowListener mockListener = mock(RebootEscrowListener.class); + mService.setRebootEscrowListener(mockListener); + mService.prepareRebootEscrow(); + + clearInvocations(mServiceConnection); + + // Setup work profile with secondary user as parent. + ArrayList<UserInfo> users = new ArrayList<>(); + users.add(createUser(PRIMARY_USER_ID, "primary", FLAG_PRIMARY, NO_PROFILE_GROUP_ID)); + users.add(createUser(WORK_PROFILE_USER_ID, "work", FLAG_PROFILE, SECURE_SECONDARY_USER_ID)); + users.add( + createUser( + SECURE_SECONDARY_USER_ID, "secure", FLAG_FULL, SECURE_SECONDARY_USER_ID)); + when(mUserManager.getUsers()).thenReturn(users); + + // escrow primary user and work profile, don't escrow secondary user + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); + verify(mockListener).onPreparedForReboot(eq(true)); + verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); + callToRebootEscrowIfNeededAndWait(WORK_PROFILE_USER_ID); + verify(mockListener).onPreparedForReboot(eq(true)); + verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); + + when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong())) + .thenAnswer(invocation -> invocation.getArgument(0)); + assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded()); + verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong()); + + assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); + assertFalse(mStorage.hasRebootEscrow(SECURE_SECONDARY_USER_ID)); + assertTrue(mStorage.hasRebootEscrow(WORK_PROFILE_USER_ID)); + assertTrue(mStorage.hasRebootEscrowServerBlob()); + + // pretend reboot happens here + when(mInjected.getBootCount()).thenReturn(1); + ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); + doNothing() + .when(mInjected) + .reportMetric( + metricsSuccessCaptor.capture(), + eq(0) /* error code */, + eq(2) /* Server based */, + eq(1) /* attempt count */, + anyInt(), + eq(0) /* vbmeta status */, + anyInt()); + when(mServiceConnection.unwrap(any(), anyLong())) + .thenAnswer(invocation -> invocation.getArgument(0)); + + mService.loadRebootEscrowDataIfAvailable(null); + + verify(mServiceConnection).unwrap(any(), anyLong()); + verify(mCallbacks).onRebootEscrowRestored(anyByte(), any(), eq(PRIMARY_USER_ID)); + verify(mCallbacks, never()) + .onRebootEscrowRestored(anyByte(), any(), eq(SECURE_SECONDARY_USER_ID)); + verify(mCallbacks, never()) + .onRebootEscrowRestored(anyByte(), any(), eq(WORK_PROFILE_USER_ID)); + verify(mCallbacks, never()) + .onRebootEscrowRestored(anyByte(), any(), eq(NONSECURE_SECONDARY_USER_ID)); + assertTrue(metricsSuccessCaptor.getValue()); + } + + @Test + public void loadRebootEscrowDataIfAvailable_noDataWorkProfile_Success() throws Exception { + setServerBasedRebootEscrowProvider(); + RebootEscrowListener mockListener = mock(RebootEscrowListener.class); + mService.setRebootEscrowListener(mockListener); + mService.prepareRebootEscrow(); + + clearInvocations(mServiceConnection); + + // escrow primary user and secondary user, don't escrow work profile + callToRebootEscrowIfNeededAndWait(PRIMARY_USER_ID); + verify(mockListener).onPreparedForReboot(eq(true)); + verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); + callToRebootEscrowIfNeededAndWait(SECURE_SECONDARY_USER_ID); + verify(mockListener).onPreparedForReboot(eq(true)); + verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); + + when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong())) + .thenAnswer(invocation -> invocation.getArgument(0)); + assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded()); + verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong()); + + assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); + assertTrue(mStorage.hasRebootEscrow(SECURE_SECONDARY_USER_ID)); + assertFalse(mStorage.hasRebootEscrow(WORK_PROFILE_USER_ID)); + assertTrue(mStorage.hasRebootEscrowServerBlob()); + + // pretend reboot happens here + when(mInjected.getBootCount()).thenReturn(1); + ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); + doNothing() + .when(mInjected) + .reportMetric( + metricsSuccessCaptor.capture(), + eq(0) /* error code */, + eq(2) /* Server based */, + eq(1) /* attempt count */, + anyInt(), + eq(0) /* vbmeta status */, + anyInt()); + when(mServiceConnection.unwrap(any(), anyLong())) + .thenAnswer(invocation -> invocation.getArgument(0)); + + mService.loadRebootEscrowDataIfAvailable(null); + + verify(mServiceConnection).unwrap(any(), anyLong()); + verify(mCallbacks).onRebootEscrowRestored(anyByte(), any(), eq(PRIMARY_USER_ID)); + verify(mCallbacks).onRebootEscrowRestored(anyByte(), any(), eq(SECURE_SECONDARY_USER_ID)); + verify(mCallbacks, never()) + .onRebootEscrowRestored(anyByte(), any(), eq(WORK_PROFILE_USER_ID)); + verify(mCallbacks, never()) + .onRebootEscrowRestored(anyByte(), any(), eq(NONSECURE_SECONDARY_USER_ID)); + assertTrue(metricsSuccessCaptor.getValue()); + } + + @Test public void loadRebootEscrowDataIfAvailable_ServerBased_Success() throws Exception { setServerBasedRebootEscrowProvider(); diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index a8b383cd4274..093923f3ed53 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -101,8 +101,8 @@ public class PackageWatchdogTest { private static final String OBSERVER_NAME_2 = "observer2"; private static final String OBSERVER_NAME_3 = "observer3"; private static final String OBSERVER_NAME_4 = "observer4"; - private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(10); - private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(50); + private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(1); + private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(5); @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -1453,8 +1453,7 @@ public class PackageWatchdogTest { raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN); - moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS - - TimeUnit.MINUTES.toMillis(1)); + moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS); // The first failure will be outside the threshold. raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, @@ -1713,9 +1712,6 @@ public class PackageWatchdogTest { watchdog.onPackageFailure(packages, failureReason); } mTestLooper.dispatchAll(); - if (Flags.recoverabilityDetection()) { - moveTimeForwardAndDispatch(watchdog.DEFAULT_MITIGATION_WINDOW_MS); - } } private PackageWatchdog createWatchdog() { |