blob: bacffb6140eda279bab93d8cc065bfa923d6214b [file] [log] [blame]
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -07001/*
2 * Copyright (C) 2017 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
Todd Kennedy7c4c55d2017-11-02 10:01:39 -070019import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
20
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000021import android.annotation.NonNull;
Gavin Corkery69395652019-12-12 19:06:47 +000022import android.annotation.Nullable;
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -070023import android.content.ContentResolver;
24import android.content.Context;
Gavin Corkery69395652019-12-12 19:06:47 +000025import android.content.pm.ApplicationInfo;
26import android.content.pm.PackageManager;
27import android.content.pm.VersionedPackage;
Jeff Sharkey9f1fc2d2017-01-24 11:05:16 -070028import android.os.Build;
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000029import android.os.Bundle;
Jeff Sharkey82311462017-04-02 23:42:17 -060030import android.os.Environment;
Jeff Sharkey1bec4482017-02-23 12:40:54 -070031import android.os.FileUtils;
Gavin Corkeryaa57ef32019-12-17 19:02:54 +000032import android.os.Process;
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -070033import android.os.RecoverySystem;
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000034import android.os.RemoteCallback;
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -070035import android.os.SystemClock;
36import android.os.SystemProperties;
37import android.os.UserHandle;
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000038import android.provider.DeviceConfig;
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -070039import android.provider.Settings;
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000040import android.util.ArraySet;
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -070041import android.util.ExceptionUtils;
Jeff Sharkeybc9caa12017-03-11 20:38:21 -070042import android.util.Log;
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -070043import android.util.MathUtils;
44import android.util.Slog;
Christian Brunschenf86039e2018-12-21 12:26:14 +000045import android.util.StatsLog;
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -070046
Gavin Corkery69395652019-12-12 19:06:47 +000047import com.android.internal.annotations.GuardedBy;
bpetrivsa7101952019-02-07 16:01:24 +000048import com.android.internal.annotations.VisibleForTesting;
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -070049import com.android.internal.util.ArrayUtils;
Gavin Corkery69395652019-12-12 19:06:47 +000050import com.android.server.PackageWatchdog.FailureReasons;
51import com.android.server.PackageWatchdog.PackageHealthObserver;
52import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
bpetrivs93075f42019-02-28 12:08:12 +000053import com.android.server.am.SettingsToPropertiesMapper;
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -070054
Jeff Sharkey1bec4482017-02-23 12:40:54 -070055import java.io.File;
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000056import java.util.ArrayList;
bpetrivs93075f42019-02-28 12:08:12 +000057import java.util.Arrays;
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000058import java.util.HashMap;
59import java.util.Iterator;
60import java.util.List;
61import java.util.Map;
62import java.util.Set;
63import java.util.concurrent.TimeUnit;
Jeff Sharkeyd9574c72017-02-20 10:45:06 -070064
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -070065/**
66 * Utilities to help rescue the system from crash loops. Callers are expected to
67 * report boot events and persistent app crashes, and if they happen frequently
68 * enough this class will slowly escalate through several rescue operations
69 * before finally rebooting and prompting the user if they want to wipe data as
70 * a last resort.
71 *
72 * @hide
73 */
74public class RescueParty {
bpetrivsa7101952019-02-07 16:01:24 +000075 @VisibleForTesting
76 static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue";
77 @VisibleForTesting
bpetrivsa7101952019-02-07 16:01:24 +000078 static final String PROP_RESCUE_LEVEL = "sys.rescue_level";
79 @VisibleForTesting
80 static final int LEVEL_NONE = 0;
81 @VisibleForTesting
82 static final int LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1;
83 @VisibleForTesting
84 static final int LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 2;
85 @VisibleForTesting
86 static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3;
87 @VisibleForTesting
88 static final int LEVEL_FACTORY_RESET = 4;
89 @VisibleForTesting
90 static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
bpetrivsa7101952019-02-07 16:01:24 +000091 @VisibleForTesting
bpetrivsa7101952019-02-07 16:01:24 +000092 static final String TAG = "RescueParty";
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +000093 @VisibleForTesting
94 static final long DEFAULT_OBSERVING_DURATION_MS = TimeUnit.DAYS.toMillis(2);
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -070095
Gavin Corkery69395652019-12-12 19:06:47 +000096 private static final String NAME = "rescue-party-observer";
97
98
Jeff Sharkey9f1fc2d2017-01-24 11:05:16 -070099 private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue";
Jeff Sharkey9d640952017-06-26 19:57:16 -0600100 private static final String PROP_VIRTUAL_DEVICE = "ro.hardware.virtual_device";
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700101
Gavin Corkery69395652019-12-12 19:06:47 +0000102 private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
103 | ApplicationInfo.FLAG_SYSTEM;
104
Gavin Corkery69395652019-12-12 19:06:47 +0000105 /** Register the Rescue Party observer as a Package Watchdog health observer */
106 public static void registerHealthObserver(Context context) {
107 PackageWatchdog.getInstance(context).registerHealthObserver(
108 RescuePartyObserver.getInstance(context));
109 }
110
Jeff Sharkey9f1fc2d2017-01-24 11:05:16 -0700111 private static boolean isDisabled() {
Jeff Sharkeybc9caa12017-03-11 20:38:21 -0700112 // Check if we're explicitly enabled for testing
Jeff Sharkey82311462017-04-02 23:42:17 -0600113 if (SystemProperties.getBoolean(PROP_ENABLE_RESCUE, false)) {
Jeff Sharkeybc9caa12017-03-11 20:38:21 -0700114 return false;
115 }
116
Jeff Sharkeycdee83a2017-01-26 15:29:16 -0700117 // We're disabled on all engineering devices
Jeff Sharkeyd9574c72017-02-20 10:45:06 -0700118 if (Build.IS_ENG) {
119 Slog.v(TAG, "Disabled because of eng build");
120 return true;
121 }
Jeff Sharkeycdee83a2017-01-26 15:29:16 -0700122
123 // We're disabled on userdebug devices connected over USB, since that's
124 // a decent signal that someone is actively trying to debug the device,
125 // or that it's in a lab environment.
Jeff Sharkeyd9574c72017-02-20 10:45:06 -0700126 if (Build.IS_USERDEBUG && isUsbActive()) {
127 Slog.v(TAG, "Disabled because of active USB connection");
128 return true;
Jeff Sharkeycdee83a2017-01-26 15:29:16 -0700129 }
130
131 // One last-ditch check
Jeff Sharkeyd9574c72017-02-20 10:45:06 -0700132 if (SystemProperties.getBoolean(PROP_DISABLE_RESCUE, false)) {
133 Slog.v(TAG, "Disabled because of manual property");
134 return true;
135 }
136
137 return false;
Jeff Sharkey9f1fc2d2017-01-24 11:05:16 -0700138 }
139
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700140 /**
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700141 * Check if we're currently attempting to reboot for a factory reset.
142 */
143 public static boolean isAttemptingFactoryReset() {
144 return SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) == LEVEL_FACTORY_RESET;
145 }
146
147 /**
bpetrivsa7101952019-02-07 16:01:24 +0000148 * Called when {@code SettingsProvider} has been published, which is a good
149 * opportunity to reset any settings depending on our rescue level.
150 */
151 public static void onSettingsProviderPublished(Context context) {
bpetrivs93075f42019-02-28 12:08:12 +0000152 handleNativeRescuePartyResets();
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000153 executeRescueLevel(context, /*failedPackage=*/ null);
154 ContentResolver contentResolver = context.getContentResolver();
155 Settings.Config.registerMonitorCallback(contentResolver, new RemoteCallback(result -> {
156 handleMonitorCallback(context, result);
157 }));
bpetrivsa7101952019-02-07 16:01:24 +0000158 }
159
160 @VisibleForTesting
bpetrivsa7101952019-02-07 16:01:24 +0000161 static long getElapsedRealtime() {
162 return SystemClock.elapsedRealtime();
163 }
164
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000165 private static void handleMonitorCallback(Context context, Bundle result) {
166 String callbackType = result.getString(Settings.EXTRA_MONITOR_CALLBACK_TYPE, "");
167 switch (callbackType) {
168 case Settings.EXTRA_NAMESPACE_UPDATED_CALLBACK:
169 String updatedNamespace = result.getString(Settings.EXTRA_NAMESPACE);
170 if (updatedNamespace != null) {
171 startObservingPackages(context, updatedNamespace);
172 }
173 break;
174 case Settings.EXTRA_ACCESS_CALLBACK:
175 String callingPackage = result.getString(Settings.EXTRA_CALLING_PACKAGE, null);
176 String namespace = result.getString(Settings.EXTRA_NAMESPACE, null);
177 if (namespace != null && callingPackage != null) {
178 RescuePartyObserver.getInstance(context).recordDeviceConfigAccess(
179 callingPackage,
180 namespace);
181 }
182 break;
183 default:
184 Slog.w(TAG, "Unrecognized DeviceConfig callback");
185 break;
186 }
187 }
188
189 private static void startObservingPackages(Context context, @NonNull String updatedNamespace) {
190 RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
191 Set<String> callingPackages = rescuePartyObserver.getCallingPackagesSet(updatedNamespace);
192 if (callingPackages == null) {
193 return;
194 }
195 List<String> callingPackageList = new ArrayList<>();
196 callingPackageList.addAll(callingPackages);
197 Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: "
198 + updatedNamespace);
199 PackageWatchdog.getInstance(context).startObservingHealth(
200 rescuePartyObserver,
201 callingPackageList,
202 DEFAULT_OBSERVING_DURATION_MS);
203 }
204
bpetrivs93075f42019-02-28 12:08:12 +0000205 private static void handleNativeRescuePartyResets() {
206 if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) {
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000207 String[] resetNativeCategories = SettingsToPropertiesMapper.getResetNativeCategories();
208 for (int i = 0; i < resetNativeCategories.length; i++) {
209 DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS,
210 resetNativeCategories[i]);
211 }
bpetrivs93075f42019-02-28 12:08:12 +0000212 }
213 }
214
bpetrivsa7101952019-02-07 16:01:24 +0000215 /**
Gavin Corkerybb3a5042020-01-29 13:44:20 +0000216 * Get the next rescue level. This indicates the next level of mitigation that may be taken.
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000217 */
Gavin Corkerybb3a5042020-01-29 13:44:20 +0000218 private static int getNextRescueLevel() {
219 return MathUtils.constrain(SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) + 1,
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000220 LEVEL_NONE, LEVEL_FACTORY_RESET);
221 }
222
223 /**
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700224 * Escalate to the next rescue level. After incrementing the level you'll
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000225 * probably want to call {@link #executeRescueLevel(Context, String)}.
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700226 */
227 private static void incrementRescueLevel(int triggerUid) {
Gavin Corkerybb3a5042020-01-29 13:44:20 +0000228 final int level = getNextRescueLevel();
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700229 SystemProperties.set(PROP_RESCUE_LEVEL, Integer.toString(level));
230
231 EventLogTags.writeRescueLevel(level, triggerUid);
Todd Kennedy7c4c55d2017-11-02 10:01:39 -0700232 logCriticalInfo(Log.WARN, "Incremented rescue level to "
Jeff Sharkeybc9caa12017-03-11 20:38:21 -0700233 + levelToString(level) + " triggered by UID " + triggerUid);
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700234 }
235
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000236 private static void executeRescueLevel(Context context, @Nullable String failedPackage) {
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700237 final int level = SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE);
238 if (level == LEVEL_NONE) return;
239
240 Slog.w(TAG, "Attempting rescue level " + levelToString(level));
241 try {
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000242 executeRescueLevelInternal(context, level, failedPackage);
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700243 EventLogTags.writeRescueSuccess(level);
Todd Kennedy7c4c55d2017-11-02 10:01:39 -0700244 logCriticalInfo(Log.DEBUG,
Jeff Sharkeybc9caa12017-03-11 20:38:21 -0700245 "Finished rescue level " + levelToString(level));
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700246 } catch (Throwable t) {
Jeff Sharkeybc9caa12017-03-11 20:38:21 -0700247 final String msg = ExceptionUtils.getCompleteMessage(t);
248 EventLogTags.writeRescueFailure(level, msg);
Todd Kennedy7c4c55d2017-11-02 10:01:39 -0700249 logCriticalInfo(Log.ERROR,
Jeff Sharkeybc9caa12017-03-11 20:38:21 -0700250 "Failed rescue level " + levelToString(level) + ": " + msg);
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700251 }
252 }
253
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000254 private static void executeRescueLevelInternal(Context context, int level, @Nullable
255 String failedPackage) throws Exception {
Christian Brunschenf86039e2018-12-21 12:26:14 +0000256 StatsLog.write(StatsLog.RESCUE_PARTY_RESET_REPORTED, level);
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700257 switch (level) {
258 case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000259 resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS, failedPackage);
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700260 break;
261 case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000262 resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_CHANGES, failedPackage);
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700263 break;
264 case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000265 resetAllSettings(context, Settings.RESET_MODE_TRUSTED_DEFAULTS, failedPackage);
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700266 break;
267 case LEVEL_FACTORY_RESET:
268 RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
269 break;
270 }
271 }
272
Gavin Corkery69395652019-12-12 19:06:47 +0000273 private static int mapRescueLevelToUserImpact(int rescueLevel) {
274 switch(rescueLevel) {
275 case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
276 case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
277 return PackageHealthObserverImpact.USER_IMPACT_LOW;
278 case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
279 case LEVEL_FACTORY_RESET:
280 return PackageHealthObserverImpact.USER_IMPACT_HIGH;
281 default:
282 return PackageHealthObserverImpact.USER_IMPACT_NONE;
283 }
284 }
285
286 private static int getPackageUid(Context context, String packageName) {
287 try {
288 return context.getPackageManager().getPackageUid(packageName, 0);
289 } catch (PackageManager.NameNotFoundException e) {
290 // Since UIDs are always >= 0, this value means the UID could not be determined.
291 return -1;
292 }
293 }
294
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000295 private static void resetAllSettings(Context context, int mode, @Nullable String failedPackage)
296 throws Exception {
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700297 // Try our best to reset all settings possible, and once finished
298 // rethrow any exception that we encountered
299 Exception res = null;
300 final ContentResolver resolver = context.getContentResolver();
301 try {
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000302 resetDeviceConfig(context, mode, failedPackage);
bpetrivs62f15982019-02-13 17:18:16 +0000303 } catch (Exception e) {
304 res = new RuntimeException("Failed to reset config settings", e);
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700305 }
bpetrivs0254ff62019-03-01 11:50:45 +0000306 try {
307 Settings.Global.resetToDefaultsAsUser(resolver, null, mode, UserHandle.USER_SYSTEM);
308 } catch (Exception e) {
309 res = new RuntimeException("Failed to reset global settings", e);
310 }
Jeff Sharkey82311462017-04-02 23:42:17 -0600311 for (int userId : getAllUserIds()) {
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700312 try {
313 Settings.Secure.resetToDefaultsAsUser(resolver, null, mode, userId);
bpetrivs62f15982019-02-13 17:18:16 +0000314 } catch (Exception e) {
315 res = new RuntimeException("Failed to reset secure settings for " + userId, e);
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700316 }
317 }
318 if (res != null) {
319 throw res;
320 }
321 }
322
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000323 private static void resetDeviceConfig(Context context, int resetMode,
324 @Nullable String failedPackage) {
325 if (!shouldPerformScopedResets() || failedPackage == null) {
326 DeviceConfig.resetToDefaults(resetMode, /*namespace=*/ null);
327 } else {
328 performScopedReset(context, resetMode, failedPackage);
329 }
330 }
331
332 private static boolean shouldPerformScopedResets() {
333 int rescueLevel = MathUtils.constrain(
334 SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE),
335 LEVEL_NONE, LEVEL_FACTORY_RESET);
336 return rescueLevel <= LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES;
337 }
338
339 private static void performScopedReset(Context context, int resetMode,
340 @NonNull String failedPackage) {
341 RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
342 Set<String> affectedNamespaces = rescuePartyObserver.getAffectedNamespaceSet(
343 failedPackage);
344 if (affectedNamespaces == null) {
345 DeviceConfig.resetToDefaults(resetMode, /*namespace=*/ null);
346 } else {
347 Slog.w(TAG,
348 "Performing scoped reset for package: " + failedPackage
349 + ", affected namespaces: "
350 + Arrays.toString(affectedNamespaces.toArray()));
351 Iterator<String> it = affectedNamespaces.iterator();
352 while (it.hasNext()) {
353 DeviceConfig.resetToDefaults(resetMode, it.next());
354 }
355 }
356 }
357
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700358 /**
Gavin Corkery69395652019-12-12 19:06:47 +0000359 * Handle mitigation action for package failures. This observer will be register to Package
360 * Watchdog and will receive calls about package failures. This observer is persistent so it
361 * may choose to mitigate failures for packages it has not explicitly asked to observe.
362 */
363 public static class RescuePartyObserver implements PackageHealthObserver {
364
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000365 private final Context mContext;
366 private final Map<String, Set<String>> mCallingPackageNamespaceSetMap = new HashMap<>();
367 private final Map<String, Set<String>> mNamespaceCallingPackageSetMap = new HashMap<>();
Gavin Corkery69395652019-12-12 19:06:47 +0000368
369 @GuardedBy("RescuePartyObserver.class")
370 static RescuePartyObserver sRescuePartyObserver;
371
372 private RescuePartyObserver(Context context) {
373 mContext = context;
374 }
375
376 /** Creates or gets singleton instance of RescueParty. */
377 public static RescuePartyObserver getInstance(Context context) {
378 synchronized (RescuePartyObserver.class) {
379 if (sRescuePartyObserver == null) {
380 sRescuePartyObserver = new RescuePartyObserver(context);
381 }
382 return sRescuePartyObserver;
383 }
384 }
385
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000386 @VisibleForTesting
387 static void reset() {
388 synchronized (RescuePartyObserver.class) {
389 sRescuePartyObserver = null;
390 }
391 }
392
Gavin Corkery69395652019-12-12 19:06:47 +0000393 @Override
394 public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
395 @FailureReasons int failureReason) {
396 if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
397 || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
Gavin Corkerybb3a5042020-01-29 13:44:20 +0000398 return mapRescueLevelToUserImpact(getNextRescueLevel());
Gavin Corkery69395652019-12-12 19:06:47 +0000399 } else {
400 return PackageHealthObserverImpact.USER_IMPACT_NONE;
401 }
402 }
403
404 @Override
405 public boolean execute(@Nullable VersionedPackage failedPackage,
406 @FailureReasons int failureReason) {
407 if (isDisabled()) {
408 return false;
409 }
410 if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
411 || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
412 int triggerUid = getPackageUid(mContext, failedPackage.getPackageName());
413 incrementRescueLevel(triggerUid);
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000414 executeRescueLevel(mContext,
415 failedPackage == null ? null : failedPackage.getPackageName());
Gavin Corkery69395652019-12-12 19:06:47 +0000416 return true;
417 } else {
418 return false;
419 }
420 }
421
422 @Override
423 public boolean isPersistent() {
424 return true;
425 }
426
427 @Override
428 public boolean mayObservePackage(String packageName) {
429 PackageManager pm = mContext.getPackageManager();
430 try {
431 // A package is a Mainline module if this is non-null
432 if (pm.getModuleInfo(packageName, 0) != null) {
433 return true;
434 }
435 ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
436 return (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK;
437 } catch (PackageManager.NameNotFoundException e) {
438 return false;
439 }
440 }
441
442 @Override
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000443 public int onBootLoop() {
444 if (isDisabled()) {
445 return PackageHealthObserverImpact.USER_IMPACT_NONE;
446 }
Gavin Corkerybb3a5042020-01-29 13:44:20 +0000447 return mapRescueLevelToUserImpact(getNextRescueLevel());
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000448 }
449
450 @Override
451 public boolean executeBootLoopMitigation() {
452 if (isDisabled()) {
453 return false;
454 }
455 incrementRescueLevel(Process.ROOT_UID);
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000456 executeRescueLevel(mContext, /*failedPackage=*/ null);
Gavin Corkeryaa57ef32019-12-17 19:02:54 +0000457 return true;
458 }
459
460 @Override
Gavin Corkery69395652019-12-12 19:06:47 +0000461 public String getName() {
462 return NAME;
463 }
Bohdan Petrivskyy095a4d32019-12-18 16:03:47 +0000464
465 private synchronized void recordDeviceConfigAccess(@NonNull String callingPackage,
466 @NonNull String namespace) {
467 // Record it in calling packages to namespace map
468 Set<String> namespaceSet = mCallingPackageNamespaceSetMap.get(callingPackage);
469 if (namespaceSet == null) {
470 namespaceSet = new ArraySet<>();
471 mCallingPackageNamespaceSetMap.put(callingPackage, namespaceSet);
472 }
473 namespaceSet.add(namespace);
474 // Record it in namespace to calling packages map
475 Set<String> callingPackageSet = mNamespaceCallingPackageSetMap.get(namespace);
476 if (callingPackageSet == null) {
477 callingPackageSet = new ArraySet<>();
478 }
479 callingPackageSet.add(callingPackage);
480 mNamespaceCallingPackageSetMap.put(namespace, callingPackageSet);
481 }
482
483 private synchronized Set<String> getAffectedNamespaceSet(String failedPackage) {
484 return mCallingPackageNamespaceSetMap.get(failedPackage);
485 }
486
487 private synchronized Set<String> getCallingPackagesSet(String namespace) {
488 return mNamespaceCallingPackageSetMap.get(namespace);
489 }
Gavin Corkery69395652019-12-12 19:06:47 +0000490 }
491
Jeff Sharkey82311462017-04-02 23:42:17 -0600492 private static int[] getAllUserIds() {
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700493 int[] userIds = { UserHandle.USER_SYSTEM };
494 try {
Jeff Sharkey82311462017-04-02 23:42:17 -0600495 for (File file : FileUtils.listFilesOrEmpty(Environment.getDataSystemDeDirectory())) {
496 try {
497 final int userId = Integer.parseInt(file.getName());
498 if (userId != UserHandle.USER_SYSTEM) {
499 userIds = ArrayUtils.appendInt(userIds, userId);
500 }
501 } catch (NumberFormatException ignored) {
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700502 }
503 }
504 } catch (Throwable t) {
505 Slog.w(TAG, "Trouble discovering users", t);
506 }
507 return userIds;
508 }
509
Jeff Sharkeyd9574c72017-02-20 10:45:06 -0700510 /**
511 * Hacky test to check if the device has an active USB connection, which is
Jeff Sharkey1bec4482017-02-23 12:40:54 -0700512 * a good proxy for someone doing local development work.
Jeff Sharkeyd9574c72017-02-20 10:45:06 -0700513 */
514 private static boolean isUsbActive() {
Jeff Sharkey9d640952017-06-26 19:57:16 -0600515 if (SystemProperties.getBoolean(PROP_VIRTUAL_DEVICE, false)) {
516 Slog.v(TAG, "Assuming virtual device is connected over USB");
517 return true;
518 }
Jeff Sharkeyd9574c72017-02-20 10:45:06 -0700519 try {
Jeff Sharkey1bec4482017-02-23 12:40:54 -0700520 final String state = FileUtils
521 .readTextFile(new File("/sys/class/android_usb/android0/state"), 128, "");
522 return "CONFIGURED".equals(state.trim());
Jeff Sharkeyd9574c72017-02-20 10:45:06 -0700523 } catch (Throwable t) {
524 Slog.w(TAG, "Failed to determine if device was on USB", t);
525 return false;
526 }
527 }
528
Jeff Sharkeyfe6f85c2017-01-20 10:42:57 -0700529 private static String levelToString(int level) {
530 switch (level) {
531 case LEVEL_NONE: return "NONE";
532 case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: return "RESET_SETTINGS_UNTRUSTED_DEFAULTS";
533 case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: return "RESET_SETTINGS_UNTRUSTED_CHANGES";
534 case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: return "RESET_SETTINGS_TRUSTED_DEFAULTS";
535 case LEVEL_FACTORY_RESET: return "FACTORY_RESET";
536 default: return Integer.toString(level);
537 }
538 }
539}