StrictMode: avoid an allocation in common case
Make the initialValue() of the ThreadLocal be null, so checking it doesn't
cause one to be created in the case of an RPC call not using StrictMode.
Change-Id: I3ea19ce444a1b3c39a6e53c5cb5d4faf4b07a6c8
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index bfe3b60..b9c9565 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1202,6 +1202,7 @@
code = EX_ILLEGAL_STATE;
}
writeInt(code);
+ StrictMode.clearGatheredViolations();
if (code == 0) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 312bca1..dc92590 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -80,6 +80,8 @@
* our offending stack traces to the caller to ultimately handle
* in the originating process.
*
+ * This must be kept in sync with the constant in libs/binder/Parcel.cpp
+ *
* @hide
*/
public static final int PENALTY_GATHER = 0x100;
@@ -98,7 +100,10 @@
private static ThreadLocal<ArrayList<ApplicationErrorReport.CrashInfo>> gatheredViolations =
new ThreadLocal<ArrayList<ApplicationErrorReport.CrashInfo>>() {
@Override protected ArrayList<ApplicationErrorReport.CrashInfo> initialValue() {
- return new ArrayList<ApplicationErrorReport.CrashInfo>(1);
+ // Starts null to avoid unnecessary allocations when
+ // checking whether there are any violations or not in
+ // hasGatheredViolations() below.
+ return null;
}
};
@@ -308,7 +313,10 @@
if ((policy & PENALTY_GATHER) != 0) {
ArrayList<ApplicationErrorReport.CrashInfo> violations = gatheredViolations.get();
- if (violations.size() >= 5) {
+ if (violations == null) {
+ violations = new ArrayList<ApplicationErrorReport.CrashInfo>(1);
+ gatheredViolations.set(violations);
+ } else if (violations.size() >= 5) {
// Too many. In a loop or something? Don't gather them all.
return;
}
@@ -393,7 +401,16 @@
* Called from Parcel.writeNoException()
*/
/* package */ static boolean hasGatheredViolations() {
- return !gatheredViolations.get().isEmpty();
+ return gatheredViolations.get() != null;
+ }
+
+ /**
+ * Called from Parcel.writeException(), so we drop this memory and
+ * don't incorrectly attribute it to the wrong caller on the next
+ * Binder call on this thread.
+ */
+ /* package */ static void clearGatheredViolations() {
+ gatheredViolations.set(null);
}
/**
@@ -401,13 +418,17 @@
*/
/* package */ static void writeGatheredViolationsToParcel(Parcel p) {
ArrayList<ApplicationErrorReport.CrashInfo> violations = gatheredViolations.get();
- p.writeInt(violations.size());
- for (int i = 0; i < violations.size(); ++i) {
- violations.get(i).writeToParcel(p, 0 /* unused flags? */);
+ if (violations == null) {
+ p.writeInt(0);
+ } else {
+ p.writeInt(violations.size());
+ for (int i = 0; i < violations.size(); ++i) {
+ violations.get(i).writeToParcel(p, 0 /* unused flags? */);
+ }
+ if (LOG_V) Log.d(TAG, "wrote violations to response parcel; num=" + violations.size());
+ violations.clear(); // somewhat redundant, as we're about to null the threadlocal
}
-
- if (LOG_V) Log.d(TAG, "wrote violations to response parcel; num=" + violations.size());
- violations.clear();
+ gatheredViolations.set(null);
}
private static class LogStackTrace extends Exception {}