Frameworks/base: Make debug helper lazy in ConnectivityManager
Place helper map for callback field names into a holder. This avoids
the reflective calls in static initialization of ConnectivityManager
in the common (non-debug) case, which means the class can be
compile-time initialized. Also saves the storage necessary (both
the storage array as well as the reflection metadata).
Follow-up to b027e6e92b2003c063de1127cd60acf7c303006e.
Bug: 27265238
Change-Id: Ib4bfaf27acd234a035a5d198458340099a156a4c
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 9070ad9..faf5c64 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -81,13 +81,6 @@
public class ConnectivityManager {
private static final String TAG = "ConnectivityManager";
- private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
- new Class[]{ConnectivityManager.class}, new String[]{"CALLBACK_"});
-
- private static final String whatToString(int what) {
- return sMagicDecoderRing.get(what, Integer.toString(what));
- }
-
/**
* A change in network connectivity has occurred. A default connection has either
* been established or lost. The NetworkInfo for the affected network is
@@ -3360,4 +3353,32 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * A holder class for debug info (mapping CALLBACK values to field names). This is stored
+ * in a holder for two reasons:
+ * 1) The reflection necessary to establish the map can't be run at compile-time. Thus, this
+ * code will make the enclosing class not compile-time initializeable, deferring its
+ * initialization to zygote startup. This leads to dirty (but shared) memory.
+ * As this is debug info, use a holder that isn't initialized by default. This way the map
+ * will be created on demand, while ConnectivityManager can be compile-time initialized.
+ * 2) Static initialization is still preferred for its strong thread safety guarantees without
+ * requiring a lock.
+ */
+ private static class NoPreloadHolder {
+ public static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
+ new Class[]{ConnectivityManager.class}, new String[]{"CALLBACK_"});
+ }
+
+ static {
+ // When debug is enabled, aggressively initialize the holder by touching the field (which
+ // will guarantee static initialization).
+ if (CallbackHandler.DBG) {
+ Object dummy = NoPreloadHolder.sMagicDecoderRing;
+ }
+ }
+
+ private static final String whatToString(int what) {
+ return NoPreloadHolder.sMagicDecoderRing.get(what, Integer.toString(what));
+ }
}