Suppress RescueParty when active USB connection.
When there is a very early system server runtime restart, we may not
yet have a published BatteryManagerInternal, so we need to go directly
to the "batteryproperties" native service to detect the USB state.
Test: builds, rescue is suppressed when USB is connected
Bug: 34872406
Change-Id: I949984cb95495c77de85ac322075177cff07b8b6
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index c77a407..33351ff 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -20,9 +20,12 @@
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.BatteryManager;
-import android.os.BatteryManagerInternal;
+import android.os.BatteryProperties;
import android.os.Build;
+import android.os.IBatteryPropertiesListener;
+import android.os.IBatteryPropertiesRegistrar;
import android.os.RecoverySystem;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -31,11 +34,15 @@
import android.text.format.DateUtils;
import android.util.ExceptionUtils;
import android.util.MathUtils;
+import android.util.MutableBoolean;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.util.ArrayUtils;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
/**
* Utilities to help rescue the system from crash loops. Callers are expected to
* report boot events and persistent app crashes, and if they happen frequently
@@ -66,24 +73,26 @@
private static boolean isDisabled() {
// We're disabled on all engineering devices
- if (Build.IS_ENG) return true;
+ if (Build.IS_ENG) {
+ Slog.v(TAG, "Disabled because of eng build");
+ return true;
+ }
// We're disabled on userdebug devices connected over USB, since that's
// a decent signal that someone is actively trying to debug the device,
// or that it's in a lab environment.
- if (Build.IS_USERDEBUG) {
- try {
- if (LocalServices.getService(BatteryManagerInternal.class)
- .getPlugType() == BatteryManager.BATTERY_PLUGGED_USB) {
- return true;
- } else {
- }
- } catch (Throwable ignored) {
- }
+ if (Build.IS_USERDEBUG && isUsbActive()) {
+ Slog.v(TAG, "Disabled because of active USB connection");
+ return true;
}
// One last-ditch check
- return SystemProperties.getBoolean(PROP_DISABLE_RESCUE, false);
+ if (SystemProperties.getBoolean(PROP_DISABLE_RESCUE, false)) {
+ Slog.v(TAG, "Disabled because of manual property");
+ return true;
+ }
+
+ return false;
}
/**
@@ -185,14 +194,14 @@
final ContentResolver resolver = context.getContentResolver();
try {
Settings.Global.resetToDefaultsAsUser(resolver, null, mode, UserHandle.USER_SYSTEM);
- } catch (Exception e) {
- res = new RuntimeException("Failed to reset global settings", e);
+ } catch (Throwable t) {
+ res = new RuntimeException("Failed to reset global settings", t);
}
for (int userId : getAllUserIds(context)) {
try {
Settings.Secure.resetToDefaultsAsUser(resolver, null, mode, userId);
- } catch (Exception e) {
- res = new RuntimeException("Failed to reset secure settings for " + userId, e);
+ } catch (Throwable t) {
+ res = new RuntimeException("Failed to reset secure settings for " + userId, t);
}
}
if (res != null) {
@@ -314,6 +323,38 @@
return userIds;
}
+ /**
+ * Hacky test to check if the device has an active USB connection, which is
+ * a good proxy for someone doing local development work. It uses a low
+ * level call since we may not have started {@link BatteryManager} yet.
+ */
+ private static boolean isUsbActive() {
+ final MutableBoolean res = new MutableBoolean(false);
+ final CountDownLatch latch = new CountDownLatch(1);
+ final IBatteryPropertiesListener listener = new IBatteryPropertiesListener.Stub() {
+ @Override
+ public void batteryPropertiesChanged(BatteryProperties props) {
+ res.value = props.chargerUsbOnline;
+ latch.countDown();
+ }
+ };
+
+ try {
+ final IBatteryPropertiesRegistrar bpr = IBatteryPropertiesRegistrar.Stub
+ .asInterface(ServiceManager.getService("batteryproperties"));
+ bpr.registerListener(listener);
+ try {
+ latch.await(5, TimeUnit.SECONDS);
+ } finally {
+ bpr.unregisterListener(listener);
+ }
+ return res.value;
+ } catch (Throwable t) {
+ Slog.w(TAG, "Failed to determine if device was on USB", t);
+ return false;
+ }
+ }
+
private static String levelToString(int level) {
switch (level) {
case LEVEL_NONE: return "NONE";