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