summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jeff Sharkey <jsharkey@android.com> 2012-03-01 20:50:32 -0800
committer Jeff Sharkey <jsharkey@android.com> 2012-03-01 21:10:05 -0800
commitd7026f1612a7c1e8cc9b484038fa99b7fc29cfd7 (patch)
tree2ba3ba651643d5b3fb1a1dec88445d26538fead3
parentc81ec3637b8e3c177ec041aeb3863e123924505b (diff)
Report leaked Context registrations to StrictMode.
When tearing down any leaked BroadcastReceiver or ServiceConnection Context registrations, report through StrictMode. Bug: 6084353 Change-Id: I5e78039299e2c9c1440cd1fd09317da78ffee82a
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/app/LoadedApk.java7
-rw-r--r--core/java/android/os/StrictMode.java45
3 files changed, 50 insertions, 3 deletions
diff --git a/api/current.txt b/api/current.txt
index 81f7a824df21..51946a98c23a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15322,6 +15322,7 @@ package android.os {
method public android.os.StrictMode.VmPolicy.Builder detectActivityLeaks();
method public android.os.StrictMode.VmPolicy.Builder detectAll();
method public android.os.StrictMode.VmPolicy.Builder detectLeakedClosableObjects();
+ method public android.os.StrictMode.VmPolicy.Builder detectLeakedRegistrationObjects();
method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index d9bbb4a33b4a..de9470e7ecc9 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -512,6 +512,7 @@ public final class LoadedApk {
public void removeContextRegistrations(Context context,
String who, String what) {
+ final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled();
HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap =
mReceivers.remove(context);
if (rmap != null) {
@@ -525,6 +526,9 @@ public final class LoadedApk {
"call to unregisterReceiver()?");
leak.setStackTrace(rd.getLocation().getStackTrace());
Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
+ if (reportRegistrationLeaks) {
+ StrictMode.onIntentReceiverLeaked(leak);
+ }
try {
ActivityManagerNative.getDefault().unregisterReceiver(
rd.getIIntentReceiver());
@@ -546,6 +550,9 @@ public final class LoadedApk {
+ sd.getServiceConnection() + " that was originally bound here");
leak.setStackTrace(sd.getLocation().getStackTrace());
Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
+ if (reportRegistrationLeaks) {
+ StrictMode.onServiceConnectionLeaked(leak);
+ }
try {
ActivityManagerNative.getDefault().unbindService(
sd.getIServiceConnection());
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 99f58a0b9199..a0ad9c0a0d7b 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -20,7 +20,10 @@ import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.ApplicationErrorReport;
import android.app.IActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.Intent;
+import android.content.ServiceConnection;
import android.util.Log;
import android.util.Printer;
import android.util.Singleton;
@@ -195,9 +198,15 @@ public final class StrictMode {
*/
private static final int DETECT_VM_INSTANCE_LEAKS = 0x1000; // for VmPolicy
+ /**
+ * @hide
+ */
+ public static final int DETECT_VM_REGISTRATION_LEAKS = 0x2000; // for VmPolicy
+
private static final int ALL_VM_DETECT_BITS =
DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS |
- DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS;
+ DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS |
+ DETECT_VM_REGISTRATION_LEAKS;
/**
* @hide
@@ -618,8 +627,8 @@ public final class StrictMode {
* but will likely expand in future releases.
*/
public Builder detectAll() {
- return enable(DETECT_VM_ACTIVITY_LEAKS |
- DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS);
+ return enable(DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_CURSOR_LEAKS
+ | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_REGISTRATION_LEAKS);
}
/**
@@ -648,6 +657,15 @@ public final class StrictMode {
}
/**
+ * Detect when a {@link BroadcastReceiver} or
+ * {@link ServiceConnection} is leaked during {@link Context}
+ * teardown.
+ */
+ public Builder detectLeakedRegistrationObjects() {
+ return enable(DETECT_VM_REGISTRATION_LEAKS);
+ }
+
+ /**
* Crashes the whole process on violation. This penalty runs at
* the end of all enabled penalties so yo you'll still get
* your logging or other violations before the process dies.
@@ -1499,6 +1517,13 @@ public final class StrictMode {
/**
* @hide
*/
+ public static boolean vmRegistrationLeaksEnabled() {
+ return (sVmPolicyMask & DETECT_VM_REGISTRATION_LEAKS) != 0;
+ }
+
+ /**
+ * @hide
+ */
public static void onSqliteObjectLeaked(String message, Throwable originStack) {
onVmPolicyViolation(message, originStack);
}
@@ -1510,6 +1535,20 @@ public final class StrictMode {
onVmPolicyViolation(null, originStack);
}
+ /**
+ * @hide
+ */
+ public static void onIntentReceiverLeaked(Throwable originStack) {
+ onVmPolicyViolation(null, originStack);
+ }
+
+ /**
+ * @hide
+ */
+ public static void onServiceConnectionLeaked(Throwable originStack) {
+ onVmPolicyViolation(null, originStack);
+ }
+
// Map from VM violation fingerprint to uptime millis.
private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();