blob: 2080fdf2e40dc21cd3802e0d6d8a73c1ae8a3b2c [file] [log] [blame]
bpetrivsa7101952019-02-07 16:01:24 +00001/*
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
17package com.android.server;
18
19import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
20import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
21import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyLong;
22import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
23import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
24import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
25import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
26import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
Gavin Corkeryaa57ef32019-12-17 19:02:54 +000027import static com.android.server.RescueParty.LEVEL_FACTORY_RESET;
bpetrivsa7101952019-02-07 16:01:24 +000028
29import static org.junit.Assert.assertEquals;
30import static org.junit.Assert.assertTrue;
31import static org.mockito.ArgumentMatchers.eq;
32import static org.mockito.ArgumentMatchers.isNull;
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000033import static org.mockito.Mockito.times;
bpetrivsa7101952019-02-07 16:01:24 +000034
35import android.content.ContentResolver;
36import android.content.Context;
Gavin Corkery69395652019-12-12 19:06:47 +000037import android.content.pm.VersionedPackage;
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000038import android.os.Bundle;
bpetrivsa7101952019-02-07 16:01:24 +000039import android.os.RecoverySystem;
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000040import android.os.RemoteCallback;
bpetrivsa7101952019-02-07 16:01:24 +000041import android.os.SystemProperties;
42import android.os.UserHandle;
bpetrivs93075f42019-02-28 12:08:12 +000043import android.provider.DeviceConfig;
bpetrivsa7101952019-02-07 16:01:24 +000044import android.provider.Settings;
45
46import com.android.dx.mockito.inline.extended.ExtendedMockito;
Gavin Corkery69395652019-12-12 19:06:47 +000047import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
48import com.android.server.RescueParty.RescuePartyObserver;
bpetrivs93075f42019-02-28 12:08:12 +000049import com.android.server.am.SettingsToPropertiesMapper;
bpetrivsa7101952019-02-07 16:01:24 +000050
51import org.junit.After;
52import org.junit.Before;
53import org.junit.Test;
54import org.mockito.Answers;
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000055import org.mockito.ArgumentCaptor;
56import org.mockito.Captor;
bpetrivsa7101952019-02-07 16:01:24 +000057import org.mockito.Mock;
58import org.mockito.MockitoSession;
59import org.mockito.quality.Strictness;
60import org.mockito.stubbing.Answer;
61
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000062import java.util.Arrays;
bpetrivsa7101952019-02-07 16:01:24 +000063import java.util.HashMap;
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000064import java.util.List;
bpetrivsa7101952019-02-07 16:01:24 +000065
66/**
67 * Test RescueParty.
68 */
69public class RescuePartyTest {
bpetrivsa7101952019-02-07 16:01:24 +000070 private static final long CURRENT_NETWORK_TIME_MILLIS = 0L;
bpetrivs93075f42019-02-28 12:08:12 +000071 private static final String FAKE_NATIVE_NAMESPACE1 = "native1";
72 private static final String FAKE_NATIVE_NAMESPACE2 = "native2";
73 private static final String[] FAKE_RESET_NATIVE_NAMESPACES =
74 {FAKE_NATIVE_NAMESPACE1, FAKE_NATIVE_NAMESPACE2};
bpetrivsa7101952019-02-07 16:01:24 +000075
Gavin Corkery69395652019-12-12 19:06:47 +000076 private static VersionedPackage sFailingPackage = new VersionedPackage("com.package.name", 1);
77 private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue";
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000078 private static final String CALLING_PACKAGE1 = "com.package.name1";
79 private static final String CALLING_PACKAGE2 = "com.package.name2";
80 private static final String NAMESPACE1 = "namespace1";
81 private static final String NAMESPACE2 = "namespace2";
Gavin Corkery69395652019-12-12 19:06:47 +000082
bpetrivsa7101952019-02-07 16:01:24 +000083 private MockitoSession mSession;
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000084 private HashMap<String, String> mSystemSettingsMap;
bpetrivsa7101952019-02-07 16:01:24 +000085
86 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
87 private Context mMockContext;
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000088 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
89 private PackageWatchdog mMockPackageWatchdog;
bpetrivsa7101952019-02-07 16:01:24 +000090 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
91 private ContentResolver mMockContentResolver;
92
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000093 @Captor
94 private ArgumentCaptor<RemoteCallback> mMonitorCallbackCaptor;
95 @Captor
96 private ArgumentCaptor<List<String>> mPackageListCaptor;
bpetrivsa7101952019-02-07 16:01:24 +000097
98 @Before
99 public void setUp() throws Exception {
100 mSession =
101 ExtendedMockito.mockitoSession().initMocks(
102 this)
103 .strictness(Strictness.LENIENT)
bpetrivs93075f42019-02-28 12:08:12 +0000104 .spyStatic(DeviceConfig.class)
bpetrivsa7101952019-02-07 16:01:24 +0000105 .spyStatic(SystemProperties.class)
106 .spyStatic(Settings.Global.class)
107 .spyStatic(Settings.Secure.class)
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000108 .spyStatic(Settings.Config.class)
bpetrivs93075f42019-02-28 12:08:12 +0000109 .spyStatic(SettingsToPropertiesMapper.class)
bpetrivsa7101952019-02-07 16:01:24 +0000110 .spyStatic(RecoverySystem.class)
111 .spyStatic(RescueParty.class)
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000112 .spyStatic(PackageWatchdog.class)
bpetrivsa7101952019-02-07 16:01:24 +0000113 .startMocking();
114 mSystemSettingsMap = new HashMap<>();
115
116 when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000117 // Reset observer instance to get new mock context on every run
118 RescuePartyObserver.reset();
bpetrivsa7101952019-02-07 16:01:24 +0000119
120 // Mock SystemProperties setter and various getters
121 doAnswer((Answer<Void>) invocationOnMock -> {
122 String key = invocationOnMock.getArgument(0);
123 String value = invocationOnMock.getArgument(1);
124
125 mSystemSettingsMap.put(key, value);
126 return null;
127 }
128 ).when(() -> SystemProperties.set(anyString(), anyString()));
129
130 doAnswer((Answer<Boolean>) invocationOnMock -> {
131 String key = invocationOnMock.getArgument(0);
132 boolean defaultValue = invocationOnMock.getArgument(1);
133
134 String storedValue = mSystemSettingsMap.get(key);
135 return storedValue == null ? defaultValue : Boolean.parseBoolean(storedValue);
136 }
137 ).when(() -> SystemProperties.getBoolean(anyString(), anyBoolean()));
138
139 doAnswer((Answer<Integer>) invocationOnMock -> {
140 String key = invocationOnMock.getArgument(0);
141 int defaultValue = invocationOnMock.getArgument(1);
142
143 String storedValue = mSystemSettingsMap.get(key);
144 return storedValue == null ? defaultValue : Integer.parseInt(storedValue);
145 }
146 ).when(() -> SystemProperties.getInt(anyString(), anyInt()));
147
148 doAnswer((Answer<Long>) invocationOnMock -> {
149 String key = invocationOnMock.getArgument(0);
150 long defaultValue = invocationOnMock.getArgument(1);
151
152 String storedValue = mSystemSettingsMap.get(key);
153 return storedValue == null ? defaultValue : Long.parseLong(storedValue);
154 }
155 ).when(() -> SystemProperties.getLong(anyString(), anyLong()));
156
bpetrivs93075f42019-02-28 12:08:12 +0000157 // Mock DeviceConfig
158 doAnswer((Answer<Boolean>) invocationOnMock -> true)
159 .when(() -> DeviceConfig.setProperty(anyString(), anyString(), anyString(),
160 anyBoolean()));
161 doAnswer((Answer<Void>) invocationOnMock -> null)
162 .when(() -> DeviceConfig.resetToDefaults(anyInt(), anyString()));
163
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000164 // Mock PackageWatchdog
165 doAnswer((Answer<PackageWatchdog>) invocationOnMock -> mMockPackageWatchdog)
166 .when(() -> PackageWatchdog.getInstance(mMockContext));
bpetrivs93075f42019-02-28 12:08:12 +0000167
bpetrivsa7101952019-02-07 16:01:24 +0000168 doReturn(CURRENT_NETWORK_TIME_MILLIS).when(() -> RescueParty.getElapsedRealtime());
bpetrivsa7101952019-02-07 16:01:24 +0000169
170 SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL,
171 Integer.toString(RescueParty.LEVEL_NONE));
172 SystemProperties.set(RescueParty.PROP_RESCUE_BOOT_COUNT, Integer.toString(0));
173 SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
174 }
175
176 @After
177 public void tearDown() throws Exception {
178 mSession.finishMocking();
179 }
180
181 @Test
182 public void testBootLoopDetectionWithExecutionForAllRescueLevels() {
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000183 noteBoot();
bpetrivsa7101952019-02-07 16:01:24 +0000184
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000185 verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
bpetrivsa7101952019-02-07 16:01:24 +0000186 assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
187 SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
188
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000189 noteBoot();
bpetrivsa7101952019-02-07 16:01:24 +0000190
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000191 verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null);
bpetrivsa7101952019-02-07 16:01:24 +0000192 assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
193 SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
194
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000195 noteBoot();
bpetrivsa7101952019-02-07 16:01:24 +0000196
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000197 verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
bpetrivsa7101952019-02-07 16:01:24 +0000198 assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
199 SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
200
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000201 noteBoot();
bpetrivsa7101952019-02-07 16:01:24 +0000202
203 verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000204 assertEquals(LEVEL_FACTORY_RESET,
bpetrivsa7101952019-02-07 16:01:24 +0000205 SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
206 }
207
208 @Test
209 public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevels() {
Gavin Corkery69395652019-12-12 19:06:47 +0000210 notePersistentAppCrash();
bpetrivsa7101952019-02-07 16:01:24 +0000211
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000212 verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
bpetrivsa7101952019-02-07 16:01:24 +0000213 assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
214 SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
215
Gavin Corkery69395652019-12-12 19:06:47 +0000216 notePersistentAppCrash();
bpetrivsa7101952019-02-07 16:01:24 +0000217
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000218 verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null);
bpetrivsa7101952019-02-07 16:01:24 +0000219 assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
220 SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
221
Gavin Corkery69395652019-12-12 19:06:47 +0000222 notePersistentAppCrash();
bpetrivsa7101952019-02-07 16:01:24 +0000223
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000224 verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
bpetrivsa7101952019-02-07 16:01:24 +0000225 assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
226 SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
227
Gavin Corkery69395652019-12-12 19:06:47 +0000228 notePersistentAppCrash();
bpetrivsa7101952019-02-07 16:01:24 +0000229
230 verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000231 assertEquals(LEVEL_FACTORY_RESET,
bpetrivsa7101952019-02-07 16:01:24 +0000232 SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
233 }
234
235 @Test
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000236 public void testNonPersistentAppCrashDetectionWithScopedResets() {
237 RescueParty.onSettingsProviderPublished(mMockContext);
238 verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
239 mMonitorCallbackCaptor.capture()));
240
241 // Record DeviceConfig accesses
242 RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
243 RemoteCallback monitorCallback = mMonitorCallbackCaptor.getValue();
244 monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE1));
245 monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE2));
246 monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE2));
247 // Fake DeviceConfig value changes
248 monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE1));
249 verify(mMockPackageWatchdog).startObservingHealth(observer,
250 Arrays.asList(CALLING_PACKAGE1), RescueParty.DEFAULT_OBSERVING_DURATION_MS);
251 monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE2));
252 verify(mMockPackageWatchdog, times(2)).startObservingHealth(eq(observer),
253 mPackageListCaptor.capture(),
254 eq(RescueParty.DEFAULT_OBSERVING_DURATION_MS));
255 assertTrue(mPackageListCaptor.getValue().containsAll(
256 Arrays.asList(CALLING_PACKAGE1, CALLING_PACKAGE2)));
257 // Perform and verify scoped resets
258 final String[] expectedResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
259 observer.execute(new VersionedPackage(
260 CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH);
261 verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, expectedResetNamespaces);
262 assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
263 SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
264
265 observer.execute(new VersionedPackage(
266 CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
267 verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, expectedResetNamespaces);
268 assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
269 SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
270
271 observer.execute(new VersionedPackage(
272 CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
273 verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/null);
274 assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
275 SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
276
277 observer.execute(new VersionedPackage(
278 CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH);
279 verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
280 assertTrue(RescueParty.isAttemptingFactoryReset());
281 }
282
283 @Test
bpetrivsa7101952019-02-07 16:01:24 +0000284 public void testIsAttemptingFactoryReset() {
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000285 for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
286 noteBoot();
287 }
bpetrivsa7101952019-02-07 16:01:24 +0000288 verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
289 assertTrue(RescueParty.isAttemptingFactoryReset());
290 }
291
292 @Test
293 public void testOnSettingsProviderPublishedExecutesRescueLevels() {
294 SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(1));
295
296 RescueParty.onSettingsProviderPublished(mMockContext);
297
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000298 verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
bpetrivsa7101952019-02-07 16:01:24 +0000299 assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
300 SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
301 }
302
bpetrivs93075f42019-02-28 12:08:12 +0000303 @Test
304 public void testNativeRescuePartyResets() {
305 doReturn(true).when(() -> SettingsToPropertiesMapper.isNativeFlagsResetPerformed());
306 doReturn(FAKE_RESET_NATIVE_NAMESPACES).when(
307 () -> SettingsToPropertiesMapper.getResetNativeCategories());
308
309 RescueParty.onSettingsProviderPublished(mMockContext);
310
311 verify(() -> DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS,
312 FAKE_NATIVE_NAMESPACE1));
313 verify(() -> DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS,
314 FAKE_NATIVE_NAMESPACE2));
bpetrivs93075f42019-02-28 12:08:12 +0000315 }
316
Gavin Corkery69395652019-12-12 19:06:47 +0000317 @Test
318 public void testExplicitlyEnablingAndDisablingRescue() {
319 SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
320 SystemProperties.set(PROP_DISABLE_RESCUE, Boolean.toString(true));
321 assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
322 PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING), false);
323
324 SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
325 assertTrue(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
326 PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING));
327 }
328
329 @Test
330 public void testHealthCheckLevels() {
331 RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
332
333 // Ensure that no action is taken for cases where the failure reason is unknown
334 SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000335 LEVEL_FACTORY_RESET));
Gavin Corkery69395652019-12-12 19:06:47 +0000336 assertEquals(observer.onHealthCheckFailed(null, PackageWatchdog.FAILURE_REASON_UNKNOWN),
337 PackageHealthObserverImpact.USER_IMPACT_NONE);
338
339 /*
340 For the following cases, ensure that the returned user impact corresponds with the user
341 impact of the next available rescue level, not the current one.
342 */
343 SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
344 RescueParty.LEVEL_NONE));
345 assertEquals(observer.onHealthCheckFailed(null,
346 PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
347 PackageHealthObserverImpact.USER_IMPACT_LOW);
348
349 SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
350 RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS));
351 assertEquals(observer.onHealthCheckFailed(null,
352 PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
353 PackageHealthObserverImpact.USER_IMPACT_LOW);
354
355
356 SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
357 RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES));
358 assertEquals(observer.onHealthCheckFailed(null,
359 PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
360 PackageHealthObserverImpact.USER_IMPACT_HIGH);
361
362
363 SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
364 RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS));
365 assertEquals(observer.onHealthCheckFailed(null,
366 PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
367 PackageHealthObserverImpact.USER_IMPACT_HIGH);
368
369
370 SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000371 LEVEL_FACTORY_RESET));
Gavin Corkery69395652019-12-12 19:06:47 +0000372 assertEquals(observer.onHealthCheckFailed(null,
373 PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
374 PackageHealthObserverImpact.USER_IMPACT_HIGH);
375 }
376
377 @Test
378 public void testRescueLevelIncrementsWhenExecuted() {
379 RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
380 SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
381 RescueParty.LEVEL_NONE));
382 observer.execute(sFailingPackage,
383 PackageWatchdog.FAILURE_REASON_APP_CRASH);
384 assertEquals(SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, -1),
385 RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS);
386 }
387
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000388 private void verifySettingsResets(int resetMode, String[] resetNamespaces) {
bpetrivsa7101952019-02-07 16:01:24 +0000389 verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null,
bpetrivs93075f42019-02-28 12:08:12 +0000390 resetMode, UserHandle.USER_SYSTEM));
bpetrivsa7101952019-02-07 16:01:24 +0000391 verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(),
392 eq(resetMode), anyInt()));
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000393 // Verify DeviceConfig resets
394 if (resetNamespaces == null) {
395 verify(() -> DeviceConfig.resetToDefaults(resetMode, /*namespace=*/ null));
396 } else {
397 for (String namespace : resetNamespaces) {
398 verify(() -> DeviceConfig.resetToDefaults(resetMode, namespace));
399 }
400 }
bpetrivsa7101952019-02-07 16:01:24 +0000401 }
402
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000403 private void noteBoot() {
404 RescuePartyObserver.getInstance(mMockContext).executeBootLoopMitigation();
bpetrivsa7101952019-02-07 16:01:24 +0000405 }
406
Gavin Corkery69395652019-12-12 19:06:47 +0000407 private void notePersistentAppCrash() {
408 RescuePartyObserver.getInstance(mMockContext).execute(new VersionedPackage(
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000409 "com.package.name", 1), PackageWatchdog.FAILURE_REASON_APP_CRASH);
410 }
411
412 private Bundle getConfigAccessBundle(String callingPackage, String namespace) {
413 Bundle result = new Bundle();
414 result.putString(Settings.EXTRA_MONITOR_CALLBACK_TYPE, Settings.EXTRA_ACCESS_CALLBACK);
415 result.putString(Settings.EXTRA_CALLING_PACKAGE, callingPackage);
416 result.putString(Settings.EXTRA_NAMESPACE, namespace);
417 return result;
418 }
419
420 private Bundle getConfigNamespaceUpdateBundle(String updatedNamespace) {
421 Bundle result = new Bundle();
422 result.putString(Settings.EXTRA_MONITOR_CALLBACK_TYPE,
423 Settings.EXTRA_NAMESPACE_UPDATED_CALLBACK);
424 result.putString(Settings.EXTRA_NAMESPACE, updatedNamespace);
425 return result;
bpetrivsa7101952019-02-07 16:01:24 +0000426 }
427}