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