Merge "Tethering and Data Saver: There Can Be Only One!" into nyc-dev
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));
+ }
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 6418614..6243f46 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -809,17 +809,7 @@
@Override
public String toString() {
int[] types = getTransportTypes();
- String transports = (types.length > 0 ? " Transports: " : "");
- for (int i = 0; i < types.length;) {
- switch (types[i]) {
- case TRANSPORT_CELLULAR: transports += "CELLULAR"; break;
- case TRANSPORT_WIFI: transports += "WIFI"; break;
- case TRANSPORT_BLUETOOTH: transports += "BLUETOOTH"; break;
- case TRANSPORT_ETHERNET: transports += "ETHERNET"; break;
- case TRANSPORT_VPN: transports += "VPN"; break;
- }
- if (++i < types.length) transports += "|";
- }
+ String transports = (types.length > 0) ? " Transports: " + transportNamesOf(types) : "";
types = getCapabilities();
String capabilities = (types.length > 0 ? " Capabilities: " : "");
@@ -859,4 +849,22 @@
return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength + "]";
}
+
+ /**
+ * @hide
+ */
+ public static String transportNamesOf(int[] types) {
+ String transports = "";
+ for (int i = 0; i < types.length;) {
+ switch (types[i]) {
+ case TRANSPORT_CELLULAR: transports += "CELLULAR"; break;
+ case TRANSPORT_WIFI: transports += "WIFI"; break;
+ case TRANSPORT_BLUETOOTH: transports += "BLUETOOTH"; break;
+ case TRANSPORT_ETHERNET: transports += "ETHERNET"; break;
+ case TRANSPORT_VPN: transports += "VPN"; break;
+ }
+ if (++i < types.length) transports += "|";
+ }
+ return transports;
+ }
}