1 /*
2  * Copyright (C) 2019 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.recoverysystem;
18 
19 import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_INVALID_PACKAGE_NAME;
20 import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED;
21 import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE;
22 import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMATCH;
23 
24 import static org.hamcrest.CoreMatchers.is;
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertFalse;
27 import static org.junit.Assert.assertThat;
28 import static org.junit.Assert.assertTrue;
29 import static org.mockito.AdditionalMatchers.not;
30 import static org.mockito.ArgumentMatchers.any;
31 import static org.mockito.ArgumentMatchers.anyBoolean;
32 import static org.mockito.ArgumentMatchers.anyInt;
33 import static org.mockito.ArgumentMatchers.anyLong;
34 import static org.mockito.ArgumentMatchers.anyString;
35 import static org.mockito.ArgumentMatchers.eq;
36 import static org.mockito.Mockito.doNothing;
37 import static org.mockito.Mockito.doReturn;
38 import static org.mockito.Mockito.doThrow;
39 import static org.mockito.Mockito.mock;
40 import static org.mockito.Mockito.never;
41 import static org.mockito.Mockito.times;
42 import static org.mockito.Mockito.verify;
43 import static org.mockito.Mockito.verifyNoMoreInteractions;
44 import static org.mockito.Mockito.when;
45 
46 import android.content.Context;
47 import android.content.IntentSender;
48 import android.content.pm.PackageManager;
49 import android.hardware.boot.IBootControl;
50 import android.os.Handler;
51 import android.os.IPowerManager;
52 import android.os.IRecoverySystemProgressListener;
53 import android.os.IThermalService;
54 import android.os.Looper;
55 import android.os.PowerManager;
56 
57 import androidx.test.InstrumentationRegistry;
58 import androidx.test.filters.SmallTest;
59 import androidx.test.runner.AndroidJUnit4;
60 
61 import com.android.internal.widget.LockSettingsInternal;
62 
63 import org.junit.Before;
64 import org.junit.Test;
65 import org.junit.runner.RunWith;
66 
67 import java.io.FileWriter;
68 
69 /**
70  * atest FrameworksServicesTests:RecoverySystemServiceTest
71  */
72 @SmallTest
73 @RunWith(AndroidJUnit4.class)
74 public class RecoverySystemServiceTest {
75     private RecoverySystemService mRecoverySystemService;
76     private RecoverySystemServiceTestable.FakeSystemProperties mSystemProperties;
77     private RecoverySystemService.UncryptSocket mUncryptSocket;
78     private Context mContext;
79     private IPowerManager mIPowerManager;
80     private IThermalService mIThermalService;
81     private FileWriter mUncryptUpdateFileWriter;
82     private LockSettingsInternal mLockSettingsInternal;
83     private IBootControl mIBootControl;
84     private RecoverySystemServiceTestable.IMetricsReporter mMetricsReporter;
85     private RecoverySystemService.PreferencesManager mSharedPreferences;
86 
87     private static final String FAKE_OTA_PACKAGE_NAME = "fake.ota.package";
88     private static final String FAKE_OTHER_PACKAGE_NAME = "fake.other.package";
89 
90     @Before
setup()91     public void setup() throws Exception {
92         mContext = mock(Context.class);
93         mSystemProperties = new RecoverySystemServiceTestable.FakeSystemProperties();
94         mUncryptSocket = mock(RecoverySystemService.UncryptSocket.class);
95         mUncryptUpdateFileWriter = mock(FileWriter.class);
96         mLockSettingsInternal = mock(LockSettingsInternal.class);
97 
98         doReturn(true).when(mLockSettingsInternal).prepareRebootEscrow();
99         doReturn(true).when(mLockSettingsInternal).clearRebootEscrow();
100         doReturn(LockSettingsInternal.ARM_REBOOT_ERROR_NONE).when(mLockSettingsInternal)
101                 .armRebootEscrow();
102 
103         Looper looper = InstrumentationRegistry.getContext().getMainLooper();
104         mIPowerManager = mock(IPowerManager.class);
105         mIThermalService = mock(IThermalService.class);
106         PowerManager powerManager = new PowerManager(mock(Context.class), mIPowerManager,
107                 mIThermalService, new Handler(looper));
108 
109         mIBootControl = mock(IBootControl.class);
110         when(mIBootControl.getCurrentSlot()).thenReturn(0);
111         when(mIBootControl.getActiveBootSlot()).thenReturn(1);
112 
113         mMetricsReporter = mock(RecoverySystemServiceTestable.IMetricsReporter.class);
114         mSharedPreferences = mock(RecoverySystemService.PreferencesManager.class);
115 
116         mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties,
117                 powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal,
118                 mIBootControl, mMetricsReporter, mSharedPreferences);
119     }
120 
121     @Test
clearBcb_success()122     public void clearBcb_success() throws Exception {
123         doNothing().when(mContext).enforceCallingOrSelfPermission(
124                 eq(android.Manifest.permission.RECOVERY), any());
125         when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100);
126 
127         assertThat(mRecoverySystemService.clearBcb(), is(true));
128 
129         assertThat(mSystemProperties.getCtlStart(), is("clear-bcb"));
130         verify(mUncryptSocket).sendAck();
131         verify(mUncryptSocket).close();
132     }
133 
134     @Test
clearBcb_uncrypt_failure()135     public void clearBcb_uncrypt_failure() throws Exception {
136         doNothing().when(mContext).enforceCallingOrSelfPermission(
137                 eq(android.Manifest.permission.RECOVERY), any());
138         when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0);
139 
140         assertThat(mRecoverySystemService.clearBcb(), is(false));
141 
142         assertThat(mSystemProperties.getCtlStart(), is("clear-bcb"));
143         verify(mUncryptSocket).sendAck();
144         verify(mUncryptSocket).close();
145     }
146 
147     @Test(expected = SecurityException.class)
clearBcb_noPerm()148     public void clearBcb_noPerm() {
149         doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission(
150                 eq(android.Manifest.permission.RECOVERY), any());
151         mRecoverySystemService.clearBcb();
152     }
153 
154     @Test
setupBcb_success()155     public void setupBcb_success() throws Exception {
156         doNothing().when(mContext).enforceCallingOrSelfPermission(
157                 eq(android.Manifest.permission.RECOVERY), any());
158         when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100);
159 
160         assertThat(mRecoverySystemService.setupBcb("foo"), is(true));
161 
162         assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
163         verify(mUncryptSocket).sendCommand("foo");
164         verify(mUncryptSocket).sendAck();
165         verify(mUncryptSocket).close();
166     }
167 
168     @Test
setupBcb_uncrypt_failure()169     public void setupBcb_uncrypt_failure() throws Exception {
170         doNothing().when(mContext).enforceCallingOrSelfPermission(
171                 eq(android.Manifest.permission.RECOVERY), any());
172         when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0);
173 
174         assertThat(mRecoverySystemService.setupBcb("foo"), is(false));
175 
176         assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
177         verify(mUncryptSocket).sendCommand("foo");
178         verify(mUncryptSocket).sendAck();
179         verify(mUncryptSocket).close();
180     }
181 
182     @Test(expected = SecurityException.class)
setupBcb_noPerm()183     public void setupBcb_noPerm() {
184         doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission(
185                 eq(android.Manifest.permission.RECOVERY), any());
186         mRecoverySystemService.setupBcb("foo");
187     }
188 
189     @Test
rebootRecoveryWithCommand_success()190     public void rebootRecoveryWithCommand_success() throws Exception {
191         doNothing().when(mContext).enforceCallingOrSelfPermission(
192                 eq(android.Manifest.permission.RECOVERY), any());
193         when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100);
194 
195         mRecoverySystemService.rebootRecoveryWithCommand("foo");
196 
197         assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
198         verify(mUncryptSocket).sendCommand("foo");
199         verify(mUncryptSocket).sendAck();
200         verify(mUncryptSocket).close();
201         verify(mIPowerManager).reboot(anyBoolean(), eq("recovery"), anyBoolean());
202     }
203 
204     @Test
rebootRecoveryWithCommand_failure()205     public void rebootRecoveryWithCommand_failure() throws Exception {
206         doNothing().when(mContext).enforceCallingOrSelfPermission(
207                 eq(android.Manifest.permission.RECOVERY), any());
208         when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0);
209 
210         mRecoverySystemService.rebootRecoveryWithCommand("foo");
211 
212         assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
213         verify(mUncryptSocket).sendCommand("foo");
214         verify(mUncryptSocket).sendAck();
215         verify(mUncryptSocket).close();
216         verifyNoMoreInteractions(mIPowerManager);
217     }
218 
219     @Test(expected = SecurityException.class)
rebootRecoveryWithCommand_noPerm()220     public void rebootRecoveryWithCommand_noPerm() {
221         doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission(
222                 eq(android.Manifest.permission.RECOVERY), any());
223         mRecoverySystemService.rebootRecoveryWithCommand("foo");
224     }
225 
226     @Test
uncrypt_success()227     public void uncrypt_success() throws Exception {
228         doNothing().when(mContext).enforceCallingOrSelfPermission(
229                 eq(android.Manifest.permission.RECOVERY), any());
230         when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0, 5, 25, 50, 90, 99, 100);
231 
232         IRecoverySystemProgressListener listener = mock(IRecoverySystemProgressListener.class);
233         assertThat(mRecoverySystemService.uncrypt("foo.zip", listener), is(true));
234 
235         assertThat(mSystemProperties.getCtlStart(), is("uncrypt"));
236         verify(mUncryptSocket, times(7)).getPercentageUncrypted();
237         verify(mUncryptSocket).sendAck();
238         verify(mUncryptSocket).close();
239     }
240 
241     @Test(expected = SecurityException.class)
requestLskf_protected()242     public void requestLskf_protected() {
243         when(mContext.checkCallingOrSelfPermission(anyString())).thenReturn(
244                 PackageManager.PERMISSION_DENIED);
245         mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null);
246     }
247 
248     @Test
requestLskf_reportMetrics()249     public void requestLskf_reportMetrics() throws Exception {
250         IntentSender intentSender = mock(IntentSender.class);
251         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
252                 is(true));
253         verify(mMetricsReporter).reportRebootEscrowPreparationMetrics(
254                 eq(1000), eq(0) /* need preparation */, eq(1) /* client count */);
255         verify(mSharedPreferences).putLong(eq(FAKE_OTA_PACKAGE_NAME
256                 + RecoverySystemService.REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX), eq(100_000L));
257     }
258 
259     @Test
requestLskf_success()260     public void requestLskf_success() throws Exception {
261         IntentSender intentSender = mock(IntentSender.class);
262         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
263                 is(true));
264 
265         when(mSharedPreferences.getLong(eq(FAKE_OTA_PACKAGE_NAME
266                 + RecoverySystemService.REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX), anyLong()))
267                 .thenReturn(200_000L).thenReturn(5000L);
268         mRecoverySystemService.onPreparedForReboot(true);
269         verify(mMetricsReporter).reportRebootEscrowLskfCapturedMetrics(
270                 eq(1000), eq(1) /* client count */,
271                 eq(-1) /* invalid duration */);
272 
273         mRecoverySystemService.onPreparedForReboot(true);
274         verify(intentSender).sendIntent(any(), anyInt(), any(), any(), any());
275         verify(mMetricsReporter).reportRebootEscrowLskfCapturedMetrics(
276                 eq(1000), eq(1) /* client count */, eq(95) /* duration */);
277     }
278 
279     @Test
requestLskf_subsequentRequestNotClearPrepared()280     public void requestLskf_subsequentRequestNotClearPrepared() throws Exception {
281         IntentSender intentSender = mock(IntentSender.class);
282         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
283                 is(true));
284         mRecoverySystemService.onPreparedForReboot(true);
285         verify(intentSender).sendIntent(any(), anyInt(), any(), any(), any());
286 
287         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
288         mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "foobar", true);
289         verify(mIPowerManager).reboot(anyBoolean(), eq("foobar"), anyBoolean());
290     }
291 
292     @Test
requestLskf_requestedButNotPrepared()293     public void requestLskf_requestedButNotPrepared() throws Exception {
294         IntentSender intentSender = mock(IntentSender.class);
295         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
296                 is(true));
297         verify(intentSender, never()).sendIntent(any(), anyInt(), any(), any(), any());
298         verify(mMetricsReporter, never()).reportRebootEscrowLskfCapturedMetrics(
299                 anyInt(), anyInt(), anyInt());
300     }
301 
302     @Test
requestLskf_lockSettingsError()303     public void requestLskf_lockSettingsError() throws Exception {
304         IntentSender intentSender = mock(IntentSender.class);
305 
306         doReturn(false).when(mLockSettingsInternal).prepareRebootEscrow();
307         assertFalse(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender));
308     }
309 
310     @Test
isLskfCaptured_requestedButNotPrepared()311     public void isLskfCaptured_requestedButNotPrepared() throws Exception {
312         IntentSender intentSender = mock(IntentSender.class);
313         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
314                 is(true));
315         assertThat(mRecoverySystemService.isLskfCaptured(FAKE_OTA_PACKAGE_NAME), is(false));
316     }
317 
318     @Test
isLskfCaptured_Prepared()319     public void isLskfCaptured_Prepared() throws Exception {
320         IntentSender intentSender = mock(IntentSender.class);
321         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
322                 is(true));
323         mRecoverySystemService.onPreparedForReboot(true);
324         verify(intentSender).sendIntent(any(), anyInt(), any(), any(), any());
325         assertThat(mRecoverySystemService.isLskfCaptured(FAKE_OTA_PACKAGE_NAME), is(true));
326     }
327 
328     @Test(expected = SecurityException.class)
clearLskf_protected()329     public void clearLskf_protected() {
330         when(mContext.checkCallingOrSelfPermission(anyString())).thenReturn(
331                 PackageManager.PERMISSION_DENIED);
332         mRecoverySystemService.clearLskf(FAKE_OTA_PACKAGE_NAME);
333     }
334 
335     @Test
clearLskf_requestedThenCleared()336     public void clearLskf_requestedThenCleared() throws Exception {
337         IntentSender intentSender = mock(IntentSender.class);
338         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
339                 is(true));
340         mRecoverySystemService.onPreparedForReboot(true);
341         verify(intentSender).sendIntent(any(), anyInt(), any(), any(), any());
342 
343         assertThat(mRecoverySystemService.clearLskf(FAKE_OTA_PACKAGE_NAME), is(true));
344         verify(mLockSettingsInternal).clearRebootEscrow();
345     }
346 
347     @Test
clearLskf_callerNotRequested_Success()348     public void clearLskf_callerNotRequested_Success() throws Exception {
349         IntentSender intentSender = mock(IntentSender.class);
350         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
351                 is(true));
352         assertThat(mRecoverySystemService.clearLskf(FAKE_OTHER_PACKAGE_NAME), is(true));
353         verify(mLockSettingsInternal, never()).clearRebootEscrow();
354     }
355 
356     @Test
clearLskf_multiClient_BothClientsClear()357     public void clearLskf_multiClient_BothClientsClear() throws Exception {
358         IntentSender intentSender = mock(IntentSender.class);
359         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
360                 is(true));
361         assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, intentSender),
362                 is(true));
363 
364         assertThat(mRecoverySystemService.clearLskf(FAKE_OTA_PACKAGE_NAME), is(true));
365         verify(mLockSettingsInternal, never()).clearRebootEscrow();
366         assertThat(mRecoverySystemService.clearLskf(FAKE_OTHER_PACKAGE_NAME), is(true));
367         verify(mLockSettingsInternal).clearRebootEscrow();
368     }
369 
370     @Test
startup_setRebootEscrowListener()371     public void startup_setRebootEscrowListener() throws Exception {
372         mRecoverySystemService.onSystemServicesReady();
373         verify(mLockSettingsInternal).setRebootEscrowListener(any());
374     }
375 
376     @Test(expected = SecurityException.class)
rebootWithLskf_protected()377     public void rebootWithLskf_protected() {
378         when(mContext.checkCallingOrSelfPermission(anyString())).thenReturn(
379                 PackageManager.PERMISSION_DENIED);
380         mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true);
381     }
382 
383     @Test
rebootWithLskf_Success()384     public void rebootWithLskf_Success() throws Exception {
385         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
386         mRecoverySystemService.onPreparedForReboot(true);
387 
388         when(mSharedPreferences.getInt(eq(FAKE_OTA_PACKAGE_NAME
389                 + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(2);
390         when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF),
391                 anyInt())).thenReturn(3);
392         when(mSharedPreferences.getLong(eq(RecoverySystemService.LSKF_CAPTURED_TIMESTAMP_PREF),
393                 anyLong())).thenReturn(40_000L);
394         mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true);
395         verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
396         verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(1000),
397                 eq(1) /* client count */, eq(2) /* request count */, eq(true) /* slot switch */,
398                 anyBoolean(), eq(60) /* duration */, eq(3) /* lskf capture count */);
399     }
400 
401 
402     @Test
rebootWithLskf_slotMismatch_Failure()403     public void rebootWithLskf_slotMismatch_Failure() throws Exception {
404         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
405         mRecoverySystemService.onPreparedForReboot(true);
406         assertEquals(RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMATCH,
407                 mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", false));
408     }
409 
410     @Test
rebootWithLskf_withoutPrepare_Failure()411     public void rebootWithLskf_withoutPrepare_Failure() throws Exception {
412         assertEquals(RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED,
413                 mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true));
414     }
415 
416     @Test
rebootWithLskf_withNullCallerId_Failure()417     public void rebootWithLskf_withNullCallerId_Failure() throws Exception {
418         assertEquals(RESUME_ON_REBOOT_REBOOT_ERROR_INVALID_PACKAGE_NAME,
419                 mRecoverySystemService.rebootWithLskf(null, null, true));
420         verifyNoMoreInteractions(mIPowerManager);
421     }
422 
423     @Test
rebootWithLskf_multiClient_ClientASuccess()424     public void rebootWithLskf_multiClient_ClientASuccess() throws Exception {
425         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
426         assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true));
427         mRecoverySystemService.onPreparedForReboot(true);
428 
429         // Client B's clear won't affect client A's preparation.
430         assertThat(mRecoverySystemService.clearLskf(FAKE_OTHER_PACKAGE_NAME), is(true));
431         mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true);
432         verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
433     }
434 
435     @Test
rebootWithLskf_multiClient_success_reportMetrics()436     public void rebootWithLskf_multiClient_success_reportMetrics() throws Exception {
437         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
438         assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true));
439         mRecoverySystemService.onPreparedForReboot(true);
440 
441         when(mSharedPreferences.getInt(eq(FAKE_OTA_PACKAGE_NAME
442                 + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(2);
443         when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF),
444                 anyInt())).thenReturn(1);
445         when(mSharedPreferences.getLong(eq(RecoverySystemService.LSKF_CAPTURED_TIMESTAMP_PREF),
446                 anyLong())).thenReturn(60_000L);
447 
448         mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true);
449         verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
450         verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(1000),
451                 eq(2) /* client count */, eq(2) /* request count */, eq(true) /* slot switch */,
452                 anyBoolean(), eq(40), eq(1) /* lskf capture count */);
453     }
454 
455     @Test
rebootWithLskf_multiClient_ClientBSuccess()456     public void rebootWithLskf_multiClient_ClientBSuccess() throws Exception {
457         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
458         mRecoverySystemService.onPreparedForReboot(true);
459         assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true));
460 
461         when(mSharedPreferences.getInt(eq(FAKE_OTHER_PACKAGE_NAME
462                 + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(2);
463         when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF),
464                 anyInt())).thenReturn(1);
465         when(mSharedPreferences.getLong(eq(RecoverySystemService.LSKF_CAPTURED_TIMESTAMP_PREF),
466                 anyLong())).thenReturn(60_000L);
467 
468         assertThat(mRecoverySystemService.clearLskf(FAKE_OTA_PACKAGE_NAME), is(true));
469         assertEquals(RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED,
470                 mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true));
471         verifyNoMoreInteractions(mIPowerManager);
472         verify(mMetricsReporter).reportRebootEscrowRebootMetrics(not(eq(0)), eq(1000),
473                 eq(1) /* client count */, anyInt() /* request count */, eq(true) /* slot switch */,
474                 anyBoolean(), eq(40), eq(1)/* lskf capture count */);
475 
476         assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true));
477         mRecoverySystemService.rebootWithLskf(FAKE_OTHER_PACKAGE_NAME, "ab-update", true);
478         verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
479 
480         verify(mMetricsReporter).reportRebootEscrowRebootMetrics((eq(0)), eq(2000),
481                 eq(1) /* client count */, eq(2) /* request count */, eq(true) /* slot switch */,
482                 anyBoolean(), eq(40), eq(1) /* lskf capture count */);
483     }
484 
485     @Test
rebootWithLskf_multiClient_BothClientsClear_Failure()486     public void rebootWithLskf_multiClient_BothClientsClear_Failure() throws Exception {
487         assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
488         mRecoverySystemService.onPreparedForReboot(true);
489         assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true));
490 
491         // Client A clears
492         assertThat(mRecoverySystemService.clearLskf(FAKE_OTA_PACKAGE_NAME), is(true));
493         assertEquals(RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED,
494                 mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true));
495         verifyNoMoreInteractions(mIPowerManager);
496 
497         // Client B clears
498         assertThat(mRecoverySystemService.clearLskf(FAKE_OTHER_PACKAGE_NAME), is(true));
499         verify(mLockSettingsInternal).clearRebootEscrow();
500         assertEquals(RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED,
501                 mRecoverySystemService.rebootWithLskf(FAKE_OTHER_PACKAGE_NAME, "ab-update", true));
502         verifyNoMoreInteractions(mIPowerManager);
503     }
504 
505     // TODO(xunchang) add more multi client tests
506 
507     @Test
rebootWithLskf_armEscrowDataFatalError_Failure()508     public void rebootWithLskf_armEscrowDataFatalError_Failure() throws Exception {
509         doReturn(LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH)
510                 .when(mLockSettingsInternal).armRebootEscrow();
511 
512         assertTrue(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null));
513         mRecoverySystemService.onPreparedForReboot(true);
514         assertTrue(mRecoverySystemService.isLskfCaptured(FAKE_OTA_PACKAGE_NAME));
515 
516         when(mSharedPreferences.getInt(eq(FAKE_OTA_PACKAGE_NAME
517                 + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(1);
518         when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF),
519                 anyInt())).thenReturn(1);
520         assertEquals(RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE,
521                 mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true));
522         // Verify that the RoR preparation state has been cleared.
523         assertFalse(mRecoverySystemService.isLskfCaptured(FAKE_OTA_PACKAGE_NAME));
524         verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(5004 /* provider mismatch */),
525                 eq(1000), eq(1) /* client count */, eq(1) /* request count */,
526                 eq(true) /* slot switch */, anyBoolean(), anyInt(),
527                 eq(1) /* lskf capture count */);
528     }
529 }
530