Merge "Extend the metrics for resume on reboot" am: 1c5faf6141 am: f593e71276
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1556763 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: I8dbb655ca1511ab9a194c68171995b93fb95a24c
This commit is contained in:
@@ -64,6 +64,8 @@ class RebootEscrowManager {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static final String REBOOT_ESCROW_ARMED_KEY = "reboot_escrow_armed_count";
|
public static final String REBOOT_ESCROW_ARMED_KEY = "reboot_escrow_armed_count";
|
||||||
|
|
||||||
|
static final String REBOOT_ESCROW_KEY_ARMED_TIMESTAMP = "reboot_escrow_key_stored_timestamp";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of boots until we consider the escrow data to be stale for the purposes of metrics.
|
* Number of boots until we consider the escrow data to be stale for the purposes of metrics.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -144,8 +146,7 @@ class RebootEscrowManager {
|
|||||||
|
|
||||||
private RebootEscrowProviderInterface createRebootEscrowProvider() {
|
private RebootEscrowProviderInterface createRebootEscrowProvider() {
|
||||||
RebootEscrowProviderInterface rebootEscrowProvider;
|
RebootEscrowProviderInterface rebootEscrowProvider;
|
||||||
if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
|
if (serverBasedResumeOnReboot()) {
|
||||||
"server_based_ror_enabled", false)) {
|
|
||||||
Slog.i(TAG, "Using server based resume on reboot");
|
Slog.i(TAG, "Using server based resume on reboot");
|
||||||
rebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(mContext, mStorage);
|
rebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(mContext, mStorage);
|
||||||
} else {
|
} else {
|
||||||
@@ -166,6 +167,11 @@ class RebootEscrowManager {
|
|||||||
handler.postDelayed(runnable, delayMillis);
|
handler.postDelayed(runnable, delayMillis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean serverBasedResumeOnReboot() {
|
||||||
|
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
|
||||||
|
"server_based_ror_enabled", false);
|
||||||
|
}
|
||||||
|
|
||||||
public Context getContext() {
|
public Context getContext() {
|
||||||
return mContext;
|
return mContext;
|
||||||
}
|
}
|
||||||
@@ -204,10 +210,12 @@ class RebootEscrowManager {
|
|||||||
DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS);
|
DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reportMetric(boolean success) {
|
public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
|
||||||
// TODO(b/179105110) design error code; and report the true value for other fields.
|
int escrowDurationInSeconds, int vbmetaDigestStatus,
|
||||||
FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, 0, 1, 1,
|
int durationSinceBootCompleteInSeconds) {
|
||||||
-1, 0, -1);
|
FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, success,
|
||||||
|
errorCode, serviceType, attemptCount, escrowDurationInSeconds,
|
||||||
|
vbmetaDigestStatus, durationSinceBootCompleteInSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RebootEscrowEventLog getEventLog() {
|
public RebootEscrowEventLog getEventLog() {
|
||||||
@@ -230,7 +238,7 @@ class RebootEscrowManager {
|
|||||||
mKeyStoreManager = injector.getKeyStoreManager();
|
mKeyStoreManager = injector.getKeyStoreManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onGetRebootEscrowKeyFailed(List<UserInfo> users) {
|
private void onGetRebootEscrowKeyFailed(List<UserInfo> users, int attemptCount) {
|
||||||
Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage.");
|
Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage.");
|
||||||
for (UserInfo user : users) {
|
for (UserInfo user : users) {
|
||||||
mStorage.removeRebootEscrow(user.id);
|
mStorage.removeRebootEscrow(user.id);
|
||||||
@@ -238,7 +246,7 @@ class RebootEscrowManager {
|
|||||||
|
|
||||||
// Clear the old key in keystore.
|
// Clear the old key in keystore.
|
||||||
mKeyStoreManager.clearKeyStoreEncryptionKey();
|
mKeyStoreManager.clearKeyStoreEncryptionKey();
|
||||||
onEscrowRestoreComplete(false);
|
onEscrowRestoreComplete(false, attemptCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadRebootEscrowDataIfAvailable(Handler retryHandler) {
|
void loadRebootEscrowDataIfAvailable(Handler retryHandler) {
|
||||||
@@ -276,7 +284,7 @@ class RebootEscrowManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
|
Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
|
||||||
onGetRebootEscrowKeyFailed(users);
|
onGetRebootEscrowKeyFailed(users, attemptNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadRebootEscrowDataWithRetry(Handler retryHandler, int attemptNumber,
|
void loadRebootEscrowDataWithRetry(Handler retryHandler, int attemptNumber,
|
||||||
@@ -299,7 +307,7 @@ class RebootEscrowManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (escrowKey == null) {
|
if (escrowKey == null) {
|
||||||
onGetRebootEscrowKeyFailed(users);
|
onGetRebootEscrowKeyFailed(users, attemptNumber + 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,16 +321,35 @@ class RebootEscrowManager {
|
|||||||
// Clear the old key in keystore. A new key will be generated by new RoR requests.
|
// Clear the old key in keystore. A new key will be generated by new RoR requests.
|
||||||
mKeyStoreManager.clearKeyStoreEncryptionKey();
|
mKeyStoreManager.clearKeyStoreEncryptionKey();
|
||||||
|
|
||||||
onEscrowRestoreComplete(allUsersUnlocked);
|
onEscrowRestoreComplete(allUsersUnlocked, attemptNumber + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onEscrowRestoreComplete(boolean success) {
|
private void reportMetricOnRestoreComplete(boolean success, int attemptCount) {
|
||||||
|
int serviceType = mInjector.serverBasedResumeOnReboot()
|
||||||
|
? FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__SERVER_BASED
|
||||||
|
: FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__HAL;
|
||||||
|
|
||||||
|
long armedTimestamp = mStorage.getLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, -1,
|
||||||
|
USER_SYSTEM);
|
||||||
|
mStorage.removeKey(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, USER_SYSTEM);
|
||||||
|
int escrowDurationInSeconds = armedTimestamp != -1
|
||||||
|
? (int) (System.currentTimeMillis() - armedTimestamp) / 1000 : -1;
|
||||||
|
|
||||||
|
// TODO(b/179105110) design error code; and report the true value for other fields.
|
||||||
|
int vbmetaDigestStatus = FrameworkStatsLog
|
||||||
|
.REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT;
|
||||||
|
|
||||||
|
mInjector.reportMetric(success, 0 /* error code */, serviceType, attemptCount,
|
||||||
|
escrowDurationInSeconds, vbmetaDigestStatus, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onEscrowRestoreComplete(boolean success, int attemptCount) {
|
||||||
int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, -1, USER_SYSTEM);
|
int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, -1, USER_SYSTEM);
|
||||||
mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
|
mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
|
||||||
|
|
||||||
int bootCountDelta = mInjector.getBootCount() - previousBootCount;
|
int bootCountDelta = mInjector.getBootCount() - previousBootCount;
|
||||||
if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) {
|
if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) {
|
||||||
mInjector.reportMetric(success);
|
reportMetricOnRestoreComplete(success, attemptCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,6 +505,8 @@ class RebootEscrowManager {
|
|||||||
boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, kk);
|
boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, kk);
|
||||||
if (armedRebootEscrow) {
|
if (armedRebootEscrow) {
|
||||||
mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
|
mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
|
||||||
|
mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, System.currentTimeMillis(),
|
||||||
|
USER_SYSTEM);
|
||||||
mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS);
|
mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import static org.junit.Assert.assertNotNull;
|
|||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.clearInvocations;
|
import static org.mockito.Mockito.clearInvocations;
|
||||||
@@ -109,7 +110,8 @@ public class RebootEscrowManagerTests {
|
|||||||
public interface MockableRebootEscrowInjected {
|
public interface MockableRebootEscrowInjected {
|
||||||
int getBootCount();
|
int getBootCount();
|
||||||
|
|
||||||
void reportMetric(boolean success);
|
void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
|
||||||
|
int escrowDurationInSeconds, int vbmetaDigestStatus, int durationSinceBootComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MockInjector extends RebootEscrowManager.Injector {
|
static class MockInjector extends RebootEscrowManager.Injector {
|
||||||
@@ -119,6 +121,7 @@ public class RebootEscrowManagerTests {
|
|||||||
private final UserManager mUserManager;
|
private final UserManager mUserManager;
|
||||||
private final MockableRebootEscrowInjected mInjected;
|
private final MockableRebootEscrowInjected mInjected;
|
||||||
private final RebootEscrowKeyStoreManager mKeyStoreManager;
|
private final RebootEscrowKeyStoreManager mKeyStoreManager;
|
||||||
|
private final boolean mServerBased;
|
||||||
|
|
||||||
MockInjector(Context context, UserManager userManager,
|
MockInjector(Context context, UserManager userManager,
|
||||||
IRebootEscrow rebootEscrow,
|
IRebootEscrow rebootEscrow,
|
||||||
@@ -128,6 +131,7 @@ public class RebootEscrowManagerTests {
|
|||||||
super(context, storage);
|
super(context, storage);
|
||||||
mRebootEscrow = rebootEscrow;
|
mRebootEscrow = rebootEscrow;
|
||||||
mServiceConnection = null;
|
mServiceConnection = null;
|
||||||
|
mServerBased = false;
|
||||||
RebootEscrowProviderHalImpl.Injector halInjector =
|
RebootEscrowProviderHalImpl.Injector halInjector =
|
||||||
new RebootEscrowProviderHalImpl.Injector() {
|
new RebootEscrowProviderHalImpl.Injector() {
|
||||||
@Override
|
@Override
|
||||||
@@ -149,6 +153,7 @@ public class RebootEscrowManagerTests {
|
|||||||
super(context, storage);
|
super(context, storage);
|
||||||
mServiceConnection = serviceConnection;
|
mServiceConnection = serviceConnection;
|
||||||
mRebootEscrow = null;
|
mRebootEscrow = null;
|
||||||
|
mServerBased = true;
|
||||||
RebootEscrowProviderServerBasedImpl.Injector injector =
|
RebootEscrowProviderServerBasedImpl.Injector injector =
|
||||||
new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection);
|
new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection);
|
||||||
mRebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(storage, injector);
|
mRebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(storage, injector);
|
||||||
@@ -167,6 +172,11 @@ public class RebootEscrowManagerTests {
|
|||||||
return mUserManager;
|
return mUserManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean serverBasedResumeOnReboot() {
|
||||||
|
return mServerBased;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RebootEscrowProviderInterface getRebootEscrowProvider() {
|
public RebootEscrowProviderInterface getRebootEscrowProvider() {
|
||||||
return mRebootEscrowProvider;
|
return mRebootEscrowProvider;
|
||||||
@@ -195,8 +205,11 @@ public class RebootEscrowManagerTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reportMetric(boolean success) {
|
public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
|
||||||
mInjected.reportMetric(success);
|
int escrowDurationInSeconds, int vbmetaDigestStatus,
|
||||||
|
int durationSinceBootComplete) {
|
||||||
|
mInjected.reportMetric(success, errorCode, serviceType, attemptCount,
|
||||||
|
escrowDurationInSeconds, vbmetaDigestStatus, durationSinceBootComplete);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,7 +431,9 @@ public class RebootEscrowManagerTests {
|
|||||||
|
|
||||||
when(mInjected.getBootCount()).thenReturn(1);
|
when(mInjected.getBootCount()).thenReturn(1);
|
||||||
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
|
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
|
||||||
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
|
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
|
||||||
|
eq(0) /* error code */, eq(1) /* HAL based */, eq(1) /* attempt count */,
|
||||||
|
anyInt(), anyInt(), anyInt());
|
||||||
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
|
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
|
||||||
|
|
||||||
mService.loadRebootEscrowDataIfAvailable(null);
|
mService.loadRebootEscrowDataIfAvailable(null);
|
||||||
@@ -451,7 +466,9 @@ public class RebootEscrowManagerTests {
|
|||||||
// pretend reboot happens here
|
// pretend reboot happens here
|
||||||
when(mInjected.getBootCount()).thenReturn(1);
|
when(mInjected.getBootCount()).thenReturn(1);
|
||||||
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
|
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
|
||||||
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
|
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
|
||||||
|
eq(0) /* error code */, eq(2) /* Server based */, eq(1) /* attempt count */,
|
||||||
|
anyInt(), anyInt(), anyInt());
|
||||||
|
|
||||||
when(mServiceConnection.unwrap(any(), anyLong()))
|
when(mServiceConnection.unwrap(any(), anyLong()))
|
||||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||||
@@ -485,7 +502,8 @@ public class RebootEscrowManagerTests {
|
|||||||
// pretend reboot happens here
|
// pretend reboot happens here
|
||||||
when(mInjected.getBootCount()).thenReturn(1);
|
when(mInjected.getBootCount()).thenReturn(1);
|
||||||
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
|
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
|
||||||
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
|
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
|
||||||
|
anyInt(), anyInt(), eq(2) /* attempt count */, anyInt(), anyInt(), anyInt());
|
||||||
|
|
||||||
when(mServiceConnection.unwrap(any(), anyLong()))
|
when(mServiceConnection.unwrap(any(), anyLong()))
|
||||||
.thenThrow(new IOException())
|
.thenThrow(new IOException())
|
||||||
@@ -528,7 +546,8 @@ public class RebootEscrowManagerTests {
|
|||||||
|
|
||||||
mService.loadRebootEscrowDataIfAvailable(null);
|
mService.loadRebootEscrowDataIfAvailable(null);
|
||||||
verify(mRebootEscrow).retrieveKey();
|
verify(mRebootEscrow).retrieveKey();
|
||||||
verify(mInjected, never()).reportMetric(anyBoolean());
|
verify(mInjected, never()).reportMetric(anyBoolean(), anyInt(), anyInt(), anyInt(),
|
||||||
|
anyInt(), anyInt(), anyInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -554,7 +573,8 @@ public class RebootEscrowManagerTests {
|
|||||||
when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
|
when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
|
||||||
|
|
||||||
mService.loadRebootEscrowDataIfAvailable(null);
|
mService.loadRebootEscrowDataIfAvailable(null);
|
||||||
verify(mInjected, never()).reportMetric(anyBoolean());
|
verify(mInjected, never()).reportMetric(anyBoolean(), anyInt(), anyInt(), anyInt(),
|
||||||
|
anyInt(), anyInt(), anyInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -588,7 +608,8 @@ public class RebootEscrowManagerTests {
|
|||||||
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
|
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
|
||||||
|
|
||||||
mService.loadRebootEscrowDataIfAvailable(null);
|
mService.loadRebootEscrowDataIfAvailable(null);
|
||||||
verify(mInjected).reportMetric(eq(true));
|
verify(mInjected).reportMetric(eq(true), eq(0) /* error code */, eq(1) /* HAL based */,
|
||||||
|
eq(1) /* attempt count */, anyInt(), anyInt(), anyInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -615,7 +636,9 @@ public class RebootEscrowManagerTests {
|
|||||||
|
|
||||||
when(mInjected.getBootCount()).thenReturn(1);
|
when(mInjected.getBootCount()).thenReturn(1);
|
||||||
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
|
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
|
||||||
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
|
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
|
||||||
|
anyInt() /* error code */, eq(1) /* HAL based */, eq(1) /* attempt count */,
|
||||||
|
anyInt(), anyInt(), anyInt());
|
||||||
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> new byte[32]);
|
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> new byte[32]);
|
||||||
mService.loadRebootEscrowDataIfAvailable(null);
|
mService.loadRebootEscrowDataIfAvailable(null);
|
||||||
verify(mRebootEscrow).retrieveKey();
|
verify(mRebootEscrow).retrieveKey();
|
||||||
|
|||||||
Reference in New Issue
Block a user