1 /* 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 17 package com.android.server; 18 19 import static android.provider.DeviceConfig.Properties; 20 21 import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.content.ContentResolver; 26 import android.content.Context; 27 import android.content.pm.ApplicationInfo; 28 import android.content.pm.PackageManager; 29 import android.content.pm.VersionedPackage; 30 import android.os.Build; 31 import android.os.Bundle; 32 import android.os.Environment; 33 import android.os.FileUtils; 34 import android.os.PowerManager; 35 import android.os.RecoverySystem; 36 import android.os.RemoteCallback; 37 import android.os.SystemClock; 38 import android.os.SystemProperties; 39 import android.os.UserHandle; 40 import android.provider.DeviceConfig; 41 import android.provider.Settings; 42 import android.text.TextUtils; 43 import android.util.ArraySet; 44 import android.util.ExceptionUtils; 45 import android.util.Log; 46 import android.util.Slog; 47 48 import com.android.internal.annotations.GuardedBy; 49 import com.android.internal.annotations.VisibleForTesting; 50 import com.android.internal.util.ArrayUtils; 51 import com.android.internal.util.FrameworkStatsLog; 52 import com.android.server.PackageWatchdog.FailureReasons; 53 import com.android.server.PackageWatchdog.PackageHealthObserver; 54 import com.android.server.PackageWatchdog.PackageHealthObserverImpact; 55 import com.android.server.am.SettingsToPropertiesMapper; 56 57 import java.io.File; 58 import java.util.ArrayList; 59 import java.util.Arrays; 60 import java.util.HashMap; 61 import java.util.HashSet; 62 import java.util.Iterator; 63 import java.util.List; 64 import java.util.Map; 65 import java.util.Set; 66 import java.util.concurrent.TimeUnit; 67 68 /** 69 * Utilities to help rescue the system from crash loops. Callers are expected to 70 * report boot events and persistent app crashes, and if they happen frequently 71 * enough this class will slowly escalate through several rescue operations 72 * before finally rebooting and prompting the user if they want to wipe data as 73 * a last resort. 74 * 75 * @hide 76 */ 77 public class RescueParty { 78 @VisibleForTesting 79 static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue"; 80 static final String PROP_ATTEMPTING_FACTORY_RESET = "sys.attempting_factory_reset"; 81 static final String PROP_ATTEMPTING_REBOOT = "sys.attempting_reboot"; 82 static final String PROP_MAX_RESCUE_LEVEL_ATTEMPTED = "sys.max_rescue_level_attempted"; 83 @VisibleForTesting 84 static final int LEVEL_NONE = 0; 85 @VisibleForTesting 86 static final int LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1; 87 @VisibleForTesting 88 static final int LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 2; 89 @VisibleForTesting 90 static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3; 91 @VisibleForTesting 92 static final int LEVEL_WARM_REBOOT = 4; 93 @VisibleForTesting 94 static final int LEVEL_FACTORY_RESET = 5; 95 @VisibleForTesting 96 static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count"; 97 @VisibleForTesting 98 static final String TAG = "RescueParty"; 99 @VisibleForTesting 100 static final long DEFAULT_OBSERVING_DURATION_MS = TimeUnit.DAYS.toMillis(2); 101 @VisibleForTesting 102 static final int DEVICE_CONFIG_RESET_MODE = Settings.RESET_MODE_TRUSTED_DEFAULTS; 103 // The DeviceConfig namespace containing all RescueParty switches. 104 @VisibleForTesting 105 static final String NAMESPACE_CONFIGURATION = "configuration"; 106 @VisibleForTesting 107 static final String NAMESPACE_TO_PACKAGE_MAPPING_FLAG = 108 "namespace_to_package_mapping"; 109 110 private static final String NAME = "rescue-party-observer"; 111 112 113 private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue"; 114 private static final String PROP_VIRTUAL_DEVICE = "ro.hardware.virtual_device"; 115 private static final String PROP_DEVICE_CONFIG_DISABLE_FLAG = 116 "persist.device_config.configuration.disable_rescue_party"; 117 private static final String PROP_DISABLE_FACTORY_RESET_FLAG = 118 "persist.device_config.configuration.disable_rescue_party_factory_reset"; 119 120 private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT 121 | ApplicationInfo.FLAG_SYSTEM; 122 123 /** Register the Rescue Party observer as a Package Watchdog health observer */ registerHealthObserver(Context context)124 public static void registerHealthObserver(Context context) { 125 PackageWatchdog.getInstance(context).registerHealthObserver( 126 RescuePartyObserver.getInstance(context)); 127 } 128 isDisabled()129 private static boolean isDisabled() { 130 // Check if we're explicitly enabled for testing 131 if (SystemProperties.getBoolean(PROP_ENABLE_RESCUE, false)) { 132 return false; 133 } 134 135 // We're disabled if the DeviceConfig disable flag is set to true. 136 // This is in case that an emergency rollback of the feature is needed. 137 if (SystemProperties.getBoolean(PROP_DEVICE_CONFIG_DISABLE_FLAG, false)) { 138 Slog.v(TAG, "Disabled because of DeviceConfig flag"); 139 return true; 140 } 141 142 // We're disabled on all engineering devices 143 if (Build.IS_ENG) { 144 Slog.v(TAG, "Disabled because of eng build"); 145 return true; 146 } 147 148 // We're disabled on userdebug devices connected over USB, since that's 149 // a decent signal that someone is actively trying to debug the device, 150 // or that it's in a lab environment. 151 if (Build.IS_USERDEBUG && isUsbActive()) { 152 Slog.v(TAG, "Disabled because of active USB connection"); 153 return true; 154 } 155 156 // One last-ditch check 157 if (SystemProperties.getBoolean(PROP_DISABLE_RESCUE, false)) { 158 Slog.v(TAG, "Disabled because of manual property"); 159 return true; 160 } 161 162 return false; 163 } 164 165 /** 166 * Check if we're currently attempting to reboot for a factory reset. This method must 167 * return true if RescueParty tries to reboot early during a boot loop, since the device 168 * will not be fully booted at this time. 169 * 170 * TODO(gavincorkery): Rename method since its scope has expanded. 171 */ isAttemptingFactoryReset()172 public static boolean isAttemptingFactoryReset() { 173 return isFactoryResetPropertySet() || isRebootPropertySet(); 174 } 175 isFactoryResetPropertySet()176 static boolean isFactoryResetPropertySet() { 177 return SystemProperties.getBoolean(PROP_ATTEMPTING_FACTORY_RESET, false); 178 } 179 isRebootPropertySet()180 static boolean isRebootPropertySet() { 181 return SystemProperties.getBoolean(PROP_ATTEMPTING_REBOOT, false); 182 } 183 184 /** 185 * Called when {@code SettingsProvider} has been published, which is a good 186 * opportunity to reset any settings depending on our rescue level. 187 */ onSettingsProviderPublished(Context context)188 public static void onSettingsProviderPublished(Context context) { 189 handleNativeRescuePartyResets(); 190 ContentResolver contentResolver = context.getContentResolver(); 191 Settings.Config.registerMonitorCallback(contentResolver, new RemoteCallback(result -> { 192 handleMonitorCallback(context, result); 193 })); 194 } 195 196 197 /** 198 * Called when {@code RollbackManager} performs Mainline module rollbacks, 199 * to avoid rolled back modules consuming flag values only expected to work 200 * on modules of newer versions. 201 */ resetDeviceConfigForPackages(List<String> packageNames)202 public static void resetDeviceConfigForPackages(List<String> packageNames) { 203 if (packageNames == null) { 204 return; 205 } 206 Set<String> namespacesToReset = new ArraySet<String>(); 207 Iterator<String> it = packageNames.iterator(); 208 RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstanceIfCreated(); 209 // Get runtime package to namespace mapping if created. 210 if (rescuePartyObserver != null) { 211 while (it.hasNext()) { 212 String packageName = it.next(); 213 Set<String> runtimeAffectedNamespaces = 214 rescuePartyObserver.getAffectedNamespaceSet(packageName); 215 if (runtimeAffectedNamespaces != null) { 216 namespacesToReset.addAll(runtimeAffectedNamespaces); 217 } 218 } 219 } 220 // Get preset package to namespace mapping if created. 221 Set<String> presetAffectedNamespaces = getPresetNamespacesForPackages( 222 packageNames); 223 if (presetAffectedNamespaces != null) { 224 namespacesToReset.addAll(presetAffectedNamespaces); 225 } 226 227 // Clear flags under the namespaces mapped to these packages. 228 // Using setProperties since DeviceConfig.resetToDefaults bans the current flag set. 229 Iterator<String> namespaceIt = namespacesToReset.iterator(); 230 while (namespaceIt.hasNext()) { 231 String namespaceToReset = namespaceIt.next(); 232 Properties properties = new Properties.Builder(namespaceToReset).build(); 233 try { 234 DeviceConfig.setProperties(properties); 235 } catch (DeviceConfig.BadConfigException exception) { 236 logCriticalInfo(Log.WARN, "namespace " + namespaceToReset 237 + " is already banned, skip reset."); 238 } 239 } 240 } 241 getPresetNamespacesForPackages(List<String> packageNames)242 private static Set<String> getPresetNamespacesForPackages(List<String> packageNames) { 243 Set<String> resultSet = new ArraySet<String>(); 244 try { 245 String flagVal = DeviceConfig.getString(NAMESPACE_CONFIGURATION, 246 NAMESPACE_TO_PACKAGE_MAPPING_FLAG, ""); 247 String[] mappingEntries = flagVal.split(","); 248 for (int i = 0; i < mappingEntries.length; i++) { 249 if (TextUtils.isEmpty(mappingEntries[i])) { 250 continue; 251 } 252 String[] splittedEntry = mappingEntries[i].split(":"); 253 if (splittedEntry.length != 2) { 254 throw new RuntimeException("Invalid mapping entry: " + mappingEntries[i]); 255 } 256 String namespace = splittedEntry[0]; 257 String packageName = splittedEntry[1]; 258 259 if (packageNames.contains(packageName)) { 260 resultSet.add(namespace); 261 } 262 } 263 } catch (Exception e) { 264 resultSet.clear(); 265 Slog.e(TAG, "Failed to read preset package to namespaces mapping.", e); 266 } finally { 267 return resultSet; 268 } 269 } 270 271 @VisibleForTesting getElapsedRealtime()272 static long getElapsedRealtime() { 273 return SystemClock.elapsedRealtime(); 274 } 275 handleMonitorCallback(Context context, Bundle result)276 private static void handleMonitorCallback(Context context, Bundle result) { 277 String callbackType = result.getString(Settings.EXTRA_MONITOR_CALLBACK_TYPE, ""); 278 switch (callbackType) { 279 case Settings.EXTRA_NAMESPACE_UPDATED_CALLBACK: 280 String updatedNamespace = result.getString(Settings.EXTRA_NAMESPACE); 281 if (updatedNamespace != null) { 282 startObservingPackages(context, updatedNamespace); 283 } 284 break; 285 case Settings.EXTRA_ACCESS_CALLBACK: 286 String callingPackage = result.getString(Settings.EXTRA_CALLING_PACKAGE, null); 287 String namespace = result.getString(Settings.EXTRA_NAMESPACE, null); 288 if (namespace != null && callingPackage != null) { 289 RescuePartyObserver.getInstance(context).recordDeviceConfigAccess( 290 callingPackage, 291 namespace); 292 } 293 break; 294 default: 295 Slog.w(TAG, "Unrecognized DeviceConfig callback"); 296 break; 297 } 298 } 299 startObservingPackages(Context context, @NonNull String updatedNamespace)300 private static void startObservingPackages(Context context, @NonNull String updatedNamespace) { 301 RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context); 302 Set<String> callingPackages = rescuePartyObserver.getCallingPackagesSet(updatedNamespace); 303 if (callingPackages == null) { 304 return; 305 } 306 List<String> callingPackageList = new ArrayList<>(); 307 callingPackageList.addAll(callingPackages); 308 Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: " 309 + updatedNamespace); 310 PackageWatchdog.getInstance(context).startObservingHealth( 311 rescuePartyObserver, 312 callingPackageList, 313 DEFAULT_OBSERVING_DURATION_MS); 314 } 315 handleNativeRescuePartyResets()316 private static void handleNativeRescuePartyResets() { 317 if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) { 318 String[] resetNativeCategories = SettingsToPropertiesMapper.getResetNativeCategories(); 319 for (int i = 0; i < resetNativeCategories.length; i++) { 320 // Don't let RescueParty reset the namespace for RescueParty switches. 321 if (NAMESPACE_CONFIGURATION.equals(resetNativeCategories[i])) { 322 continue; 323 } 324 DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE, 325 resetNativeCategories[i]); 326 } 327 } 328 } 329 getMaxRescueLevel(boolean mayPerformFactoryReset)330 private static int getMaxRescueLevel(boolean mayPerformFactoryReset) { 331 if (!mayPerformFactoryReset 332 || SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) { 333 return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS; 334 } 335 return LEVEL_FACTORY_RESET; 336 } 337 338 /** 339 * Get the rescue level to perform if this is the n-th attempt at mitigating failure. 340 * 341 * @param mitigationCount: the mitigation attempt number (1 = first attempt etc.) 342 * @param mayPerformFactoryReset: whether or not a factory reset may be performed for the given 343 * failure. 344 * @return the rescue level for the n-th mitigation attempt. 345 */ getRescueLevel(int mitigationCount, boolean mayPerformFactoryReset)346 private static int getRescueLevel(int mitigationCount, boolean mayPerformFactoryReset) { 347 if (mitigationCount == 1) { 348 return LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS; 349 } else if (mitigationCount == 2) { 350 return LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES; 351 } else if (mitigationCount == 3) { 352 return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS; 353 } else if (mitigationCount == 4) { 354 return Math.min(getMaxRescueLevel(mayPerformFactoryReset), LEVEL_WARM_REBOOT); 355 } else if (mitigationCount >= 5) { 356 return Math.min(getMaxRescueLevel(mayPerformFactoryReset), LEVEL_FACTORY_RESET); 357 } else { 358 Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount); 359 return LEVEL_NONE; 360 } 361 } 362 executeRescueLevel(Context context, @Nullable String failedPackage, int level)363 private static void executeRescueLevel(Context context, @Nullable String failedPackage, 364 int level) { 365 Slog.w(TAG, "Attempting rescue level " + levelToString(level)); 366 try { 367 executeRescueLevelInternal(context, level, failedPackage); 368 EventLogTags.writeRescueSuccess(level); 369 String successMsg = "Finished rescue level " + levelToString(level); 370 if (!TextUtils.isEmpty(failedPackage)) { 371 successMsg += " for package " + failedPackage; 372 } 373 logCriticalInfo(Log.DEBUG, successMsg); 374 } catch (Throwable t) { 375 logRescueException(level, failedPackage, t); 376 } 377 } 378 executeRescueLevelInternal(Context context, int level, @Nullable String failedPackage)379 private static void executeRescueLevelInternal(Context context, int level, @Nullable 380 String failedPackage) throws Exception { 381 FrameworkStatsLog.write(FrameworkStatsLog.RESCUE_PARTY_RESET_REPORTED, level); 382 // Try our best to reset all settings possible, and once finished 383 // rethrow any exception that we encountered 384 Exception res = null; 385 Runnable runnable; 386 Thread thread; 387 switch (level) { 388 case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: 389 try { 390 resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS, 391 level); 392 } catch (Exception e) { 393 res = e; 394 } 395 try { 396 resetDeviceConfig(context, /*isScoped=*/true, failedPackage); 397 } catch (Exception e) { 398 res = e; 399 } 400 break; 401 case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: 402 try { 403 resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_CHANGES, 404 level); 405 } catch (Exception e) { 406 res = e; 407 } 408 try { 409 resetDeviceConfig(context, /*isScoped=*/true, failedPackage); 410 } catch (Exception e) { 411 res = e; 412 } 413 break; 414 case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: 415 try { 416 resetAllSettingsIfNecessary(context, Settings.RESET_MODE_TRUSTED_DEFAULTS, 417 level); 418 } catch (Exception e) { 419 res = e; 420 } 421 try { 422 resetDeviceConfig(context, /*isScoped=*/false, failedPackage); 423 } catch (Exception e) { 424 res = e; 425 } 426 break; 427 case LEVEL_WARM_REBOOT: 428 // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog 429 // when device shutting down. 430 SystemProperties.set(PROP_ATTEMPTING_REBOOT, "true"); 431 runnable = () -> { 432 try { 433 PowerManager pm = context.getSystemService(PowerManager.class); 434 if (pm != null) { 435 pm.reboot(TAG); 436 } 437 } catch (Throwable t) { 438 logRescueException(level, failedPackage, t); 439 } 440 }; 441 thread = new Thread(runnable); 442 thread.start(); 443 break; 444 case LEVEL_FACTORY_RESET: 445 SystemProperties.set(PROP_ATTEMPTING_FACTORY_RESET, "true"); 446 runnable = new Runnable() { 447 @Override 448 public void run() { 449 try { 450 RecoverySystem.rebootPromptAndWipeUserData(context, TAG); 451 } catch (Throwable t) { 452 logRescueException(level, failedPackage, t); 453 } 454 } 455 }; 456 thread = new Thread(runnable); 457 thread.start(); 458 break; 459 } 460 461 if (res != null) { 462 throw res; 463 } 464 } 465 logRescueException(int level, @Nullable String failedPackageName, Throwable t)466 private static void logRescueException(int level, @Nullable String failedPackageName, 467 Throwable t) { 468 final String msg = ExceptionUtils.getCompleteMessage(t); 469 EventLogTags.writeRescueFailure(level, msg); 470 String failureMsg = "Failed rescue level " + levelToString(level); 471 if (!TextUtils.isEmpty(failedPackageName)) { 472 failureMsg += " for package " + failedPackageName; 473 } 474 logCriticalInfo(Log.ERROR, failureMsg + ": " + msg); 475 } 476 mapRescueLevelToUserImpact(int rescueLevel)477 private static int mapRescueLevelToUserImpact(int rescueLevel) { 478 switch(rescueLevel) { 479 case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: 480 case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: 481 return PackageHealthObserverImpact.USER_IMPACT_LOW; 482 case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: 483 case LEVEL_WARM_REBOOT: 484 case LEVEL_FACTORY_RESET: 485 return PackageHealthObserverImpact.USER_IMPACT_HIGH; 486 default: 487 return PackageHealthObserverImpact.USER_IMPACT_NONE; 488 } 489 } 490 resetAllSettingsIfNecessary(Context context, int mode, int level)491 private static void resetAllSettingsIfNecessary(Context context, int mode, 492 int level) throws Exception { 493 // No need to reset Settings again if they are already reset in the current level once. 494 if (SystemProperties.getInt(PROP_MAX_RESCUE_LEVEL_ATTEMPTED, LEVEL_NONE) >= level) { 495 return; 496 } 497 SystemProperties.set(PROP_MAX_RESCUE_LEVEL_ATTEMPTED, Integer.toString(level)); 498 // Try our best to reset all settings possible, and once finished 499 // rethrow any exception that we encountered 500 Exception res = null; 501 final ContentResolver resolver = context.getContentResolver(); 502 try { 503 Settings.Global.resetToDefaultsAsUser(resolver, null, mode, UserHandle.USER_SYSTEM); 504 } catch (Exception e) { 505 res = new RuntimeException("Failed to reset global settings", e); 506 } 507 for (int userId : getAllUserIds()) { 508 try { 509 Settings.Secure.resetToDefaultsAsUser(resolver, null, mode, userId); 510 } catch (Exception e) { 511 res = new RuntimeException("Failed to reset secure settings for " + userId, e); 512 } 513 } 514 if (res != null) { 515 throw res; 516 } 517 } 518 resetDeviceConfig(Context context, boolean isScoped, @Nullable String failedPackage)519 private static void resetDeviceConfig(Context context, boolean isScoped, 520 @Nullable String failedPackage) throws Exception { 521 final ContentResolver resolver = context.getContentResolver(); 522 try { 523 if (!isScoped || failedPackage == null) { 524 resetAllAffectedNamespaces(context); 525 } else { 526 performScopedReset(context, failedPackage); 527 } 528 } catch (Exception e) { 529 throw new RuntimeException("Failed to reset config settings", e); 530 } 531 } 532 resetAllAffectedNamespaces(Context context)533 private static void resetAllAffectedNamespaces(Context context) { 534 RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context); 535 Set<String> allAffectedNamespaces = rescuePartyObserver.getAllAffectedNamespaceSet(); 536 537 Slog.w(TAG, 538 "Performing reset for all affected namespaces: " 539 + Arrays.toString(allAffectedNamespaces.toArray())); 540 Iterator<String> it = allAffectedNamespaces.iterator(); 541 while (it.hasNext()) { 542 String namespace = it.next(); 543 // Don't let RescueParty reset the namespace for RescueParty switches. 544 if (NAMESPACE_CONFIGURATION.equals(namespace)) { 545 continue; 546 } 547 DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE, namespace); 548 } 549 } 550 performScopedReset(Context context, @NonNull String failedPackage)551 private static void performScopedReset(Context context, @NonNull String failedPackage) { 552 RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context); 553 Set<String> affectedNamespaces = rescuePartyObserver.getAffectedNamespaceSet( 554 failedPackage); 555 // If we can't find namespaces affected for current package, 556 // skip this round of reset. 557 if (affectedNamespaces != null) { 558 Slog.w(TAG, 559 "Performing scoped reset for package: " + failedPackage 560 + ", affected namespaces: " 561 + Arrays.toString(affectedNamespaces.toArray())); 562 Iterator<String> it = affectedNamespaces.iterator(); 563 while (it.hasNext()) { 564 String namespace = it.next(); 565 // Don't let RescueParty reset the namespace for RescueParty switches. 566 if (NAMESPACE_CONFIGURATION.equals(namespace)) { 567 continue; 568 } 569 DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE, namespace); 570 } 571 } 572 } 573 574 /** 575 * Handle mitigation action for package failures. This observer will be register to Package 576 * Watchdog and will receive calls about package failures. This observer is persistent so it 577 * may choose to mitigate failures for packages it has not explicitly asked to observe. 578 */ 579 public static class RescuePartyObserver implements PackageHealthObserver { 580 581 private final Context mContext; 582 private final Map<String, Set<String>> mCallingPackageNamespaceSetMap = new HashMap<>(); 583 private final Map<String, Set<String>> mNamespaceCallingPackageSetMap = new HashMap<>(); 584 585 @GuardedBy("RescuePartyObserver.class") 586 static RescuePartyObserver sRescuePartyObserver; 587 RescuePartyObserver(Context context)588 private RescuePartyObserver(Context context) { 589 mContext = context; 590 } 591 592 /** Creates or gets singleton instance of RescueParty. */ getInstance(Context context)593 public static RescuePartyObserver getInstance(Context context) { 594 synchronized (RescuePartyObserver.class) { 595 if (sRescuePartyObserver == null) { 596 sRescuePartyObserver = new RescuePartyObserver(context); 597 } 598 return sRescuePartyObserver; 599 } 600 } 601 602 /** Gets singleton instance. It returns null if the instance is not created yet.*/ 603 @Nullable getInstanceIfCreated()604 public static RescuePartyObserver getInstanceIfCreated() { 605 synchronized (RescuePartyObserver.class) { 606 return sRescuePartyObserver; 607 } 608 } 609 610 @VisibleForTesting reset()611 static void reset() { 612 synchronized (RescuePartyObserver.class) { 613 sRescuePartyObserver = null; 614 } 615 } 616 617 @Override onHealthCheckFailed(@ullable VersionedPackage failedPackage, @FailureReasons int failureReason, int mitigationCount)618 public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage, 619 @FailureReasons int failureReason, int mitigationCount) { 620 if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH 621 || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) { 622 return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, 623 mayPerformFactoryReset(failedPackage))); 624 } else { 625 return PackageHealthObserverImpact.USER_IMPACT_NONE; 626 } 627 } 628 629 @Override execute(@ullable VersionedPackage failedPackage, @FailureReasons int failureReason, int mitigationCount)630 public boolean execute(@Nullable VersionedPackage failedPackage, 631 @FailureReasons int failureReason, int mitigationCount) { 632 if (isDisabled()) { 633 return false; 634 } 635 if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH 636 || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) { 637 final int level = getRescueLevel(mitigationCount, 638 mayPerformFactoryReset(failedPackage)); 639 executeRescueLevel(mContext, 640 failedPackage == null ? null : failedPackage.getPackageName(), level); 641 return true; 642 } else { 643 return false; 644 } 645 } 646 647 @Override isPersistent()648 public boolean isPersistent() { 649 return true; 650 } 651 652 @Override mayObservePackage(String packageName)653 public boolean mayObservePackage(String packageName) { 654 PackageManager pm = mContext.getPackageManager(); 655 try { 656 // A package is a module if this is non-null 657 if (pm.getModuleInfo(packageName, 0) != null) { 658 return true; 659 } 660 } catch (PackageManager.NameNotFoundException ignore) { 661 } 662 663 return isPersistentSystemApp(packageName); 664 } 665 666 @Override onBootLoop(int mitigationCount)667 public int onBootLoop(int mitigationCount) { 668 if (isDisabled()) { 669 return PackageHealthObserverImpact.USER_IMPACT_NONE; 670 } 671 return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, true)); 672 } 673 674 @Override executeBootLoopMitigation(int mitigationCount)675 public boolean executeBootLoopMitigation(int mitigationCount) { 676 if (isDisabled()) { 677 return false; 678 } 679 executeRescueLevel(mContext, /*failedPackage=*/ null, 680 getRescueLevel(mitigationCount, true)); 681 return true; 682 } 683 684 @Override getName()685 public String getName() { 686 return NAME; 687 } 688 689 /** 690 * Returns {@code true} if the failing package is non-null and performing a reboot or 691 * prompting a factory reset is an acceptable mitigation strategy for the package's 692 * failure, {@code false} otherwise. 693 */ mayPerformFactoryReset(@ullable VersionedPackage failingPackage)694 private boolean mayPerformFactoryReset(@Nullable VersionedPackage failingPackage) { 695 if (failingPackage == null) { 696 return false; 697 } 698 699 return isPersistentSystemApp(failingPackage.getPackageName()); 700 } 701 isPersistentSystemApp(@onNull String packageName)702 private boolean isPersistentSystemApp(@NonNull String packageName) { 703 PackageManager pm = mContext.getPackageManager(); 704 try { 705 ApplicationInfo info = pm.getApplicationInfo(packageName, 0); 706 return (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK; 707 } catch (PackageManager.NameNotFoundException e) { 708 return false; 709 } 710 } 711 recordDeviceConfigAccess(@onNull String callingPackage, @NonNull String namespace)712 private synchronized void recordDeviceConfigAccess(@NonNull String callingPackage, 713 @NonNull String namespace) { 714 // Record it in calling packages to namespace map 715 Set<String> namespaceSet = mCallingPackageNamespaceSetMap.get(callingPackage); 716 if (namespaceSet == null) { 717 namespaceSet = new ArraySet<>(); 718 mCallingPackageNamespaceSetMap.put(callingPackage, namespaceSet); 719 } 720 namespaceSet.add(namespace); 721 // Record it in namespace to calling packages map 722 Set<String> callingPackageSet = mNamespaceCallingPackageSetMap.get(namespace); 723 if (callingPackageSet == null) { 724 callingPackageSet = new ArraySet<>(); 725 } 726 callingPackageSet.add(callingPackage); 727 mNamespaceCallingPackageSetMap.put(namespace, callingPackageSet); 728 } 729 getAffectedNamespaceSet(String failedPackage)730 private synchronized Set<String> getAffectedNamespaceSet(String failedPackage) { 731 return mCallingPackageNamespaceSetMap.get(failedPackage); 732 } 733 getAllAffectedNamespaceSet()734 private synchronized Set<String> getAllAffectedNamespaceSet() { 735 return new HashSet<String>(mNamespaceCallingPackageSetMap.keySet()); 736 } 737 getCallingPackagesSet(String namespace)738 private synchronized Set<String> getCallingPackagesSet(String namespace) { 739 return mNamespaceCallingPackageSetMap.get(namespace); 740 } 741 } 742 getAllUserIds()743 private static int[] getAllUserIds() { 744 int[] userIds = { UserHandle.USER_SYSTEM }; 745 try { 746 for (File file : FileUtils.listFilesOrEmpty(Environment.getDataSystemDeDirectory())) { 747 try { 748 final int userId = Integer.parseInt(file.getName()); 749 if (userId != UserHandle.USER_SYSTEM) { 750 userIds = ArrayUtils.appendInt(userIds, userId); 751 } 752 } catch (NumberFormatException ignored) { 753 } 754 } 755 } catch (Throwable t) { 756 Slog.w(TAG, "Trouble discovering users", t); 757 } 758 return userIds; 759 } 760 761 /** 762 * Hacky test to check if the device has an active USB connection, which is 763 * a good proxy for someone doing local development work. 764 */ isUsbActive()765 private static boolean isUsbActive() { 766 if (SystemProperties.getBoolean(PROP_VIRTUAL_DEVICE, false)) { 767 Slog.v(TAG, "Assuming virtual device is connected over USB"); 768 return true; 769 } 770 try { 771 final String state = FileUtils 772 .readTextFile(new File("/sys/class/android_usb/android0/state"), 128, ""); 773 return "CONFIGURED".equals(state.trim()); 774 } catch (Throwable t) { 775 Slog.w(TAG, "Failed to determine if device was on USB", t); 776 return false; 777 } 778 } 779 levelToString(int level)780 private static String levelToString(int level) { 781 switch (level) { 782 case LEVEL_NONE: return "NONE"; 783 case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: return "RESET_SETTINGS_UNTRUSTED_DEFAULTS"; 784 case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: return "RESET_SETTINGS_UNTRUSTED_CHANGES"; 785 case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: return "RESET_SETTINGS_TRUSTED_DEFAULTS"; 786 case LEVEL_WARM_REBOOT: return "WARM_REBOOT"; 787 case LEVEL_FACTORY_RESET: return "FACTORY_RESET"; 788 default: return Integer.toString(level); 789 } 790 } 791 } 792