From 1eb8ead904026376076cd1972493139fe8111824 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Tue, 3 Mar 2020 11:00:24 -0800 Subject: [PATCH] RebootEscrowManager: always report success metric In the process of OTAing from a build that does not have the armed status marker, all metrics are going to be lost. Since a success is a sure indication that reboot escrow was prepared before reboot, then we should mark it as a success always. On the other side, a failure could be a manual reboot if we did not have the armed marker. (cherry picked from commit bdb3cdc49741b0eff3ebc138f1771baae17638c5) Bug: 149833390 Test: atest RebootEscrowManagerTests Merged-In: Iaa179039eb7f587a6596a70176d42761e09b0fac Change-Id: Iaa179039eb7f587a6596a70176d42761e09b0fac --- .../locksettings/RebootEscrowManager.java | 8 +-- .../RebootEscrowManagerTests.java | 64 ++++++++++++++++++- 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java index 351dd6ed3d3d5..dabf886706399 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java @@ -181,15 +181,13 @@ class RebootEscrowManager { } private void onEscrowRestoreComplete(boolean success) { - int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, 0, USER_SYSTEM); + int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, -1, USER_SYSTEM); mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM); int bootCountDelta = mInjector.getBootCount() - previousBootCount; - if (bootCountDelta > BOOT_COUNT_TOLERANCE) { - return; + if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) { + mInjector.reportMetric(success); } - - mInjector.reportMetric(success); } private RebootEscrowKey getAndClearRebootEscrowKey() { 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 1cf8525eecdd3..4127fece17bd8 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java @@ -293,9 +293,8 @@ public class RebootEscrowManagerTests { verify(mRebootEscrow, never()).storeKey(any()); - ArgumentCaptor keyByteCaptor = ArgumentCaptor.forClass(byte[].class); assertTrue(mService.armRebootEscrowIfNeeded()); - verify(mRebootEscrow).storeKey(keyByteCaptor.capture()); + verify(mRebootEscrow).storeKey(any()); assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); assertFalse(mStorage.hasRebootEscrow(NONSECURE_SECONDARY_USER_ID)); @@ -303,13 +302,72 @@ public class RebootEscrowManagerTests { // pretend reboot happens here when(mInjected.getBootCount()).thenReturn(10); - when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue()); + when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]); mService.loadRebootEscrowDataIfAvailable(); verify(mRebootEscrow).retrieveKey(); verify(mInjected, never()).reportMetric(anyBoolean()); } + @Test + public void loadRebootEscrowDataIfAvailable_ManualReboot_Failure_NoMetrics() throws Exception { + when(mInjected.getBootCount()).thenReturn(0); + + RebootEscrowListener mockListener = mock(RebootEscrowListener.class); + mService.setRebootEscrowListener(mockListener); + mService.prepareRebootEscrow(); + + clearInvocations(mRebootEscrow); + mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + verify(mockListener).onPreparedForReboot(eq(true)); + + verify(mRebootEscrow, never()).storeKey(any()); + + assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); + assertFalse(mStorage.hasRebootEscrow(NONSECURE_SECONDARY_USER_ID)); + + // pretend reboot happens here + + when(mInjected.getBootCount()).thenReturn(10); + when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]); + + mService.loadRebootEscrowDataIfAvailable(); + verify(mInjected, never()).reportMetric(anyBoolean()); + } + + @Test + public void loadRebootEscrowDataIfAvailable_OTAFromBeforeArmedStatus_SuccessMetrics() + throws Exception { + when(mInjected.getBootCount()).thenReturn(0); + + RebootEscrowListener mockListener = mock(RebootEscrowListener.class); + mService.setRebootEscrowListener(mockListener); + mService.prepareRebootEscrow(); + + clearInvocations(mRebootEscrow); + mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + verify(mockListener).onPreparedForReboot(eq(true)); + + verify(mRebootEscrow, never()).storeKey(any()); + + ArgumentCaptor keyByteCaptor = ArgumentCaptor.forClass(byte[].class); + assertTrue(mService.armRebootEscrowIfNeeded()); + verify(mRebootEscrow).storeKey(keyByteCaptor.capture()); + + assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); + assertFalse(mStorage.hasRebootEscrow(NONSECURE_SECONDARY_USER_ID)); + + // Delete key to simulate old version that didn't have it. + mStorage.removeKey(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM); + + // pretend reboot happens here + + when(mInjected.getBootCount()).thenReturn(10); + when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue()); + + mService.loadRebootEscrowDataIfAvailable(); + verify(mInjected).reportMetric(eq(true)); + } @Test public void loadRebootEscrowDataIfAvailable_RestoreUnsuccessful_Failure() throws Exception {