1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.locksettings;
18 
19 import static android.os.UserHandle.USER_SYSTEM;
20 
21 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY;
22 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_KEYSTORE_FAILURE;
23 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;
24 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_ESCROW_KEY;
25 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_PROVIDER;
26 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH;
27 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_STORE_ESCROW_KEY;
28 import static com.android.internal.widget.LockSettingsInternal.ArmRebootEscrowErrorCode;
29 
30 import android.annotation.IntDef;
31 import android.annotation.NonNull;
32 import android.annotation.UserIdInt;
33 import android.content.Context;
34 import android.content.pm.PackageManager;
35 import android.content.pm.UserInfo;
36 import android.net.ConnectivityManager;
37 import android.net.Network;
38 import android.net.NetworkCapabilities;
39 import android.net.NetworkRequest;
40 import android.os.Handler;
41 import android.os.PowerManager;
42 import android.os.SystemClock;
43 import android.os.SystemProperties;
44 import android.os.UserManager;
45 import android.provider.DeviceConfig;
46 import android.provider.Settings;
47 import android.util.Slog;
48 
49 import com.android.internal.annotations.GuardedBy;
50 import com.android.internal.annotations.VisibleForTesting;
51 import com.android.internal.util.FrameworkStatsLog;
52 import com.android.internal.util.IndentingPrintWriter;
53 import com.android.internal.widget.RebootEscrowListener;
54 import com.android.server.pm.UserManagerInternal;
55 
56 import java.io.IOException;
57 import java.lang.annotation.Retention;
58 import java.lang.annotation.RetentionPolicy;
59 import java.text.SimpleDateFormat;
60 import java.util.ArrayList;
61 import java.util.Collections;
62 import java.util.Date;
63 import java.util.HashSet;
64 import java.util.List;
65 import java.util.Locale;
66 import java.util.Objects;
67 import java.util.Set;
68 
69 import javax.crypto.SecretKey;
70 
71 /**
72  * This class aims to persists the synthetic password(SP) across reboot in a secure way. In
73  * particular, it manages the encryption of the sp before reboot, and decryption of the sp after
74  * reboot. Here are the meaning of some terms.
75  *   SP: synthetic password
76  *   K_s: The RebootEscrowKey, i.e. AES-GCM key stored in memory
77  *   K_k: AES-GCM key in android keystore
78  *   RebootEscrowData: The synthetic password and its encrypted blob. We encrypt SP with K_s first,
79  *      then with K_k, i.e. E(K_k, E(K_s, SP))
80  */
81 class RebootEscrowManager {
82     private static final String TAG = "RebootEscrowManager";
83 
84     /**
85      * Used in the database storage to indicate the boot count at which the reboot escrow was
86      * previously armed.
87      */
88     @VisibleForTesting
89     public static final String REBOOT_ESCROW_ARMED_KEY = "reboot_escrow_armed_count";
90 
91     static final String REBOOT_ESCROW_KEY_ARMED_TIMESTAMP = "reboot_escrow_key_stored_timestamp";
92     static final String REBOOT_ESCROW_KEY_PROVIDER = "reboot_escrow_key_provider";
93 
94     /**
95      * The verified boot 2.0 vbmeta digest of the current slot, the property value is always
96      * available after boot.
97      */
98     static final String VBMETA_DIGEST_PROP_NAME = "ro.boot.vbmeta.digest";
99     /**
100      * The system prop contains vbmeta digest of the inactive slot. The build property is set after
101      * an OTA update. RebootEscrowManager will store it in disk before the OTA reboot, so the value
102      * is available for vbmeta digest verification after the device reboots.
103      */
104     static final String OTHER_VBMETA_DIGEST_PROP_NAME = "ota.other.vbmeta_digest";
105     static final String REBOOT_ESCROW_KEY_VBMETA_DIGEST = "reboot_escrow_key_vbmeta_digest";
106     static final String REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST =
107             "reboot_escrow_key_other_vbmeta_digest";
108 
109     /**
110      * Number of boots until we consider the escrow data to be stale for the purposes of metrics.
111      *
112      * <p>If the delta between the current boot number and the boot number stored when the mechanism
113      * was armed is under this number and the escrow mechanism fails, we report it as a failure of
114      * the mechanism.
115      *
116      * <p>If the delta over this number and escrow fails, we will not report the metric as failed
117      * since there most likely was some other issue if the device rebooted several times before
118      * getting to the escrow restore code.
119      */
120     private static final int BOOT_COUNT_TOLERANCE = 5;
121 
122     /**
123      * The default retry specs for loading reboot escrow data. We will attempt to retry loading
124      * escrow data on temporarily errors, e.g. unavailable network.
125      */
126     private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT = 3;
127     private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS = 30;
128 
129     // 3 minutes. It's enough for the default 3 retries with 30 seconds interval
130     private static final int DEFAULT_LOAD_ESCROW_BASE_TIMEOUT_MILLIS = 180_000;
131     // 5 seconds. An extension of the overall RoR timeout to account for overhead.
132     private static final int DEFAULT_LOAD_ESCROW_TIMEOUT_EXTENSION_MILLIS = 5000;
133 
134     @IntDef(prefix = {"ERROR_"}, value = {
135             ERROR_NONE,
136             ERROR_UNKNOWN,
137             ERROR_NO_PROVIDER,
138             ERROR_LOAD_ESCROW_KEY,
139             ERROR_RETRY_COUNT_EXHAUSTED,
140             ERROR_UNLOCK_ALL_USERS,
141             ERROR_PROVIDER_MISMATCH,
142             ERROR_KEYSTORE_FAILURE,
143             ERROR_NO_NETWORK,
144             ERROR_TIMEOUT_EXHAUSTED,
145             ERROR_NO_REBOOT_ESCROW_DATA,
146     })
147     @Retention(RetentionPolicy.SOURCE)
148     @interface RebootEscrowErrorCode {
149     }
150 
151     static final int ERROR_NONE = 0;
152     static final int ERROR_UNKNOWN = 1;
153     static final int ERROR_NO_PROVIDER = 2;
154     static final int ERROR_LOAD_ESCROW_KEY = 3;
155     static final int ERROR_RETRY_COUNT_EXHAUSTED = 4;
156     static final int ERROR_UNLOCK_ALL_USERS = 5;
157     static final int ERROR_PROVIDER_MISMATCH = 6;
158     static final int ERROR_KEYSTORE_FAILURE = 7;
159     static final int ERROR_NO_NETWORK = 8;
160     static final int ERROR_TIMEOUT_EXHAUSTED = 9;
161     static final int ERROR_NO_REBOOT_ESCROW_DATA = 10;
162 
163     private @RebootEscrowErrorCode int mLoadEscrowDataErrorCode = ERROR_NONE;
164 
165     /**
166      * Logs events for later debugging in bugreports.
167      */
168     private final RebootEscrowEventLog mEventLog;
169 
170     /**
171      * Used to track when the reboot escrow is wanted. Should stay true once escrow is requested
172      * unless clearRebootEscrow is called. This will allow all the active users to be unlocked
173      * after reboot.
174      */
175     private boolean mRebootEscrowWanted;
176 
177     /** Used to track when reboot escrow is ready. */
178     private boolean mRebootEscrowReady;
179 
180     /** Notified when mRebootEscrowReady changes. */
181     private RebootEscrowListener mRebootEscrowListener;
182 
183     /** Set when unlocking reboot escrow times out. */
184     private boolean mRebootEscrowTimedOut = false;
185 
186     /**
187      * Set when {@link #loadRebootEscrowDataWithRetry} is called to ensure the function is only
188      * called once.
189      */
190     private boolean mLoadEscrowDataWithRetry = false;
191 
192     /**
193      * Hold this lock when checking or generating the reboot escrow key.
194      */
195     private final Object mKeyGenerationLock = new Object();
196 
197     /**
198      * Stores the reboot escrow data between when it's supplied and when
199      * {@link #armRebootEscrowIfNeeded()} is called.
200      */
201     @GuardedBy("mKeyGenerationLock")
202     private RebootEscrowKey mPendingRebootEscrowKey;
203 
204     private final UserManager mUserManager;
205 
206     private final Injector mInjector;
207 
208     private final LockSettingsStorage mStorage;
209 
210     private final Callbacks mCallbacks;
211 
212     private final RebootEscrowKeyStoreManager mKeyStoreManager;
213 
214     private final Handler mHandler;
215 
216     PowerManager.WakeLock mWakeLock;
217 
218     private ConnectivityManager.NetworkCallback mNetworkCallback;
219 
220     interface Callbacks {
isUserSecure(int userId)221         boolean isUserSecure(int userId);
222 
onRebootEscrowRestored(byte spVersion, byte[] syntheticPassword, int userId)223         void onRebootEscrowRestored(byte spVersion, byte[] syntheticPassword, int userId);
224     }
225 
226     static class Injector {
227         protected Context mContext;
228         private final RebootEscrowKeyStoreManager mKeyStoreManager;
229         private final LockSettingsStorage mStorage;
230         private RebootEscrowProviderInterface mRebootEscrowProvider;
231         private final UserManagerInternal mUserManagerInternal;
232 
Injector( Context context, LockSettingsStorage storage, UserManagerInternal userManagerInternal)233         Injector(
234                 Context context,
235                 LockSettingsStorage storage,
236                 UserManagerInternal userManagerInternal) {
237             mContext = context;
238             mStorage = storage;
239             mKeyStoreManager = new RebootEscrowKeyStoreManager();
240             mUserManagerInternal = userManagerInternal;
241         }
242 
createRebootEscrowProvider()243         private RebootEscrowProviderInterface createRebootEscrowProvider() {
244             RebootEscrowProviderInterface rebootEscrowProvider;
245             if (serverBasedResumeOnReboot()) {
246                 Slog.i(TAG, "Using server based resume on reboot");
247                 rebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(mContext, mStorage);
248             } else {
249                 Slog.i(TAG, "Using HAL based resume on reboot");
250                 rebootEscrowProvider = new RebootEscrowProviderHalImpl();
251             }
252 
253             if (rebootEscrowProvider.hasRebootEscrowSupport()) {
254                 return rebootEscrowProvider;
255             }
256             return null;
257         }
258 
post(Handler handler, Runnable runnable)259         void post(Handler handler, Runnable runnable) {
260             handler.post(runnable);
261         }
262 
postDelayed(Handler handler, Runnable runnable, long delayMillis)263         void postDelayed(Handler handler, Runnable runnable, long delayMillis) {
264             handler.postDelayed(runnable, delayMillis);
265         }
266 
serverBasedResumeOnReboot()267         public boolean serverBasedResumeOnReboot() {
268             // Always use the server based RoR if the HAL isn't installed on device.
269             if (!mContext.getPackageManager().hasSystemFeature(
270                     PackageManager.FEATURE_REBOOT_ESCROW)) {
271                 return true;
272             }
273 
274             return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
275                     "server_based_ror_enabled", false);
276         }
277 
waitForInternet()278         public boolean waitForInternet() {
279             return DeviceConfig.getBoolean(
280                     DeviceConfig.NAMESPACE_OTA, "wait_for_internet_ror", false);
281         }
282 
isNetworkConnected()283         public boolean isNetworkConnected() {
284             final ConnectivityManager connectivityManager =
285                     mContext.getSystemService(ConnectivityManager.class);
286             if (connectivityManager == null) {
287                 return false;
288             }
289 
290             Network activeNetwork = connectivityManager.getActiveNetwork();
291             NetworkCapabilities networkCapabilities =
292                     connectivityManager.getNetworkCapabilities(activeNetwork);
293             return networkCapabilities != null
294                     && networkCapabilities.hasCapability(
295                             NetworkCapabilities.NET_CAPABILITY_INTERNET)
296                     && networkCapabilities.hasCapability(
297                             NetworkCapabilities.NET_CAPABILITY_VALIDATED);
298         }
299 
300         /**
301          * Request network with internet connectivity with timeout.
302          *
303          * @param networkCallback callback to be executed if connectivity manager exists.
304          * @return true if success
305          */
requestNetworkWithInternet( ConnectivityManager.NetworkCallback networkCallback)306         public boolean requestNetworkWithInternet(
307                 ConnectivityManager.NetworkCallback networkCallback) {
308             final ConnectivityManager connectivityManager =
309                     mContext.getSystemService(ConnectivityManager.class);
310             if (connectivityManager == null) {
311                 return false;
312             }
313             NetworkRequest request =
314                     new NetworkRequest.Builder()
315                             .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
316                             .build();
317 
318             connectivityManager.requestNetwork(
319                     request, networkCallback, getLoadEscrowTimeoutMillis());
320             return true;
321         }
322 
stopRequestingNetwork(ConnectivityManager.NetworkCallback networkCallback)323         public void stopRequestingNetwork(ConnectivityManager.NetworkCallback networkCallback) {
324             final ConnectivityManager connectivityManager =
325                     mContext.getSystemService(ConnectivityManager.class);
326             if (connectivityManager == null) {
327                 return;
328             }
329             connectivityManager.unregisterNetworkCallback(networkCallback);
330         }
331 
getContext()332         public Context getContext() {
333             return mContext;
334         }
335 
getUserManager()336         public UserManager getUserManager() {
337             return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
338         }
339 
getUserManagerInternal()340         public UserManagerInternal getUserManagerInternal() {
341             return mUserManagerInternal;
342         }
343 
getKeyStoreManager()344         public RebootEscrowKeyStoreManager getKeyStoreManager() {
345             return mKeyStoreManager;
346         }
347 
createRebootEscrowProviderIfNeeded()348         public RebootEscrowProviderInterface createRebootEscrowProviderIfNeeded() {
349             // Initialize for the provider lazily. Because the device_config and service
350             // implementation apps may change when system server is running.
351             if (mRebootEscrowProvider == null) {
352                 mRebootEscrowProvider = createRebootEscrowProvider();
353             }
354 
355             return mRebootEscrowProvider;
356         }
357 
getWakeLock()358         PowerManager.WakeLock getWakeLock() {
359             final PowerManager pm = mContext.getSystemService(PowerManager.class);
360             return pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "RebootEscrowManager");
361         }
362 
getRebootEscrowProvider()363         public RebootEscrowProviderInterface getRebootEscrowProvider() {
364             return mRebootEscrowProvider;
365         }
366 
clearRebootEscrowProvider()367         public void clearRebootEscrowProvider() {
368             mRebootEscrowProvider = null;
369         }
370 
getBootCount()371         public int getBootCount() {
372             return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.BOOT_COUNT,
373                     0);
374         }
375 
getCurrentTimeMillis()376         public long getCurrentTimeMillis() {
377             return System.currentTimeMillis();
378         }
379 
getLoadEscrowDataRetryLimit()380         public int getLoadEscrowDataRetryLimit() {
381             return DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
382                     "load_escrow_data_retry_count", DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT);
383         }
384 
getLoadEscrowDataRetryIntervalSeconds()385         public int getLoadEscrowDataRetryIntervalSeconds() {
386             return DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
387                     "load_escrow_data_retry_interval_seconds",
388                     DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS);
389         }
390 
391         @VisibleForTesting
getLoadEscrowTimeoutMillis()392         public int getLoadEscrowTimeoutMillis() {
393             return DEFAULT_LOAD_ESCROW_BASE_TIMEOUT_MILLIS;
394         }
395 
396         @VisibleForTesting
getWakeLockTimeoutMillis()397         public int getWakeLockTimeoutMillis() {
398             return getLoadEscrowTimeoutMillis() + DEFAULT_LOAD_ESCROW_TIMEOUT_EXTENSION_MILLIS;
399         }
400 
reportMetric(boolean success, int errorCode, int serviceType, int attemptCount, int escrowDurationInSeconds, int vbmetaDigestStatus, int durationSinceBootCompleteInSeconds)401         public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
402                 int escrowDurationInSeconds, int vbmetaDigestStatus,
403                 int durationSinceBootCompleteInSeconds) {
404             FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, success,
405                     errorCode, serviceType, attemptCount, escrowDurationInSeconds,
406                     vbmetaDigestStatus, durationSinceBootCompleteInSeconds);
407         }
408 
getEventLog()409         public RebootEscrowEventLog getEventLog() {
410             return new RebootEscrowEventLog();
411         }
412 
getVbmetaDigest(boolean other)413         public String getVbmetaDigest(boolean other) {
414             return other ? SystemProperties.get(OTHER_VBMETA_DIGEST_PROP_NAME)
415                     : SystemProperties.get(VBMETA_DIGEST_PROP_NAME);
416         }
417     }
418 
RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage, Handler handler, UserManagerInternal userManagerInternal)419     RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage,
420                         Handler handler, UserManagerInternal userManagerInternal) {
421         this(new Injector(context, storage, userManagerInternal), callbacks, storage, handler);
422     }
423 
424     @VisibleForTesting
RebootEscrowManager(Injector injector, Callbacks callbacks, LockSettingsStorage storage, Handler handler)425     RebootEscrowManager(Injector injector, Callbacks callbacks,
426             LockSettingsStorage storage, Handler handler) {
427         mInjector = injector;
428         mCallbacks = callbacks;
429         mStorage = storage;
430         mUserManager = injector.getUserManager();
431         mEventLog = injector.getEventLog();
432         mKeyStoreManager = injector.getKeyStoreManager();
433         mHandler = handler;
434     }
435 
436     /** Wrapper function to set error code serialized through handler, */
setLoadEscrowDataErrorCode(@ebootEscrowErrorCode int value, Handler handler)437     private void setLoadEscrowDataErrorCode(@RebootEscrowErrorCode int value, Handler handler) {
438         if (mInjector.waitForInternet()) {
439             mInjector.post(
440                     handler,
441                     () -> {
442                         mLoadEscrowDataErrorCode = value;
443                     });
444         } else {
445             mLoadEscrowDataErrorCode = value;
446         }
447     }
448 
449     /** Wrapper function to compare and set error code serialized through handler. */
compareAndSetLoadEscrowDataErrorCode( @ebootEscrowErrorCode int expectedValue, @RebootEscrowErrorCode int newValue, Handler handler)450     private void compareAndSetLoadEscrowDataErrorCode(
451             @RebootEscrowErrorCode int expectedValue,
452             @RebootEscrowErrorCode int newValue,
453             Handler handler) {
454         if (expectedValue == mLoadEscrowDataErrorCode) {
455             setLoadEscrowDataErrorCode(newValue, handler);
456         }
457     }
458 
onGetRebootEscrowKeyFailed( List<UserInfo> users, int attemptCount, Handler retryHandler)459     private void onGetRebootEscrowKeyFailed(
460             List<UserInfo> users, int attemptCount, Handler retryHandler) {
461         Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage.");
462         for (UserInfo user : users) {
463             mStorage.removeRebootEscrow(user.id);
464         }
465 
466         onEscrowRestoreComplete(false, attemptCount, retryHandler);
467     }
468 
getUsersToUnlock(List<UserInfo> users)469     private List<UserInfo> getUsersToUnlock(List<UserInfo> users) {
470         // System user must be unlocked to unlock any other user
471         if (mCallbacks.isUserSecure(USER_SYSTEM) && !mStorage.hasRebootEscrow(USER_SYSTEM)) {
472             Slog.i(TAG, "No reboot escrow data found for system user");
473             return Collections.emptyList();
474         }
475 
476         Set<Integer> noEscrowDataUsers = new HashSet<>();
477         for (UserInfo user : users) {
478             if (mCallbacks.isUserSecure(user.id)
479                     && !mStorage.hasRebootEscrow(user.id)) {
480                 Slog.d(TAG, "No reboot escrow data found for user " + user);
481                 noEscrowDataUsers.add(user.id);
482             }
483         }
484 
485         List<UserInfo> rebootEscrowUsers = new ArrayList<>();
486         for (UserInfo user : users) {
487             // No lskf, no need to unlock.
488             if (!mCallbacks.isUserSecure(user.id)) {
489                 continue;
490             }
491             // Don't unlock if user or user's parent does not have reboot data
492             int userId = user.id;
493             if (noEscrowDataUsers.contains(userId)
494                     || noEscrowDataUsers.contains(
495                             mInjector.getUserManagerInternal().getProfileParentId(userId))) {
496                 continue;
497             }
498             rebootEscrowUsers.add(user);
499         }
500         return rebootEscrowUsers;
501     }
502 
loadRebootEscrowDataIfAvailable(Handler retryHandler)503     void loadRebootEscrowDataIfAvailable(Handler retryHandler) {
504         List<UserInfo> users = mUserManager.getUsers();
505         List<UserInfo> rebootEscrowUsers = getUsersToUnlock(users);
506 
507         if (rebootEscrowUsers.isEmpty()) {
508             Slog.i(TAG, "No reboot escrow data found for users,"
509                     + " skipping loading escrow data");
510             setLoadEscrowDataErrorCode(ERROR_NO_REBOOT_ESCROW_DATA, retryHandler);
511             reportMetricOnRestoreComplete(
512                     /* success= */ false, /* attemptCount= */ 1, retryHandler);
513             clearMetricsStorage();
514             return;
515         }
516 
517         // Acquire the wake lock to make sure our scheduled task will run.
518         mWakeLock = mInjector.getWakeLock();
519         if (mWakeLock != null) {
520             mWakeLock.setReferenceCounted(false);
521             mWakeLock.acquire(mInjector.getWakeLockTimeoutMillis());
522         }
523 
524         if (mInjector.waitForInternet()) {
525             // Timeout to stop retrying same as the wake lock timeout.
526             mInjector.postDelayed(
527                     retryHandler,
528                     () -> {
529                         mRebootEscrowTimedOut = true;
530                     },
531                     mInjector.getLoadEscrowTimeoutMillis());
532 
533             mInjector.post(
534                     retryHandler,
535                     () -> loadRebootEscrowDataOnInternet(retryHandler, users, rebootEscrowUsers));
536             return;
537         }
538 
539         mInjector.post(retryHandler, () -> loadRebootEscrowDataWithRetry(
540                 retryHandler, 0, users, rebootEscrowUsers));
541     }
542 
scheduleLoadRebootEscrowDataOrFail( Handler retryHandler, int attemptNumber, List<UserInfo> users, List<UserInfo> rebootEscrowUsers)543     void scheduleLoadRebootEscrowDataOrFail(
544             Handler retryHandler,
545             int attemptNumber,
546             List<UserInfo> users,
547             List<UserInfo> rebootEscrowUsers) {
548         Objects.requireNonNull(retryHandler);
549 
550         final int retryLimit = mInjector.getLoadEscrowDataRetryLimit();
551         final int retryIntervalInSeconds = mInjector.getLoadEscrowDataRetryIntervalSeconds();
552 
553         if (attemptNumber < retryLimit && !mRebootEscrowTimedOut) {
554             Slog.i(TAG, "Scheduling loadRebootEscrowData retry number: " + attemptNumber);
555             mInjector.postDelayed(retryHandler, () -> loadRebootEscrowDataWithRetry(
556                             retryHandler, attemptNumber, users, rebootEscrowUsers),
557                     retryIntervalInSeconds * 1000);
558             return;
559         }
560 
561         if (mInjector.waitForInternet()) {
562             if (mRebootEscrowTimedOut) {
563                 Slog.w(TAG, "Failed to load reboot escrow data within timeout");
564                 compareAndSetLoadEscrowDataErrorCode(
565                         ERROR_NONE, ERROR_TIMEOUT_EXHAUSTED, retryHandler);
566             } else {
567                 Slog.w(
568                         TAG,
569                         "Failed to load reboot escrow data after " + attemptNumber + " attempts");
570                 compareAndSetLoadEscrowDataErrorCode(
571                         ERROR_NONE, ERROR_RETRY_COUNT_EXHAUSTED, retryHandler);
572             }
573             onGetRebootEscrowKeyFailed(users, attemptNumber, retryHandler);
574             return;
575         }
576 
577         Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
578         if (mInjector.serverBasedResumeOnReboot() && !mInjector.isNetworkConnected()) {
579             mLoadEscrowDataErrorCode = ERROR_NO_NETWORK;
580         } else {
581             mLoadEscrowDataErrorCode = ERROR_RETRY_COUNT_EXHAUSTED;
582         }
583         onGetRebootEscrowKeyFailed(users, attemptNumber, retryHandler);
584     }
585 
loadRebootEscrowDataOnInternet( Handler retryHandler, List<UserInfo> users, List<UserInfo> rebootEscrowUsers)586     void loadRebootEscrowDataOnInternet(
587             Handler retryHandler, List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
588 
589         // HAL-Based RoR does not require network connectivity.
590         if (!mInjector.serverBasedResumeOnReboot()) {
591             loadRebootEscrowDataWithRetry(
592                     retryHandler, /* attemptNumber = */ 0, users, rebootEscrowUsers);
593             return;
594         }
595 
596         mNetworkCallback =
597                 new ConnectivityManager.NetworkCallback() {
598                     @Override
599                     public void onAvailable(Network network) {
600                         compareAndSetLoadEscrowDataErrorCode(
601                                 ERROR_NO_NETWORK, ERROR_NONE, retryHandler);
602 
603                         if (!mLoadEscrowDataWithRetry) {
604                             mLoadEscrowDataWithRetry = true;
605                             // Only kickoff retry mechanism on first onAvailable call.
606                             loadRebootEscrowDataWithRetry(
607                                     retryHandler,
608                                     /* attemptNumber = */ 0,
609                                     users,
610                                     rebootEscrowUsers);
611                         }
612                     }
613 
614                     @Override
615                     public void onUnavailable() {
616                         Slog.w(TAG, "Failed to connect to network within timeout");
617                         compareAndSetLoadEscrowDataErrorCode(
618                                 ERROR_NONE, ERROR_NO_NETWORK, retryHandler);
619                         onGetRebootEscrowKeyFailed(users, /* attemptCount= */ 0, retryHandler);
620                     }
621 
622                     @Override
623                     public void onLost(Network lostNetwork) {
624                         // TODO(b/231660348): If network is lost, wait for network to become
625                         // available again.
626                         Slog.w(TAG, "Network lost, still attempting to load escrow key.");
627                         compareAndSetLoadEscrowDataErrorCode(
628                                 ERROR_NONE, ERROR_NO_NETWORK, retryHandler);
629                     }
630                 };
631 
632         // Fallback to retrying without waiting for internet on failure.
633         boolean success = mInjector.requestNetworkWithInternet(mNetworkCallback);
634         if (!success) {
635             loadRebootEscrowDataWithRetry(
636                     retryHandler, /* attemptNumber = */ 0, users, rebootEscrowUsers);
637         }
638     }
639 
loadRebootEscrowDataWithRetry( Handler retryHandler, int attemptNumber, List<UserInfo> users, List<UserInfo> rebootEscrowUsers)640     void loadRebootEscrowDataWithRetry(
641             Handler retryHandler,
642             int attemptNumber,
643             List<UserInfo> users,
644             List<UserInfo> rebootEscrowUsers) {
645         // Fetch the key from keystore to decrypt the escrow data & escrow key; this key is
646         // generated before reboot. Note that we will clear the escrow key even if the keystore key
647         // is null.
648         SecretKey kk = mKeyStoreManager.getKeyStoreEncryptionKey();
649         if (kk == null) {
650             Slog.i(TAG, "Failed to load the key for resume on reboot from key store.");
651         }
652 
653         RebootEscrowKey escrowKey;
654         try {
655             escrowKey = getAndClearRebootEscrowKey(kk, retryHandler);
656         } catch (IOException e) {
657             Slog.i(TAG, "Failed to load escrow key, scheduling retry.", e);
658             scheduleLoadRebootEscrowDataOrFail(retryHandler, attemptNumber + 1, users,
659                     rebootEscrowUsers);
660             return;
661         }
662 
663         if (escrowKey == null) {
664             if (mLoadEscrowDataErrorCode == ERROR_NONE) {
665                 // Specifically check if the RoR provider has changed after reboot.
666                 int providerType = mInjector.serverBasedResumeOnReboot()
667                         ? RebootEscrowProviderInterface.TYPE_SERVER_BASED
668                         : RebootEscrowProviderInterface.TYPE_HAL;
669                 if (providerType != mStorage.getInt(REBOOT_ESCROW_KEY_PROVIDER, -1, USER_SYSTEM)) {
670                     setLoadEscrowDataErrorCode(ERROR_PROVIDER_MISMATCH, retryHandler);
671                 } else {
672                     setLoadEscrowDataErrorCode(ERROR_LOAD_ESCROW_KEY, retryHandler);
673                 }
674             }
675             onGetRebootEscrowKeyFailed(users, attemptNumber + 1, retryHandler);
676             return;
677         }
678 
679         mEventLog.addEntry(RebootEscrowEvent.FOUND_ESCROW_DATA);
680 
681         boolean allUsersUnlocked = true;
682         for (UserInfo user : rebootEscrowUsers) {
683             allUsersUnlocked &= restoreRebootEscrowForUser(user.id, escrowKey, kk);
684         }
685 
686         if (!allUsersUnlocked) {
687             compareAndSetLoadEscrowDataErrorCode(ERROR_NONE, ERROR_UNLOCK_ALL_USERS, retryHandler);
688         }
689         onEscrowRestoreComplete(allUsersUnlocked, attemptNumber + 1, retryHandler);
690     }
691 
clearMetricsStorage()692     private void clearMetricsStorage() {
693         mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
694         mStorage.removeKey(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, USER_SYSTEM);
695         mStorage.removeKey(REBOOT_ESCROW_KEY_VBMETA_DIGEST, USER_SYSTEM);
696         mStorage.removeKey(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST, USER_SYSTEM);
697         mStorage.removeKey(REBOOT_ESCROW_KEY_PROVIDER, USER_SYSTEM);
698     }
699 
getVbmetaDigestStatusOnRestoreComplete()700     private int getVbmetaDigestStatusOnRestoreComplete() {
701         String currentVbmetaDigest = mInjector.getVbmetaDigest(false);
702         String vbmetaDigestStored = mStorage.getString(REBOOT_ESCROW_KEY_VBMETA_DIGEST,
703                 "", USER_SYSTEM);
704         String vbmetaDigestOtherStored = mStorage.getString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST,
705                 "", USER_SYSTEM);
706 
707         // The other vbmeta digest is never set, assume no slot switch is attempted.
708         if (vbmetaDigestOtherStored.isEmpty()) {
709             if (currentVbmetaDigest.equals(vbmetaDigestStored)) {
710                 return FrameworkStatsLog
711                         .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT;
712             }
713             return FrameworkStatsLog
714                     .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MISMATCH;
715         }
716 
717         // The other vbmeta digest is set, we expect to boot into the new slot.
718         if (currentVbmetaDigest.equals(vbmetaDigestOtherStored)) {
719             return FrameworkStatsLog
720                     .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT;
721         } else if (currentVbmetaDigest.equals(vbmetaDigestStored)) {
722             return FrameworkStatsLog
723                     .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_FALLBACK_SLOT;
724         }
725         return FrameworkStatsLog
726                 .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MISMATCH;
727     }
728 
reportMetricOnRestoreComplete( boolean success, int attemptCount, Handler retryHandler)729     private void reportMetricOnRestoreComplete(
730             boolean success, int attemptCount, Handler retryHandler) {
731         int serviceType = mInjector.serverBasedResumeOnReboot()
732                 ? FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__SERVER_BASED
733                 : FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__HAL;
734 
735         long armedTimestamp = mStorage.getLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, -1,
736                 USER_SYSTEM);
737         int escrowDurationInSeconds = -1;
738         long currentTimeStamp = mInjector.getCurrentTimeMillis();
739         if (armedTimestamp != -1 && currentTimeStamp > armedTimestamp) {
740             escrowDurationInSeconds = (int) (currentTimeStamp - armedTimestamp) / 1000;
741         }
742 
743         int vbmetaDigestStatus = getVbmetaDigestStatusOnRestoreComplete();
744         if (!success) {
745             compareAndSetLoadEscrowDataErrorCode(ERROR_NONE, ERROR_UNKNOWN, retryHandler);
746         }
747 
748         Slog.i(
749                 TAG,
750                 "Reporting RoR recovery metrics, success: "
751                         + success
752                         + ", service type: "
753                         + serviceType
754                         + ", error code: "
755                         + mLoadEscrowDataErrorCode);
756         // TODO(179105110) report the duration since boot complete.
757         mInjector.reportMetric(
758                 success,
759                 mLoadEscrowDataErrorCode,
760                 serviceType,
761                 attemptCount,
762                 escrowDurationInSeconds,
763                 vbmetaDigestStatus,
764                 -1);
765 
766         setLoadEscrowDataErrorCode(ERROR_NONE, retryHandler);
767     }
768 
onEscrowRestoreComplete(boolean success, int attemptCount, Handler retryHandler)769     private void onEscrowRestoreComplete(boolean success, int attemptCount, Handler retryHandler) {
770         int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, -1, USER_SYSTEM);
771 
772         int bootCountDelta = mInjector.getBootCount() - previousBootCount;
773         if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) {
774             reportMetricOnRestoreComplete(success, attemptCount, retryHandler);
775         }
776         // Clear the old key in keystore. A new key will be generated by new RoR requests.
777         mKeyStoreManager.clearKeyStoreEncryptionKey();
778         // Clear the saved reboot escrow provider
779         mInjector.clearRebootEscrowProvider();
780         clearMetricsStorage();
781 
782         if (mNetworkCallback != null) {
783             mInjector.stopRequestingNetwork(mNetworkCallback);
784         }
785 
786         if (mWakeLock != null) {
787             mWakeLock.release();
788         }
789     }
790 
getAndClearRebootEscrowKey(SecretKey kk, Handler retryHandler)791     private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk, Handler retryHandler)
792             throws IOException {
793         RebootEscrowProviderInterface rebootEscrowProvider =
794                 mInjector.createRebootEscrowProviderIfNeeded();
795         if (rebootEscrowProvider == null) {
796             Slog.w(
797                     TAG,
798                     "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
799             setLoadEscrowDataErrorCode(ERROR_NO_PROVIDER, retryHandler);
800             return null;
801         }
802 
803         // Server based RoR always need the decryption key from keystore.
804         if (rebootEscrowProvider.getType() == RebootEscrowProviderInterface.TYPE_SERVER_BASED
805                 && kk == null) {
806             setLoadEscrowDataErrorCode(ERROR_KEYSTORE_FAILURE, retryHandler);
807             return null;
808         }
809 
810         // The K_s blob maybe encrypted by K_k as well.
811         RebootEscrowKey key = rebootEscrowProvider.getAndClearRebootEscrowKey(kk);
812         if (key != null) {
813             mEventLog.addEntry(RebootEscrowEvent.RETRIEVED_STORED_KEK);
814         }
815         return key;
816     }
817 
restoreRebootEscrowForUser(@serIdInt int userId, RebootEscrowKey ks, SecretKey kk)818     private boolean restoreRebootEscrowForUser(@UserIdInt int userId, RebootEscrowKey ks,
819             SecretKey kk) {
820         if (!mStorage.hasRebootEscrow(userId)) {
821             return false;
822         }
823 
824         try {
825             byte[] blob = mStorage.readRebootEscrow(userId);
826             mStorage.removeRebootEscrow(userId);
827 
828             RebootEscrowData escrowData = RebootEscrowData.fromEncryptedData(ks, blob, kk);
829 
830             mCallbacks.onRebootEscrowRestored(escrowData.getSpVersion(),
831                     escrowData.getSyntheticPassword(), userId);
832             Slog.i(TAG, "Restored reboot escrow data for user " + userId);
833             mEventLog.addEntry(RebootEscrowEvent.RETRIEVED_LSKF_FOR_USER, userId);
834             return true;
835         } catch (IOException e) {
836             Slog.w(TAG, "Could not load reboot escrow data for user " + userId, e);
837             return false;
838         }
839     }
840 
callToRebootEscrowIfNeeded(@serIdInt int userId, byte spVersion, byte[] syntheticPassword)841     void callToRebootEscrowIfNeeded(@UserIdInt int userId, byte spVersion,
842             byte[] syntheticPassword) {
843         if (!mRebootEscrowWanted) {
844             return;
845         }
846 
847         if (mInjector.createRebootEscrowProviderIfNeeded() == null) {
848             Slog.w(TAG, "Not storing escrow data, RebootEscrowProvider is unavailable");
849             return;
850         }
851 
852         RebootEscrowKey escrowKey = generateEscrowKeyIfNeeded();
853         if (escrowKey == null) {
854             Slog.e(TAG, "Could not generate escrow key");
855             return;
856         }
857 
858         SecretKey kk = mKeyStoreManager.generateKeyStoreEncryptionKeyIfNeeded();
859         if (kk == null) {
860             Slog.e(TAG, "Failed to generate encryption key from keystore.");
861             return;
862         }
863 
864         final RebootEscrowData escrowData;
865         try {
866             escrowData = RebootEscrowData.fromSyntheticPassword(escrowKey, spVersion,
867                     syntheticPassword, kk);
868         } catch (IOException e) {
869             setRebootEscrowReady(false);
870             Slog.w(TAG, "Could not escrow reboot data", e);
871             return;
872         }
873 
874         mStorage.writeRebootEscrow(userId, escrowData.getBlob());
875         mEventLog.addEntry(RebootEscrowEvent.STORED_LSKF_FOR_USER, userId);
876 
877         setRebootEscrowReady(true);
878     }
879 
generateEscrowKeyIfNeeded()880     private RebootEscrowKey generateEscrowKeyIfNeeded() {
881         synchronized (mKeyGenerationLock) {
882             if (mPendingRebootEscrowKey != null) {
883                 return mPendingRebootEscrowKey;
884             }
885 
886             RebootEscrowKey key;
887             try {
888                 key = RebootEscrowKey.generate();
889             } catch (IOException e) {
890                 Slog.w(TAG, "Could not generate reboot escrow key");
891                 return null;
892             }
893 
894             mPendingRebootEscrowKey = key;
895             return key;
896         }
897     }
898 
clearRebootEscrowIfNeeded()899     private void clearRebootEscrowIfNeeded() {
900         mRebootEscrowWanted = false;
901         setRebootEscrowReady(false);
902 
903         // We want to clear the internal data inside the provider, so always try to create the
904         // provider.
905         RebootEscrowProviderInterface rebootEscrowProvider =
906                 mInjector.createRebootEscrowProviderIfNeeded();
907         if (rebootEscrowProvider == null) {
908             Slog.w(TAG, "RebootEscrowProvider is unavailable for clear request");
909         } else {
910             rebootEscrowProvider.clearRebootEscrowKey();
911         }
912 
913         mInjector.clearRebootEscrowProvider();
914         clearMetricsStorage();
915 
916         List<UserInfo> users = mUserManager.getUsers();
917         for (UserInfo user : users) {
918             mStorage.removeRebootEscrow(user.id);
919         }
920 
921         mEventLog.addEntry(RebootEscrowEvent.CLEARED_LSKF_REQUEST);
922     }
923 
armRebootEscrowIfNeeded()924     @ArmRebootEscrowErrorCode int armRebootEscrowIfNeeded() {
925         if (!mRebootEscrowReady) {
926             return ARM_REBOOT_ERROR_ESCROW_NOT_READY;
927         }
928 
929         RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
930         if (rebootEscrowProvider == null) {
931             Slog.w(TAG, "Not storing escrow key, RebootEscrowProvider is unavailable");
932             clearRebootEscrowIfNeeded();
933             return ARM_REBOOT_ERROR_NO_PROVIDER;
934         }
935 
936         int expectedProviderType = mInjector.serverBasedResumeOnReboot()
937                 ? RebootEscrowProviderInterface.TYPE_SERVER_BASED
938                 : RebootEscrowProviderInterface.TYPE_HAL;
939         int actualProviderType = rebootEscrowProvider.getType();
940         if (expectedProviderType != actualProviderType) {
941             Slog.w(TAG, "Expect reboot escrow provider " + expectedProviderType
942                     + ", but the RoR is prepared with " + actualProviderType
943                     + ". Please prepare the RoR again.");
944             clearRebootEscrowIfNeeded();
945             return ARM_REBOOT_ERROR_PROVIDER_MISMATCH;
946         }
947 
948         RebootEscrowKey escrowKey;
949         synchronized (mKeyGenerationLock) {
950             escrowKey = mPendingRebootEscrowKey;
951         }
952 
953         if (escrowKey == null) {
954             Slog.e(TAG, "Escrow key is null, but escrow was marked as ready");
955             clearRebootEscrowIfNeeded();
956             return ARM_REBOOT_ERROR_NO_ESCROW_KEY;
957         }
958 
959         // We will use the same key from keystore to encrypt the escrow key and escrow data blob.
960         SecretKey kk = mKeyStoreManager.getKeyStoreEncryptionKey();
961         if (kk == null) {
962             Slog.e(TAG, "Failed to get encryption key from keystore.");
963             clearRebootEscrowIfNeeded();
964             return ARM_REBOOT_ERROR_KEYSTORE_FAILURE;
965         }
966 
967         // TODO(b/183140900) design detailed errors for store escrow key errors.
968         // We don't clear rebootEscrow here, because some errors may be recoverable, e.g. network
969         // unavailable for server based provider.
970         boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, kk);
971         if (!armedRebootEscrow) {
972             return ARM_REBOOT_ERROR_STORE_ESCROW_KEY;
973         }
974 
975         mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
976         mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, mInjector.getCurrentTimeMillis(),
977                 USER_SYSTEM);
978         // Store the vbmeta digest of both slots.
979         mStorage.setString(REBOOT_ESCROW_KEY_VBMETA_DIGEST, mInjector.getVbmetaDigest(false),
980                 USER_SYSTEM);
981         mStorage.setString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST,
982                 mInjector.getVbmetaDigest(true), USER_SYSTEM);
983         mStorage.setInt(REBOOT_ESCROW_KEY_PROVIDER, actualProviderType, USER_SYSTEM);
984         mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS);
985 
986         return ARM_REBOOT_ERROR_NONE;
987     }
988 
setRebootEscrowReady(boolean ready)989     private void setRebootEscrowReady(boolean ready) {
990         if (mRebootEscrowReady != ready) {
991             mHandler.post(() -> mRebootEscrowListener.onPreparedForReboot(ready));
992         }
993         mRebootEscrowReady = ready;
994     }
995 
prepareRebootEscrow()996     boolean prepareRebootEscrow() {
997         clearRebootEscrowIfNeeded();
998         if (mInjector.createRebootEscrowProviderIfNeeded() == null) {
999             Slog.w(TAG, "No reboot escrow provider, skipping resume on reboot preparation.");
1000             return false;
1001         }
1002 
1003         mRebootEscrowWanted = true;
1004         mEventLog.addEntry(RebootEscrowEvent.REQUESTED_LSKF);
1005         return true;
1006     }
1007 
clearRebootEscrow()1008     boolean clearRebootEscrow() {
1009         clearRebootEscrowIfNeeded();
1010         return true;
1011     }
1012 
setRebootEscrowListener(RebootEscrowListener listener)1013     void setRebootEscrowListener(RebootEscrowListener listener) {
1014         mRebootEscrowListener = listener;
1015     }
1016 
1017     @VisibleForTesting
1018     public static class RebootEscrowEvent {
1019         static final int FOUND_ESCROW_DATA = 1;
1020         static final int SET_ARMED_STATUS = 2;
1021         static final int CLEARED_LSKF_REQUEST = 3;
1022         static final int RETRIEVED_STORED_KEK = 4;
1023         static final int REQUESTED_LSKF = 5;
1024         static final int STORED_LSKF_FOR_USER = 6;
1025         static final int RETRIEVED_LSKF_FOR_USER = 7;
1026 
1027         final int mEventId;
1028         final Integer mUserId;
1029         final long mWallTime;
1030         final long mTimestamp;
1031 
RebootEscrowEvent(int eventId)1032         RebootEscrowEvent(int eventId) {
1033             this(eventId, null);
1034         }
1035 
RebootEscrowEvent(int eventId, Integer userId)1036         RebootEscrowEvent(int eventId, Integer userId) {
1037             mEventId = eventId;
1038             mUserId = userId;
1039             mTimestamp = SystemClock.uptimeMillis();
1040             mWallTime = System.currentTimeMillis();
1041         }
1042 
getEventDescription()1043         String getEventDescription() {
1044             switch (mEventId) {
1045                 case FOUND_ESCROW_DATA:
1046                     return "Found escrow data";
1047                 case SET_ARMED_STATUS:
1048                     return "Set armed status";
1049                 case CLEARED_LSKF_REQUEST:
1050                     return "Cleared request for LSKF";
1051                 case RETRIEVED_STORED_KEK:
1052                     return "Retrieved stored KEK";
1053                 case REQUESTED_LSKF:
1054                     return "Requested LSKF";
1055                 case STORED_LSKF_FOR_USER:
1056                     return "Stored LSKF for user";
1057                 case RETRIEVED_LSKF_FOR_USER:
1058                     return "Retrieved LSKF for user";
1059                 default:
1060                     return "Unknown event ID " + mEventId;
1061             }
1062         }
1063     }
1064 
1065     @VisibleForTesting
1066     public static class RebootEscrowEventLog {
1067         private RebootEscrowEvent[] mEntries = new RebootEscrowEvent[16];
1068         private int mNextIndex = 0;
1069 
addEntry(int eventId)1070         void addEntry(int eventId) {
1071             addEntryInternal(new RebootEscrowEvent(eventId));
1072         }
1073 
addEntry(int eventId, int userId)1074         void addEntry(int eventId, int userId) {
1075             addEntryInternal(new RebootEscrowEvent(eventId, userId));
1076         }
1077 
addEntryInternal(RebootEscrowEvent event)1078         private void addEntryInternal(RebootEscrowEvent event) {
1079             final int index = mNextIndex;
1080             mEntries[index] = event;
1081             mNextIndex = (mNextIndex + 1) % mEntries.length;
1082         }
1083 
dump(@onNull IndentingPrintWriter pw)1084         void dump(@NonNull IndentingPrintWriter pw) {
1085             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
1086 
1087             for (int i = 0; i < mEntries.length; ++i) {
1088                 RebootEscrowEvent event = mEntries[(i + mNextIndex) % mEntries.length];
1089                 if (event == null) {
1090                     continue;
1091                 }
1092 
1093                 pw.print("Event #");
1094                 pw.println(i);
1095 
1096                 pw.println(" time=" + sdf.format(new Date(event.mWallTime))
1097                         + " (timestamp=" + event.mTimestamp + ")");
1098 
1099                 pw.print(" event=");
1100                 pw.println(event.getEventDescription());
1101 
1102                 if (event.mUserId != null) {
1103                     pw.print(" user=");
1104                     pw.println(event.mUserId);
1105                 }
1106             }
1107         }
1108     }
1109 
dump(@onNull IndentingPrintWriter pw)1110     void dump(@NonNull IndentingPrintWriter pw) {
1111         pw.print("mRebootEscrowWanted=");
1112         pw.println(mRebootEscrowWanted);
1113 
1114         pw.print("mRebootEscrowReady=");
1115         pw.println(mRebootEscrowReady);
1116 
1117         pw.print("mRebootEscrowListener=");
1118         pw.println(mRebootEscrowListener);
1119 
1120         pw.print("mLoadEscrowDataErrorCode=");
1121         pw.println(mLoadEscrowDataErrorCode);
1122 
1123         boolean keySet;
1124         synchronized (mKeyGenerationLock) {
1125             keySet = mPendingRebootEscrowKey != null;
1126         }
1127 
1128         pw.print("mPendingRebootEscrowKey is ");
1129         pw.println(keySet ? "set" : "not set");
1130 
1131         RebootEscrowProviderInterface provider = mInjector.getRebootEscrowProvider();
1132         String providerType = provider == null ? "null" : String.valueOf(provider.getType());
1133         pw.print("RebootEscrowProvider type is " + providerType);
1134 
1135         pw.println();
1136         pw.println("Event log:");
1137         pw.increaseIndent();
1138         mEventLog.dump(pw);
1139         pw.println();
1140         pw.decreaseIndent();
1141     }
1142 }
1143