Merge "Revisit the lifetime of the RebootEscrowProvider" am: d746cc814f

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1678645

Change-Id: I0c1c67e28ee46c7647c9ca07099f5476ed5c0877
This commit is contained in:
Tianjie Xu
2021-04-19 23:12:02 +00:00
committed by Automerger Merge Worker
2 changed files with 59 additions and 30 deletions

View File

@@ -205,6 +205,7 @@ class RebootEscrowManager {
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 {
Slog.i(TAG, "Using HAL based resume on reboot");
rebootEscrowProvider = new RebootEscrowProviderHalImpl(); rebootEscrowProvider = new RebootEscrowProviderHalImpl();
} }
@@ -239,7 +240,7 @@ class RebootEscrowManager {
return mKeyStoreManager; return mKeyStoreManager;
} }
public RebootEscrowProviderInterface getRebootEscrowProvider() { public RebootEscrowProviderInterface createRebootEscrowProviderIfNeeded() {
// Initialize for the provider lazily. Because the device_config and service // Initialize for the provider lazily. Because the device_config and service
// implementation apps may change when system server is running. // implementation apps may change when system server is running.
if (mRebootEscrowProvider == null) { if (mRebootEscrowProvider == null) {
@@ -249,6 +250,14 @@ class RebootEscrowManager {
return mRebootEscrowProvider; return mRebootEscrowProvider;
} }
public RebootEscrowProviderInterface getRebootEscrowProvider() {
return mRebootEscrowProvider;
}
public void clearRebootEscrowProvider() {
mRebootEscrowProvider = null;
}
public int getBootCount() { public int getBootCount() {
return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.BOOT_COUNT, return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.BOOT_COUNT,
0); 0);
@@ -308,8 +317,6 @@ class RebootEscrowManager {
mStorage.removeRebootEscrow(user.id); mStorage.removeRebootEscrow(user.id);
} }
// Clear the old key in keystore.
mKeyStoreManager.clearKeyStoreEncryptionKey();
onEscrowRestoreComplete(false, attemptCount); onEscrowRestoreComplete(false, attemptCount);
} }
@@ -395,9 +402,6 @@ class RebootEscrowManager {
allUsersUnlocked &= restoreRebootEscrowForUser(user.id, escrowKey, kk); allUsersUnlocked &= restoreRebootEscrowForUser(user.id, escrowKey, kk);
} }
// Clear the old key in keystore. A new key will be generated by new RoR requests.
mKeyStoreManager.clearKeyStoreEncryptionKey();
if (!allUsersUnlocked && mLoadEscrowDataErrorCode == ERROR_NONE) { if (!allUsersUnlocked && mLoadEscrowDataErrorCode == ERROR_NONE) {
mLoadEscrowDataErrorCode = ERROR_UNLOCK_ALL_USERS; mLoadEscrowDataErrorCode = ERROR_UNLOCK_ALL_USERS;
} }
@@ -473,11 +477,17 @@ class RebootEscrowManager {
if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) { if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) {
reportMetricOnRestoreComplete(success, attemptCount); reportMetricOnRestoreComplete(success, attemptCount);
} }
// Clear the old key in keystore. A new key will be generated by new RoR requests.
mKeyStoreManager.clearKeyStoreEncryptionKey();
// Clear the saved reboot escrow provider
mInjector.clearRebootEscrowProvider();
clearMetricsStorage(); clearMetricsStorage();
} }
private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) throws IOException { private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) throws IOException {
RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider(); RebootEscrowProviderInterface rebootEscrowProvider =
mInjector.createRebootEscrowProviderIfNeeded();
if (rebootEscrowProvider == null) { if (rebootEscrowProvider == null) {
Slog.w(TAG, Slog.w(TAG,
"Had reboot escrow data for users, but RebootEscrowProvider is unavailable"); "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
@@ -529,9 +539,8 @@ class RebootEscrowManager {
return; return;
} }
if (mInjector.getRebootEscrowProvider() == null) { if (mInjector.createRebootEscrowProviderIfNeeded() == null) {
Slog.w(TAG, Slog.w(TAG, "Not storing escrow data, RebootEscrowProvider is unavailable");
"Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
return; return;
} }
@@ -586,13 +595,17 @@ class RebootEscrowManager {
mRebootEscrowWanted = false; mRebootEscrowWanted = false;
setRebootEscrowReady(false); setRebootEscrowReady(false);
RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider(); // We want to clear the internal data inside the provider, so always try to create the
// provider.
RebootEscrowProviderInterface rebootEscrowProvider =
mInjector.createRebootEscrowProviderIfNeeded();
if (rebootEscrowProvider == null) { if (rebootEscrowProvider == null) {
Slog.w(TAG, "RebootEscrowProvider is unavailable for clear request"); Slog.w(TAG, "RebootEscrowProvider is unavailable for clear request");
} else { } else {
rebootEscrowProvider.clearRebootEscrowKey(); rebootEscrowProvider.clearRebootEscrowKey();
} }
mInjector.clearRebootEscrowProvider();
clearMetricsStorage(); clearMetricsStorage();
List<UserInfo> users = mUserManager.getUsers(); List<UserInfo> users = mUserManager.getUsers();
@@ -610,8 +623,7 @@ class RebootEscrowManager {
RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider(); RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
if (rebootEscrowProvider == null) { if (rebootEscrowProvider == null) {
Slog.w(TAG, Slog.w(TAG, "Not storing escrow key, RebootEscrowProvider is unavailable");
"Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
clearRebootEscrowIfNeeded(); clearRebootEscrowIfNeeded();
return ARM_REBOOT_ERROR_NO_PROVIDER; return ARM_REBOOT_ERROR_NO_PROVIDER;
} }
@@ -677,11 +689,12 @@ class RebootEscrowManager {
} }
boolean prepareRebootEscrow() { boolean prepareRebootEscrow() {
if (mInjector.getRebootEscrowProvider() == null) { clearRebootEscrowIfNeeded();
if (mInjector.createRebootEscrowProviderIfNeeded() == null) {
Slog.w(TAG, "No reboot escrow provider, skipping resume on reboot preparation.");
return false; return false;
} }
clearRebootEscrowIfNeeded();
mRebootEscrowWanted = true; mRebootEscrowWanted = true;
mEventLog.addEntry(RebootEscrowEvent.REQUESTED_LSKF); mEventLog.addEntry(RebootEscrowEvent.REQUESTED_LSKF);
return true; return true;
@@ -807,6 +820,10 @@ class RebootEscrowManager {
pw.print("mPendingRebootEscrowKey is "); pw.print("mPendingRebootEscrowKey is ");
pw.println(keySet ? "set" : "not set"); pw.println(keySet ? "set" : "not set");
RebootEscrowProviderInterface provider = mInjector.getRebootEscrowProvider();
String providerType = provider == null ? "null" : String.valueOf(provider.getType());
pw.print("RebootEscrowProvider type is " + providerType);
pw.println(); pw.println();
pw.println("Event log:"); pw.println("Event log:");
pw.increaseIndent(); pw.increaseIndent();

View File

@@ -112,14 +112,13 @@ public class RebootEscrowManagerTests {
private MockableRebootEscrowInjected mInjected; private MockableRebootEscrowInjected mInjected;
private RebootEscrowManager mService; private RebootEscrowManager mService;
private SecretKey mAesKey; private SecretKey mAesKey;
private MockInjector mMockInjector;
public interface MockableRebootEscrowInjected { public interface MockableRebootEscrowInjected {
int getBootCount(); int getBootCount();
long getCurrentTimeMillis(); long getCurrentTimeMillis();
boolean forceServerBased();
void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount, void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
int escrowDurationInSeconds, int vbmetaDigestStatus, int durationSinceBootComplete); int escrowDurationInSeconds, int vbmetaDigestStatus, int durationSinceBootComplete);
} }
@@ -127,11 +126,12 @@ public class RebootEscrowManagerTests {
static class MockInjector extends RebootEscrowManager.Injector { static class MockInjector extends RebootEscrowManager.Injector {
private final IRebootEscrow mRebootEscrow; private final IRebootEscrow mRebootEscrow;
private final ResumeOnRebootServiceConnection mServiceConnection; private final ResumeOnRebootServiceConnection mServiceConnection;
private final RebootEscrowProviderInterface mRebootEscrowProvider; private final RebootEscrowProviderInterface mDefaultRebootEscrowProvider;
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; private boolean mServerBased;
private RebootEscrowProviderInterface mRebootEscrowProviderInUse;
MockInjector(Context context, UserManager userManager, MockInjector(Context context, UserManager userManager,
IRebootEscrow rebootEscrow, IRebootEscrow rebootEscrow,
@@ -149,7 +149,7 @@ public class RebootEscrowManagerTests {
return mRebootEscrow; return mRebootEscrow;
} }
}; };
mRebootEscrowProvider = new RebootEscrowProviderHalImpl(halInjector); mDefaultRebootEscrowProvider = new RebootEscrowProviderHalImpl(halInjector);
mUserManager = userManager; mUserManager = userManager;
mKeyStoreManager = keyStoreManager; mKeyStoreManager = keyStoreManager;
mInjected = injected; mInjected = injected;
@@ -166,7 +166,8 @@ public class RebootEscrowManagerTests {
mServerBased = true; mServerBased = true;
RebootEscrowProviderServerBasedImpl.Injector injector = RebootEscrowProviderServerBasedImpl.Injector injector =
new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection); new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection);
mRebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(storage, injector); mDefaultRebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(
storage, injector);
mUserManager = userManager; mUserManager = userManager;
mKeyStoreManager = keyStoreManager; mKeyStoreManager = keyStoreManager;
mInjected = injected; mInjected = injected;
@@ -184,15 +185,23 @@ public class RebootEscrowManagerTests {
@Override @Override
public boolean serverBasedResumeOnReboot() { public boolean serverBasedResumeOnReboot() {
if (mInjected.forceServerBased()) {
return true;
}
return mServerBased; return mServerBased;
} }
@Override
public RebootEscrowProviderInterface createRebootEscrowProviderIfNeeded() {
mRebootEscrowProviderInUse = mDefaultRebootEscrowProvider;
return mRebootEscrowProviderInUse;
}
@Override @Override
public RebootEscrowProviderInterface getRebootEscrowProvider() { public RebootEscrowProviderInterface getRebootEscrowProvider() {
return mRebootEscrowProvider; return mRebootEscrowProviderInUse;
}
@Override
public void clearRebootEscrowProvider() {
mRebootEscrowProviderInUse = null;
} }
@Override @Override
@@ -264,13 +273,15 @@ public class RebootEscrowManagerTests {
when(mCallbacks.isUserSecure(NONSECURE_SECONDARY_USER_ID)).thenReturn(false); when(mCallbacks.isUserSecure(NONSECURE_SECONDARY_USER_ID)).thenReturn(false);
when(mCallbacks.isUserSecure(SECURE_SECONDARY_USER_ID)).thenReturn(true); when(mCallbacks.isUserSecure(SECURE_SECONDARY_USER_ID)).thenReturn(true);
mInjected = mock(MockableRebootEscrowInjected.class); mInjected = mock(MockableRebootEscrowInjected.class);
mService = new RebootEscrowManager(new MockInjector(mContext, mUserManager, mRebootEscrow, mMockInjector = new MockInjector(mContext, mUserManager, mRebootEscrow,
mKeyStoreManager, mStorage, mInjected), mCallbacks, mStorage); mKeyStoreManager, mStorage, mInjected);
mService = new RebootEscrowManager(mMockInjector, mCallbacks, mStorage);
} }
private void setServerBasedRebootEscrowProvider() throws Exception { private void setServerBasedRebootEscrowProvider() throws Exception {
mService = new RebootEscrowManager(new MockInjector(mContext, mUserManager, mMockInjector = new MockInjector(mContext, mUserManager, mServiceConnection,
mServiceConnection, mKeyStoreManager, mStorage, mInjected), mCallbacks, mStorage); mKeyStoreManager, mStorage, mInjected);
mService = new RebootEscrowManager(mMockInjector, mCallbacks, mStorage);
} }
@Test @Test
@@ -317,6 +328,7 @@ public class RebootEscrowManagerTests {
doThrow(ServiceSpecificException.class).when(mRebootEscrow).storeKey(any()); doThrow(ServiceSpecificException.class).when(mRebootEscrow).storeKey(any());
mService.clearRebootEscrow(); mService.clearRebootEscrow();
verify(mRebootEscrow).storeKey(eq(new byte[32])); verify(mRebootEscrow).storeKey(eq(new byte[32]));
assertNull(mMockInjector.getRebootEscrowProvider());
} }
@Test @Test
@@ -785,7 +797,7 @@ public class RebootEscrowManagerTests {
assertNull( assertNull(
mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM)); mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
// Change the provider to server based, expect the reboot to fail // Change the provider to server based, expect the reboot to fail
when(mInjected.forceServerBased()).thenReturn(true); mMockInjector.mServerBased = true;
assertEquals(ARM_REBOOT_ERROR_PROVIDER_MISMATCH, mService.armRebootEscrowIfNeeded()); assertEquals(ARM_REBOOT_ERROR_PROVIDER_MISMATCH, mService.armRebootEscrowIfNeeded());
assertNull( assertNull(
mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM)); mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));