Merge "Fix NetworkNotificationManagerTest"
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 4dd8ce9..8665b9c 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -423,8 +423,10 @@
      */
     public static final int TRANSPORT_WIFI_AWARE = 5;
 
-    private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
-    private static final int MAX_TRANSPORT = TRANSPORT_WIFI_AWARE;
+    /** @hide */
+    public static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
+    /** @hide */
+    public static final int MAX_TRANSPORT = TRANSPORT_WIFI_AWARE;
 
     /**
      * Adds the given transport type to this {@code NetworkCapability} instance.
@@ -476,6 +478,17 @@
     }
 
     /**
+     * Gets all the transports set on this {@code NetworkCapability} instance.
+     *
+     * @return a bit field composed of up bits at indexes defined by
+     * {@code NetworkCapabilities.TRANSPORT_*} values for this instance.
+     * @hide
+     */
+    public long getTransports() {
+        return mTransportTypes;
+    }
+
+    /**
      * Tests for the presence of a transport on this instance.
      *
      * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be tested for.
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index a4f9f21..d02b726 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3085,7 +3085,17 @@
         boolean tetherEnabledInSettings = (Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.TETHER_SUPPORTED, defaultVal) != 0)
                 && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
-        return tetherEnabledInSettings && mUserManager.isAdminUser() &&
+
+        // Elevate to system UID to avoid caller requiring MANAGE_USERS permission.
+        boolean adminUser = false;
+        final long token = Binder.clearCallingIdentity();
+        try {
+            adminUser = mUserManager.isAdminUser();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+
+        return tetherEnabledInSettings && adminUser &&
                mTethering.hasTetherableConfiguration();
     }
 
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
index 48861bd..d819b96 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
@@ -26,6 +26,11 @@
 import static com.android.server.connectivity.MetricsTestUtil.b;
 import static com.android.server.connectivity.MetricsTestUtil.describeIpEvent;
 import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.BLUETOOTH;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.CELLULAR;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.ETHERNET;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.MULTIPLE;
+import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.WIFI;
 
 import android.net.ConnectivityMetricsEvent;
 import android.net.metrics.ApfProgramEvent;
@@ -47,6 +52,135 @@
 public class IpConnectivityEventBuilderTest extends TestCase {
 
     @SmallTest
+    public void testLinkLayerInferrence() {
+        ConnectivityMetricsEvent ev = describeIpEvent(
+                aType(IpReachabilityEvent.class),
+                anInt(IpReachabilityEvent.NUD_FAILED));
+
+        String want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  if_name: \"\"",
+                "  link_layer: 0",
+                "  network_id: 0",
+                "  time_ms: 1",
+                "  transports: 0",
+                "  ip_reachability_event <",
+                "    event_type: 512",
+                "    if_name: \"\"",
+                "  >",
+                ">",
+                "version: 2");
+        verifySerialization(want, ev);
+
+        ev.netId = 123;
+        ev.transports = 3; // transports have priority for inferrence of link layer
+        ev.ifname = "wlan0";
+        want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  if_name: \"\"",
+                String.format("  link_layer: %d", MULTIPLE),
+                "  network_id: 123",
+                "  time_ms: 1",
+                "  transports: 3",
+                "  ip_reachability_event <",
+                "    event_type: 512",
+                "    if_name: \"\"",
+                "  >",
+                ">",
+                "version: 2");
+        verifySerialization(want, ev);
+
+        ev.transports = 1;
+        ev.ifname = null;
+        want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  if_name: \"\"",
+                String.format("  link_layer: %d", CELLULAR),
+                "  network_id: 123",
+                "  time_ms: 1",
+                "  transports: 1",
+                "  ip_reachability_event <",
+                "    event_type: 512",
+                "    if_name: \"\"",
+                "  >",
+                ">",
+                "version: 2");
+        verifySerialization(want, ev);
+
+        ev.transports = 0;
+        ev.ifname = "not_inferred";
+        want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  if_name: \"not_inferred\"",
+                "  link_layer: 0",
+                "  network_id: 123",
+                "  time_ms: 1",
+                "  transports: 0",
+                "  ip_reachability_event <",
+                "    event_type: 512",
+                "    if_name: \"\"",
+                "  >",
+                ">",
+                "version: 2");
+        verifySerialization(want, ev);
+
+        ev.ifname = "bt-pan";
+        want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  if_name: \"\"",
+                String.format("  link_layer: %d", BLUETOOTH),
+                "  network_id: 123",
+                "  time_ms: 1",
+                "  transports: 0",
+                "  ip_reachability_event <",
+                "    event_type: 512",
+                "    if_name: \"\"",
+                "  >",
+                ">",
+                "version: 2");
+        verifySerialization(want, ev);
+
+        ev.ifname = "rmnet_ipa0";
+        want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  if_name: \"\"",
+                String.format("  link_layer: %d", CELLULAR),
+                "  network_id: 123",
+                "  time_ms: 1",
+                "  transports: 0",
+                "  ip_reachability_event <",
+                "    event_type: 512",
+                "    if_name: \"\"",
+                "  >",
+                ">",
+                "version: 2");
+        verifySerialization(want, ev);
+
+        ev.ifname = "wlan0";
+        want = joinLines(
+                "dropped_events: 0",
+                "events <",
+                "  if_name: \"\"",
+                String.format("  link_layer: %d", WIFI),
+                "  network_id: 123",
+                "  time_ms: 1",
+                "  transports: 0",
+                "  ip_reachability_event <",
+                "    event_type: 512",
+                "    if_name: \"\"",
+                "  >",
+                ">",
+                "version: 2");
+        verifySerialization(want, ev);
+    }
+
+    @SmallTest
     public void testDefaultNetworkEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(DefaultNetworkEvent.class),
@@ -86,7 +220,6 @@
     public void testDhcpClientEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(DhcpClientEvent.class),
-                aString("wlan0"),
                 aString("SomeState"),
                 anInt(192));
 
@@ -100,7 +233,7 @@
                 "  transports: 0",
                 "  dhcp_event <",
                 "    duration_ms: 192",
-                "    if_name: \"wlan0\"",
+                "    if_name: \"\"",
                 "    state_transition: \"SomeState\"",
                 "  >",
                 ">",
@@ -113,7 +246,6 @@
     public void testDhcpErrorEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(DhcpErrorEvent.class),
-                aString("wlan0"),
                 anInt(DhcpErrorEvent.L4_NOT_UDP));
 
         String want = joinLines(
@@ -126,7 +258,7 @@
                 "  transports: 0",
                 "  dhcp_event <",
                 "    duration_ms: 0",
-                "    if_name: \"wlan0\"",
+                "    if_name: \"\"",
                 "    error_code: 50397184",
                 "  >",
                 ">",
@@ -191,7 +323,6 @@
     public void testIpManagerEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(IpManagerEvent.class),
-                aString("wlan0"),
                 anInt(IpManagerEvent.PROVISIONING_OK),
                 aLong(5678));
 
@@ -205,7 +336,7 @@
                 "  transports: 0",
                 "  ip_provisioning_event <",
                 "    event_type: 1",
-                "    if_name: \"wlan0\"",
+                "    if_name: \"\"",
                 "    latency_ms: 5678",
                 "  >",
                 ">",
@@ -218,7 +349,6 @@
     public void testIpReachabilityEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(IpReachabilityEvent.class),
-                aString("wlan0"),
                 anInt(IpReachabilityEvent.NUD_FAILED));
 
         String want = joinLines(
@@ -231,7 +361,7 @@
                 "  transports: 0",
                 "  ip_reachability_event <",
                 "    event_type: 512",
-                "    if_name: \"wlan0\"",
+                "    if_name: \"\"",
                 "  >",
                 ">",
                 "version: 2");
@@ -272,7 +402,6 @@
     public void testValidationProbeEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(ValidationProbeEvent.class),
-                anInt(120),
                 aLong(40730),
                 anInt(ValidationProbeEvent.PROBE_HTTP),
                 anInt(204));
@@ -287,9 +416,6 @@
                 "  transports: 0",
                 "  validation_probe_event <",
                 "    latency_ms: 40730",
-                "    network_id <",
-                "      network_id: 120",
-                "    >",
                 "    probe_result: 204",
                 "    probe_type: 1",
                 "  >",
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 785e1ce..68786d0 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -48,7 +48,7 @@
 
 public class IpConnectivityMetricsTest extends TestCase {
     static final IpReachabilityEvent FAKE_EV =
-            new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED);
+            new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED);
 
     @Mock Context mCtx;
     @Mock IIpConnectivityMetrics mMockService;
@@ -153,48 +153,58 @@
         apfStats.programUpdatesAll = 7;
         apfStats.programUpdatesAllowingMulticast = 3;
         apfStats.maxProgramSize = 2048;
+
+        ValidationProbeEvent validationEv = new ValidationProbeEvent();
+        validationEv.durationMs = 40730;
+        validationEv.probeType = ValidationProbeEvent.PROBE_HTTP;
+        validationEv.returnCode = 204;
+
         Parcelable[] events = {
-            new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED),
-            new DhcpClientEvent("wlan0", "SomeState", 192),
+            new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED),
+            new DhcpClientEvent("SomeState", 192),
             new DefaultNetworkEvent(102, new int[]{1,2,3}, 101, true, false),
-            new IpManagerEvent("wlan0", IpManagerEvent.PROVISIONING_OK, 5678),
-            new ValidationProbeEvent(120, 40730, ValidationProbeEvent.PROBE_HTTP, 204),
+            new IpManagerEvent(IpManagerEvent.PROVISIONING_OK, 5678),
+            validationEv,
             apfStats,
             new RaEvent(2000, 400, 300, -1, 1000, -1)
         };
 
         for (int i = 0; i < events.length; i++) {
-            logger.log(100 * (i + 1), events[i]);
+            ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
+            ev.timestamp = 100 * (i + 1);
+            ev.ifname = "wlan0";
+            ev.data = events[i];
+            logger.log(ev);
         }
 
         String want = joinLines(
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
-                "  link_layer: 0",
+                "  link_layer: 4",
                 "  network_id: 0",
                 "  time_ms: 100",
                 "  transports: 0",
                 "  ip_reachability_event <",
                 "    event_type: 512",
-                "    if_name: \"wlan0\"",
+                "    if_name: \"\"",
                 "  >",
                 ">",
                 "events <",
                 "  if_name: \"\"",
-                "  link_layer: 0",
+                "  link_layer: 4",
                 "  network_id: 0",
                 "  time_ms: 200",
                 "  transports: 0",
                 "  dhcp_event <",
                 "    duration_ms: 192",
-                "    if_name: \"wlan0\"",
+                "    if_name: \"\"",
                 "    state_transition: \"SomeState\"",
                 "  >",
                 ">",
                 "events <",
                 "  if_name: \"\"",
-                "  link_layer: 0",
+                "  link_layer: 4",
                 "  network_id: 0",
                 "  time_ms: 300",
                 "  transports: 0",
@@ -213,34 +223,31 @@
                 ">",
                 "events <",
                 "  if_name: \"\"",
-                "  link_layer: 0",
+                "  link_layer: 4",
                 "  network_id: 0",
                 "  time_ms: 400",
                 "  transports: 0",
                 "  ip_provisioning_event <",
                 "    event_type: 1",
-                "    if_name: \"wlan0\"",
+                "    if_name: \"\"",
                 "    latency_ms: 5678",
                 "  >",
                 ">",
                 "events <",
                 "  if_name: \"\"",
-                "  link_layer: 0",
+                "  link_layer: 4",
                 "  network_id: 0",
                 "  time_ms: 500",
                 "  transports: 0",
                 "  validation_probe_event <",
                 "    latency_ms: 40730",
-                "    network_id <",
-                "      network_id: 120",
-                "    >",
                 "    probe_result: 204",
                 "    probe_type: 1",
                 "  >",
                 ">",
                 "events <",
                 "  if_name: \"\"",
-                "  link_layer: 0",
+                "  link_layer: 4",
                 "  network_id: 0",
                 "  time_ms: 600",
                 "  transports: 0",
@@ -259,7 +266,7 @@
                 ">",
                 "events <",
                 "  if_name: \"\"",
-                "  link_layer: 0",
+                "  link_layer: 4",
                 "  network_id: 0",
                 "  time_ms: 700",
                 "  transports: 0",