Merge "Remove filegroup connectivity-module-utils-srcs in connectivity."
diff --git a/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java b/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
index 18ef631..898b124 100644
--- a/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
+++ b/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
@@ -168,13 +168,13 @@
}
@Override
- public boolean attachProgram(String iface, boolean downstream) {
+ public boolean attachProgram(String iface, boolean downstream, boolean ipv4) {
/* no op */
return true;
}
@Override
- public boolean detachProgram(String iface) {
+ public boolean detachProgram(String iface, boolean ipv4) {
/* no op */
return true;
}
diff --git a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
index fd9dab5..776832f 100644
--- a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
+++ b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
@@ -425,11 +425,11 @@
}
@Override
- public boolean attachProgram(String iface, boolean downstream) {
+ public boolean attachProgram(String iface, boolean downstream, boolean ipv4) {
if (!isInitialized()) return false;
try {
- BpfUtils.attachProgram(iface, downstream);
+ BpfUtils.attachProgram(iface, downstream, ipv4);
} catch (IOException e) {
mLog.e("Could not attach program: " + e);
return false;
@@ -438,11 +438,11 @@
}
@Override
- public boolean detachProgram(String iface) {
+ public boolean detachProgram(String iface, boolean ipv4) {
if (!isInitialized()) return false;
try {
- BpfUtils.detachProgram(iface);
+ BpfUtils.detachProgram(iface, ipv4);
} catch (IOException e) {
mLog.e("Could not detach program: " + e);
return false;
diff --git a/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java b/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
index 69cbab5..51cecfe 100644
--- a/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
+++ b/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
@@ -172,16 +172,24 @@
/**
* Attach BPF program.
*
+ * @param iface the interface name to attach program.
+ * @param downstream indicate the datapath. true if downstream, false if upstream.
+ * @param ipv4 indicate the protocol family. true if ipv4, false if ipv6.
+ *
* TODO: consider using InterfaceParams to replace interface name.
*/
- public abstract boolean attachProgram(@NonNull String iface, boolean downstream);
+ public abstract boolean attachProgram(@NonNull String iface, boolean downstream,
+ boolean ipv4);
/**
* Detach BPF program.
*
+ * @param iface the interface name to detach program.
+ * @param ipv4 indicate the protocol family. true if ipv4, false if ipv6.
+ *
* TODO: consider using InterfaceParams to replace interface name.
*/
- public abstract boolean detachProgram(@NonNull String iface);
+ public abstract boolean detachProgram(@NonNull String iface, boolean ipv4);
/**
* Add interface index mapping.
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 49442a6..7e0a589 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -895,6 +895,28 @@
}
}
+ private boolean is464XlatInterface(@NonNull String ifaceName) {
+ return ifaceName.startsWith("v4-");
+ }
+
+ private void maybeAttachProgramImpl(@NonNull String iface, boolean downstream) {
+ mBpfCoordinatorShim.attachProgram(iface, downstream, true /* ipv4 */);
+
+ // Ignore 464xlat interface because it is IPv4 only.
+ if (!is464XlatInterface(iface)) {
+ mBpfCoordinatorShim.attachProgram(iface, downstream, false /* ipv4 */);
+ }
+ }
+
+ private void maybeDetachProgramImpl(@NonNull String iface) {
+ mBpfCoordinatorShim.detachProgram(iface, true /* ipv4 */);
+
+ // Ignore 464xlat interface because it is IPv4 only.
+ if (!is464XlatInterface(iface)) {
+ mBpfCoordinatorShim.detachProgram(iface, false /* ipv4 */);
+ }
+ }
+
/**
* Attach BPF program
*
@@ -905,13 +927,19 @@
if (forwardingPairExists(intIface, extIface)) return;
+ boolean firstUpstreamForThisDownstream = !isAnyForwardingPairOnDownstream(intIface);
boolean firstDownstreamForThisUpstream = !isAnyForwardingPairOnUpstream(extIface);
forwardingPairAdd(intIface, extIface);
- mBpfCoordinatorShim.attachProgram(intIface, UPSTREAM);
+ // Attach if the downstream is the first time to be used in a forwarding pair.
+ // Ex: IPv6 only interface has two forwarding pair, iface and v4-iface, on the
+ // same downstream.
+ if (firstUpstreamForThisDownstream) {
+ maybeAttachProgramImpl(intIface, UPSTREAM);
+ }
// Attach if the upstream is the first time to be used in a forwarding pair.
if (firstDownstreamForThisUpstream) {
- mBpfCoordinatorShim.attachProgram(extIface, DOWNSTREAM);
+ maybeAttachProgramImpl(extIface, DOWNSTREAM);
}
}
@@ -922,10 +950,12 @@
forwardingPairRemove(intIface, extIface);
// Detaching program may fail because the interface has been removed already.
- mBpfCoordinatorShim.detachProgram(intIface);
+ if (!isAnyForwardingPairOnDownstream(intIface)) {
+ maybeDetachProgramImpl(intIface);
+ }
// Detach if no more forwarding pair is using the upstream.
if (!isAnyForwardingPairOnUpstream(extIface)) {
- mBpfCoordinatorShim.detachProgram(extIface);
+ maybeDetachProgramImpl(extIface);
}
}
@@ -1827,6 +1857,13 @@
return mForwardingPairs.containsKey(extIface);
}
+ private boolean isAnyForwardingPairOnDownstream(@NonNull String intIface) {
+ for (final HashSet downstreams : mForwardingPairs.values()) {
+ if (downstreams.contains(intIface)) return true;
+ }
+ return false;
+ }
+
@NonNull
private NetworkStats buildNetworkStats(@NonNull StatsType type, int ifIndex,
@NonNull final ForwardedStats diff) {
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfUtils.java b/Tethering/src/com/android/networkstack/tethering/BpfUtils.java
index 3d2dfaa..12a0c96 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfUtils.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfUtils.java
@@ -74,7 +74,7 @@
*
* TODO: use interface index to replace interface name.
*/
- public static void attachProgram(@NonNull String iface, boolean downstream)
+ public static void attachProgram(@NonNull String iface, boolean downstream, boolean ipv4)
throws IOException {
final InterfaceParams params = InterfaceParams.getByName(iface);
if (params == null) {
@@ -88,24 +88,26 @@
throw new IOException("isEthernet(" + params.index + "[" + iface + "]) failure: " + e);
}
- try {
- // tc filter add dev .. ingress prio 1 protocol ipv6 bpf object-pinned /sys/fs/bpf/...
- // direct-action
- TcUtils.tcFilterAddDevBpf(params.index, INGRESS, PRIO_TETHER6, (short) ETH_P_IPV6,
- makeProgPath(downstream, 6, ether));
- } catch (IOException e) {
- throw new IOException("tc filter add dev (" + params.index + "[" + iface
- + "]) ingress prio PRIO_TETHER6 protocol ipv6 failure: " + e);
- }
-
- try {
- // tc filter add dev .. ingress prio 2 protocol ip bpf object-pinned /sys/fs/bpf/...
- // direct-action
- TcUtils.tcFilterAddDevBpf(params.index, INGRESS, PRIO_TETHER4, (short) ETH_P_IP,
- makeProgPath(downstream, 4, ether));
- } catch (IOException e) {
- throw new IOException("tc filter add dev (" + params.index + "[" + iface
- + "]) ingress prio PRIO_TETHER4 protocol ip failure: " + e);
+ if (ipv4) {
+ try {
+ // tc filter add dev .. ingress prio 2 protocol ip bpf object-pinned /sys/fs/bpf/...
+ // direct-action
+ TcUtils.tcFilterAddDevBpf(params.index, INGRESS, PRIO_TETHER4, (short) ETH_P_IP,
+ makeProgPath(downstream, 4, ether));
+ } catch (IOException e) {
+ throw new IOException("tc filter add dev (" + params.index + "[" + iface
+ + "]) ingress prio PRIO_TETHER4 protocol ip failure: " + e);
+ }
+ } else {
+ try {
+ // tc filter add dev .. ingress prio 1 protocol ipv6 bpf object-pinned
+ // /sys/fs/bpf/... direct-action
+ TcUtils.tcFilterAddDevBpf(params.index, INGRESS, PRIO_TETHER6, (short) ETH_P_IPV6,
+ makeProgPath(downstream, 6, ether));
+ } catch (IOException e) {
+ throw new IOException("tc filter add dev (" + params.index + "[" + iface
+ + "]) ingress prio PRIO_TETHER6 protocol ipv6 failure: " + e);
+ }
}
}
@@ -114,26 +116,28 @@
*
* TODO: use interface index to replace interface name.
*/
- public static void detachProgram(@NonNull String iface) throws IOException {
+ public static void detachProgram(@NonNull String iface, boolean ipv4) throws IOException {
final InterfaceParams params = InterfaceParams.getByName(iface);
if (params == null) {
throw new IOException("Fail to get interface params for interface " + iface);
}
- try {
- // tc filter del dev .. ingress prio 1 protocol ipv6
- TcUtils.tcFilterDelDev(params.index, INGRESS, PRIO_TETHER6, (short) ETH_P_IPV6);
- } catch (IOException e) {
- throw new IOException("tc filter del dev (" + params.index + "[" + iface
- + "]) ingress prio PRIO_TETHER6 protocol ipv6 failure: " + e);
- }
-
- try {
- // tc filter del dev .. ingress prio 2 protocol ip
- TcUtils.tcFilterDelDev(params.index, INGRESS, PRIO_TETHER4, (short) ETH_P_IP);
- } catch (IOException e) {
- throw new IOException("tc filter del dev (" + params.index + "[" + iface
- + "]) ingress prio PRIO_TETHER4 protocol ip failure: " + e);
+ if (ipv4) {
+ try {
+ // tc filter del dev .. ingress prio 2 protocol ip
+ TcUtils.tcFilterDelDev(params.index, INGRESS, PRIO_TETHER4, (short) ETH_P_IP);
+ } catch (IOException e) {
+ throw new IOException("tc filter del dev (" + params.index + "[" + iface
+ + "]) ingress prio PRIO_TETHER4 protocol ip failure: " + e);
+ }
+ } else {
+ try {
+ // tc filter del dev .. ingress prio 1 protocol ipv6
+ TcUtils.tcFilterDelDev(params.index, INGRESS, PRIO_TETHER6, (short) ETH_P_IPV6);
+ } catch (IOException e) {
+ throw new IOException("tc filter del dev (" + params.index + "[" + iface
+ + "]) ingress prio PRIO_TETHER6 protocol ipv6 failure: " + e);
+ }
}
}
}
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 0c59b61..75f63c8 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -2772,7 +2772,8 @@
// If we don't care about this type of interface, ignore.
final int interfaceType = ifaceNameToType(iface);
if (!checkTetherableType(interfaceType)) {
- mLog.log(iface + " is used for " + interfaceType + " which is not tetherable");
+ mLog.log(iface + " is used for " + interfaceType + " which is not tetherable"
+ + " (-1 == INVALID is expected on upstream interface)");
return;
}
diff --git a/Tethering/tests/integration/Android.bp b/Tethering/tests/integration/Android.bp
index ca8d3de..9aa2cff 100644
--- a/Tethering/tests/integration/Android.bp
+++ b/Tethering/tests/integration/Android.bp
@@ -79,7 +79,6 @@
defaults: ["TetheringIntegrationTestsDefaults"],
test_suites: [
"device-tests",
- "mts-tethering",
],
compile_multilib: "both",
jarjar_rules: ":NetworkStackJarJarRules",
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
index fa1d881..63bb731 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
@@ -59,6 +59,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
@@ -141,6 +142,9 @@
@Rule
public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
+ private static final boolean IPV4 = true;
+ private static final boolean IPV6 = false;
+
private static final int TEST_NET_ID = 24;
private static final int TEST_NET_ID2 = 25;
@@ -1277,48 +1281,72 @@
try {
final String intIface1 = "wlan1";
final String intIface2 = "rndis0";
- final String extIface = "rmnet_data0";
+ final String extIface1 = "rmnet_data0";
+ final String extIface2 = "v4-rmnet_data0";
final String virtualIface = "ipsec0";
final BpfUtils mockMarkerBpfUtils = staticMockMarker(BpfUtils.class);
final BpfCoordinator coordinator = makeBpfCoordinator();
// [1] Add the forwarding pair <wlan1, rmnet_data0>. Expect that attach both wlan1 and
// rmnet_data0.
- coordinator.maybeAttachProgram(intIface1, extIface);
- ExtendedMockito.verify(() -> BpfUtils.attachProgram(extIface, DOWNSTREAM));
- ExtendedMockito.verify(() -> BpfUtils.attachProgram(intIface1, UPSTREAM));
+ coordinator.maybeAttachProgram(intIface1, extIface1);
+ ExtendedMockito.verify(() -> BpfUtils.attachProgram(extIface1, DOWNSTREAM, IPV4));
+ ExtendedMockito.verify(() -> BpfUtils.attachProgram(extIface1, DOWNSTREAM, IPV6));
+ ExtendedMockito.verify(() -> BpfUtils.attachProgram(intIface1, UPSTREAM, IPV4));
+ ExtendedMockito.verify(() -> BpfUtils.attachProgram(intIface1, UPSTREAM, IPV6));
ExtendedMockito.verifyNoMoreInteractions(mockMarkerBpfUtils);
ExtendedMockito.clearInvocations(mockMarkerBpfUtils);
// [2] Add the forwarding pair <wlan1, rmnet_data0> again. Expect no more action.
- coordinator.maybeAttachProgram(intIface1, extIface);
+ coordinator.maybeAttachProgram(intIface1, extIface1);
ExtendedMockito.verifyNoMoreInteractions(mockMarkerBpfUtils);
ExtendedMockito.clearInvocations(mockMarkerBpfUtils);
// [3] Add the forwarding pair <rndis0, rmnet_data0>. Expect that attach rndis0 only.
- coordinator.maybeAttachProgram(intIface2, extIface);
- ExtendedMockito.verify(() -> BpfUtils.attachProgram(intIface2, UPSTREAM));
+ coordinator.maybeAttachProgram(intIface2, extIface1);
+ ExtendedMockito.verify(() -> BpfUtils.attachProgram(intIface2, UPSTREAM, IPV4));
+ ExtendedMockito.verify(() -> BpfUtils.attachProgram(intIface2, UPSTREAM, IPV6));
ExtendedMockito.verifyNoMoreInteractions(mockMarkerBpfUtils);
ExtendedMockito.clearInvocations(mockMarkerBpfUtils);
- // [4] Remove the forwarding pair <rndis0, rmnet_data0>. Expect detach rndis0 only.
- coordinator.maybeDetachProgram(intIface2, extIface);
- ExtendedMockito.verify(() -> BpfUtils.detachProgram(intIface2));
+ // [4] Add the forwarding pair <rndis0, v4-rmnet_data0>. Expect that attach
+ // v4-rmnet_data0 IPv4 program only.
+ coordinator.maybeAttachProgram(intIface2, extIface2);
+ ExtendedMockito.verify(() -> BpfUtils.attachProgram(extIface2, DOWNSTREAM, IPV4));
+ ExtendedMockito.verify(() -> BpfUtils.attachProgram(extIface2, DOWNSTREAM, IPV6),
+ never());
ExtendedMockito.verifyNoMoreInteractions(mockMarkerBpfUtils);
ExtendedMockito.clearInvocations(mockMarkerBpfUtils);
- // [5] Remove the forwarding pair <wlan1, rmnet_data0>. Expect that detach both wlan1
+ // [5] Remove the forwarding pair <rndis0, v4-rmnet_data0>. Expect detach
+ // v4-rmnet_data0 IPv4 program only.
+ coordinator.maybeDetachProgram(intIface2, extIface2);
+ ExtendedMockito.verify(() -> BpfUtils.detachProgram(extIface2, IPV4));
+ ExtendedMockito.verify(() -> BpfUtils.detachProgram(extIface2, IPV6), never());
+ ExtendedMockito.verifyNoMoreInteractions(mockMarkerBpfUtils);
+ ExtendedMockito.clearInvocations(mockMarkerBpfUtils);
+
+ // [6] Remove the forwarding pair <rndis0, rmnet_data0>. Expect detach rndis0 only.
+ coordinator.maybeDetachProgram(intIface2, extIface1);
+ ExtendedMockito.verify(() -> BpfUtils.detachProgram(intIface2, IPV4));
+ ExtendedMockito.verify(() -> BpfUtils.detachProgram(intIface2, IPV6));
+ ExtendedMockito.verifyNoMoreInteractions(mockMarkerBpfUtils);
+ ExtendedMockito.clearInvocations(mockMarkerBpfUtils);
+
+ // [7] Remove the forwarding pair <wlan1, rmnet_data0>. Expect that detach both wlan1
// and rmnet_data0.
- coordinator.maybeDetachProgram(intIface1, extIface);
- ExtendedMockito.verify(() -> BpfUtils.detachProgram(extIface));
- ExtendedMockito.verify(() -> BpfUtils.detachProgram(intIface1));
+ coordinator.maybeDetachProgram(intIface1, extIface1);
+ ExtendedMockito.verify(() -> BpfUtils.detachProgram(extIface1, IPV4));
+ ExtendedMockito.verify(() -> BpfUtils.detachProgram(extIface1, IPV6));
+ ExtendedMockito.verify(() -> BpfUtils.detachProgram(intIface1, IPV4));
+ ExtendedMockito.verify(() -> BpfUtils.detachProgram(intIface1, IPV6));
ExtendedMockito.verifyNoMoreInteractions(mockMarkerBpfUtils);
ExtendedMockito.clearInvocations(mockMarkerBpfUtils);
- // [6] Skip attaching if upstream is virtual interface.
+ // [8] Skip attaching if upstream is virtual interface.
coordinator.maybeAttachProgram(intIface1, virtualIface);
- ExtendedMockito.verify(() -> BpfUtils.attachProgram(extIface, DOWNSTREAM), never());
- ExtendedMockito.verify(() -> BpfUtils.attachProgram(intIface1, UPSTREAM), never());
+ ExtendedMockito.verify(() ->
+ BpfUtils.attachProgram(anyString(), anyBoolean(), anyBoolean()), never());
ExtendedMockito.verifyNoMoreInteractions(mockMarkerBpfUtils);
ExtendedMockito.clearInvocations(mockMarkerBpfUtils);
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 8de7836..66ad167 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -837,9 +837,9 @@
}
private void verifyInterfaceServingModeStarted(String ifname) throws Exception {
- verify(mNetd, times(1)).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
- verify(mNetd, times(1)).tetherInterfaceAdd(ifname);
- verify(mNetd, times(1)).networkAddInterface(INetd.LOCAL_NET_ID, ifname);
+ verify(mNetd).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd).tetherInterfaceAdd(ifname);
+ verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, ifname);
verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(ifname),
anyString(), anyString());
}
@@ -934,6 +934,52 @@
failingLocalOnlyHotspotLegacyApBroadcast(false);
}
+ private void verifyStopHotpot() throws Exception {
+ verify(mNetd).tetherApplyDnsInterfaces();
+ verify(mNetd).tetherInterfaceRemove(TEST_WLAN_IFNAME);
+ verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME);
+ // interfaceSetCfg() called once for enabling and twice disabling IPv4.
+ verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
+ verify(mNetd).tetherStop();
+ verify(mNetd).ipfwdDisableForwarding(TETHERING_NAME);
+ verify(mWifiManager, times(3)).updateInterfaceIpState(
+ TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+ verifyNoMoreInteractions(mNetd);
+ verifyNoMoreInteractions(mWifiManager);
+ // Asking for the last error after the per-interface state machine
+ // has been reaped yields an unknown interface error.
+ assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastErrorForTest(TEST_WLAN_IFNAME));
+ }
+
+ private void verifyStartHotspot() throws Exception {
+ verifyStartHotspot(false /* isLocalOnly */);
+ }
+
+ private void verifyStartHotspot(boolean isLocalOnly) throws Exception {
+ verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
+ verify(mWifiManager).updateInterfaceIpState(
+ TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+
+ verify(mNetd).ipfwdEnableForwarding(TETHERING_NAME);
+ verify(mNetd).tetherStartWithConfiguration(any());
+ verifyNoMoreInteractions(mNetd);
+
+ final int expectedState = isLocalOnly ? IFACE_IP_MODE_LOCAL_ONLY : IFACE_IP_MODE_TETHERED;
+ verify(mWifiManager).updateInterfaceIpState(TEST_WLAN_IFNAME, expectedState);
+ verifyNoMoreInteractions(mWifiManager);
+
+ verify(mUpstreamNetworkMonitor).startObserveAllNetworks();
+ if (isLocalOnly) {
+ // There are 2 IpServer state change events: STATE_AVAILABLE -> STATE_LOCAL_ONLY.
+ verify(mNotificationUpdater, times(2)).onDownstreamChanged(DOWNSTREAM_NONE);
+ } else {
+ // There are 2 IpServer state change events: STATE_AVAILABLE -> STATE_TETHERED.
+ verify(mNotificationUpdater).onDownstreamChanged(DOWNSTREAM_NONE);
+ verify(mNotificationUpdater).onDownstreamChanged(eq(1 << TETHERING_WIFI));
+ }
+ }
+
public void workingLocalOnlyHotspotEnrichedApBroadcast(
boolean emulateInterfaceStatusChanged) throws Exception {
// Emulate externally-visible WifiManager effects, causing the
@@ -944,20 +990,8 @@
}
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_LOCAL_ONLY);
- verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
- verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME);
- verify(mNetd, times(1)).tetherStartWithConfiguration(any());
- verifyNoMoreInteractions(mNetd);
- verify(mWifiManager).updateInterfaceIpState(
- TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
- verify(mWifiManager).updateInterfaceIpState(
- TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
- verifyNoMoreInteractions(mWifiManager);
+ verifyStartHotspot(true /* isLocalOnly */);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
- verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
- // There are 2 IpServer state change events: STATE_AVAILABLE -> STATE_LOCAL_ONLY
- verify(mNotificationUpdater, times(2)).onDownstreamChanged(DOWNSTREAM_NONE);
// Emulate externally-visible WifiManager effects, when hotspot mode
// is being torn down.
@@ -965,20 +999,7 @@
mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
mLooper.dispatchAll();
- verify(mNetd, times(1)).tetherApplyDnsInterfaces();
- verify(mNetd, times(1)).tetherInterfaceRemove(TEST_WLAN_IFNAME);
- verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME);
- // interfaceSetCfg() called once for enabling and twice disabling IPv4.
- verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
- verify(mNetd, times(1)).tetherStop();
- verify(mNetd, times(1)).ipfwdDisableForwarding(TETHERING_NAME);
- verify(mWifiManager, times(3)).updateInterfaceIpState(
- TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
- verifyNoMoreInteractions(mNetd);
- verifyNoMoreInteractions(mWifiManager);
- // Asking for the last error after the per-interface state machine
- // has been reaped yields an unknown interface error.
- assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastErrorForTest(TEST_WLAN_IFNAME));
+ verifyStopHotpot();
}
/**
@@ -1499,26 +1520,11 @@
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
- verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
- verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME);
- verify(mNetd, times(1)).tetherStartWithConfiguration(any());
- verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(TEST_WLAN_IFNAME),
- anyString(), anyString());
- verifyNoMoreInteractions(mNetd);
- verify(mWifiManager).updateInterfaceIpState(
- TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
- verify(mWifiManager).updateInterfaceIpState(
- TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
- verifyNoMoreInteractions(mWifiManager);
+ verifyStartHotspot();
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER);
- verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
// In tethering mode, in the default configuration, an explicit request
// for a mobile network is also made.
verify(mUpstreamNetworkMonitor, times(1)).setTryCell(true);
- // There are 2 IpServer state change events: STATE_AVAILABLE -> STATE_TETHERED
- verify(mNotificationUpdater, times(1)).onDownstreamChanged(DOWNSTREAM_NONE);
- verify(mNotificationUpdater, times(1)).onDownstreamChanged(eq(1 << TETHERING_WIFI));
/////
// We do not currently emulate any upstream being found.
@@ -1540,20 +1546,7 @@
mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
mLooper.dispatchAll();
- verify(mNetd, times(1)).tetherApplyDnsInterfaces();
- verify(mNetd, times(1)).tetherInterfaceRemove(TEST_WLAN_IFNAME);
- verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME);
- // interfaceSetCfg() called once for enabling and twice for disabling IPv4.
- verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
- verify(mNetd, times(1)).tetherStop();
- verify(mNetd, times(1)).ipfwdDisableForwarding(TETHERING_NAME);
- verify(mWifiManager, times(3)).updateInterfaceIpState(
- TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
- verifyNoMoreInteractions(mNetd);
- verifyNoMoreInteractions(mWifiManager);
- // Asking for the last error after the per-interface state machine
- // has been reaped yields an unknown interface error.
- assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastErrorForTest(TEST_WLAN_IFNAME));
+ verifyStopHotpot();
}
// TODO: Test with and without interfaceStatusChanged().
diff --git a/bpf_progs/bpf_tethering.h b/bpf_progs/bpf_tethering.h
index f9ef6ef..9dae6c9 100644
--- a/bpf_progs/bpf_tethering.h
+++ b/bpf_progs/bpf_tethering.h
@@ -26,31 +26,33 @@
// - The BPF programs in Tethering/bpf_progs/
// - JNI code that depends on the bpf_connectivity_headers library.
-#define BPF_TETHER_ERRORS \
- ERR(INVALID_IP_VERSION) \
- ERR(LOW_TTL) \
- ERR(INVALID_TCP_HEADER) \
- ERR(TCP_CONTROL_PACKET) \
- ERR(NON_GLOBAL_SRC) \
- ERR(NON_GLOBAL_DST) \
- ERR(LOCAL_SRC_DST) \
- ERR(NO_STATS_ENTRY) \
- ERR(NO_LIMIT_ENTRY) \
- ERR(BELOW_IPV4_MTU) \
- ERR(BELOW_IPV6_MTU) \
- ERR(LIMIT_REACHED) \
- ERR(CHANGE_HEAD_FAILED) \
- ERR(TOO_SHORT) \
- ERR(HAS_IP_OPTIONS) \
- ERR(IS_IP_FRAG) \
- ERR(CHECKSUM) \
- ERR(NON_TCP_UDP) \
- ERR(NON_TCP) \
- ERR(SHORT_L4_HEADER) \
- ERR(SHORT_TCP_HEADER) \
- ERR(SHORT_UDP_HEADER) \
- ERR(UDP_CSUM_ZERO) \
- ERR(TRUNCATED_IPV4) \
+#define BPF_TETHER_ERRORS \
+ ERR(INVALID_IPV4_VERSION) \
+ ERR(INVALID_IPV6_VERSION) \
+ ERR(LOW_TTL) \
+ ERR(INVALID_TCP_HEADER) \
+ ERR(TCPV4_CONTROL_PACKET) \
+ ERR(TCPV6_CONTROL_PACKET) \
+ ERR(NON_GLOBAL_SRC) \
+ ERR(NON_GLOBAL_DST) \
+ ERR(LOCAL_SRC_DST) \
+ ERR(NO_STATS_ENTRY) \
+ ERR(NO_LIMIT_ENTRY) \
+ ERR(BELOW_IPV4_MTU) \
+ ERR(BELOW_IPV6_MTU) \
+ ERR(LIMIT_REACHED) \
+ ERR(CHANGE_HEAD_FAILED) \
+ ERR(TOO_SHORT) \
+ ERR(HAS_IP_OPTIONS) \
+ ERR(IS_IP_FRAG) \
+ ERR(CHECKSUM) \
+ ERR(NON_TCP_UDP) \
+ ERR(NON_TCP) \
+ ERR(SHORT_L4_HEADER) \
+ ERR(SHORT_TCP_HEADER) \
+ ERR(SHORT_UDP_HEADER) \
+ ERR(UDP_CSUM_ZERO) \
+ ERR(TRUNCATED_IPV4) \
ERR(_MAX)
#define ERR(x) BPF_TETHER_ERR_ ##x,
diff --git a/bpf_progs/clatd.c b/bpf_progs/clatd.c
index 66e9616..a2214dc 100644
--- a/bpf_progs/clatd.c
+++ b/bpf_progs/clatd.c
@@ -342,4 +342,4 @@
}
LICENSE("Apache 2.0");
-CRITICAL("netd");
+CRITICAL("Connectivity");
diff --git a/bpf_progs/dscpPolicy.c b/bpf_progs/dscpPolicy.c
index f308931..3e4456f 100644
--- a/bpf_progs/dscpPolicy.c
+++ b/bpf_progs/dscpPolicy.c
@@ -57,7 +57,7 @@
uint64_t cookie = bpf_get_socket_cookie(skb);
if (!cookie) return;
- uint16_t sport = 0;
+ __be16 sport = 0;
uint16_t dport = 0;
uint8_t protocol = 0; // TODO: Use are reserved value? Or int (-1) and cast to uint below?
struct in6_addr src_ip = {};
@@ -106,14 +106,14 @@
udp = data + hdr_size;
if ((void*)(udp + 1) > data_end) return;
sport = udp->source;
- dport = udp->dest;
+ dport = ntohs(udp->dest);
} break;
case IPPROTO_TCP: {
struct tcphdr* tcp;
tcp = data + hdr_size;
if ((void*)(tcp + 1) > data_end) return;
sport = tcp->source;
- dport = tcp->dest;
+ dport = ntohs(tcp->dest);
} break;
default:
return;
@@ -121,10 +121,13 @@
RuleEntry* existing_rule = bpf_socket_policy_cache_map_lookup_elem(&cookie);
- if (existing_rule && v6_equal(src_ip, existing_rule->src_ip) &&
- v6_equal(dst_ip, existing_rule->dst_ip) && skb->ifindex == existing_rule->ifindex &&
- ntohs(sport) == htons(existing_rule->src_port) &&
- ntohs(dport) == htons(existing_rule->dst_port) && protocol == existing_rule->proto) {
+ if (existing_rule &&
+ v6_equal(src_ip, existing_rule->src_ip) &&
+ v6_equal(dst_ip, existing_rule->dst_ip) &&
+ skb->ifindex == existing_rule->ifindex &&
+ sport == existing_rule->src_port &&
+ dport == existing_rule->dst_port &&
+ protocol == existing_rule->proto) {
if (existing_rule->dscp_val < 0) return;
if (ipv4) {
uint8_t newTos = UPDATE_TOS(existing_rule->dscp_val, tos);
@@ -145,8 +148,6 @@
int8_t new_dscp = -1;
for (register uint64_t i = 0; i < MAX_POLICIES; i++) {
- int score = 0;
- uint8_t temp_mask = 0;
// Using a uint64 in for loop prevents infinite loop during BPF load,
// but the key is uint32, so convert back.
uint32_t key = i;
@@ -158,38 +159,35 @@
policy = bpf_ipv6_dscp_policies_map_lookup_elem(&key);
}
- // If the policy lookup failed, present_fields is 0, or iface index does not match
- // index on skb buff, then we can continue to next policy.
- if (!policy || policy->present_fields == 0 || policy->ifindex != skb->ifindex) continue;
+ // If the policy lookup failed, just continue (this should not ever happen)
+ if (!policy) continue;
- if ((policy->present_fields & SRC_IP_MASK_FLAG) == SRC_IP_MASK_FLAG &&
- v6_equal(src_ip, policy->src_ip)) {
- score++;
- temp_mask |= SRC_IP_MASK_FLAG;
- }
- if ((policy->present_fields & DST_IP_MASK_FLAG) == DST_IP_MASK_FLAG &&
- v6_equal(dst_ip, policy->dst_ip)) {
- score++;
- temp_mask |= DST_IP_MASK_FLAG;
- }
- if ((policy->present_fields & SRC_PORT_MASK_FLAG) == SRC_PORT_MASK_FLAG &&
- ntohs(sport) == htons(policy->src_port)) {
- score++;
- temp_mask |= SRC_PORT_MASK_FLAG;
- }
- if ((policy->present_fields & DST_PORT_MASK_FLAG) == DST_PORT_MASK_FLAG &&
- ntohs(dport) >= htons(policy->dst_port_start) &&
- ntohs(dport) <= htons(policy->dst_port_end)) {
- score++;
- temp_mask |= DST_PORT_MASK_FLAG;
- }
- if ((policy->present_fields & PROTO_MASK_FLAG) == PROTO_MASK_FLAG &&
- protocol == policy->proto) {
- score++;
- temp_mask |= PROTO_MASK_FLAG;
- }
+ // If policy iface index does not match skb, then skip to next policy.
+ if (policy->ifindex != skb->ifindex) continue;
- if (score > best_score && temp_mask == policy->present_fields) {
+ int score = 0;
+
+ if (policy->present_fields & PROTO_MASK_FLAG) {
+ if (protocol != policy->proto) continue;
+ score += 0xFFFF;
+ }
+ if (policy->present_fields & SRC_IP_MASK_FLAG) {
+ if (v6_not_equal(src_ip, policy->src_ip)) continue;
+ score += 0xFFFF;
+ }
+ if (policy->present_fields & DST_IP_MASK_FLAG) {
+ if (v6_not_equal(dst_ip, policy->dst_ip)) continue;
+ score += 0xFFFF;
+ }
+ if (policy->present_fields & SRC_PORT_MASK_FLAG) {
+ if (sport != policy->src_port) continue;
+ score += 0xFFFF;
+ }
+ if (dport < policy->dst_port_start) continue;
+ if (dport > policy->dst_port_end) continue;
+ score += 0xFFFF + policy->dst_port_start - policy->dst_port_end;
+
+ if (score > best_score) {
best_score = score;
new_dscp = policy->dscp_val;
}
diff --git a/bpf_progs/dscpPolicy.h b/bpf_progs/dscpPolicy.h
index c1db6ab..e565966 100644
--- a/bpf_progs/dscpPolicy.h
+++ b/bpf_progs/dscpPolicy.h
@@ -20,16 +20,22 @@
#define SRC_IP_MASK_FLAG 1
#define DST_IP_MASK_FLAG 2
#define SRC_PORT_MASK_FLAG 4
-#define DST_PORT_MASK_FLAG 8
-#define PROTO_MASK_FLAG 16
+#define PROTO_MASK_FLAG 8
#define STRUCT_SIZE(name, size) _Static_assert(sizeof(name) == (size), "Incorrect struct size.")
-#define v6_equal(a, b) \
- (((a.s6_addr32[0] ^ b.s6_addr32[0]) | \
- (a.s6_addr32[1] ^ b.s6_addr32[1]) | \
- (a.s6_addr32[2] ^ b.s6_addr32[2]) | \
- (a.s6_addr32[3] ^ b.s6_addr32[3])) == 0)
+// Retrieve the first (ie. high) 64 bits of an IPv6 address (in network order)
+#define v6_hi_be64(v) (*(uint64_t*)&((v).s6_addr32[0]))
+
+// Retrieve the last (ie. low) 64 bits of an IPv6 address (in network order)
+#define v6_lo_be64(v) (*(uint64_t*)&((v).s6_addr32[2]))
+
+// This returns a non-zero u64 iff a != b
+#define v6_not_equal(a, b) ((v6_hi_be64(a) ^ v6_hi_be64(b)) \
+ | (v6_lo_be64(a) ^ v6_lo_be64(b)))
+
+// Returns 'a == b' as boolean
+#define v6_equal(a, b) (!v6_not_equal((a), (b)))
// TODO: these are already defined in packages/modules/Connectivity/bpf_progs/bpf_net_helpers.h.
// smove to common location in future.
@@ -47,8 +53,8 @@
struct in6_addr dst_ip;
uint32_t ifindex;
__be16 src_port;
- __be16 dst_port_start;
- __be16 dst_port_end;
+ uint16_t dst_port_start;
+ uint16_t dst_port_end;
uint8_t proto;
int8_t dscp_val; // -1 none, or 0..63 DSCP value
uint8_t present_fields;
@@ -59,11 +65,11 @@
typedef struct {
struct in6_addr src_ip;
struct in6_addr dst_ip;
- __u32 ifindex;
+ uint32_t ifindex;
__be16 src_port;
- __be16 dst_port;
- __u8 proto;
- __s8 dscp_val; // -1 none, or 0..63 DSCP value
- __u8 pad[2];
+ uint16_t dst_port;
+ uint8_t proto;
+ int8_t dscp_val; // -1 none, or 0..63 DSCP value
+ uint8_t pad[2];
} RuleEntry;
STRUCT_SIZE(RuleEntry, 2 * 16 + 1 * 4 + 2 * 2 + 2 * 1 + 2); // 44
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index 44f76de..10559dd 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -85,10 +85,18 @@
DEFINE_BPF_MAP_NO_NETD(iface_index_name_map, HASH, uint32_t, IfaceValue, IFACE_INDEX_NAME_MAP_SIZE)
// iptables xt_bpf programs need to be usable by both netd and netutils_wrappers
+// selinux contexts, because even non-xt_bpf iptables mutations are implemented as
+// a full table dump, followed by an update in userspace, and then a reload into the kernel,
+// where any already in-use xt_bpf matchers are serialized as the path to the pinned
+// program (see XT_BPF_MODE_PATH_PINNED) and then the iptables binary (or rather
+// the kernel acting on behalf of it) must be able to retrieve the pinned program
+// for the reload to succeed
#define DEFINE_XTBPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
DEFINE_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog)
// programs that need to be usable by netd, but not by netutils_wrappers
+// (this is because these are currently attached by the mainline provided libnetd_updatable .so
+// which is loaded into netd and thus runs as netd uid/gid/selinux context)
#define DEFINE_NETD_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, \
KVER_NONE, KVER_INF, false, "fs_bpf_netd_readonly", "")
@@ -432,4 +440,4 @@
}
LICENSE("Apache 2.0");
-CRITICAL("netd");
+CRITICAL("Connectivity and netd");
diff --git a/bpf_progs/offload.c b/bpf_progs/offload.c
index 4eb1e8d..bb9fc34 100644
--- a/bpf_progs/offload.c
+++ b/bpf_progs/offload.c
@@ -155,7 +155,7 @@
if (is_ethernet && (eth->h_proto != htons(ETH_P_IPV6))) return TC_ACT_PIPE;
// IP version must be 6
- if (ip6->version != 6) TC_PUNT(INVALID_IP_VERSION);
+ if (ip6->version != 6) TC_PUNT(INVALID_IPV6_VERSION);
// Cannot decrement during forward if already zero or would be zero,
// Let the kernel's stack handle these cases and generate appropriate ICMP errors.
@@ -171,7 +171,7 @@
TC_PUNT(INVALID_TCP_HEADER);
// Do not offload TCP packets with any one of the SYN/FIN/RST flags
- if (tcph->syn || tcph->fin || tcph->rst) TC_PUNT(TCP_CONTROL_PACKET);
+ if (tcph->syn || tcph->fin || tcph->rst) TC_PUNT(TCPV6_CONTROL_PACKET);
}
// Protect against forwarding packets sourced from ::1 or fe80::/64 or other weirdness.
@@ -320,50 +320,32 @@
// ANDROID: net: bpf: permit redirect from ingress L3 to egress L2 devices at near max mtu
// (the first of those has already been upstreamed)
//
-// 5.4 kernel support was only added to Android Common Kernel in R,
-// and thus a 5.4 kernel always supports this.
+// These were added to 4.14+ Android Common Kernel in R (including the original release of ACK 5.4)
+// and there is a test in kernel/tests/net/test/bpf_test.py testSkbChangeHead()
+// and in system/netd/tests/binder_test.cpp NetdBinderTest TetherOffloadForwarding.
//
-// Hence, these mandatory (must load successfully) implementations for 5.4+ kernels:
-DEFINE_BPF_PROG_KVER("schedcls/tether_downstream6_rawip$5_4", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_downstream6_rawip_5_4, KVER(5, 4, 0))
+// Hence, these mandatory (must load successfully) implementations for 4.14+ kernels:
+DEFINE_BPF_PROG_KVER("schedcls/tether_downstream6_rawip$4_14", TETHERING_UID, TETHERING_GID,
+ sched_cls_tether_downstream6_rawip_4_14, KVER(4, 14, 0))
(struct __sk_buff* skb) {
return do_forward6(skb, /* is_ethernet */ false, /* downstream */ true);
}
-DEFINE_BPF_PROG_KVER("schedcls/tether_upstream6_rawip$5_4", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_upstream6_rawip_5_4, KVER(5, 4, 0))
+DEFINE_BPF_PROG_KVER("schedcls/tether_upstream6_rawip$4_14", TETHERING_UID, TETHERING_GID,
+ sched_cls_tether_upstream6_rawip_4_14, KVER(4, 14, 0))
(struct __sk_buff* skb) {
return do_forward6(skb, /* is_ethernet */ false, /* downstream */ false);
}
-// and these identical optional (may fail to load) implementations for [4.14..5.4) patched kernels:
-DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_downstream6_rawip$4_14",
- TETHERING_UID, TETHERING_GID,
- sched_cls_tether_downstream6_rawip_4_14,
- KVER(4, 14, 0), KVER(5, 4, 0))
-(struct __sk_buff* skb) {
- return do_forward6(skb, /* is_ethernet */ false, /* downstream */ true);
-}
-
-DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_upstream6_rawip$4_14",
- TETHERING_UID, TETHERING_GID,
- sched_cls_tether_upstream6_rawip_4_14,
- KVER(4, 14, 0), KVER(5, 4, 0))
-(struct __sk_buff* skb) {
- return do_forward6(skb, /* is_ethernet */ false, /* downstream */ false);
-}
-
-// and define no-op stubs for [4.9,4.14) and unpatched [4.14,5.4) kernels.
-// (if the above real 4.14+ program loaded successfully, then bpfloader will have already pinned
-// it at the same location this one would be pinned at and will thus skip loading this stub)
+// and define no-op stubs for pre-4.14 kernels.
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_downstream6_rawip$stub", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_downstream6_rawip_stub, KVER_NONE, KVER(5, 4, 0))
+ sched_cls_tether_downstream6_rawip_stub, KVER_NONE, KVER(4, 14, 0))
(struct __sk_buff* skb) {
return TC_ACT_PIPE;
}
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_upstream6_rawip$stub", TETHERING_UID, TETHERING_GID,
- sched_cls_tether_upstream6_rawip_stub, KVER_NONE, KVER(5, 4, 0))
+ sched_cls_tether_upstream6_rawip_stub, KVER_NONE, KVER(4, 14, 0))
(struct __sk_buff* skb) {
return TC_ACT_PIPE;
}
@@ -388,7 +370,7 @@
// If hardware offload is running and programming flows based on conntrack entries, try not
// to interfere with it, so do not offload TCP packets with any one of the SYN/FIN/RST flags
- if (tcph->syn || tcph->fin || tcph->rst) TC_PUNT(TCP_CONTROL_PACKET);
+ if (tcph->syn || tcph->fin || tcph->rst) TC_PUNT(TCPV4_CONTROL_PACKET);
} else { // UDP
// Make sure we can get at the udp header
if (data + l2_header_size + sizeof(*ip) + sizeof(*udph) > data_end)
@@ -594,7 +576,7 @@
if (is_ethernet && (eth->h_proto != htons(ETH_P_IP))) return TC_ACT_PIPE;
// IP version must be 4
- if (ip->version != 4) TC_PUNT(INVALID_IP_VERSION);
+ if (ip->version != 4) TC_PUNT(INVALID_IPV4_VERSION);
// We cannot handle IP options, just standard 20 byte == 5 dword minimal IPv4 header
if (ip->ihl != 5) TC_PUNT(HAS_IP_OPTIONS);
@@ -882,4 +864,4 @@
}
LICENSE("Apache 2.0");
-CRITICAL("tethering");
+CRITICAL("Connectivity (Tethering)");
diff --git a/framework-t/Android.bp b/framework-t/Android.bp
index c76416f..c32742b 100644
--- a/framework-t/Android.bp
+++ b/framework-t/Android.bp
@@ -43,14 +43,9 @@
":framework-connectivity-tiramisu-updatable-sources",
":framework-nearby-java-sources",
],
- stub_only_libs: [
- // Use prebuilt framework-connectivity stubs to avoid circular dependencies
- "sdk_module-lib_current_framework-connectivity",
- ],
libs: [
"unsupportedappusage",
"app-compat-annotations",
- "sdk_module-lib_current_framework-connectivity",
],
impl_only_libs: [
// The build system will use framework-bluetooth module_current stubs, because
@@ -104,6 +99,13 @@
// The jarjar rules are only so that references to jarjared utils in
// framework-connectivity-pre-jarjar match at runtime.
jarjar_rules: ":framework-connectivity-jarjar-rules",
+ stub_only_libs: [
+ // Use prebuilt framework-connectivity stubs to avoid circular dependencies
+ "sdk_module-lib_current_framework-connectivity",
+ ],
+ libs: [
+ "sdk_module-lib_current_framework-connectivity",
+ ],
permitted_packages: [
"android.app.usage",
"android.net",
diff --git a/framework-t/src/android/net/NetworkStats.java b/framework-t/src/android/net/NetworkStats.java
index a655a9b..8719960 100644
--- a/framework-t/src/android/net/NetworkStats.java
+++ b/framework-t/src/android/net/NetworkStats.java
@@ -302,20 +302,8 @@
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Entry() {
- this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
- }
-
- /** @hide */
- public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
- this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets,
- operations);
- }
-
- /** @hide */
- public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
- long txBytes, long txPackets, long operations) {
- this(iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
- rxBytes, rxPackets, txBytes, txPackets, operations);
+ this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
}
/**
@@ -607,7 +595,8 @@
public NetworkStats insertEntry(
String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
return insertEntry(
- iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
+ iface, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
+ rxBytes, rxPackets, txBytes, txPackets, 0L);
}
/** @hide */
@@ -615,7 +604,8 @@
public NetworkStats insertEntry(String iface, int uid, int set, int tag, long rxBytes,
long rxPackets, long txBytes, long txPackets, long operations) {
return insertEntry(new Entry(
- iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
+ iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
+ rxBytes, rxPackets, txBytes, txPackets, operations));
}
/** @hide */
@@ -787,7 +777,8 @@
public NetworkStats combineValues(String iface, int uid, int set, int tag,
long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
return combineValues(new Entry(
- iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
+ iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
+ rxBytes, rxPackets, txBytes, txPackets, operations));
}
/**
diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java
index df42b58..e23faa4 100644
--- a/framework-t/src/android/net/NetworkStatsCollection.java
+++ b/framework-t/src/android/net/NetworkStatsCollection.java
@@ -309,7 +309,8 @@
// ourselves something to scale with.
if (entry.rxBytes == 0 || entry.txBytes == 0) {
combined.recordData(augmentStart, augmentEnd,
- new NetworkStats.Entry(1, 0, 1, 0, 0));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1L, 0L, 1L, 0L, 0L));
combined.getValues(augmentStart, augmentEnd, entry);
}
diff --git a/framework-t/src/android/net/NetworkStatsHistory.java b/framework-t/src/android/net/NetworkStatsHistory.java
index 738e9cc..c345747 100644
--- a/framework-t/src/android/net/NetworkStatsHistory.java
+++ b/framework-t/src/android/net/NetworkStatsHistory.java
@@ -17,7 +17,10 @@
package android.net;
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
@@ -529,7 +532,8 @@
@Deprecated
public void recordData(long start, long end, long rxBytes, long txBytes) {
recordData(start, end, new NetworkStats.Entry(
- IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L));
+ IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, rxBytes, 0L, txBytes, 0L, 0L));
}
/**
@@ -611,7 +615,8 @@
*/
public void recordHistory(NetworkStatsHistory input, long start, long end) {
final NetworkStats.Entry entry = new NetworkStats.Entry(
- IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
+ IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
for (int i = 0; i < input.bucketCount; i++) {
final long bucketStart = input.bucketStart[i];
final long bucketEnd = bucketStart + input.bucketDuration;
@@ -854,7 +859,8 @@
ensureBuckets(start, end);
final NetworkStats.Entry entry = new NetworkStats.Entry(
- IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
+ IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
while (rxBytes > 1024 || rxPackets > 128 || txBytes > 1024 || txPackets > 128
|| operations > 32) {
final long curStart = randomLong(r, start, end);
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 28f0699..1fbbd25 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -984,7 +984,16 @@
/**
* Firewall chain used for OEM-specific application restrictions.
- * Denylist of apps that will not have network access due to OEM-specific restrictions.
+ *
+ * Denylist of apps that will not have network access due to OEM-specific restrictions. If an
+ * app UID is placed on this chain, and the chain is enabled, the app's packets will be dropped.
+ *
+ * All the {@code FIREWALL_CHAIN_OEM_DENY_x} chains are equivalent, and each one is
+ * independent of the others. The chains can be enabled and disabled independently, and apps can
+ * be added and removed from each chain independently.
+ *
+ * @see #FIREWALL_CHAIN_OEM_DENY_2
+ * @see #FIREWALL_CHAIN_OEM_DENY_3
* @hide
*/
@SystemApi(client = MODULE_LIBRARIES)
@@ -992,7 +1001,16 @@
/**
* Firewall chain used for OEM-specific application restrictions.
- * Denylist of apps that will not have network access due to OEM-specific restrictions.
+ *
+ * Denylist of apps that will not have network access due to OEM-specific restrictions. If an
+ * app UID is placed on this chain, and the chain is enabled, the app's packets will be dropped.
+ *
+ * All the {@code FIREWALL_CHAIN_OEM_DENY_x} chains are equivalent, and each one is
+ * independent of the others. The chains can be enabled and disabled independently, and apps can
+ * be added and removed from each chain independently.
+ *
+ * @see #FIREWALL_CHAIN_OEM_DENY_1
+ * @see #FIREWALL_CHAIN_OEM_DENY_3
* @hide
*/
@SystemApi(client = MODULE_LIBRARIES)
@@ -1000,7 +1018,16 @@
/**
* Firewall chain used for OEM-specific application restrictions.
- * Denylist of apps that will not have network access due to OEM-specific restrictions.
+ *
+ * Denylist of apps that will not have network access due to OEM-specific restrictions. If an
+ * app UID is placed on this chain, and the chain is enabled, the app's packets will be dropped.
+ *
+ * All the {@code FIREWALL_CHAIN_OEM_DENY_x} chains are equivalent, and each one is
+ * independent of the others. The chains can be enabled and disabled independently, and apps can
+ * be added and removed from each chain independently.
+ *
+ * @see #FIREWALL_CHAIN_OEM_DENY_1
+ * @see #FIREWALL_CHAIN_OEM_DENY_2
* @hide
*/
@SystemApi(client = MODULE_LIBRARIES)
@@ -1080,7 +1107,7 @@
/**
* Tests if a given integer represents a valid network type.
* @param networkType the type to be tested
- * @return a boolean. {@code true} if the type is valid, else {@code false}
+ * @return {@code true} if the type is valid, else {@code false}
* @deprecated All APIs accepting a network type are deprecated. There should be no need to
* validate a network type.
*/
@@ -1439,9 +1466,8 @@
}
/**
- * Returns details about the currently active default data network
- * for a given uid. This is for internal use only to avoid spying
- * other apps.
+ * Returns details about the currently active default data network for a given uid.
+ * This is for privileged use only to avoid spying on other apps.
*
* @return a {@link NetworkInfo} object for the current default network
* for the given uid or {@code null} if no default network is
@@ -1465,8 +1491,7 @@
}
/**
- * Returns connection status information about a particular
- * network type.
+ * Returns connection status information about a particular network type.
*
* @param networkType integer specifying which networkType in
* which you're interested.
@@ -1494,8 +1519,7 @@
}
/**
- * Returns connection status information about a particular
- * Network.
+ * Returns connection status information about a particular Network.
*
* @param network {@link Network} specifying which network
* in which you're interested.
@@ -1521,8 +1545,7 @@
}
/**
- * Returns connection status information about all network
- * types supported by the device.
+ * Returns connection status information about all network types supported by the device.
*
* @return an array of {@link NetworkInfo} objects. Check each
* {@link NetworkInfo#getType} for which type each applies.
@@ -1582,8 +1605,7 @@
}
/**
- * Returns an array of all {@link Network} currently tracked by the
- * framework.
+ * Returns an array of all {@link Network} currently tracked by the framework.
*
* @deprecated This method does not provide any notification of network state changes, forcing
* apps to call it repeatedly. This is inefficient and prone to race conditions.
@@ -1786,7 +1808,7 @@
* that may be relevant for other components trying to detect captive portals.
*
* @hide
- * @deprecated This API returns URL which is not guaranteed to be one of the URLs used by the
+ * @deprecated This API returns a URL which is not guaranteed to be one of the URLs used by the
* system.
*/
@Deprecated
@@ -2365,8 +2387,7 @@
}
/**
- * Request that keepalives be started on a TCP socket.
- * The socket must be established.
+ * Request that keepalives be started on a TCP socket. The socket must be established.
*
* @param network The {@link Network} the socket is on.
* @param socket The socket that needs to be kept alive.
@@ -2653,7 +2674,7 @@
}
/**
- * Check if the package is a allowed to write settings. This also accounts that such an access
+ * Check if the package is allowed to write settings. This also records that such an access
* happened.
*
* @return {@code true} iff the package is allowed to write settings.
@@ -2756,7 +2777,7 @@
}
/**
- * Attempt to tether the named interface. This will setup a dhcp server
+ * Attempt to tether the named interface. This will set up a dhcp server
* on the interface, forward and NAT IP packets and forward DNS requests
* to the best active upstream network interface. Note that if no upstream
* IP network interface is available, dhcp will still run and traffic will be
@@ -3265,10 +3286,10 @@
/**
* Get the last value of the entitlement check on this downstream. If the cached value is
- * {@link #TETHER_ERROR_NO_ERROR} or showEntitlementUi argument is false, it just return the
- * cached value. Otherwise, a UI-based entitlement check would be performed. It is not
+ * {@link #TETHER_ERROR_NO_ERROR} or showEntitlementUi argument is false, this just returns the
+ * cached value. Otherwise, a UI-based entitlement check will be performed. It is not
* guaranteed that the UI-based entitlement check will complete in any specific time period
- * and may in fact never complete. Any successful entitlement check the platform performs for
+ * and it may in fact never complete. Any successful entitlement check the platform performs for
* any reason will update the cached value.
*
* @param type the downstream type of tethering. Must be one of
@@ -3455,12 +3476,11 @@
}
/**
- * Returns true if the hardware supports the given network type
- * else it returns false. This doesn't indicate we have coverage
- * or are authorized onto a network, just whether or not the
- * hardware supports it. For example a GSM phone without a SIM
- * should still return {@code true} for mobile data, but a wifi only
- * tablet would return {@code false}.
+ * Returns whether the hardware supports the given network type.
+ *
+ * This doesn't indicate there is coverage or such a network is available, just whether the
+ * hardware supports it. For example a GSM phone without a SIM card will return {@code true}
+ * for mobile data, but a WiFi only tablet would return {@code false}.
*
* @param networkType The network type we'd like to check
* @return {@code true} if supported, else {@code false}
@@ -4826,9 +4846,8 @@
* Unregisters a {@code NetworkCallback} and possibly releases networks originating from
* {@link #requestNetwork(NetworkRequest, NetworkCallback)} and
* {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} calls.
- * If the given {@code NetworkCallback} had previously been used with
- * {@code #requestNetwork}, any networks that had been connected to only to satisfy that request
- * will be disconnected.
+ * If the given {@code NetworkCallback} had previously been used with {@code #requestNetwork},
+ * any networks that the device brought up only to satisfy that request will be disconnected.
*
* Notifications that would have triggered that {@code NetworkCallback} will immediately stop
* triggering it as soon as this call returns.
@@ -4963,7 +4982,7 @@
}
/**
- * Temporarily allow bad wifi to override {@code config_networkAvoidBadWifi} configuration.
+ * Temporarily allow bad Wi-Fi to override {@code config_networkAvoidBadWifi} configuration.
*
* @param timeMs The expired current time. The value should be set within a limited time from
* now.
@@ -5022,7 +5041,7 @@
}
/**
- * Determine whether the device is configured to avoid bad wifi.
+ * Determine whether the device is configured to avoid bad Wi-Fi.
* @hide
*/
@SystemApi
@@ -5091,9 +5110,9 @@
* each such operation.
*
* @param network The network on which the application desires to use multipath data.
- * If {@code null}, this method will return the a preference that will generally
+ * If {@code null}, this method will return a preference that will generally
* apply to metered networks.
- * @return a bitwise OR of zero or more of the {@code MULTIPATH_PREFERENCE_*} constants.
+ * @return a bitwise OR of zero or more of the {@code MULTIPATH_PREFERENCE_*} constants.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public @MultipathPreference int getMultipathPreference(@Nullable Network network) {
@@ -5206,7 +5225,7 @@
*/
@Nullable
public Network getBoundNetworkForProcess() {
- // Forcing callers to call thru non-static function ensures ConnectivityManager
+ // Forcing callers to call through non-static function ensures ConnectivityManager has been
// instantiated.
return getProcessDefaultNetwork();
}
@@ -5851,7 +5870,7 @@
}
/**
- * Removes the specified UID from the list of UIds that can use use background data on metered
+ * Removes the specified UID from the list of UIDs that can use background data on metered
* networks if background data is not restricted. The deny list takes precedence over the
* allow list.
*
diff --git a/framework/src/android/net/NetworkScore.java b/framework/src/android/net/NetworkScore.java
index 7be7deb..815e2b0 100644
--- a/framework/src/android/net/NetworkScore.java
+++ b/framework/src/android/net/NetworkScore.java
@@ -181,7 +181,7 @@
@Override
public String toString() {
- return "Score(" + mLegacyInt + " ; Policies : " + mPolicies + ")";
+ return "Score(Policies : " + mPolicies + ")";
}
@Override
diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp
index fad6bbb..2810d80 100644
--- a/netd/BpfHandler.cpp
+++ b/netd/BpfHandler.cpp
@@ -64,6 +64,16 @@
return netdutils::status::ok;
}
+static Status checkProgramAccessible(const char* programPath) {
+ unique_fd prog(retrieveProgram(programPath));
+ if (prog == -1) {
+ int ret = errno;
+ ALOGE("Failed to get program from %s: %s", programPath, strerror(ret));
+ return statusFromErrno(ret, "program retrieve failed");
+ }
+ return netdutils::status::ok;
+}
+
static Status initPrograms(const char* cg2_path) {
unique_fd cg_fd(open(cg2_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
if (cg_fd == -1) {
@@ -71,6 +81,10 @@
ALOGE("Failed to open the cgroup directory: %s", strerror(ret));
return statusFromErrno(ret, "Open the cgroup directory failed");
}
+ RETURN_IF_NOT_OK(checkProgramAccessible(XT_BPF_ALLOWLIST_PROG_PATH));
+ RETURN_IF_NOT_OK(checkProgramAccessible(XT_BPF_DENYLIST_PROG_PATH));
+ RETURN_IF_NOT_OK(checkProgramAccessible(XT_BPF_EGRESS_PROG_PATH));
+ RETURN_IF_NOT_OK(checkProgramAccessible(XT_BPF_INGRESS_PROG_PATH));
RETURN_IF_NOT_OK(attachProgramToCgroup(BPF_EGRESS_PROG_PATH, cg_fd, BPF_CGROUP_INET_EGRESS));
RETURN_IF_NOT_OK(attachProgramToCgroup(BPF_INGRESS_PROG_PATH, cg_fd, BPF_CGROUP_INET_INGRESS));
RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE));
diff --git a/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
index 8b6526f..a3299a7 100644
--- a/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
+++ b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
@@ -93,118 +93,6 @@
return env->NewLongArray(size);
}
-static int legacyReadNetworkStatsDetail(std::vector<stats_line>* lines,
- const std::vector<std::string>& limitIfaces,
- int limitTag, int limitUid, const char* path) {
- FILE* fp = fopen(path, "re");
- if (fp == NULL) {
- return -1;
- }
-
- int lastIdx = 1;
- int idx;
- char buffer[384];
- while (fgets(buffer, sizeof(buffer), fp) != NULL) {
- stats_line s;
- int64_t rawTag;
- char* pos = buffer;
- char* endPos;
- // First field is the index.
- idx = (int)strtol(pos, &endPos, 10);
- //ALOGI("Index #%d: %s", idx, buffer);
- if (pos == endPos) {
- // Skip lines that don't start with in index. In particular,
- // this will skip the initial header line.
- continue;
- }
- if (idx != lastIdx + 1) {
- ALOGE("inconsistent idx=%d after lastIdx=%d: %s", idx, lastIdx, buffer);
- fclose(fp);
- return -1;
- }
- lastIdx = idx;
- pos = endPos;
- // Skip whitespace.
- while (*pos == ' ') {
- pos++;
- }
- // Next field is iface.
- int ifaceIdx = 0;
- while (*pos != ' ' && *pos != 0 && ifaceIdx < (int)(sizeof(s.iface)-1)) {
- s.iface[ifaceIdx] = *pos;
- ifaceIdx++;
- pos++;
- }
- if (*pos != ' ') {
- ALOGE("bad iface: %s", buffer);
- fclose(fp);
- return -1;
- }
- s.iface[ifaceIdx] = 0;
- if (limitIfaces.size() > 0) {
- // Is this an iface the caller is interested in?
- int i = 0;
- while (i < (int)limitIfaces.size()) {
- if (limitIfaces[i] == s.iface) {
- break;
- }
- i++;
- }
- if (i >= (int)limitIfaces.size()) {
- // Nothing matched; skip this line.
- //ALOGI("skipping due to iface: %s", buffer);
- continue;
- }
- }
-
- // Ignore whitespace
- while (*pos == ' ') pos++;
-
- // Find end of tag field
- endPos = pos;
- while (*endPos != ' ') endPos++;
-
- // Three digit field is always 0x0, otherwise parse
- if (endPos - pos == 3) {
- rawTag = 0;
- } else {
- if (sscanf(pos, "%" PRIx64, &rawTag) != 1) {
- ALOGE("bad tag: %s", pos);
- fclose(fp);
- return -1;
- }
- }
- s.tag = rawTag >> 32;
- if (limitTag != -1 && s.tag != static_cast<uint32_t>(limitTag)) {
- //ALOGI("skipping due to tag: %s", buffer);
- continue;
- }
- pos = endPos;
-
- // Ignore whitespace
- while (*pos == ' ') pos++;
-
- // Parse remaining fields.
- if (sscanf(pos, "%u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64,
- &s.uid, &s.set, &s.rxBytes, &s.rxPackets,
- &s.txBytes, &s.txPackets) == 6) {
- if (limitUid != -1 && static_cast<uint32_t>(limitUid) != s.uid) {
- //ALOGI("skipping due to uid: %s", buffer);
- continue;
- }
- lines->push_back(s);
- } else {
- //ALOGI("skipping due to bad remaining fields: %s", pos);
- }
- }
-
- if (fclose(fp) != 0) {
- ALOGE("Failed to close netstats file");
- return -1;
- }
- return 0;
-}
-
static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats,
std::vector<stats_line>& lines) {
int size = lines.size();
@@ -282,9 +170,8 @@
return 0;
}
-static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path,
- jint limitUid, jobjectArray limitIfacesObj, jint limitTag,
- jboolean useBpfStats) {
+static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jint limitUid,
+ jobjectArray limitIfacesObj, jint limitTag) {
std::vector<std::string> limitIfaces;
if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
@@ -299,20 +186,8 @@
}
std::vector<stats_line> lines;
-
- if (useBpfStats) {
- if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
- return -1;
- } else {
- ScopedUtfChars path8(env, path);
- if (path8.c_str() == NULL) {
- ALOGE("the qtaguid legacy path is invalid: %s", path8.c_str());
- return -1;
- }
- if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag,
- limitUid, path8.c_str()) < 0)
- return -1;
- }
+ if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
+ return -1;
return statsLinesToNetworkStats(env, clazz, stats, lines);
}
@@ -328,7 +203,7 @@
static const JNINativeMethod gMethods[] = {
{ "nativeReadNetworkStatsDetail",
- "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;IZ)I",
+ "(Landroid/net/NetworkStats;I[Ljava/lang/String;I)I",
(void*) readNetworkStatsDetail },
{ "nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I",
(void*) readNetworkStatsDev },
diff --git a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java
index 6006539..e4445d0 100644
--- a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java
+++ b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java
@@ -107,8 +107,13 @@
}
private void loadConfigFileLocked(final String filepath) {
+ // readIpConfigurations can return null when the version is invalid.
final ArrayMap<String, IpConfiguration> configs =
IpConfigStore.readIpConfigurations(filepath);
+ if (configs == null) {
+ Log.e(TAG, "IpConfigStore#readIpConfigurations() returned null");
+ return;
+ }
mIpConfigurations.putAll(configs);
}
diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java
index 3e71093..be9beed 100644
--- a/service-t/src/com/android/server/ethernet/EthernetTracker.java
+++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java
@@ -87,14 +87,17 @@
private static final String TEST_IFACE_REGEXP = TEST_TAP_PREFIX + "\\d+";
/**
- * Interface names we track. This is a product-dependent regular expression, plus,
- * if setIncludeTestInterfaces is true, any test interfaces.
+ * Interface names we track. This is a product-dependent regular expression.
+ * Use isValidEthernetInterface to check if a interface name is a valid ethernet interface (this
+ * includes test interfaces if setIncludeTestInterfaces is set to true).
*/
- private volatile String mIfaceMatch;
+ private final String mIfaceMatch;
+
/**
* Track test interfaces if true, don't track otherwise.
+ * Volatile is needed as getInterfaceList() does not run on the handler thread.
*/
- private boolean mIncludeTestInterfaces = false;
+ private volatile boolean mIncludeTestInterfaces = false;
/** Mapping between {iface name | mac address} -> {NetworkCapabilities} */
private final ConcurrentHashMap<String, NetworkCapabilities> mNetworkCapabilities =
@@ -161,7 +164,7 @@
mDeps = deps;
// Interface match regex.
- updateIfaceMatchRegexp();
+ mIfaceMatch = mDeps.getInterfaceRegexFromResource(mContext);
// Read default Ethernet interface configuration from resources
final String[] interfaceConfigs = mDeps.getInterfaceConfigFromResource(context);
@@ -320,9 +323,17 @@
Log.e(TAG, "Could not get list of interfaces " + e);
return interfaceList;
}
- final String ifaceMatch = mIfaceMatch;
+
+ // There is a possible race with setIncludeTestInterfaces() which can affect
+ // isValidEthernetInterface (it returns true for test interfaces if setIncludeTestInterfaces
+ // is set to true).
+ // setIncludeTestInterfaces() is only used in tests, and since getInterfaceList() does not
+ // run on the handler thread, the behavior around setIncludeTestInterfaces() is
+ // indeterminate either way. This can easily be circumvented by waiting on a callback from
+ // a test interface after calling setIncludeTestInterfaces() before calling this function.
+ // In production code, this has no effect.
for (String iface : ifaces) {
- if (iface.matches(ifaceMatch)) interfaceList.add(iface);
+ if (isValidEthernetInterface(iface)) interfaceList.add(iface);
}
return interfaceList;
}
@@ -357,7 +368,6 @@
public void setIncludeTestInterfaces(boolean include) {
mHandler.post(() -> {
mIncludeTestInterfaces = include;
- updateIfaceMatchRegexp();
if (!include) {
removeTestData();
}
@@ -569,7 +579,7 @@
}
private void maybeTrackInterface(String iface) {
- if (!iface.matches(mIfaceMatch)) {
+ if (!isValidEthernetInterface(iface)) {
return;
}
@@ -840,12 +850,8 @@
return ret;
}
- private void updateIfaceMatchRegexp() {
- final String match = mDeps.getInterfaceRegexFromResource(mContext);
- mIfaceMatch = mIncludeTestInterfaces
- ? "(" + match + "|" + TEST_IFACE_REGEXP + ")"
- : match;
- Log.d(TAG, "Interface match regexp set to '" + mIfaceMatch + "'");
+ private boolean isValidEthernetInterface(String iface) {
+ return iface.matches(mIfaceMatch) || isValidTestInterface(iface);
}
/**
diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java
index 4a6741c..c9d1718 100644
--- a/service-t/src/com/android/server/net/NetworkStatsFactory.java
+++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java
@@ -91,8 +91,7 @@
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
// TODO: remove both path and useBpfStats arguments.
// The path is never used if useBpfStats is true.
- final int ret = nativeReadNetworkStatsDetail(stats, null /* path */,
- limitUid, limitIfaces, limitTag, true /* useBpfStats */);
+ final int ret = nativeReadNetworkStatsDetail(stats, limitUid, limitIfaces, limitTag);
if (ret != 0) {
throw new IOException("Failed to parse network stats");
}
@@ -334,8 +333,8 @@
* are expected to monotonically increase since device boot.
*/
@VisibleForTesting
- public static native int nativeReadNetworkStatsDetail(NetworkStats stats, String path,
- int limitUid, String[] limitIfaces, int limitTag, boolean useBpfStats);
+ public static native int nativeReadNetworkStatsDetail(NetworkStats stats, int limitUid,
+ String[] limitIfaces, int limitTag);
@VisibleForTesting
public static native int nativeReadNetworkStatsDev(NetworkStats stats);
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 77931b1..96c615b 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -27,12 +27,15 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.IFACE_VT;
import static android.net.NetworkStats.INTERFACES_ALL;
import static android.net.NetworkStats.METERED_ALL;
+import static android.net.NetworkStats.METERED_NO;
import static android.net.NetworkStats.METERED_YES;
import static android.net.NetworkStats.ROAMING_ALL;
+import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.SET_FOREGROUND;
@@ -53,6 +56,7 @@
import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_XT;
import static android.os.Trace.TRACE_TAG_NETWORK;
import static android.system.OsConstants.ENOENT;
+import static android.system.OsConstants.R_OK;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
@@ -130,6 +134,7 @@
import android.service.NetworkInterfaceProto;
import android.service.NetworkStatsServiceDumpProto;
import android.system.ErrnoException;
+import android.system.Os;
import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionPlan;
import android.text.TextUtils;
@@ -156,6 +161,7 @@
import com.android.net.module.util.LocationPermissionChecker;
import com.android.net.module.util.NetworkStatsUtils;
import com.android.net.module.util.PermissionUtils;
+import com.android.net.module.util.Struct;
import com.android.net.module.util.Struct.U32;
import com.android.net.module.util.Struct.U8;
import com.android.net.module.util.bpf.CookieTagMapKey;
@@ -2698,6 +2704,23 @@
mUidTagRecorder.dumpLocked(pw, fullHistory);
pw.decreaseIndent();
}
+
+ pw.println();
+ pw.println("BPF map status:");
+ pw.increaseIndent();
+ dumpMapStatus(pw);
+ pw.decreaseIndent();
+ pw.println();
+
+ // Following BPF map content dump contains uid and tag regardless of the flags because
+ // following dumps are moved from TrafficController and bug report already contains this
+ // information.
+ pw.println("BPF map content:");
+ pw.increaseIndent();
+ dumpCookieTagMapLocked(pw);
+ dumpUidCounterSetMapLocked(pw);
+ dumpAppUidStatsMapLocked(pw);
+ pw.decreaseIndent();
}
}
@@ -2732,6 +2755,102 @@
}
}
+ private <K extends Struct, V extends Struct> String getMapStatus(
+ final IBpfMap<K, V> map, final String path) {
+ if (map != null) {
+ return "OK";
+ }
+ try {
+ Os.access(path, R_OK);
+ return "NULL(map is pinned to " + path + ")";
+ } catch (ErrnoException e) {
+ return "NULL(map is not pinned to " + path + ": " + Os.strerror(e.errno) + ")";
+ }
+ }
+
+ private void dumpMapStatus(final IndentingPrintWriter pw) {
+ pw.println("mCookieTagMap: " + getMapStatus(mCookieTagMap, COOKIE_TAG_MAP_PATH));
+ pw.println("mUidCounterSetMap: "
+ + getMapStatus(mUidCounterSetMap, UID_COUNTERSET_MAP_PATH));
+ pw.println("mAppUidStatsMap: " + getMapStatus(mAppUidStatsMap, APP_UID_STATS_MAP_PATH));
+ }
+
+ @GuardedBy("mStatsLock")
+ private void dumpCookieTagMapLocked(final IndentingPrintWriter pw) {
+ if (mCookieTagMap == null) {
+ return;
+ }
+ pw.println("mCookieTagMap:");
+ pw.increaseIndent();
+ try {
+ mCookieTagMap.forEach((key, value) -> {
+ // value could be null if there is a concurrent entry deletion.
+ // http://b/220084230.
+ if (value != null) {
+ pw.println("cookie=" + key.socketCookie
+ + " tag=0x" + Long.toHexString(value.tag)
+ + " uid=" + value.uid);
+ } else {
+ pw.println("Entry is deleted while dumping, iterating from first entry");
+ }
+ });
+ } catch (ErrnoException e) {
+ pw.println("mCookieTagMap dump end with error: " + Os.strerror(e.errno));
+ }
+ pw.decreaseIndent();
+ }
+
+ @GuardedBy("mStatsLock")
+ private void dumpUidCounterSetMapLocked(final IndentingPrintWriter pw) {
+ if (mUidCounterSetMap == null) {
+ return;
+ }
+ pw.println("mUidCounterSetMap:");
+ pw.increaseIndent();
+ try {
+ mUidCounterSetMap.forEach((uid, set) -> {
+ // set could be null if there is a concurrent entry deletion.
+ // http://b/220084230.
+ if (set != null) {
+ pw.println("uid=" + uid.val + " set=" + set.val);
+ } else {
+ pw.println("Entry is deleted while dumping, iterating from first entry");
+ }
+ });
+ } catch (ErrnoException e) {
+ pw.println("mUidCounterSetMap dump end with error: " + Os.strerror(e.errno));
+ }
+ pw.decreaseIndent();
+ }
+
+ @GuardedBy("mStatsLock")
+ private void dumpAppUidStatsMapLocked(final IndentingPrintWriter pw) {
+ if (mAppUidStatsMap == null) {
+ return;
+ }
+ pw.println("mAppUidStatsMap:");
+ pw.increaseIndent();
+ pw.println("uid rxBytes rxPackets txBytes txPackets");
+ try {
+ mAppUidStatsMap.forEach((key, value) -> {
+ // value could be null if there is a concurrent entry deletion.
+ // http://b/220084230.
+ if (value != null) {
+ pw.println(key.uid + " "
+ + value.rxBytes + " "
+ + value.rxPackets + " "
+ + value.txBytes + " "
+ + value.txPackets);
+ } else {
+ pw.println("Entry is deleted while dumping, iterating from first entry");
+ }
+ });
+ } catch (ErrnoException e) {
+ pw.println("mAppUidStatsMap dump end with error: " + Os.strerror(e.errno));
+ }
+ pw.decreaseIndent();
+ }
+
private NetworkStats readNetworkStatsSummaryDev() {
try {
return mStatsFactory.readNetworkStatsSummaryDev();
@@ -2806,7 +2925,8 @@
for (TetherStatsParcel tetherStats : tetherStatsParcels) {
try {
stats.combineValues(new NetworkStats.Entry(tetherStats.iface, UID_TETHERING,
- SET_DEFAULT, TAG_NONE, tetherStats.rxBytes, tetherStats.rxPackets,
+ SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
+ tetherStats.rxBytes, tetherStats.rxPackets,
tetherStats.txBytes, tetherStats.txPackets, 0L));
} catch (ArrayIndexOutOfBoundsException e) {
throw new IllegalStateException("invalid tethering stats " + e);
diff --git a/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml b/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml
index fdca468..b24dee0 100644
--- a/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml
+++ b/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml
@@ -22,7 +22,7 @@
<string name="network_available_sign_in" msgid="2622520134876355561">"Acceder a la red"</string>
<!-- no translation found for network_available_sign_in_detailed (8439369644697866359) -->
<skip />
- <string name="wifi_no_internet" msgid="1326348603404555475">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>no tiene acceso a Internet"</string>
+ <string name="wifi_no_internet" msgid="1326348603404555475">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> no tiene acceso a Internet"</string>
<string name="wifi_no_internet_detailed" msgid="1746921096565304090">"Presiona para ver opciones"</string>
<string name="mobile_no_internet" msgid="4087718456753201450">"La red móvil no tiene acceso a Internet"</string>
<string name="other_networks_no_internet" msgid="5693932964749676542">"La red no tiene acceso a Internet"</string>
diff --git a/service/ServiceConnectivityResources/res/values-or/strings.xml b/service/ServiceConnectivityResources/res/values-or/strings.xml
index 8b85884..49a773a 100644
--- a/service/ServiceConnectivityResources/res/values-or/strings.xml
+++ b/service/ServiceConnectivityResources/res/values-or/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="2476261877900882974">"ସିଷ୍ଟମର ସଂଯୋଗ ସମ୍ବନ୍ଧିତ ରିସୋର୍ସଗୁଡ଼ିକ"</string>
+ <string name="connectivityResourcesAppLabel" msgid="2476261877900882974">"ସିଷ୍ଟମ କନେକ୍ଟିଭିଟୀ ରିସୋର୍ସ"</string>
<string name="wifi_available_sign_in" msgid="8041178343789805553">"ୱାଇ-ଫାଇ ନେଟୱର୍କରେ ସାଇନ୍-ଇନ୍ କରନ୍ତୁ"</string>
<string name="network_available_sign_in" msgid="2622520134876355561">"ନେଟ୍ୱର୍କରେ ସାଇନ୍ ଇନ୍ କରନ୍ତୁ"</string>
<!-- no translation found for network_available_sign_in_detailed (8439369644697866359) -->
diff --git a/service/jni/com_android_server_BpfNetMaps.cpp b/service/jni/com_android_server_BpfNetMaps.cpp
index 2780044..11ba235 100644
--- a/service/jni/com_android_server_BpfNetMaps.cpp
+++ b/service/jni/com_android_server_BpfNetMaps.cpp
@@ -26,6 +26,8 @@
#include <nativehelper/ScopedPrimitiveArray.h>
#include <netjniutils/netjniutils.h>
#include <net/if.h>
+#include <private/android_filesystem_config.h>
+#include <unistd.h>
#include <vector>
@@ -48,6 +50,12 @@
static void native_init(JNIEnv* env, jclass clazz) {
Status status = mTc.start();
CHECK_LOG(status);
+ if (!isOk(status)) {
+ uid_t uid = getuid();
+ ALOGE("BpfNetMaps jni init failure as uid=%d", uid);
+ // TODO: Fix tests to not use this jni lib, so we can unconditionally abort()
+ if (uid == AID_SYSTEM || uid == AID_NETWORK_STACK) abort();
+ }
}
static jint native_addNaughtyApp(JNIEnv* env, jobject self, jint uid) {
diff --git a/service/native/TrafficController.cpp b/service/native/TrafficController.cpp
index 4dc056d..303112f 100644
--- a/service/native/TrafficController.cpp
+++ b/service/native/TrafficController.cpp
@@ -173,13 +173,8 @@
RETURN_IF_NOT_OK(mIfaceStatsMap.init(IFACE_STATS_MAP_PATH));
RETURN_IF_NOT_OK(mConfigurationMap.init(CONFIGURATION_MAP_PATH));
- RETURN_IF_NOT_OK(
- mConfigurationMap.writeValue(UID_RULES_CONFIGURATION_KEY, DEFAULT_CONFIG, BPF_ANY));
- RETURN_IF_NOT_OK(mConfigurationMap.writeValue(CURRENT_STATS_MAP_CONFIGURATION_KEY, SELECT_MAP_A,
- BPF_ANY));
RETURN_IF_NOT_OK(mUidOwnerMap.init(UID_OWNER_MAP_PATH));
- RETURN_IF_NOT_OK(mUidOwnerMap.clear());
RETURN_IF_NOT_OK(mUidPermissionMap.init(UID_PERMISSION_MAP_PATH));
ALOGI("%s successfully", __func__);
@@ -619,10 +614,6 @@
dw.blankline();
dw.println("mCookieTagMap status: %s",
getMapStatus(mCookieTagMap.getMap(), COOKIE_TAG_MAP_PATH).c_str());
- dw.println("mUidCounterSetMap status: %s",
- getMapStatus(mUidCounterSetMap.getMap(), UID_COUNTERSET_MAP_PATH).c_str());
- dw.println("mAppUidStatsMap status: %s",
- getMapStatus(mAppUidStatsMap.getMap(), APP_UID_STATS_MAP_PATH).c_str());
dw.println("mStatsMapA status: %s",
getMapStatus(mStatsMapA.getMap(), STATS_MAP_A_PATH).c_str());
dw.println("mStatsMapB status: %s",
@@ -659,6 +650,8 @@
ScopedIndent indentForMapContent(dw);
// Print CookieTagMap content.
+ // TagSocketTest in CTS was using the output of mCookieTagMap dump.
+ // So, mCookieTagMap dump can not be removed until the previous CTS support period is over.
dumpBpfMap("mCookieTagMap", dw, "");
const auto printCookieTagInfo = [&dw](const uint64_t& key, const UidTagValue& value,
const BpfMap<uint64_t, UidTagValue>&) {
@@ -670,31 +663,6 @@
dw.println("mCookieTagMap print end with error: %s", res.error().message().c_str());
}
- // Print UidCounterSetMap content.
- dumpBpfMap("mUidCounterSetMap", dw, "");
- const auto printUidInfo = [&dw](const uint32_t& key, const uint8_t& value,
- const BpfMap<uint32_t, uint8_t>&) {
- dw.println("%u %u", key, value);
- return base::Result<void>();
- };
- res = mUidCounterSetMap.iterateWithValue(printUidInfo);
- if (!res.ok()) {
- dw.println("mUidCounterSetMap print end with error: %s", res.error().message().c_str());
- }
-
- // Print AppUidStatsMap content.
- std::string appUidStatsHeader = StringPrintf("uid rxBytes rxPackets txBytes txPackets");
- dumpBpfMap("mAppUidStatsMap:", dw, appUidStatsHeader);
- auto printAppUidStatsInfo = [&dw](const uint32_t& key, const StatsValue& value,
- const BpfMap<uint32_t, StatsValue>&) {
- dw.println("%u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, key, value.rxBytes,
- value.rxPackets, value.txBytes, value.txPackets);
- return base::Result<void>();
- };
- res = mAppUidStatsMap.iterateWithValue(printAppUidStatsInfo);
- if (!res.ok()) {
- dw.println("mAppUidStatsMap print end with error: %s", res.error().message().c_str());
- }
// Print uidStatsMap content.
std::string statsHeader = StringPrintf("ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes"
diff --git a/service/native/TrafficControllerTest.cpp b/service/native/TrafficControllerTest.cpp
index 7730c13..d08ffee 100644
--- a/service/native/TrafficControllerTest.cpp
+++ b/service/native/TrafficControllerTest.cpp
@@ -793,11 +793,6 @@
std::vector<std::string> expectedLines = {
"mCookieTagMap:",
fmt::format("cookie={} tag={:#x} uid={}", TEST_COOKIE, TEST_TAG, TEST_UID),
- "mUidCounterSetMap:",
- fmt::format("{} {}", TEST_UID3, TEST_COUNTERSET),
- "mAppUidStatsMap::", // TODO@: fix double colon
- "uid rxBytes rxPackets txBytes txPackets",
- fmt::format("{} {} {} {} {}", TEST_UID, RXBYTES, RXPACKETS, TXBYTES, TXPACKETS),
"mStatsMapA",
"ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes rxPackets txBytes txPackets",
fmt::format("{} {} {:#x} {} {} {} {} {} {}",
@@ -834,8 +829,6 @@
std::vector<std::string> expectedLines = {
fmt::format("mCookieTagMap {}", kErrIterate),
- fmt::format("mUidCounterSetMap {}", kErrIterate),
- fmt::format("mAppUidStatsMap {}", kErrIterate),
fmt::format("mStatsMapA {}", kErrIterate),
fmt::format("mStatsMapB {}", kErrIterate),
fmt::format("mIfaceIndexNameMap {}", kErrIterate),
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 0270fc2..594223c 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -40,7 +40,6 @@
import android.system.Os;
import android.util.Log;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.BpfMap;
@@ -87,6 +86,11 @@
private static final String UID_OWNER_MAP_PATH =
"/sys/fs/bpf/netd_shared/map_netd_uid_owner_map";
private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0);
+ private static final U32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new U32(1);
+ private static final long UID_RULES_DEFAULT_CONFIGURATION = 0;
+ private static final long STATS_SELECT_MAP_A = 0;
+ private static final long STATS_SELECT_MAP_B = 1;
+
private static BpfMap<U32, U32> sConfigurationMap = null;
// BpfMap for UID_OWNER_MAP_PATH. This map is not accessed by others.
private static BpfMap<U32, UidOwnerValue> sUidOwnerMap = null;
@@ -149,13 +153,31 @@
}
}
- private static void setBpfMaps() {
+ private static void initBpfMaps() {
if (sConfigurationMap == null) {
sConfigurationMap = getConfigurationMap();
}
+ try {
+ sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY,
+ new U32(UID_RULES_DEFAULT_CONFIGURATION));
+ } catch (ErrnoException e) {
+ throw new IllegalStateException("Failed to initialize uid rules configuration", e);
+ }
+ try {
+ sConfigurationMap.updateEntry(CURRENT_STATS_MAP_CONFIGURATION_KEY,
+ new U32(STATS_SELECT_MAP_A));
+ } catch (ErrnoException e) {
+ throw new IllegalStateException("Failed to initialize current stats configuration", e);
+ }
+
if (sUidOwnerMap == null) {
sUidOwnerMap = getUidOwnerMap();
}
+ try {
+ sUidOwnerMap.clear();
+ } catch (ErrnoException e) {
+ throw new IllegalStateException("Failed to initialize uid owner map", e);
+ }
}
/**
@@ -171,7 +193,7 @@
}
Log.d(TAG, "BpfNetMaps is initialized with sEnableJavaBpfMap=" + sEnableJavaBpfMap);
- setBpfMaps();
+ initBpfMaps();
native_init();
sInitialized = true;
}
@@ -342,7 +364,13 @@
*/
public void addNaughtyApp(final int uid) {
throwIfPreT("addNaughtyApp is not available on pre-T devices");
- addRule(uid, PENALTY_BOX_MATCH, "addNaughtyApp");
+
+ if (sEnableJavaBpfMap) {
+ addRule(uid, PENALTY_BOX_MATCH, "addNaughtyApp");
+ } else {
+ final int err = native_addNaughtyApp(uid);
+ maybeThrow(err, "Unable to add naughty app");
+ }
}
/**
@@ -354,7 +382,13 @@
*/
public void removeNaughtyApp(final int uid) {
throwIfPreT("removeNaughtyApp is not available on pre-T devices");
- removeRule(uid, PENALTY_BOX_MATCH, "removeNaughtyApp");
+
+ if (sEnableJavaBpfMap) {
+ removeRule(uid, PENALTY_BOX_MATCH, "removeNaughtyApp");
+ } else {
+ final int err = native_removeNaughtyApp(uid);
+ maybeThrow(err, "Unable to remove naughty app");
+ }
}
/**
@@ -366,7 +400,13 @@
*/
public void addNiceApp(final int uid) {
throwIfPreT("addNiceApp is not available on pre-T devices");
- addRule(uid, HAPPY_BOX_MATCH, "addNiceApp");
+
+ if (sEnableJavaBpfMap) {
+ addRule(uid, HAPPY_BOX_MATCH, "addNiceApp");
+ } else {
+ final int err = native_addNiceApp(uid);
+ maybeThrow(err, "Unable to add nice app");
+ }
}
/**
@@ -378,7 +418,13 @@
*/
public void removeNiceApp(final int uid) {
throwIfPreT("removeNiceApp is not available on pre-T devices");
- removeRule(uid, HAPPY_BOX_MATCH, "removeNiceApp");
+
+ if (sEnableJavaBpfMap) {
+ removeRule(uid, HAPPY_BOX_MATCH, "removeNiceApp");
+ } else {
+ final int err = native_removeNiceApp(uid);
+ maybeThrow(err, "Unable to remove nice app");
+ }
}
/**
@@ -393,16 +439,21 @@
public void setChildChain(final int childChain, final boolean enable) {
throwIfPreT("setChildChain is not available on pre-T devices");
- final long match = getMatchByFirewallChain(childChain);
- try {
- synchronized (sUidRulesConfigBpfMapLock) {
- final U32 config = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY);
- final long newConfig = enable ? (config.val | match) : (config.val & ~match);
- sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(newConfig));
+ if (sEnableJavaBpfMap) {
+ final long match = getMatchByFirewallChain(childChain);
+ try {
+ synchronized (sUidRulesConfigBpfMapLock) {
+ final U32 config = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY);
+ final long newConfig = enable ? (config.val | match) : (config.val & ~match);
+ sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(newConfig));
+ }
+ } catch (ErrnoException e) {
+ throw new ServiceSpecificException(e.errno,
+ "Unable to set child chain: " + Os.strerror(e.errno));
}
- } catch (ErrnoException e) {
- throw new ServiceSpecificException(e.errno,
- "Unable to set child chain: " + Os.strerror(e.errno));
+ } else {
+ final int err = native_setChildChain(childChain, enable);
+ maybeThrow(err, "Unable to set child chain");
}
}
@@ -440,36 +491,73 @@
public void replaceUidChain(final int chain, final int[] uids) {
throwIfPreT("replaceUidChain is not available on pre-T devices");
- final long match;
- try {
- match = getMatchByFirewallChain(chain);
- } catch (ServiceSpecificException e) {
- // Throws IllegalArgumentException to keep the behavior of
- // ConnectivityManager#replaceFirewallChain API
- throw new IllegalArgumentException("Invalid firewall chain: " + chain);
- }
- final Set<Integer> uidSet = Arrays.stream(uids).boxed().collect(Collectors.toSet());
- final Set<Integer> uidSetToRemoveRule = new HashSet<>();
- try {
- synchronized (sUidOwnerMap) {
- sUidOwnerMap.forEach((uid, config) -> {
- // config could be null if there is a concurrent entry deletion.
- // http://b/220084230.
- if (config != null
- && !uidSet.contains((int) uid.val) && (config.rule & match) != 0) {
- uidSetToRemoveRule.add((int) uid.val);
- }
- });
-
- for (final int uid : uidSetToRemoveRule) {
- removeRule(uid, match, "replaceUidChain");
- }
- for (final int uid : uids) {
- addRule(uid, match, "replaceUidChain");
- }
+ if (sEnableJavaBpfMap) {
+ final long match;
+ try {
+ match = getMatchByFirewallChain(chain);
+ } catch (ServiceSpecificException e) {
+ // Throws IllegalArgumentException to keep the behavior of
+ // ConnectivityManager#replaceFirewallChain API
+ throw new IllegalArgumentException("Invalid firewall chain: " + chain);
}
- } catch (ErrnoException | ServiceSpecificException e) {
- Log.e(TAG, "replaceUidChain failed: " + e);
+ final Set<Integer> uidSet = Arrays.stream(uids).boxed().collect(Collectors.toSet());
+ final Set<Integer> uidSetToRemoveRule = new HashSet<>();
+ try {
+ synchronized (sUidOwnerMap) {
+ sUidOwnerMap.forEach((uid, config) -> {
+ // config could be null if there is a concurrent entry deletion.
+ // http://b/220084230.
+ if (config != null
+ && !uidSet.contains((int) uid.val) && (config.rule & match) != 0) {
+ uidSetToRemoveRule.add((int) uid.val);
+ }
+ });
+
+ for (final int uid : uidSetToRemoveRule) {
+ removeRule(uid, match, "replaceUidChain");
+ }
+ for (final int uid : uids) {
+ addRule(uid, match, "replaceUidChain");
+ }
+ }
+ } catch (ErrnoException | ServiceSpecificException e) {
+ Log.e(TAG, "replaceUidChain failed: " + e);
+ }
+ } else {
+ final int err;
+ switch (chain) {
+ case FIREWALL_CHAIN_DOZABLE:
+ err = native_replaceUidChain("fw_dozable", true /* isAllowList */, uids);
+ break;
+ case FIREWALL_CHAIN_STANDBY:
+ err = native_replaceUidChain("fw_standby", false /* isAllowList */, uids);
+ break;
+ case FIREWALL_CHAIN_POWERSAVE:
+ err = native_replaceUidChain("fw_powersave", true /* isAllowList */, uids);
+ break;
+ case FIREWALL_CHAIN_RESTRICTED:
+ err = native_replaceUidChain("fw_restricted", true /* isAllowList */, uids);
+ break;
+ case FIREWALL_CHAIN_LOW_POWER_STANDBY:
+ err = native_replaceUidChain(
+ "fw_low_power_standby", true /* isAllowList */, uids);
+ break;
+ case FIREWALL_CHAIN_OEM_DENY_1:
+ err = native_replaceUidChain("fw_oem_deny_1", false /* isAllowList */, uids);
+ break;
+ case FIREWALL_CHAIN_OEM_DENY_2:
+ err = native_replaceUidChain("fw_oem_deny_2", false /* isAllowList */, uids);
+ break;
+ case FIREWALL_CHAIN_OEM_DENY_3:
+ err = native_replaceUidChain("fw_oem_deny_3", false /* isAllowList */, uids);
+ break;
+ default:
+ throw new IllegalArgumentException("replaceFirewallChain with invalid chain: "
+ + chain);
+ }
+ if (err != 0) {
+ Log.e(TAG, "replaceUidChain failed: " + Os.strerror(-err));
+ }
}
}
@@ -485,15 +573,20 @@
public void setUidRule(final int childChain, final int uid, final int firewallRule) {
throwIfPreT("setUidRule is not available on pre-T devices");
- final long match = getMatchByFirewallChain(childChain);
- final boolean isAllowList = isFirewallAllowList(childChain);
- final boolean add = (firewallRule == FIREWALL_RULE_ALLOW && isAllowList)
- || (firewallRule == FIREWALL_RULE_DENY && !isAllowList);
+ if (sEnableJavaBpfMap) {
+ final long match = getMatchByFirewallChain(childChain);
+ final boolean isAllowList = isFirewallAllowList(childChain);
+ final boolean add = (firewallRule == FIREWALL_RULE_ALLOW && isAllowList)
+ || (firewallRule == FIREWALL_RULE_DENY && !isAllowList);
- if (add) {
- addRule(uid, match, "setUidRule");
+ if (add) {
+ addRule(uid, match, "setUidRule");
+ } else {
+ removeRule(uid, match, "setUidRule");
+ }
} else {
- removeRule(uid, match, "setUidRule");
+ final int err = native_setUidRule(childChain, uid, firewallRule);
+ maybeThrow(err, "Unable to set uid rule");
}
}
@@ -519,24 +612,30 @@
mNetd.firewallAddUidInterfaceRules(ifName, uids);
return;
}
- // Null ifName is a wildcard to allow apps to receive packets on all interfaces and ifIndex
- // is set to 0.
- final int ifIndex;
- if (ifName == null) {
- ifIndex = 0;
+
+ if (sEnableJavaBpfMap) {
+ // Null ifName is a wildcard to allow apps to receive packets on all interfaces and
+ // ifIndex is set to 0.
+ final int ifIndex;
+ if (ifName == null) {
+ ifIndex = 0;
+ } else {
+ ifIndex = mDeps.getIfIndex(ifName);
+ if (ifIndex == 0) {
+ throw new ServiceSpecificException(ENODEV,
+ "Failed to get index of interface " + ifName);
+ }
+ }
+ for (final int uid : uids) {
+ try {
+ addRule(uid, IIF_MATCH, ifIndex, "addUidInterfaceRules");
+ } catch (ServiceSpecificException e) {
+ Log.e(TAG, "addRule failed uid=" + uid + " ifName=" + ifName + ", " + e);
+ }
+ }
} else {
- ifIndex = mDeps.getIfIndex(ifName);
- if (ifIndex == 0) {
- throw new ServiceSpecificException(ENODEV,
- "Failed to get index of interface " + ifName);
- }
- }
- for (final int uid: uids) {
- try {
- addRule(uid, IIF_MATCH, ifIndex, "addUidInterfaceRules");
- } catch (ServiceSpecificException e) {
- Log.e(TAG, "addRule failed uid=" + uid + " ifName=" + ifName + ", " + e);
- }
+ final int err = native_addUidInterfaceRules(ifName, uids);
+ maybeThrow(err, "Unable to add uid interface rules");
}
}
@@ -556,12 +655,18 @@
mNetd.firewallRemoveUidInterfaceRules(uids);
return;
}
- for (final int uid: uids) {
- try {
- removeRule(uid, IIF_MATCH, "removeUidInterfaceRules");
- } catch (ServiceSpecificException e) {
- Log.e(TAG, "removeRule failed uid=" + uid + ", " + e);
+
+ if (sEnableJavaBpfMap) {
+ for (final int uid : uids) {
+ try {
+ removeRule(uid, IIF_MATCH, "removeUidInterfaceRules");
+ } catch (ServiceSpecificException e) {
+ Log.e(TAG, "removeRule failed uid=" + uid + ", " + e);
+ }
}
+ } else {
+ final int err = native_removeUidInterfaceRules(uids);
+ maybeThrow(err, "Unable to remove uid interface rules");
}
}
@@ -575,10 +680,16 @@
*/
public void updateUidLockdownRule(final int uid, final boolean add) {
throwIfPreT("updateUidLockdownRule is not available on pre-T devices");
- if (add) {
- addRule(uid, LOCKDOWN_VPN_MATCH, "updateUidLockdownRule");
+
+ if (sEnableJavaBpfMap) {
+ if (add) {
+ addRule(uid, LOCKDOWN_VPN_MATCH, "updateUidLockdownRule");
+ } else {
+ removeRule(uid, LOCKDOWN_VPN_MATCH, "updateUidLockdownRule");
+ }
} else {
- removeRule(uid, LOCKDOWN_VPN_MATCH, "updateUidLockdownRule");
+ final int err = native_updateUidLockdownRule(uid, add);
+ maybeThrow(err, "Unable to update lockdown rule");
}
}
@@ -629,24 +740,15 @@
}
private static native void native_init();
- @GuardedBy("sUidOwnerMap")
private native int native_addNaughtyApp(int uid);
- @GuardedBy("sUidOwnerMap")
private native int native_removeNaughtyApp(int uid);
- @GuardedBy("sUidOwnerMap")
private native int native_addNiceApp(int uid);
- @GuardedBy("sUidOwnerMap")
private native int native_removeNiceApp(int uid);
private native int native_setChildChain(int childChain, boolean enable);
- @GuardedBy("sUidOwnerMap")
private native int native_replaceUidChain(String name, boolean isAllowlist, int[] uids);
- @GuardedBy("sUidOwnerMap")
private native int native_setUidRule(int childChain, int uid, int firewallRule);
- @GuardedBy("sUidOwnerMap")
private native int native_addUidInterfaceRules(String ifName, int[] uids);
- @GuardedBy("sUidOwnerMap")
private native int native_removeUidInterfaceRules(int[] uids);
- @GuardedBy("sUidOwnerMap")
private native int native_updateUidLockdownRule(int uid, boolean add);
private native int native_swapActiveStatsMap();
private native void native_setPermissionForUids(int permissions, int[] uids);
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index da51f07..1caca01 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -380,7 +380,7 @@
// See ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
private final int mReleasePendingIntentDelayMs;
- private MockableSystemProperties mSystemProperties;
+ private final MockableSystemProperties mSystemProperties;
@VisibleForTesting
protected final PermissionMonitor mPermissionMonitor;
@@ -396,7 +396,7 @@
* Stale copy of uid blocked reasons provided by NPMS. As long as they are accessed only in
* internal handler thread, they don't need a lock.
*/
- private SparseIntArray mUidBlockedReasons = new SparseIntArray();
+ private final SparseIntArray mUidBlockedReasons = new SparseIntArray();
private final Context mContext;
private final ConnectivityResources mResources;
@@ -412,9 +412,8 @@
@VisibleForTesting
protected INetd mNetd;
private DscpPolicyTracker mDscpPolicyTracker = null;
- private NetworkStatsManager mStatsManager;
- private NetworkPolicyManager mPolicyManager;
- private final NetdCallback mNetdCallback;
+ private final NetworkStatsManager mStatsManager;
+ private final NetworkPolicyManager mPolicyManager;
private final BpfNetMaps mBpfNetMaps;
/**
@@ -780,7 +779,7 @@
private boolean mSystemReady;
private Intent mInitialBroadcast;
- private PowerManager.WakeLock mNetTransitionWakeLock;
+ private final PowerManager.WakeLock mNetTransitionWakeLock;
private final PowerManager.WakeLock mPendingIntentWakeLock;
// A helper object to track the current default HTTP proxy. ConnectivityService needs to tell
@@ -790,10 +789,10 @@
final private SettingsObserver mSettingsObserver;
- private UserManager mUserManager;
+ private final UserManager mUserManager;
// the set of network types that can only be enabled by system/sig apps
- private List<Integer> mProtectedNetworks;
+ private final List<Integer> mProtectedNetworks;
private Set<String> mWolSupportedInterfaces;
@@ -803,10 +802,10 @@
private final LocationPermissionChecker mLocationPermissionChecker;
- private KeepaliveTracker mKeepaliveTracker;
- private QosCallbackTracker mQosCallbackTracker;
- private NetworkNotificationManager mNotifier;
- private LingerMonitor mLingerMonitor;
+ private final KeepaliveTracker mKeepaliveTracker;
+ private final QosCallbackTracker mQosCallbackTracker;
+ private final NetworkNotificationManager mNotifier;
+ private final LingerMonitor mLingerMonitor;
// sequence number of NetworkRequests
private int mNextNetworkRequestId = NetworkRequest.FIRST_REQUEST_ID;
@@ -834,7 +833,7 @@
private final IpConnectivityLog mMetricsLog;
@GuardedBy("mBandwidthRequests")
- private final SparseArray<Integer> mBandwidthRequests = new SparseArray(10);
+ private final SparseArray<Integer> mBandwidthRequests = new SparseArray<>(10);
@VisibleForTesting
final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
@@ -893,7 +892,7 @@
* - getRestoreTimerForType(type) is also synchronized on mTypeLists.
* - dump is thread-safe with respect to concurrent add and remove calls.
*/
- private final ArrayList<NetworkAgentInfo> mTypeLists[];
+ private final ArrayList<NetworkAgentInfo>[] mTypeLists;
@NonNull
private final ConnectivityService mService;
@@ -1096,8 +1095,7 @@
}
}
- // send out another legacy broadcast - currently only used for suspend/unsuspend
- // toggle
+ // send out another legacy broadcast - currently only used for suspend/unsuspend toggle
public void update(NetworkAgentInfo nai) {
final boolean isDefault = mService.isDefaultNetwork(nai);
final DetailedState state = nai.networkInfo.getDetailedState();
@@ -1221,31 +1219,16 @@
*/
public void incrementCountOrThrow(final int uid) {
synchronized (mUidToNetworkRequestCount) {
- incrementCountOrThrow(uid, 1 /* numToIncrement */);
+ final int newRequestCount = mUidToNetworkRequestCount.get(uid, 0) + 1;
+ if (newRequestCount >= mMaxCountPerUid) {
+ throw new ServiceSpecificException(
+ ConnectivityManager.Errors.TOO_MANY_REQUESTS,
+ "Uid " + uid + " exceeded its allotted requests limit");
+ }
+ mUidToNetworkRequestCount.put(uid, newRequestCount);
}
}
- private void incrementCountOrThrow(final int uid, final int numToIncrement) {
- final int newRequestCount =
- mUidToNetworkRequestCount.get(uid, 0) + numToIncrement;
- if (newRequestCount >= mMaxCountPerUid
- // HACK : the system server is allowed to go over the request count limit
- // when it is creating requests on behalf of another app (but not itself,
- // so it can still detect its own request leaks). This only happens in the
- // per-app API flows in which case the old requests for that particular
- // UID will be removed soon.
- // TODO : instead of this hack, addPerAppDefaultNetworkRequests and other
- // users of transact() should unregister the requests to decrease the count
- // before they increase it again by creating a new NRI. Then remove the
- // transact() method.
- && (Process.myUid() == uid || Process.myUid() != Binder.getCallingUid())) {
- throw new ServiceSpecificException(
- ConnectivityManager.Errors.TOO_MANY_REQUESTS,
- "Uid " + uid + " exceeded its allotted requests limit");
- }
- mUidToNetworkRequestCount.put(uid, newRequestCount);
- }
-
/**
* Decrements the request count of the given uid.
*
@@ -1253,21 +1236,18 @@
*/
public void decrementCount(final int uid) {
synchronized (mUidToNetworkRequestCount) {
- decrementCount(uid, 1 /* numToDecrement */);
+ /* numToDecrement */
+ final int newRequestCount = mUidToNetworkRequestCount.get(uid, 0) - 1;
+ if (newRequestCount < 0) {
+ logwtf("BUG: too small request count " + newRequestCount + " for UID " + uid);
+ } else if (newRequestCount == 0) {
+ mUidToNetworkRequestCount.delete(uid);
+ } else {
+ mUidToNetworkRequestCount.put(uid, newRequestCount);
+ }
}
}
- private void decrementCount(final int uid, final int numToDecrement) {
- final int newRequestCount =
- mUidToNetworkRequestCount.get(uid, 0) - numToDecrement;
- if (newRequestCount < 0) {
- logwtf("BUG: too small request count " + newRequestCount + " for UID " + uid);
- } else if (newRequestCount == 0) {
- mUidToNetworkRequestCount.delete(uid);
- } else {
- mUidToNetworkRequestCount.put(uid, newRequestCount);
- }
- }
}
/**
@@ -1376,7 +1356,11 @@
/**
* @see CarrierPrivilegeAuthenticator
+ *
+ * This method returns null in versions before T, where carrier privilege
+ * authentication is not supported.
*/
+ @Nullable
public CarrierPrivilegeAuthenticator makeCarrierPrivilegeAuthenticator(
@NonNull final Context context, @NonNull final TelephonyManager tm) {
if (SdkLevel.isAtLeastT()) {
@@ -1396,7 +1380,7 @@
/**
* Get the BpfNetMaps implementation to use in ConnectivityService.
- * @param netd
+ * @param netd a netd binder
* @return BpfNetMaps implementation.
*/
public BpfNetMaps getBpfNetMaps(Context context, INetd netd) {
@@ -1581,9 +1565,9 @@
mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNetd);
- mNetdCallback = new NetdCallback();
+ final NetdCallback netdCallback = new NetdCallback();
try {
- mNetd.registerUnsolicitedEventListener(mNetdCallback);
+ mNetd.registerUnsolicitedEventListener(netdCallback);
} catch (RemoteException | ServiceSpecificException e) {
loge("Error registering event listener :" + e);
}
@@ -1722,11 +1706,6 @@
mHandler.sendEmptyMessage(EVENT_INGRESS_RATE_LIMIT_CHANGED);
}
- private void handleAlwaysOnNetworkRequest(NetworkRequest networkRequest, int id) {
- final boolean enable = mContext.getResources().getBoolean(id);
- handleAlwaysOnNetworkRequest(networkRequest, enable);
- }
-
private void handleAlwaysOnNetworkRequest(
NetworkRequest networkRequest, String settingName, boolean defaultValue) {
final boolean enable = toBool(Settings.Global.getInt(
@@ -1769,12 +1748,12 @@
Settings.Global.getUriFor(Settings.Global.HTTP_PROXY),
EVENT_APPLY_GLOBAL_HTTP_PROXY);
- // Watch for whether or not to keep mobile data always on.
+ // Watch for whether to keep mobile data always on.
mSettingsObserver.observe(
Settings.Global.getUriFor(ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON),
EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
- // Watch for whether or not to keep wifi always on.
+ // Watch for whether to keep wifi always on.
mSettingsObserver.observe(
Settings.Global.getUriFor(ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED),
EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
@@ -1804,6 +1783,7 @@
}
@VisibleForTesting
+ @Nullable
protected NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
if (network == null) {
return null;
@@ -1818,6 +1798,7 @@
}
// TODO: determine what to do when more than one VPN applies to |uid|.
+ @Nullable
private NetworkAgentInfo getVpnForUid(int uid) {
synchronized (mNetworkForNetId) {
for (int i = 0; i < mNetworkForNetId.size(); i++) {
@@ -1830,6 +1811,7 @@
return null;
}
+ @Nullable
private Network[] getVpnUnderlyingNetworks(int uid) {
if (mLockdownEnabled) return null;
final NetworkAgentInfo nai = getVpnForUid(uid);
@@ -1941,6 +1923,7 @@
* active
*/
@Override
+ @Nullable
public NetworkInfo getActiveNetworkInfo() {
enforceAccessPermission();
final int uid = mDeps.getCallingUid();
@@ -1952,17 +1935,20 @@
}
@Override
+ @Nullable
public Network getActiveNetwork() {
enforceAccessPermission();
return getActiveNetworkForUidInternal(mDeps.getCallingUid(), false);
}
@Override
+ @Nullable
public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) {
enforceNetworkStackPermission(mContext);
return getActiveNetworkForUidInternal(uid, ignoreBlocked);
}
+ @Nullable
private Network getActiveNetworkForUidInternal(final int uid, boolean ignoreBlocked) {
final NetworkAgentInfo vpnNai = getVpnForUid(uid);
if (vpnNai != null) {
@@ -1981,6 +1967,7 @@
}
@Override
+ @Nullable
public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) {
enforceNetworkStackPermission(mContext);
final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
@@ -2017,6 +2004,7 @@
}
@Override
+ @Nullable
public NetworkInfo getNetworkInfo(int networkType) {
enforceAccessPermission();
final int uid = mDeps.getCallingUid();
@@ -2035,6 +2023,7 @@
}
@Override
+ @Nullable
public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) {
enforceAccessPermission();
final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
@@ -2057,6 +2046,7 @@
}
@Override
+ @Nullable
public Network getNetworkForType(int networkType) {
enforceAccessPermission();
if (!mLegacyTypeTracker.isTypeSupported(networkType)) {
@@ -2074,6 +2064,7 @@
}
@Override
+ @NonNull
public Network[] getAllNetworks() {
enforceAccessPermission();
synchronized (mNetworkForNetId) {
@@ -2534,7 +2525,7 @@
snapshot.getNetwork(), snapshot.getSubscriberId()));
}
}
- return result.toArray(new NetworkState[result.size()]);
+ return result.toArray(new NetworkState[0]);
}
@Override
@@ -2632,7 +2623,7 @@
try {
addr = InetAddress.getByAddress(hostAddress);
} catch (UnknownHostException e) {
- if (DBG) log("requestRouteToHostAddress got " + e.toString());
+ if (DBG) log("requestRouteToHostAddress got " + e);
return false;
}
@@ -2643,7 +2634,7 @@
NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
if (nai == null) {
- if (mLegacyTypeTracker.isTypeSupported(networkType) == false) {
+ if (!mLegacyTypeTracker.isTypeSupported(networkType)) {
if (DBG) log("requestRouteToHostAddress on unsupported network: " + networkType);
} else {
if (DBG) log("requestRouteToHostAddress on down network: " + networkType);
@@ -2736,7 +2727,7 @@
// the caller thread of registerNetworkAgent. Thus, it's not allowed to register netd
// event callback for certain nai. e.g. cellular. Register here to pass to
// NetworkMonitor instead.
- // TODO: Move the Dns Event to NetworkMonitor. NetdEventListenerService only allow one
+ // TODO: Move the Dns Event to NetworkMonitor. NetdEventListenerService only allows one
// callback from each caller type. Need to re-factor NetdEventListenerService to allow
// multiple NetworkMonitor registrants.
if (nai != null && nai.satisfies(mDefaultRequest.mRequests.get(0))) {
@@ -3101,8 +3092,9 @@
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS));
// Update mobile data preference if necessary.
- // Note that empty uid list can be skip here only because no uid rules applied before system
- // ready. Normally, the empty uid list means to clear the uids rules on netd.
+ // Note that updating can be skipped here if the list is empty only because no uid
+ // rules are applied before system ready. Normally, the empty uid list means to clear
+ // the uids rules on netd.
if (!ConnectivitySettingsManager.getMobileDataPreferredUids(mContext).isEmpty()) {
updateMobileDataPreferredUids();
}
@@ -3216,7 +3208,7 @@
}
private void dumpNetworkDiagnostics(IndentingPrintWriter pw) {
- final List<NetworkDiagnostics> netDiags = new ArrayList<NetworkDiagnostics>();
+ final List<NetworkDiagnostics> netDiags = new ArrayList<>();
final long DIAG_TIME_MS = 5000;
for (NetworkAgentInfo nai : networksSortedById()) {
PrivateDnsConfig privateDnsCfg = mDnsManager.getPrivateDnsConfig(nai.network);
@@ -3604,12 +3596,11 @@
switch (msg.what) {
case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
- nai.declaredCapabilitiesUnsanitized =
- new NetworkCapabilities((NetworkCapabilities) arg.second);
- final NetworkCapabilities sanitized = sanitizedCapabilitiesFromAgent(
- mCarrierPrivilegeAuthenticator, nai);
+ nai.setDeclaredCapabilities((NetworkCapabilities) arg.second);
+ final NetworkCapabilities sanitized =
+ nai.getDeclaredCapabilitiesSanitized(mCarrierPrivilegeAuthenticator);
maybeUpdateWifiRoamTimestamp(nai, sanitized);
- updateCapabilities(nai.getCurrentScore(), nai, sanitized);
+ updateCapabilities(nai.getScore(), nai, sanitized);
break;
}
case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {
@@ -3877,7 +3868,7 @@
log(nai.toShortString() + " validation " + (valid ? "passed" : "failed") + logMsg);
}
if (valid != nai.lastValidated) {
- final int oldScore = nai.getCurrentScore();
+ final FullScore oldScore = nai.getScore();
nai.lastValidated = valid;
nai.everValidated |= valid;
updateCapabilities(oldScore, nai, nai.networkCapabilities);
@@ -3953,7 +3944,7 @@
}
@Override
- public void handleMessage(Message msg) {
+ public void handleMessage(@NonNull Message msg) {
if (!maybeHandleNetworkMonitorMessage(msg)
&& !maybeHandleNetworkAgentInfoMessage(msg)) {
maybeHandleNetworkAgentMessage(msg);
@@ -4422,12 +4413,14 @@
}
config = new NativeNetworkConfig(nai.network.getNetId(), NativeNetworkType.VIRTUAL,
INetd.PERMISSION_NONE,
- (nai.networkAgentConfig == null || !nai.networkAgentConfig.allowBypass),
+ !nai.networkAgentConfig.allowBypass /* secure */,
getVpnType(nai), nai.networkAgentConfig.excludeLocalRouteVpn);
} else {
config = new NativeNetworkConfig(nai.network.getNetId(), NativeNetworkType.PHYSICAL,
- getNetworkPermission(nai.networkCapabilities), /*secure=*/ false,
- VpnManager.TYPE_VPN_NONE, /*excludeLocalRoutes=*/ false);
+ getNetworkPermission(nai.networkCapabilities),
+ false /* secure */,
+ VpnManager.TYPE_VPN_NONE,
+ false /* excludeLocalRoutes */);
}
mNetd.networkCreate(config);
mDnsResolver.createNetworkCache(nai.network.getNetId());
@@ -7260,8 +7253,7 @@
* later : see {@link #updateLinkProperties}.
* @param networkCapabilities the initial capabilites of this network. They can be updated
* later : see {@link #updateCapabilities}.
- * @param initialScore the initial score of the network. See
- * {@link NetworkAgentInfo#getCurrentScore}.
+ * @param initialScore the initial score of the network. See {@link NetworkAgentInfo#getScore}.
* @param networkAgentConfig metadata about the network. This is never updated.
* @param providerId the ID of the provider owning this NetworkAgent.
* @return the network created for this agent.
@@ -7296,18 +7288,23 @@
NetworkScore currentScore, NetworkAgentConfig networkAgentConfig, int providerId,
int uid) {
+ // Make a copy of the passed NI, LP, NC as the caller may hold a reference to them
+ // and mutate them at any time.
+ final NetworkInfo niCopy = new NetworkInfo(networkInfo);
+ final NetworkCapabilities ncCopy = new NetworkCapabilities(networkCapabilities);
+ final LinkProperties lpCopy = new LinkProperties(linkProperties);
+
// At this point the capabilities/properties are untrusted and unverified, e.g. checks that
- // the capabilities' access UID comply with security limitations. They will be sanitized
+ // the capabilities' access UIDs comply with security limitations. They will be sanitized
// as the NAI registration finishes, in handleRegisterNetworkAgent(). This is
// because some of the checks must happen on the handler thread.
final NetworkAgentInfo nai = new NetworkAgentInfo(na,
- new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo),
- linkProperties, networkCapabilities,
+ new Network(mNetIdManager.reserveNetId()), niCopy, lpCopy, ncCopy,
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
this, mNetd, mDnsResolver, providerId, uid, mLingerDelayMs,
mQosCallbackTracker, mDeps);
- final String extraInfo = networkInfo.getExtraInfo();
+ final String extraInfo = niCopy.getExtraInfo();
final String name = TextUtils.isEmpty(extraInfo)
? nai.networkCapabilities.getSsid() : extraInfo;
if (DBG) log("registerNetworkAgent " + nai);
@@ -7322,19 +7319,12 @@
private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) {
if (VDBG) log("Network Monitor created for " + nai);
- // nai.nc and nai.lp are the same object that was passed by the network agent if the agent
- // lives in the same process as this code (e.g. wifi), so make sure this code doesn't
- // mutate their object. TODO : make this copy much earlier to avoid them mutating it
- // while the network monitor is starting.
- final LinkProperties lp = new LinkProperties(nai.linkProperties);
// Store a copy of the declared capabilities.
- nai.declaredCapabilitiesUnsanitized = new NetworkCapabilities(nai.networkCapabilities);
+ nai.setDeclaredCapabilities(nai.networkCapabilities);
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info said.
- final NetworkCapabilities nc =
- sanitizedCapabilitiesFromAgent(mCarrierPrivilegeAuthenticator, nai);
- nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
- processLinkPropertiesFromAgent(nai, lp);
- nai.linkProperties = lp;
+ nai.getAndSetNetworkCapabilities(mixInCapabilities(nai,
+ nai.getDeclaredCapabilitiesSanitized(mCarrierPrivilegeAuthenticator)));
+ processLinkPropertiesFromAgent(nai, nai.linkProperties);
nai.onNetworkMonitorCreated(networkMonitor);
@@ -7795,38 +7785,6 @@
}
}
- /**
- * Sanitize capabilities coming from a network agent.
- *
- * Agents have restrictions on what capabilities they can send to Connectivity. For example,
- * they can't change the owner UID from what they declared before, and complex restrictions
- * apply to the accessUids field.
- * They also should not mutate immutable capabilities, although for backward-compatibility
- * this is not enforced and limited to just a log.
- *
- * This method returns a sanitized copy of the passed capabilities to make sure they don't
- * contain stuff they should not, and should generally be called by code that accesses
- * {@link NetworkAgentInfo#declaredCapabilitiesUnsanitized}.
- */
- // TODO : move this to NetworkAgentInfo
- private NetworkCapabilities sanitizedCapabilitiesFromAgent(
- final CarrierPrivilegeAuthenticator carrierPrivilegeAuthenticator,
- @NonNull final NetworkAgentInfo nai) {
- final NetworkCapabilities nc = new NetworkCapabilities(nai.declaredCapabilitiesUnsanitized);
- if (nc.hasConnectivityManagedCapability()) {
- Log.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
- }
- if (nai.networkCapabilities.getOwnerUid() != nc.getOwnerUid()) {
- Log.e(TAG, nai.toShortString() + ": ignoring attempt to change owner from "
- + nai.networkCapabilities.getOwnerUid() + " to " + nc.getOwnerUid());
- nc.setOwnerUid(nai.networkCapabilities.getOwnerUid());
- }
- NetworkAgentInfo.restrictCapabilitiesFromNetworkAgent(nc, nai.creatorUid,
- mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE),
- carrierPrivilegeAuthenticator);
- return nc;
- }
-
/** Modifies |newNc| based on the capabilities of |underlyingNetworks| and |agentCaps|. */
@VisibleForTesting
void applyUnderlyingCapabilities(@Nullable Network[] underlyingNetworks,
@@ -7952,7 +7910,7 @@
if (nai.propagateUnderlyingCapabilities()) {
applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks,
- sanitizedCapabilitiesFromAgent(mCarrierPrivilegeAuthenticator, nai),
+ nai.getDeclaredCapabilitiesSanitized(mCarrierPrivilegeAuthenticator),
newNc);
}
@@ -7994,7 +7952,7 @@
* @param nai the network having its capabilities updated.
* @param nc the new network capabilities.
*/
- private void updateCapabilities(final int oldScore, @NonNull final NetworkAgentInfo nai,
+ private void updateCapabilities(final FullScore oldScore, @NonNull final NetworkAgentInfo nai,
@NonNull final NetworkCapabilities nc) {
NetworkCapabilities newNc = mixInCapabilities(nai, nc);
if (Objects.equals(nai.networkCapabilities, newNc)) return;
@@ -8005,7 +7963,7 @@
updateAllowedUids(nai, prevNc, newNc);
nai.updateScoreForNetworkAgentUpdate();
- if (nai.getCurrentScore() == oldScore && newNc.equalRequestableCapabilities(prevNc)) {
+ if (nai.getScore().equals(oldScore) && newNc.equalRequestableCapabilities(prevNc)) {
// If the requestable capabilities haven't changed, and the score hasn't changed, then
// the change we're processing can't affect any requests, it can only affect the listens
// on this network. We might have been called by rematchNetworkAndRequests when a
@@ -8049,7 +8007,7 @@
/** Convenience method to update the capabilities for a given network. */
private void updateCapabilitiesForNetwork(NetworkAgentInfo nai) {
- updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
+ updateCapabilities(nai.getScore(), nai, nai.networkCapabilities);
}
/**
@@ -8359,8 +8317,11 @@
releasePendingNetworkRequestWithDelay(pendingIntent);
}
+ // networkAgent is only allowed to be null if notificationType is
+ // CALLBACK_UNAVAIL. This is because UNAVAIL is about no network being
+ // available, while all other cases are about some particular network.
private void callCallbackForRequest(@NonNull final NetworkRequestInfo nri,
- @NonNull final NetworkAgentInfo networkAgent, final int notificationType,
+ @Nullable final NetworkAgentInfo networkAgent, final int notificationType,
final int arg1) {
if (nri.mMessenger == null) {
// Default request has no msgr. Also prevents callbacks from being invoked for
@@ -8382,14 +8343,13 @@
switch (notificationType) {
case ConnectivityManager.CALLBACK_AVAILABLE: {
final NetworkCapabilities nc =
- networkCapabilitiesRestrictedForCallerPermissions(
- networkAgent.networkCapabilities, nri.mPid, nri.mUid);
- putParcelable(
- bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, includeLocationSensitiveInfo, nri.mPid, nri.mUid,
+ networkCapabilitiesRestrictedForCallerPermissions(
+ networkAgent.networkCapabilities, nri.mPid, nri.mUid),
+ includeLocationSensitiveInfo, nri.mPid, nri.mUid,
nrForCallback.getRequestorPackageName(),
- nri.mCallingAttributionTag));
+ nri.mCallingAttributionTag);
+ putParcelable(bundle, nc);
putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
networkAgent.linkProperties, nri.mPid, nri.mUid));
// For this notification, arg1 contains the blocked status.
@@ -8843,15 +8803,22 @@
@NonNull final Set<NetworkRequestInfo> networkRequests) {
ensureRunningOnConnectivityServiceThread();
// TODO: This may be slow, and should be optimized.
- final long now = SystemClock.elapsedRealtime();
+ final long start = SystemClock.elapsedRealtime();
final NetworkReassignment changes = computeNetworkReassignment(networkRequests);
+ final long computed = SystemClock.elapsedRealtime();
+ applyNetworkReassignment(changes, start);
+ final long applied = SystemClock.elapsedRealtime();
+ issueNetworkNeeds();
+ final long end = SystemClock.elapsedRealtime();
if (VDBG || DDBG) {
+ log(String.format("Rematched networks [computed %dms] [applied %dms] [issued %d]",
+ computed - start, applied - computed, end - applied));
log(changes.debugString());
} else if (DBG) {
- log(changes.toString()); // Shorter form, only one line of log
+ // Shorter form, only one line of log
+ log(String.format("%s [c %d] [a %d] [i %d]", changes.toString(),
+ computed - start, applied - computed, end - applied));
}
- applyNetworkReassignment(changes, now);
- issueNetworkNeeds();
}
private void applyNetworkReassignment(@NonNull final NetworkReassignment changes,
@@ -9523,9 +9490,7 @@
final UnderlyingNetworkInfo[] underlyingNetworkInfos = getAllVpnInfo();
try {
final ArrayList<NetworkStateSnapshot> snapshots = new ArrayList<>();
- for (final NetworkStateSnapshot snapshot : getAllNetworkStateSnapshots()) {
- snapshots.add(snapshot);
- }
+ snapshots.addAll(getAllNetworkStateSnapshots());
mStatsManager.notifyNetworkStatus(getDefaultNetworks(),
snapshots, activeIface, Arrays.asList(underlyingNetworkInfos));
} catch (Exception ignored) {
@@ -9912,14 +9877,12 @@
private static class NetworkTestedResults {
private final int mNetId;
private final int mTestResult;
- private final long mTimestampMillis;
@Nullable private final String mRedirectUrl;
private NetworkTestedResults(
int netId, int testResult, long timestampMillis, @Nullable String redirectUrl) {
mNetId = netId;
mTestResult = testResult;
- mTimestampMillis = timestampMillis;
mRedirectUrl = redirectUrl;
}
}
@@ -10343,14 +10306,14 @@
}
@Override
- public void onInterfaceLinkStateChanged(String iface, boolean up) {
+ public void onInterfaceLinkStateChanged(@NonNull String iface, boolean up) {
for (NetworkAgentInfo nai : mNetworkAgentInfos) {
nai.clatd.interfaceLinkStateChanged(iface, up);
}
}
@Override
- public void onInterfaceRemoved(String iface) {
+ public void onInterfaceRemoved(@NonNull String iface) {
for (NetworkAgentInfo nai : mNetworkAgentInfos) {
nai.clatd.interfaceRemoved(iface);
}
@@ -10373,10 +10336,10 @@
@GuardedBy("mActiveIdleTimers")
private boolean mNetworkActive;
@GuardedBy("mActiveIdleTimers")
- private final ArrayMap<String, IdleTimerParams> mActiveIdleTimers = new ArrayMap();
+ private final ArrayMap<String, IdleTimerParams> mActiveIdleTimers = new ArrayMap<>();
private final Handler mHandler;
- private class IdleTimerParams {
+ private static class IdleTimerParams {
public final int timeout;
public final int transportType;
@@ -10422,7 +10385,7 @@
try {
mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
} catch (RemoteException | RuntimeException e) {
- loge("Fail to send network activie to listener " + e);
+ loge("Fail to send network activity to listener " + e);
}
}
} finally {
@@ -10643,8 +10606,8 @@
@VisibleForTesting
public void registerQosCallbackInternal(@NonNull final QosFilter filter,
@NonNull final IQosCallback callback, @NonNull final NetworkAgentInfo nai) {
- if (filter == null) throw new IllegalArgumentException("filter must be non-null");
- if (callback == null) throw new IllegalArgumentException("callback must be non-null");
+ Objects.requireNonNull(filter, "filter must be non-null");
+ Objects.requireNonNull(callback, "callback must be non-null");
if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
// TODO: Check allowed list here and ensure that either a) any QoS callback registered
@@ -10722,8 +10685,7 @@
+ "or the device owner must be set. ");
}
- final List<ProfileNetworkPreferenceList.Preference> preferenceList =
- new ArrayList<ProfileNetworkPreferenceList.Preference>();
+ final List<ProfileNetworkPreferenceList.Preference> preferenceList = new ArrayList<>();
boolean hasDefaultPreference = false;
for (final ProfileNetworkPreference preference : preferences) {
final NetworkCapabilities nc;
@@ -10804,7 +10766,7 @@
uidRangeSet = UidRangeUtils.removeRangeSetFromUidRange(profileUids,
disallowUidRangeSet);
} else {
- uidRangeSet = new ArraySet<UidRange>();
+ uidRangeSet = new ArraySet<>();
uidRangeSet.add(profileUids);
}
}
@@ -10813,8 +10775,7 @@
private boolean isEnterpriseIdentifierValid(
@NetworkCapabilities.EnterpriseId int identifier) {
- if ((identifier >= NET_ENTERPRISE_ID_1)
- && (identifier <= NET_ENTERPRISE_ID_5)) {
+ if ((identifier >= NET_ENTERPRISE_ID_1) && (identifier <= NET_ENTERPRISE_ID_5)) {
return true;
}
return false;
@@ -10886,6 +10847,7 @@
removeDefaultNetworkRequestsForPreference(PREFERENCE_ORDER_PROFILE);
addPerAppDefaultNetworkRequests(
createNrisFromProfileNetworkPreferences(mProfileNetworkPreferences));
+
// Finally, rematch.
rematchAllNetworksAndRequests();
diff --git a/service/src/com/android/server/connectivity/DscpPolicyValue.java b/service/src/com/android/server/connectivity/DscpPolicyValue.java
index 4bb41da..fed96b4 100644
--- a/service/src/com/android/server/connectivity/DscpPolicyValue.java
+++ b/service/src/com/android/server/connectivity/DscpPolicyValue.java
@@ -43,10 +43,10 @@
@Field(order = 3, type = Type.UBE16)
public final int srcPort;
- @Field(order = 4, type = Type.UBE16)
+ @Field(order = 4, type = Type.U16)
public final int dstPortStart;
- @Field(order = 5, type = Type.UBE16)
+ @Field(order = 5, type = Type.U16)
public final int dstPortEnd;
@Field(order = 6, type = Type.U8)
@@ -61,8 +61,7 @@
private static final int SRC_IP_MASK = 0x1;
private static final int DST_IP_MASK = 0x02;
private static final int SRC_PORT_MASK = 0x4;
- private static final int DST_PORT_MASK = 0x8;
- private static final int PROTO_MASK = 0x10;
+ private static final int PROTO_MASK = 0x8;
private boolean ipEmpty(final byte[] ip) {
for (int i = 0; i < ip.length; i++) {
@@ -111,9 +110,6 @@
if (srcPort != -1) {
mask |= SRC_PORT_MASK;
}
- if (dstPortStart != -1 && dstPortEnd != -1) {
- mask |= DST_PORT_MASK;
- }
if (proto != -1) {
mask |= PROTO_MASK;
}
@@ -131,7 +127,7 @@
// If they are -1 BpfMap write will throw errors.
this.srcPort = srcPort != -1 ? srcPort : 0;
this.dstPortStart = dstPortStart != -1 ? dstPortStart : 0;
- this.dstPortEnd = dstPortEnd != -1 ? dstPortEnd : 0;
+ this.dstPortEnd = dstPortEnd != -1 ? dstPortEnd : 65535;
this.proto = proto != -1 ? proto : 0;
this.dscp = dscp;
diff --git a/service/src/com/android/server/connectivity/FullScore.java b/service/src/com/android/server/connectivity/FullScore.java
index b156045..c4754eb 100644
--- a/service/src/com/android/server/connectivity/FullScore.java
+++ b/service/src/com/android/server/connectivity/FullScore.java
@@ -49,10 +49,6 @@
public class FullScore {
private static final String TAG = FullScore.class.getSimpleName();
- // This will be removed soon. Do *NOT* depend on it for any new code that is not part of
- // a migration.
- private final int mLegacyInt;
-
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"POLICY_"}, value = {
@@ -146,9 +142,7 @@
private final int mKeepConnectedReason;
- FullScore(final int legacyInt, final long policies,
- @KeepConnectedReason final int keepConnectedReason) {
- mLegacyInt = legacyInt;
+ FullScore(final long policies, @KeepConnectedReason final int keepConnectedReason) {
mPolicies = policies;
mKeepConnectedReason = keepConnectedReason;
}
@@ -170,7 +164,7 @@
public static FullScore fromNetworkScore(@NonNull final NetworkScore score,
@NonNull final NetworkCapabilities caps, @NonNull final NetworkAgentConfig config,
final boolean everValidated, final boolean yieldToBadWiFi, final boolean destroyed) {
- return withPolicies(score.getLegacyInt(), score.getPolicies(),
+ return withPolicies(score.getPolicies(),
score.getKeepConnectedReason(),
caps.hasCapability(NET_CAPABILITY_VALIDATED),
caps.hasTransport(TRANSPORT_VPN),
@@ -216,7 +210,7 @@
// A prospective score is invincible if the legacy int in the filter is over the maximum
// score.
final boolean invincible = score.getLegacyInt() > NetworkRanker.LEGACY_INT_MAX;
- return withPolicies(score.getLegacyInt(), score.getPolicies(), KEEP_CONNECTED_NONE,
+ return withPolicies(score.getPolicies(), KEEP_CONNECTED_NONE,
mayValidate, vpn, unmetered, everValidated, everUserSelected, acceptUnvalidated,
yieldToBadWiFi, destroyed, invincible);
}
@@ -236,7 +230,7 @@
final boolean everValidated,
final boolean yieldToBadWifi,
final boolean destroyed) {
- return withPolicies(mLegacyInt, mPolicies, mKeepConnectedReason,
+ return withPolicies(mPolicies, mKeepConnectedReason,
caps.hasCapability(NET_CAPABILITY_VALIDATED),
caps.hasTransport(TRANSPORT_VPN),
caps.hasCapability(NET_CAPABILITY_NOT_METERED),
@@ -251,8 +245,7 @@
// TODO : this shouldn't manage bad wifi avoidance – instead this should be done by the
// telephony factory, so that it depends on the carrier. For now this is handled by
// connectivity for backward compatibility.
- private static FullScore withPolicies(@NonNull final int legacyInt,
- final long externalPolicies,
+ private static FullScore withPolicies(final long externalPolicies,
@KeepConnectedReason final int keepConnectedReason,
final boolean isValidated,
final boolean isVpn,
@@ -263,7 +256,7 @@
final boolean yieldToBadWiFi,
final boolean destroyed,
final boolean invincible) {
- return new FullScore(legacyInt, (externalPolicies & EXTERNAL_POLICIES_MASK)
+ return new FullScore((externalPolicies & EXTERNAL_POLICIES_MASK)
| (isValidated ? 1L << POLICY_IS_VALIDATED : 0)
| (isVpn ? 1L << POLICY_IS_VPN : 0)
| (isUnmetered ? 1L << POLICY_IS_UNMETERED : 0)
@@ -280,8 +273,7 @@
* Returns this score but with the specified yield to bad wifi policy.
*/
public FullScore withYieldToBadWiFi(final boolean newYield) {
- return new FullScore(mLegacyInt,
- newYield ? mPolicies | (1L << POLICY_YIELD_TO_BAD_WIFI)
+ return new FullScore(newYield ? mPolicies | (1L << POLICY_YIELD_TO_BAD_WIFI)
: mPolicies & ~(1L << POLICY_YIELD_TO_BAD_WIFI),
mKeepConnectedReason);
}
@@ -290,49 +282,7 @@
* Returns this score but validated.
*/
public FullScore asValidated() {
- return new FullScore(mLegacyInt, mPolicies | (1L << POLICY_IS_VALIDATED),
- mKeepConnectedReason);
- }
-
- /**
- * For backward compatibility, get the legacy int.
- * This will be removed before S is published.
- */
- public int getLegacyInt() {
- return getLegacyInt(false /* pretendValidated */);
- }
-
- public int getLegacyIntAsValidated() {
- return getLegacyInt(true /* pretendValidated */);
- }
-
- // TODO : remove these two constants
- // Penalty applied to scores of Networks that have not been validated.
- private static final int UNVALIDATED_SCORE_PENALTY = 40;
-
- // Score for a network that can be used unvalidated
- private static final int ACCEPT_UNVALIDATED_NETWORK_SCORE = 100;
-
- private int getLegacyInt(boolean pretendValidated) {
- // If the user has chosen this network at least once, give it the maximum score when
- // checking to pretend it's validated, or if it doesn't need to validate because the
- // user said to use it even if it doesn't validate.
- // This ensures that networks that have been selected in UI are not torn down before the
- // user gets a chance to prefer it when a higher-scoring network (e.g., Ethernet) is
- // available.
- if (hasPolicy(POLICY_EVER_USER_SELECTED)
- && (hasPolicy(POLICY_ACCEPT_UNVALIDATED) || pretendValidated)) {
- return ACCEPT_UNVALIDATED_NETWORK_SCORE;
- }
-
- int score = mLegacyInt;
- // Except for VPNs, networks are subject to a penalty for not being validated.
- // Apply the penalty unless the network is a VPN, or it's validated or pretending to be.
- if (!hasPolicy(POLICY_IS_VALIDATED) && !pretendValidated && !hasPolicy(POLICY_IS_VPN)) {
- score -= UNVALIDATED_SCORE_PENALTY;
- }
- if (score < 0) score = 0;
- return score;
+ return new FullScore(mPolicies | (1L << POLICY_IS_VALIDATED), mKeepConnectedReason);
}
/**
@@ -350,15 +300,32 @@
return mKeepConnectedReason;
}
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ final FullScore fullScore = (FullScore) o;
+
+ if (mPolicies != fullScore.mPolicies) return false;
+ return mKeepConnectedReason == fullScore.mKeepConnectedReason;
+ }
+
+ @Override
+ public int hashCode() {
+ return 2 * ((int) mPolicies)
+ + 3 * (int) (mPolicies >>> 32)
+ + 5 * mKeepConnectedReason;
+ }
+
// Example output :
- // Score(50 ; Policies : EVER_USER_SELECTED&IS_VALIDATED)
+ // Score(Policies : EVER_USER_SELECTED&IS_VALIDATED ; KeepConnected : )
@Override
public String toString() {
final StringJoiner sj = new StringJoiner(
"&", // delimiter
- "Score(" + mLegacyInt + " ; KeepConnected : " + mKeepConnectedReason
- + " ; Policies : ", // prefix
- ")"); // suffix
+ "Score(Policies : ", // prefix
+ " ; KeepConnected : " + mKeepConnectedReason + ")"); // suffix
for (int i = NetworkScore.MIN_AGENT_MANAGED_POLICY;
i <= NetworkScore.MAX_AGENT_MANAGED_POLICY; ++i) {
if (hasPolicy(i)) sj.add(policyNameOf(i));
diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
index 04031af..04f378f 100644
--- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -26,6 +26,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.net.CaptivePortalData;
import android.net.DscpPolicy;
import android.net.IDnsResolver;
@@ -66,6 +67,7 @@
import com.android.server.ConnectivityService;
import java.io.PrintWriter;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -104,7 +106,7 @@
// for example:
// a. a captive portal is present, or
// b. a WiFi router whose Internet backhaul is down, or
-// c. a wireless connection stops transfering packets temporarily (e.g. device is in elevator
+// c. a wireless connection stops transferring packets temporarily (e.g. device is in elevator
// or tunnel) but does not disconnect from the AP/cell tower, or
// d. a stand-alone device offering a WiFi AP without an uplink for configuration purposes.
// 5. registered, created, connected, validated
@@ -157,7 +159,7 @@
// the network is no longer considered "lingering". After the linger timer expires, if the network
// is satisfying one or more background NetworkRequests it is kept up in the background. If it is
// not, ConnectivityService disconnects the NetworkAgent's AsyncChannel.
-public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRanker.Scoreable {
+public class NetworkAgentInfo implements NetworkRanker.Scoreable {
@NonNull public NetworkInfo networkInfo;
// This Network object should always be used if possible, so as to encourage reuse of the
@@ -184,9 +186,8 @@
//
// As the name implies, these capabilities are not sanitized and are not to
// be trusted. Most callers should simply use the {@link networkCapabilities}
- // field instead, and callers who need the declared capabilities should generally
- // pass these to {@link ConnectivityService#sanitizedCapabilitiesFromAgent} before using them.
- public @Nullable NetworkCapabilities declaredCapabilitiesUnsanitized;
+ // field instead.
+ private @Nullable NetworkCapabilities mDeclaredCapabilitiesUnsanitized;
// Indicates if netd has been told to create this Network. From this point on the appropriate
// routing rules are setup and routes are added so packets can begin flowing over the Network.
@@ -240,6 +241,53 @@
// URL, Terms & Conditions URL, and network friendly name.
public CaptivePortalData networkAgentPortalData;
+ /**
+ * Sets the capabilities sent by the agent for later retrieval.
+ *
+ * This method does not sanitize the capabilities ; instead, use
+ * {@link #getDeclaredCapabilitiesSanitized} to retrieve a sanitized
+ * copy of the capabilities as they were passed here.
+ *
+ * This method makes a defensive copy to avoid issues where the passed object is later mutated.
+ *
+ * @param caps the caps sent by the agent
+ */
+ public void setDeclaredCapabilities(@NonNull final NetworkCapabilities caps) {
+ mDeclaredCapabilitiesUnsanitized = new NetworkCapabilities(caps);
+ }
+
+ /**
+ * Get the latest capabilities sent by the network agent, after sanitizing them.
+ *
+ * These are the capabilities as they were sent by the agent (but sanitized to conform to
+ * their restrictions). They are NOT the capabilities currently applying to this agent ;
+ * for that, use {@link #networkCapabilities}.
+ *
+ * Agents have restrictions on what capabilities they can send to Connectivity. For example,
+ * they can't change the owner UID from what they declared before, and complex restrictions
+ * apply to the allowedUids field.
+ * They also should not mutate immutable capabilities, although for backward-compatibility
+ * this is not enforced and limited to just a log.
+ *
+ * @param carrierPrivilegeAuthenticator the authenticator, to check access UIDs.
+ */
+ public NetworkCapabilities getDeclaredCapabilitiesSanitized(
+ final CarrierPrivilegeAuthenticator carrierPrivilegeAuthenticator) {
+ final NetworkCapabilities nc = new NetworkCapabilities(mDeclaredCapabilitiesUnsanitized);
+ if (nc.hasConnectivityManagedCapability()) {
+ Log.wtf(TAG, "BUG: " + this + " has CS-managed capability.");
+ }
+ if (networkCapabilities.getOwnerUid() != nc.getOwnerUid()) {
+ Log.e(TAG, toShortString() + ": ignoring attempt to change owner from "
+ + networkCapabilities.getOwnerUid() + " to " + nc.getOwnerUid());
+ nc.setOwnerUid(networkCapabilities.getOwnerUid());
+ }
+ restrictCapabilitiesFromNetworkAgent(nc, creatorUid,
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE),
+ carrierPrivilegeAuthenticator);
+ return nc;
+ }
+
// Networks are lingered when they become unneeded as a result of their NetworkRequests being
// satisfied by a higher-scoring network. so as to allow communication to wrap up before the
// network is taken down. This usually only happens to the default network. Lingering ends with
@@ -370,6 +418,8 @@
private final Handler mHandler;
private final QosCallbackTracker mQosCallbackTracker;
+ private final long mCreationTime;
+
public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
@NonNull LinkProperties lp, @NonNull NetworkCapabilities nc,
@NonNull NetworkScore score, Context context,
@@ -402,6 +452,7 @@
declaredUnderlyingNetworks = (nc.getUnderlyingNetworks() != null)
? nc.getUnderlyingNetworks().toArray(new Network[0])
: null;
+ mCreationTime = System.currentTimeMillis();
}
private class AgentDeathMonitor implements IBinder.DeathRecipient {
@@ -967,18 +1018,6 @@
return mScore;
}
- // Get the current score for this Network. This may be modified from what the
- // NetworkAgent sent, as it has modifiers applied to it.
- public int getCurrentScore() {
- return mScore.getLegacyInt();
- }
-
- // Get the current score for this Network as if it was validated. This may be modified from
- // what the NetworkAgent sent, as it has modifiers applied to it.
- public int getCurrentScoreAsValidated() {
- return mScore.getLegacyIntAsValidated();
- }
-
/**
* Mix-in the ConnectivityService-managed bits in the score.
*/
@@ -1283,6 +1322,7 @@
return "NetworkAgentInfo{"
+ "network{" + network + "} handle{" + network.getNetworkHandle() + "} ni{"
+ networkInfo.toShortString() + "} "
+ + "created=" + Instant.ofEpochMilli(mCreationTime) + " "
+ mScore + " "
+ (created ? " created" : "")
+ (destroyed ? " destroyed" : "")
@@ -1316,12 +1356,6 @@
+ transportNamesOf(networkCapabilities.getTransportTypes()) + "]";
}
- // Enables sorting in descending order of score.
- @Override
- public int compareTo(NetworkAgentInfo other) {
- return other.getCurrentScore() - getCurrentScore();
- }
-
/**
* Null-guarding version of NetworkAgentInfo#toShortString()
*/
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 5edf727..6ff2458 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -413,14 +413,17 @@
// All tests in this class require a working Internet connection as they start. Make
// sure there is still one as they end that's ready to use for the next test to use.
- final TestNetworkCallback callback = new TestNetworkCallback();
- registerDefaultNetworkCallback(callback);
- try {
- assertNotNull("Couldn't restore Internet connectivity", callback.waitForAvailable());
- } finally {
- // Unregister all registered callbacks.
- unregisterRegisteredCallbacks();
- }
+ mTestValidationConfigRule.runAfterNextCleanup(() -> {
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ registerDefaultNetworkCallback(callback);
+ try {
+ assertNotNull("Couldn't restore Internet connectivity",
+ callback.waitForAvailable());
+ } finally {
+ // Unregister all registered callbacks.
+ unregisterRegisteredCallbacks();
+ }
+ });
}
@Test
diff --git a/tests/cts/net/src/android/net/cts/DeviceConfigRule.kt b/tests/cts/net/src/android/net/cts/DeviceConfigRule.kt
index d31a4e0..3a739f2 100644
--- a/tests/cts/net/src/android/net/cts/DeviceConfigRule.kt
+++ b/tests/cts/net/src/android/net/cts/DeviceConfigRule.kt
@@ -21,6 +21,7 @@
import android.provider.DeviceConfig
import android.util.Log
import com.android.modules.utils.build.SdkLevel
+import com.android.testutils.ExceptionUtils.ThrowingRunnable
import com.android.testutils.runAsShell
import com.android.testutils.tryTest
import org.junit.rules.TestRule
@@ -51,7 +52,7 @@
/**
* Actions to be run after cleanup of the config, for the current test only.
*/
- private val currentTestCleanupActions = mutableListOf<Runnable>()
+ private val currentTestCleanupActions = mutableListOf<ThrowingRunnable>()
override fun apply(base: Statement, description: Description): Statement {
return TestValidationUrlStatement(base, description)
@@ -93,8 +94,13 @@
originalConfig.clear()
usedConfig.clear()
} cleanup {
- currentTestCleanupActions.forEach { it.run() }
- currentTestCleanupActions.clear()
+ // Fold all cleanup actions into cleanup steps of an empty tryTest, so they are
+ // all run even if exceptions are thrown, and exceptions are reported properly.
+ currentTestCleanupActions.fold(tryTest { }) {
+ tryBlock, action -> tryBlock.cleanupStep { action.run() }
+ }.cleanup {
+ currentTestCleanupActions.clear()
+ }
}
}
}
@@ -118,7 +124,7 @@
/**
* Add an action to be run after config cleanup when the current test case ends.
*/
- fun runAfterNextCleanup(action: Runnable) {
+ fun runAfterNextCleanup(action: ThrowingRunnable) {
currentTestCleanupActions.add(action)
}
}
diff --git a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
index 77dca95..1f76773 100644
--- a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
+++ b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
@@ -16,10 +16,8 @@
package android.net.cts
-import android.net.cts.util.CtsNetUtils.TestNetworkCallback
-
-import android.app.Instrumentation
import android.Manifest.permission.MANAGE_TEST_NETWORKS
+import android.app.Instrumentation
import android.content.Context
import android.net.ConnectivityManager
import android.net.DscpPolicy
@@ -27,8 +25,8 @@
import android.net.IpPrefix
import android.net.LinkAddress
import android.net.LinkProperties
-import android.net.Network
import android.net.MacAddress
+import android.net.Network
import android.net.NetworkAgent
import android.net.NetworkAgent.DSCP_POLICY_STATUS_DELETED
import android.net.NetworkAgent.DSCP_POLICY_STATUS_SUCCESS
@@ -43,9 +41,10 @@
import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkRequest
+import android.net.RouteInfo
import android.net.TestNetworkInterface
import android.net.TestNetworkManager
-import android.net.RouteInfo
+import android.net.cts.util.CtsNetUtils.TestNetworkCallback
import android.os.HandlerThread
import android.os.SystemClock
import android.platform.test.annotations.AppModeFull
@@ -61,6 +60,7 @@
import android.util.Range
import androidx.test.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
+import com.android.net.module.util.IpUtils
import com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4
import com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6
import com.android.net.module.util.Struct
@@ -69,21 +69,15 @@
import com.android.testutils.CompatUtil
import com.android.testutils.ConnectivityModuleTest
import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.assertParcelingIsLossless
import com.android.testutils.RouterAdvertisementResponder
-import com.android.testutils.runAsShell
import com.android.testutils.SC_V2
import com.android.testutils.TapPacketReader
import com.android.testutils.TestableNetworkAgent
-import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkCreated
import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnDscpPolicyStatusUpdated
+import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkCreated
import com.android.testutils.TestableNetworkCallback
-import org.junit.After
-import org.junit.Assume.assumeTrue
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
+import com.android.testutils.assertParcelingIsLossless
+import com.android.testutils.runAsShell
import java.net.Inet4Address
import java.net.Inet6Address
import java.net.InetSocketAddress
@@ -94,6 +88,12 @@
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import kotlin.test.fail
+import org.junit.After
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
private const val MAX_PACKET_LENGTH = 1500
@@ -220,33 +220,32 @@
private fun waitForGlobalIpv6Address(network: Network): Inet6Address {
// Wait for global IPv6 address to be available
- val sock = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
- network.bindSocket(sock)
-
var inet6Addr: Inet6Address? = null
- val timeout = SystemClock.elapsedRealtime() + PACKET_TIMEOUT_MS
- while (timeout > SystemClock.elapsedRealtime()) {
+ val onLinkPrefix = raResponder.prefix
+ val startTime = SystemClock.elapsedRealtime()
+ while (SystemClock.elapsedRealtime() - startTime < PACKET_TIMEOUT_MS) {
+ SystemClock.sleep(1 /* ms */)
+ val sock = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
try {
- // Pick any arbitrary port
- Os.connect(sock, TEST_TARGET_IPV6_ADDR, 12345)
- val sockAddr = Os.getsockname(sock) as InetSocketAddress
+ network.bindSocket(sock)
- // TODO: make RouterAdvertisementResponder.SLAAC_PREFIX public and use it here,
- // or make it configurable and configure it here.
- if (IpPrefix("2001:db8::/64").contains(sockAddr.address)) {
+ try {
+ // Pick any arbitrary port
+ Os.connect(sock, TEST_TARGET_IPV6_ADDR, 12345)
+ } catch (e: ErrnoException) {
+ // there may not be an address available yet.
+ if (e.errno == ENETUNREACH) continue
+ throw e
+ }
+ val sockAddr = Os.getsockname(sock) as InetSocketAddress
+ if (onLinkPrefix.contains(sockAddr.address)) {
inet6Addr = sockAddr.address as Inet6Address
break
}
- } catch (e: ErrnoException) {
- // ignore ENETUNREACH -- there may not be an address available yet.
- if (e.errno != ENETUNREACH) {
- Os.close(sock)
- throw e
- }
+ } finally {
+ Os.close(sock)
}
- SystemClock.sleep(10 /* ms */)
}
- Os.close(sock)
assertNotNull(inet6Addr)
return inet6Addr!!
}
@@ -317,6 +316,9 @@
}
fun parseV4PacketDscp(buffer: ByteBuffer): Int {
+ // Validate checksum before parsing packet.
+ val calCheck = IpUtils.ipChecksum(buffer, Struct.getSize(EthernetHeader::class.java))
+
val ip_ver = buffer.get()
val tos = buffer.get()
val length = buffer.getShort()
@@ -325,6 +327,8 @@
val ttl = buffer.get()
val ipType = buffer.get()
val checksum = buffer.getShort()
+
+ assertEquals(0, calCheck, "Invalid IPv4 header checksum")
return tos.toInt().shr(2)
}
@@ -399,6 +403,7 @@
val packets = generateSequence { reader.poll(PACKET_TIMEOUT_MS) }
for (packet in packets) {
val buffer = ByteBuffer.wrap(packet, 0, packet.size).order(ByteOrder.BIG_ENDIAN)
+
// TODO: consider using Struct.parse for all packet parsing.
val etherHdr = Struct.parse(EthernetHeader::class.java, buffer)
val expectedType = if (sendV6) ETHER_TYPE_IPV6 else ETHER_TYPE_IPV4
@@ -442,6 +447,9 @@
assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
}
validatePacket(agent, dscpValue = 1, dstPort = 4444)
+ // Send a second packet to validate that the stored BPF policy
+ // is correct for subsequent packets.
+ validatePacket(agent, dscpValue = 1, dstPort = 4444)
agent.sendRemoveDscpPolicy(1)
agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
@@ -480,6 +488,9 @@
assertEquals(DSCP_POLICY_STATUS_SUCCESS, it.status)
}
validatePacket(agent, true, dscpValue = 1, dstPort = 4444)
+ // Send a second packet to validate that the stored BPF policy
+ // is correct for subsequent packets.
+ validatePacket(agent, true, dscpValue = 1, dstPort = 4444)
agent.sendRemoveDscpPolicy(1)
agent.expectCallback<OnDscpPolicyStatusUpdated>().let {
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
index 89b107e..ce8584f 100644
--- a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -68,6 +68,7 @@
import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged
import com.android.testutils.RecorderCallback.CallbackEntry.Lost
import com.android.testutils.RouterAdvertisementResponder
+import com.android.testutils.SkipPresubmit
import com.android.testutils.TapPacketReader
import com.android.testutils.TestableNetworkCallback
import com.android.testutils.anyNetwork
@@ -79,6 +80,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import java.net.Inet6Address
+import java.util.Random
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit
@@ -117,6 +119,7 @@
@RunWith(DevSdkIgnoreRunner::class)
// This test depends on behavior introduced post-T as part of connectivity module updates
@ConnectivityModuleTest
+@SkipPresubmit(reason = "Flaky: b/240323229; remove annotation after fixing")
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
class EthernetManagerTest {
@@ -153,8 +156,9 @@
val mtu = tapInterface.mtu
packetReader = TapPacketReader(handler, tapInterface.fileDescriptor.fileDescriptor, mtu)
raResponder = RouterAdvertisementResponder(packetReader)
- raResponder.addRouterEntry(MacAddress.fromString("01:23:45:67:89:ab"),
- InetAddresses.parseNumericAddress("fe80::abcd") as Inet6Address)
+ val iidString = "fe80::${Integer.toHexString(Random().nextInt(65536))}"
+ val linklocal = InetAddresses.parseNumericAddress(iidString) as Inet6Address
+ raResponder.addRouterEntry(MacAddress.fromString("01:23:45:67:89:ab"), linklocal)
packetReader.startAsyncForTest()
raResponder.start()
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
index 7254319..f035f72 100644
--- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -16,11 +16,13 @@
package android.net.cts.util;
+import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static com.android.compatibility.common.util.PropertyUtil.getFirstApiLevel;
+import static com.android.testutils.TestPermissionUtil.runAsShell;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -288,7 +290,8 @@
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiver(receiver, filter);
- final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+ final WifiInfo wifiInfo = runAsShell(NETWORK_SETTINGS,
+ () -> mWifiManager.getConnectionInfo());
final boolean wasWifiConnected = wifiInfo != null && wifiInfo.getNetworkId() != -1;
// Assert that we can establish a TCP connection on wifi.
Socket wifiBoundSocket = null;
diff --git a/tests/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/integration/util/com/android/server/NetworkAgentWrapper.java
index 2763f5a..97688d5 100644
--- a/tests/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -61,6 +61,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
private final NetworkCapabilities mNetworkCapabilities;
@@ -83,14 +84,35 @@
private final ArrayTrackRecord<CallbackType>.ReadHead mCallbackHistory =
new ArrayTrackRecord<CallbackType>().newReadHead();
+ public static class Callbacks {
+ public final Consumer<NetworkAgent> onNetworkCreated;
+ public final Consumer<NetworkAgent> onNetworkUnwanted;
+ public final Consumer<NetworkAgent> onNetworkDestroyed;
+
+ public Callbacks() {
+ this(null, null, null);
+ }
+
+ public Callbacks(Consumer<NetworkAgent> onNetworkCreated,
+ Consumer<NetworkAgent> onNetworkUnwanted,
+ Consumer<NetworkAgent> onNetworkDestroyed) {
+ this.onNetworkCreated = onNetworkCreated;
+ this.onNetworkUnwanted = onNetworkUnwanted;
+ this.onNetworkDestroyed = onNetworkDestroyed;
+ }
+ }
+
+ private final Callbacks mCallbacks;
+
public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
NetworkCapabilities ncTemplate, Context context) throws Exception {
- this(transport, linkProperties, ncTemplate, null /* provider */, context);
+ this(transport, linkProperties, ncTemplate, null /* provider */,
+ null /* callbacks */, context);
}
public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
NetworkCapabilities ncTemplate, NetworkProvider provider,
- Context context) throws Exception {
+ Callbacks callbacks, Context context) throws Exception {
final int type = transportToLegacyType(transport);
final String typeName = ConnectivityManager.getNetworkTypeName(type);
mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
@@ -135,6 +157,7 @@
.setLegacyTypeName(typeName)
.setLegacyExtraInfo(extraInfo)
.build();
+ mCallbacks = (callbacks != null) ? callbacks : new Callbacks();
mNetworkAgent = makeNetworkAgent(linkProperties, mNetworkAgentConfig, provider);
}
@@ -214,6 +237,31 @@
protected void removeKeepalivePacketFilter(Message msg) {
Log.i(mWrapper.mLogTag, "Remove keepalive packet filter.");
}
+
+ @Override
+ public void onNetworkCreated() {
+ super.onNetworkCreated();
+ if (mWrapper.mCallbacks.onNetworkCreated != null) {
+ mWrapper.mCallbacks.onNetworkCreated.accept(this);
+ }
+ }
+
+ @Override
+ public void onNetworkUnwanted() {
+ super.onNetworkUnwanted();
+ if (mWrapper.mCallbacks.onNetworkUnwanted != null) {
+ mWrapper.mCallbacks.onNetworkUnwanted.accept(this);
+ }
+ }
+
+ @Override
+ public void onNetworkDestroyed() {
+ super.onNetworkDestroyed();
+ if (mWrapper.mCallbacks.onNetworkDestroyed != null) {
+ mWrapper.mCallbacks.onNetworkDestroyed.accept(this);
+ }
+ }
+
}
public void setScore(@NonNull final NetworkScore score) {
diff --git a/tests/native/utilities/Android.bp b/tests/native/utilities/Android.bp
index 7668cc1..4706b3d 100644
--- a/tests/native/utilities/Android.bp
+++ b/tests/native/utilities/Android.bp
@@ -13,6 +13,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
cc_test_library {
name: "libconnectivity_native_test_utils",
defaults: [
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 0908ad2..72324d9 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -150,6 +150,5 @@
jni_libs: [
"libandroid_net_connectivity_com_android_net_module_util_jni",
"libservice-connectivity",
- "libandroid_net_connectivity_com_android_net_module_util_jni",
],
}
diff --git a/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java b/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
index 71c03ff..8a537be 100644
--- a/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
+++ b/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
@@ -88,20 +88,28 @@
Entry uid1Entry1 = new Entry("if1", uid1,
android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
+ android.net.NetworkStats.METERED_NO, android.net.NetworkStats.ROAMING_NO,
+ android.net.NetworkStats.DEFAULT_NETWORK_NO,
100, 10, 200, 20, 0);
Entry uid1Entry2 = new Entry(
"if2", uid1,
android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
+ android.net.NetworkStats.METERED_NO, android.net.NetworkStats.ROAMING_NO,
+ android.net.NetworkStats.DEFAULT_NETWORK_NO,
100, 10, 200, 20, 0);
Entry uid2Entry1 = new Entry("if1", uid2,
android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
+ android.net.NetworkStats.METERED_NO, android.net.NetworkStats.ROAMING_NO,
+ android.net.NetworkStats.DEFAULT_NETWORK_NO,
150, 10, 250, 20, 0);
Entry uid2Entry2 = new Entry(
"if2", uid2,
android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
+ android.net.NetworkStats.METERED_NO, android.net.NetworkStats.ROAMING_NO,
+ android.net.NetworkStats.DEFAULT_NETWORK_NO,
150, 10, 250, 20, 0);
NetworkStatsHistory history1 = new NetworkStatsHistory(10, 2);
diff --git a/tests/unit/java/android/net/NetworkStatsCollectionTest.java b/tests/unit/java/android/net/NetworkStatsCollectionTest.java
index b518a61..a6e9e95 100644
--- a/tests/unit/java/android/net/NetworkStatsCollectionTest.java
+++ b/tests/unit/java/android/net/NetworkStatsCollectionTest.java
@@ -18,6 +18,10 @@
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.NetworkIdentity.OEM_NONE;
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.TAG_NONE;
@@ -480,7 +484,8 @@
ident.add(new NetworkIdentity(ConnectivityManager.TYPE_MOBILE, -1, TEST_IMSI, null,
false, true, true, OEM_NONE, TEST_SUBID));
large.recordData(ident, UID_ALL, SET_ALL, TAG_NONE, TIME_A, TIME_B,
- new NetworkStats.Entry(12_730_893_164L, 1, 0, 0, 0));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 12_730_893_164L, 1, 0, 0, 0));
// Verify untouched total
assertEquals(12_730_893_164L, getHistory(large, null, TIME_A, TIME_C).getTotalBytes());
@@ -659,26 +664,33 @@
private static void assertEntry(long rxBytes, long rxPackets, long txBytes, long txPackets,
NetworkStats.Entry actual) {
- assertEntry(new NetworkStats.Entry(rxBytes, rxPackets, txBytes, txPackets, 0L), actual);
+ assertEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes, rxPackets, txBytes, txPackets, 0L),
+ actual);
}
private static void assertEntry(long rxBytes, long rxPackets, long txBytes, long txPackets,
NetworkStatsHistory.Entry actual) {
- assertEntry(new NetworkStats.Entry(rxBytes, rxPackets, txBytes, txPackets, 0L), actual);
+ assertEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes, rxPackets, txBytes, txPackets, 0L),
+ actual);
}
private static void assertEntry(NetworkStats.Entry expected,
NetworkStatsHistory.Entry actual) {
- assertEntry(expected, new NetworkStats.Entry(actual.rxBytes, actual.rxPackets,
+ assertEntry(expected, new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, actual.rxBytes, actual.rxPackets,
actual.txBytes, actual.txPackets, 0L));
}
private static void assertEntry(NetworkStatsHistory.Entry expected,
NetworkStatsHistory.Entry actual) {
- assertEntry(new NetworkStats.Entry(actual.rxBytes, actual.rxPackets,
- actual.txBytes, actual.txPackets, 0L),
- new NetworkStats.Entry(actual.rxBytes, actual.rxPackets,
- actual.txBytes, actual.txPackets, 0L));
+ assertEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, actual.rxBytes, actual.rxPackets,
+ actual.txBytes, actual.txPackets, 0L),
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, actual.rxBytes, actual.rxPackets,
+ actual.txBytes, actual.txPackets, 0L));
}
private static void assertEntry(NetworkStats.Entry expected,
diff --git a/tests/unit/java/android/net/NetworkStatsHistoryTest.java b/tests/unit/java/android/net/NetworkStatsHistoryTest.java
index 43e331b..2170882 100644
--- a/tests/unit/java/android/net/NetworkStatsHistoryTest.java
+++ b/tests/unit/java/android/net/NetworkStatsHistoryTest.java
@@ -16,6 +16,13 @@
package android.net;
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.ROAMING_NO;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLong;
import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLong;
import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
@@ -110,7 +117,8 @@
// record data into narrow window to get single bucket
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
assertEquals(1, stats.size());
assertValues(stats, 0, SECOND_IN_MILLIS, 1024L, 10L, 2048L, 20L, 2L);
@@ -124,7 +132,8 @@
// split equally across two buckets
final long recordStart = TEST_START + (bucketDuration / 2);
stats.recordData(recordStart, recordStart + bucketDuration,
- new NetworkStats.Entry(1024L, 10L, 128L, 2L, 2L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 128L, 2L, 2L));
assertEquals(2, stats.size());
assertValues(stats, 0, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
@@ -141,7 +150,8 @@
final long recordStart = (TEST_START + BUCKET_SIZE) - MINUTE_IN_MILLIS;
final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4);
stats.recordData(recordStart, recordEnd,
- new NetworkStats.Entry(1000L, 2000L, 5000L, 10000L, 100L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1000L, 2000L, 5000L, 10000L, 100L));
assertEquals(3, stats.size());
// first bucket should have (1/20 of value)
@@ -161,9 +171,11 @@
final long firstStart = TEST_START;
final long lastStart = TEST_START + WEEK_IN_MILLIS;
stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS,
- new NetworkStats.Entry(128L, 2L, 256L, 4L, 1L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 128L, 2L, 256L, 4L, 1L));
stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS,
- new NetworkStats.Entry(64L, 1L, 512L, 8L, 2L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 64L, 1L, 512L, 8L, 2L));
// we should have two buckets, far apart from each other
assertEquals(2, stats.size());
@@ -174,7 +186,8 @@
final long middleStart = TEST_START + DAY_IN_MILLIS;
final long middleEnd = middleStart + (HOUR_IN_MILLIS * 2);
stats.recordData(middleStart, middleEnd,
- new NetworkStats.Entry(2048L, 4L, 2048L, 4L, 2L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 2048L, 4L, 2048L, 4L, 2L));
// now should have four buckets, with new record in middle two buckets
assertEquals(4, stats.size());
@@ -191,10 +204,12 @@
// record some data in one bucket, and another overlapping buckets
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
- new NetworkStats.Entry(256L, 2L, 256L, 2L, 1L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 256L, 2L, 256L, 2L, 1L));
final long midStart = TEST_START + (HOUR_IN_MILLIS / 2);
stats.recordData(midStart, midStart + HOUR_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 1024L, 10L, 10L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 1024L, 10L, 10L));
// should have two buckets, with some data mixed together
assertEquals(2, stats.size());
@@ -371,9 +386,11 @@
MINUTE_IN_MILLIS, 0, FIELD_RX_BYTES | FIELD_TX_BYTES);
history.recordData(0, MINUTE_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 4L));
history.recordData(0, 2 * MINUTE_IN_MILLIS,
- new NetworkStats.Entry(2L, 2L, 2L, 2L, 2L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 2L, 2L, 2L, 2L, 2L));
assertFullValues(history, UNKNOWN, 1026L, UNKNOWN, 2050L, UNKNOWN, UNKNOWN);
}
@@ -385,7 +402,8 @@
MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
full.recordData(0, MINUTE_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 4L));
partial.recordEntireHistory(full);
assertFullValues(partial, UNKNOWN, UNKNOWN, 10L, UNKNOWN, UNKNOWN, 4L);
@@ -398,7 +416,8 @@
MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
partial.recordData(0, MINUTE_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 4L));
full.recordEntireHistory(partial);
assertFullValues(full, MINUTE_IN_MILLIS, 0L, 10L, 0L, 0L, 4L);
@@ -408,9 +427,11 @@
public void testSerialize() throws Exception {
final NetworkStatsHistory before = new NetworkStatsHistory(MINUTE_IN_MILLIS, 40, FIELD_ALL);
before.recordData(0, 4 * MINUTE_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 4L));
before.recordData(DAY_IN_MILLIS, DAY_IN_MILLIS + MINUTE_IN_MILLIS,
- new NetworkStats.Entry(10L, 20L, 30L, 40L, 50L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 10L, 20L, 30L, 40L, 50L));
final ByteArrayOutputStream out = new ByteArrayOutputStream();
before.writeToStream(new DataOutputStream(out));
@@ -451,11 +472,14 @@
final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
stats.recordData(FIRST_START, FIRST_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
stats.recordData(SECOND_START, SECOND_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
stats.recordData(THIRD_START, THIRD_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
// should have buckets: 2+1+2
assertEquals(5, stats.size());
@@ -494,11 +518,14 @@
final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
stats.recordData(FIRST_START, FIRST_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
stats.recordData(SECOND_START, SECOND_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
stats.recordData(THIRD_START, THIRD_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
assertFalse(stats.intersects(10, 20));
assertFalse(stats.intersects(TEST_START + YEAR_IN_MILLIS, TEST_START + YEAR_IN_MILLIS + 1));
@@ -520,7 +547,8 @@
public void testSetValues() throws Exception {
stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
stats.recordData(TEST_START, TEST_START + 1,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L));
assertEquals(1024L + 2048L, stats.getTotalBytes());
diff --git a/tests/unit/java/android/net/NetworkStatsTest.java b/tests/unit/java/android/net/NetworkStatsTest.java
index 6d79869..709b722 100644
--- a/tests/unit/java/android/net/NetworkStatsTest.java
+++ b/tests/unit/java/android/net/NetworkStatsTest.java
@@ -960,7 +960,7 @@
// Ipv4 traffic sent/received by an app on stacked interface.
final NetworkStats.Entry appEntry = new NetworkStats.Entry(
- v4Iface, appUid, SET_DEFAULT, TAG_NONE,
+ v4Iface, appUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
30501490 /* rxBytes */,
22401 /* rxPackets */,
876235 /* txBytes */,
@@ -969,7 +969,8 @@
// Traffic measured for the root uid on the base interface.
final NetworkStats.Entry rootUidEntry = new NetworkStats.Entry(
- baseIface, rootUid, SET_DEFAULT, TAG_NONE,
+ baseIface, rootUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO,
163577 /* rxBytes */,
187 /* rxPackets */,
17607 /* txBytes */,
@@ -977,7 +978,8 @@
0 /* operations */);
final NetworkStats.Entry otherEntry = new NetworkStats.Entry(
- otherIface, appUid, SET_DEFAULT, TAG_NONE,
+ otherIface, appUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO,
2600 /* rxBytes */,
2 /* rxPackets */,
3800 /* txBytes */,
@@ -993,14 +995,14 @@
assertEquals(3, stats.size());
final NetworkStats.Entry expectedAppUid = new NetworkStats.Entry(
- v4Iface, appUid, SET_DEFAULT, TAG_NONE,
+ v4Iface, appUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
30949510,
22401,
1152335,
13805,
0);
final NetworkStats.Entry expectedRootUid = new NetworkStats.Entry(
- baseIface, 0, SET_DEFAULT, TAG_NONE,
+ baseIface, 0, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
163577,
187,
17607,
@@ -1014,14 +1016,16 @@
@Test
public void testApply464xlatAdjustments_noStackedIface() {
NetworkStats.Entry firstEntry = new NetworkStats.Entry(
- "if1", 10002, SET_DEFAULT, TAG_NONE,
+ "if1", 10002, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO,
2600 /* rxBytes */,
2 /* rxPackets */,
3800 /* txBytes */,
3 /* txPackets */,
0 /* operations */);
NetworkStats.Entry secondEntry = new NetworkStats.Entry(
- "if2", 10002, SET_DEFAULT, TAG_NONE,
+ "if2", 10002, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO,
5000 /* rxBytes */,
3 /* rxPackets */,
6000 /* txBytes */,
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index d6c8741..f8e70c4 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -241,6 +241,7 @@
import android.net.ConnectivityThread;
import android.net.DataStallReportParcelable;
import android.net.EthernetManager;
+import android.net.EthernetNetworkSpecifier;
import android.net.IConnectivityDiagnosticsCallback;
import android.net.IDnsResolver;
import android.net.INetd;
@@ -428,6 +429,7 @@
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Matcher;
@@ -922,9 +924,6 @@
private int mProbesSucceeded;
private String mNmValidationRedirectUrl = null;
private boolean mNmProvNotificationRequested = false;
- private Runnable mCreatedCallback;
- private Runnable mUnwantedCallback;
- private Runnable mDisconnectedCallback;
private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
// Contains the redirectUrl from networkStatus(). Before reading, wait for
@@ -932,22 +931,34 @@
private String mRedirectUrl;
TestNetworkAgentWrapper(int transport) throws Exception {
- this(transport, new LinkProperties(), null /* ncTemplate */, null /* provider */);
+ this(transport, new LinkProperties(), null /* ncTemplate */, null /* provider */, null);
}
TestNetworkAgentWrapper(int transport, LinkProperties linkProperties)
throws Exception {
- this(transport, linkProperties, null /* ncTemplate */, null /* provider */);
+ this(transport, linkProperties, null /* ncTemplate */, null /* provider */, null);
}
private TestNetworkAgentWrapper(int transport, LinkProperties linkProperties,
NetworkCapabilities ncTemplate) throws Exception {
- this(transport, linkProperties, ncTemplate, null /* provider */);
+ this(transport, linkProperties, ncTemplate, null /* provider */, null);
}
private TestNetworkAgentWrapper(int transport, LinkProperties linkProperties,
NetworkCapabilities ncTemplate, NetworkProvider provider) throws Exception {
- super(transport, linkProperties, ncTemplate, provider, mServiceContext);
+ this(transport, linkProperties, ncTemplate, provider /* provider */, null);
+ }
+
+ private TestNetworkAgentWrapper(int transport, NetworkAgentWrapper.Callbacks callbacks)
+ throws Exception {
+ this(transport, new LinkProperties(), null /* ncTemplate */, null /* provider */,
+ callbacks);
+ }
+
+ private TestNetworkAgentWrapper(int transport, LinkProperties linkProperties,
+ NetworkCapabilities ncTemplate, NetworkProvider provider,
+ NetworkAgentWrapper.Callbacks callbacks) throws Exception {
+ super(transport, linkProperties, ncTemplate, provider, callbacks, mServiceContext);
// Waits for the NetworkAgent to be registered, which includes the creation of the
// NetworkMonitor.
@@ -968,23 +979,6 @@
mNetworkStatusReceived.open();
}
- @Override
- public void onNetworkCreated() {
- super.onNetworkCreated();
- if (mCreatedCallback != null) mCreatedCallback.run();
- }
-
- @Override
- public void onNetworkUnwanted() {
- super.onNetworkUnwanted();
- if (mUnwantedCallback != null) mUnwantedCallback.run();
- }
-
- @Override
- public void onNetworkDestroyed() {
- super.onNetworkDestroyed();
- if (mDisconnectedCallback != null) mDisconnectedCallback.run();
- }
}
@Override
@@ -1214,18 +1208,6 @@
p.timestampMillis = DATA_STALL_TIMESTAMP;
mNmCallbacks.notifyDataStallSuspected(p);
}
-
- public void setCreatedCallback(Runnable r) {
- mCreatedCallback = r;
- }
-
- public void setUnwantedCallback(Runnable r) {
- mUnwantedCallback = r;
- }
-
- public void setDisconnectedCallback(Runnable r) {
- mDisconnectedCallback = r;
- }
}
/**
@@ -3565,37 +3547,35 @@
final NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_WIFI).build();
final TestNetworkCallback callback = new TestNetworkCallback();
- final AtomicReference<Network> wifiNetwork = new AtomicReference<>();
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
// Expectations for state when various callbacks fire. These expectations run on the handler
// thread and not on the test thread because they need to prevent the handler thread from
// advancing while they examine state.
// 1. When onCreated fires, netd has been told to create the network.
- mWiFiNetworkAgent.setCreatedCallback(() -> {
+ final Consumer<NetworkAgent> onNetworkCreated = (agent) -> {
eventOrder.offer("onNetworkCreated");
- wifiNetwork.set(mWiFiNetworkAgent.getNetwork());
- assertNotNull(wifiNetwork.get());
try {
verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- wifiNetwork.get().getNetId(), INetd.PERMISSION_NONE));
+ agent.getNetwork().getNetId(), INetd.PERMISSION_NONE));
} catch (RemoteException impossible) {
fail();
}
- });
+ };
// 2. onNetworkUnwanted isn't precisely ordered with respect to any particular events. Just
// check that it is fired at some point after disconnect.
- mWiFiNetworkAgent.setUnwantedCallback(() -> eventOrder.offer("onNetworkUnwanted"));
+ final Consumer<NetworkAgent> onNetworkUnwanted = (agent) -> {
+ eventOrder.offer("onNetworkUnwanted");
+ };
// 3. While the teardown timer is running, connectivity APIs report the network is gone, but
// netd has not yet been told to destroy it.
- final Runnable duringTeardown = () -> {
+ final Consumer<Network> duringTeardown = (network) -> {
eventOrder.offer("timePasses");
- assertNull(mCm.getLinkProperties(wifiNetwork.get()));
+ assertNull(mCm.getLinkProperties(network));
try {
- verify(mMockNetd, never()).networkDestroy(wifiNetwork.get().getNetId());
+ verify(mMockNetd, never()).networkDestroy(network.getNetId());
} catch (RemoteException impossible) {
fail();
}
@@ -3603,15 +3583,20 @@
// 4. After onNetworkDisconnected is called, connectivity APIs report the network is gone,
// and netd has been told to destroy it.
- mWiFiNetworkAgent.setDisconnectedCallback(() -> {
+ final Consumer<NetworkAgent> onNetworkDisconnected = (agent) -> {
eventOrder.offer("onNetworkDisconnected");
- assertNull(mCm.getLinkProperties(wifiNetwork.get()));
+ assertNull(mCm.getLinkProperties(agent.getNetwork()));
try {
- verify(mMockNetd).networkDestroy(wifiNetwork.get().getNetId());
+ verify(mMockNetd).networkDestroy(agent.getNetwork().getNetId());
} catch (RemoteException impossible) {
fail();
}
- });
+ };
+
+ final NetworkAgentWrapper.Callbacks callbacks = new NetworkAgentWrapper.Callbacks(
+ onNetworkCreated, onNetworkUnwanted, onNetworkDisconnected);
+
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, callbacks);
// Connect a network, and file a request for it after it has come up, to ensure the nascent
// timer is cleared and the test does not have to wait for it. Filing the request after the
@@ -3633,7 +3618,7 @@
// down the network and started the teardown timer, and short enough that the lambda is
// scheduled to run before the teardown timer.
final Handler h = new Handler(mCsHandlerThread.getLooper());
- h.postDelayed(duringTeardown, 150);
+ h.postDelayed(() -> duringTeardown.accept(mWiFiNetworkAgent.getNetwork()), 150);
// Disconnect the network and check that events happened in the right order.
mCm.unregisterNetworkCallback(callback);
@@ -8548,8 +8533,7 @@
// Enable always-on VPN lockdown. The main user loses network access because no VPN is up.
final ArrayList<String> allowList = new ArrayList<>();
- mVpnManagerService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE,
- true /* lockdown */, allowList);
+ mMockVpn.setAlwaysOnPackage(ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
waitForIdle();
assertNull(mCm.getActiveNetworkForUid(uid));
// This is arguably overspecified: a UID that is not running doesn't have an active network.
@@ -8581,8 +8565,7 @@
assertNull(mCm.getActiveNetworkForUid(uid));
assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
- mVpnManagerService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */,
- allowList);
+ mMockVpn.setAlwaysOnPackage(null, false /* lockdown */, allowList);
waitForIdle();
}
@@ -9040,10 +9023,8 @@
new Handler(ConnectivityThread.getInstanceLooper()));
final int uid = Process.myUid();
- final int userId = UserHandle.getUserId(uid);
final ArrayList<String> allowList = new ArrayList<>();
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
- allowList);
+ mMockVpn.setAlwaysOnPackage(ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
waitForIdle();
final Set<Integer> excludedUids = new ArraySet<Integer>();
@@ -9073,7 +9054,7 @@
assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
// Disable lockdown, expect to see the network unblocked.
- mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ mMockVpn.setAlwaysOnPackage(null, false /* lockdown */, allowList);
callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
vpnUidCallback.assertNoCallback();
@@ -9088,8 +9069,7 @@
// Add our UID to the allowlist and re-enable lockdown, expect network is not blocked.
allowList.add(TEST_PACKAGE_NAME);
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
- allowList);
+ mMockVpn.setAlwaysOnPackage(ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
callback.assertNoCallback();
defaultCallback.assertNoCallback();
vpnUidCallback.assertNoCallback();
@@ -9127,12 +9107,11 @@
// Disable lockdown, remove our UID from the allowlist, and re-enable lockdown.
// Everything should now be blocked.
- mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ mMockVpn.setAlwaysOnPackage(null, false /* lockdown */, allowList);
waitForIdle();
expectNetworkRejectNonSecureVpn(inOrder, false, uidRangeParcelsAlsoExcludingUs);
allowList.clear();
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
- allowList);
+ mMockVpn.setAlwaysOnPackage(ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
waitForIdle();
expectNetworkRejectNonSecureVpn(inOrder, true, uidRangeParcels);
defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
@@ -9147,7 +9126,7 @@
assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
// Disable lockdown. Everything is unblocked.
- mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ mMockVpn.setAlwaysOnPackage(null, false /* lockdown */, allowList);
defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
assertBlockedCallbackInAnyOrder(callback, false, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();
@@ -9161,8 +9140,7 @@
// Enable and disable an always-on VPN package without lockdown. Expect no changes.
reset(mMockNetd);
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, false /* lockdown */,
- allowList);
+ mMockVpn.setAlwaysOnPackage(ALWAYS_ON_PACKAGE, false /* lockdown */, allowList);
inOrder.verify(mMockNetd, never()).networkRejectNonSecureVpn(anyBoolean(), any());
callback.assertNoCallback();
defaultCallback.assertNoCallback();
@@ -9175,7 +9153,7 @@
assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ mMockVpn.setAlwaysOnPackage(null, false /* lockdown */, allowList);
inOrder.verify(mMockNetd, never()).networkRejectNonSecureVpn(anyBoolean(), any());
callback.assertNoCallback();
defaultCallback.assertNoCallback();
@@ -9189,8 +9167,7 @@
assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
// Enable lockdown and connect a VPN. The VPN is not blocked.
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
- allowList);
+ mMockVpn.setAlwaysOnPackage(ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();
@@ -15724,6 +15701,45 @@
mCm.unregisterNetworkCallback(cb);
}
+ @Test
+ public void testSanitizedCapabilitiesFromAgentDoesNotMutateArgument()
+ throws Exception {
+ // This NetworkCapabilities builds an usual object to maximize the chance that this requires
+ // sanitization, so we have a high chance to detect any changes to the original.
+ final NetworkCapabilities unsanitized = new NetworkCapabilities.Builder()
+ .withoutDefaultCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .setOwnerUid(12345)
+ .setAdministratorUids(new int[] {12345, 23456, 34567})
+ .setLinkUpstreamBandwidthKbps(20)
+ .setLinkDownstreamBandwidthKbps(10)
+ .setNetworkSpecifier(new EthernetNetworkSpecifier("foobar"))
+ .setTransportInfo(new WifiInfo.Builder().setBssid("AA:AA:AA:AA:AA:AA").build())
+ .setSignalStrength(-75)
+ .setSsid("SSID1")
+ .setRequestorUid(98765)
+ .setRequestorPackageName("TestPackage")
+ .setSubscriptionIds(Collections.singleton(Process.myUid()))
+ .setUids(UidRange.toIntRanges(uidRangesForUids(
+ UserHandle.getUid(PRIMARY_USER, 10100),
+ UserHandle.getUid(SECONDARY_USER, 10101),
+ UserHandle.getUid(TERTIARY_USER, 10043))))
+ .setAllowedUids(Set.of(45678, 56789, 65432))
+ .setUnderlyingNetworks(List.of(new Network(99999)))
+ .build();
+ final NetworkCapabilities copyOfUnsanitized = new NetworkCapabilities(unsanitized);
+ final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE,
+ ConnectivityManager.getNetworkTypeName(TYPE_MOBILE),
+ TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
+ final NetworkAgentInfo agent = fakeNai(unsanitized, info);
+ agent.setDeclaredCapabilities(unsanitized);
+ final NetworkCapabilities sanitized = agent.getDeclaredCapabilitiesSanitized(
+ null /* carrierPrivilegeAuthenticator */);
+ assertEquals(copyOfUnsanitized, unsanitized);
+ assertNotEquals(sanitized, unsanitized);
+ }
+
/**
* Validate request counts are counted accurately on setProfileNetworkPreference on set/replace.
*/
diff --git a/tests/unit/java/com/android/server/VpnManagerServiceTest.java b/tests/unit/java/com/android/server/VpnManagerServiceTest.java
index c814cc5..c8a93a6 100644
--- a/tests/unit/java/com/android/server/VpnManagerServiceTest.java
+++ b/tests/unit/java/com/android/server/VpnManagerServiceTest.java
@@ -22,7 +22,11 @@
import static com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import static com.android.testutils.MiscAsserts.assertThrows;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
@@ -44,10 +48,14 @@
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
+import android.security.Credentials;
import androidx.test.filters.SmallTest;
+import com.android.internal.net.VpnProfile;
import com.android.server.connectivity.Vpn;
+import com.android.server.connectivity.VpnProfileStore;
+import com.android.server.net.LockdownVpnTracker;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
import com.android.testutils.HandlerUtils;
@@ -60,6 +68,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
@RunWith(DevSdkIgnoreRunner.class)
@IgnoreUpTo(R) // VpnManagerService is not available before R
@SmallTest
@@ -79,6 +90,8 @@
@Mock private UserManager mUserManager;
@Mock private INetd mNetd;
@Mock private PackageManager mPackageManager;
+ @Mock private VpnProfileStore mVpnProfileStore;
+ @Mock private LockdownVpnTracker mLockdownVpnTracker;
private VpnManagerServiceDependencies mDeps;
private VpnManagerService mService;
@@ -107,6 +120,17 @@
INetd netd, @UserIdInt int userId) {
return mVpn;
}
+
+ @Override
+ public VpnProfileStore getVpnProfileStore() {
+ return mVpnProfileStore;
+ }
+
+ @Override
+ public LockdownVpnTracker createLockDownVpnTracker(Context context, Handler handler,
+ Vpn vpn, VpnProfile profile) {
+ return mLockdownVpnTracker;
+ }
}
@Before
@@ -203,10 +227,14 @@
}
private void sendIntent(Intent intent) {
+ sendIntent(mIntentReceiver, mContext, intent);
+ }
+
+ private void sendIntent(BroadcastReceiver receiver, Context context, Intent intent) {
final Handler h = mHandlerThread.getThreadHandler();
// Send in handler thread.
- h.post(() -> mIntentReceiver.onReceive(mContext, intent));
+ h.post(() -> receiver.onReceive(context, intent));
HandlerUtils.waitForIdle(mHandlerThread, TIMEOUT_MS);
}
@@ -215,6 +243,21 @@
null /* packageName */, userId, -1 /* uid */, false /* isReplacing */));
}
+ private void onUserUnlocked(int userId) {
+ sendIntent(buildIntent(Intent.ACTION_USER_UNLOCKED,
+ null /* packageName */, userId, -1 /* uid */, false /* isReplacing */));
+ }
+
+ private void onUserStopped(int userId) {
+ sendIntent(buildIntent(Intent.ACTION_USER_STOPPED,
+ null /* packageName */, userId, -1 /* uid */, false /* isReplacing */));
+ }
+
+ private void onLockDownReset() {
+ sendIntent(buildIntent(LockdownVpnTracker.ACTION_LOCKDOWN_RESET, null /* packageName */,
+ UserHandle.USER_SYSTEM, -1 /* uid */, false /* isReplacing */));
+ }
+
private void onPackageAdded(String packageName, int userId, int uid, boolean isReplacing) {
sendIntent(buildIntent(Intent.ACTION_PACKAGE_ADDED, packageName, userId, uid, isReplacing));
}
@@ -241,4 +284,111 @@
assertThrows(IllegalStateException.class, () ->
mUserPresentReceiver.onReceive(mContext, new Intent(Intent.ACTION_USER_PRESENT)));
}
+
+ private void setupLockdownVpn(String packageName) {
+ final byte[] profileTag = packageName.getBytes(StandardCharsets.UTF_8);
+ doReturn(profileTag).when(mVpnProfileStore).get(Credentials.LOCKDOWN_VPN);
+ }
+
+ private void setupVpnProfile(String profileName) {
+ final VpnProfile profile = new VpnProfile(profileName);
+ profile.name = profileName;
+ profile.server = "192.0.2.1";
+ profile.dnsServers = "8.8.8.8";
+ profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK;
+ final byte[] encodedProfile = profile.encode();
+ doReturn(encodedProfile).when(mVpnProfileStore).get(Credentials.VPN + profileName);
+ }
+
+ @Test
+ public void testUserPresent() {
+ // Verify that LockDownVpnTracker is not created.
+ verify(mLockdownVpnTracker, never()).init();
+
+ setupLockdownVpn(TEST_VPN_PKG);
+ setupVpnProfile(TEST_VPN_PKG);
+
+ // mUserPresentReceiver only registers ACTION_USER_PRESENT intent and does no verification
+ // on action, so an empty intent is enough.
+ sendIntent(mUserPresentReceiver, mSystemContext, new Intent());
+
+ verify(mLockdownVpnTracker).init();
+ verify(mSystemContext).unregisterReceiver(mUserPresentReceiver);
+ verify(mUserAllContext, never()).unregisterReceiver(any());
+ }
+
+ @Test
+ public void testUpdateLockdownVpn() {
+ setupLockdownVpn(TEST_VPN_PKG);
+ onUserUnlocked(SYSTEM_USER_ID);
+
+ // Will not create lockDownVpnTracker w/o valid profile configured in the keystore
+ verify(mLockdownVpnTracker, never()).init();
+
+ setupVpnProfile(TEST_VPN_PKG);
+
+ // Remove the user from mVpns
+ onUserStopped(SYSTEM_USER_ID);
+ onUserUnlocked(SYSTEM_USER_ID);
+ verify(mLockdownVpnTracker, never()).init();
+
+ // Add user back
+ onUserStarted(SYSTEM_USER_ID);
+ verify(mLockdownVpnTracker).init();
+
+ // Trigger another update. The existing LockDownVpnTracker should be shut down and
+ // initialize another one.
+ onUserUnlocked(SYSTEM_USER_ID);
+ verify(mLockdownVpnTracker).shutdown();
+ verify(mLockdownVpnTracker, times(2)).init();
+ }
+
+ @Test
+ public void testLockdownReset() {
+ // Init LockdownVpnTracker
+ setupLockdownVpn(TEST_VPN_PKG);
+ setupVpnProfile(TEST_VPN_PKG);
+ onUserUnlocked(SYSTEM_USER_ID);
+ verify(mLockdownVpnTracker).init();
+
+ onLockDownReset();
+ verify(mLockdownVpnTracker).reset();
+ }
+
+ @Test
+ public void testLockdownResetWhenLockdownVpnTrackerIsNotInit() {
+ setupLockdownVpn(TEST_VPN_PKG);
+ setupVpnProfile(TEST_VPN_PKG);
+
+ onLockDownReset();
+
+ // LockDownVpnTracker is not created. Lockdown reset will not take effect.
+ verify(mLockdownVpnTracker, never()).reset();
+ }
+
+ @Test
+ public void testIsVpnLockdownEnabled() {
+ // Vpn is created but the VPN lockdown is not enabled.
+ assertFalse(mService.isVpnLockdownEnabled(SYSTEM_USER_ID));
+
+ // Set lockdown for the SYSTEM_USER_ID VPN.
+ doReturn(true).when(mVpn).getLockdown();
+ assertTrue(mService.isVpnLockdownEnabled(SYSTEM_USER_ID));
+
+ // Even lockdown is enabled but no Vpn is created for SECONDARY_USER.
+ assertFalse(mService.isVpnLockdownEnabled(SECONDARY_USER.id));
+ }
+
+ @Test
+ public void testGetVpnLockdownAllowlist() {
+ doReturn(null).when(mVpn).getLockdownAllowlist();
+ assertNull(mService.getVpnLockdownAllowlist(SYSTEM_USER_ID));
+
+ final List<String> expected = List.of(PKGS);
+ doReturn(expected).when(mVpn).getLockdownAllowlist();
+ assertEquals(expected, mService.getVpnLockdownAllowlist(SYSTEM_USER_ID));
+
+ // Even lockdown is enabled but no Vpn is created for SECONDARY_USER.
+ assertNull(mService.getVpnLockdownAllowlist(SECONDARY_USER.id));
+ }
}
diff --git a/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt b/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt
index c03a9cd..a194131 100644
--- a/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt
@@ -18,6 +18,8 @@
import android.net.NetworkAgentConfig
import android.net.NetworkCapabilities
+import android.net.NetworkScore
+import android.net.NetworkScore.KEEP_CONNECTED_FOR_HANDOVER
import android.net.NetworkScore.KEEP_CONNECTED_NONE
import android.os.Build
import android.text.TextUtils
@@ -25,6 +27,7 @@
import android.util.Log
import androidx.test.filters.SmallTest
import com.android.server.connectivity.FullScore.MAX_CS_MANAGED_POLICY
+import com.android.server.connectivity.FullScore.MIN_CS_MANAGED_POLICY
import com.android.server.connectivity.FullScore.POLICY_ACCEPT_UNVALIDATED
import com.android.server.connectivity.FullScore.POLICY_EVER_USER_SELECTED
import com.android.server.connectivity.FullScore.POLICY_IS_DESTROYED
@@ -40,6 +43,7 @@
import kotlin.reflect.full.staticProperties
import kotlin.test.assertEquals
import kotlin.test.assertFalse
+import kotlin.test.assertNotEquals
import kotlin.test.assertTrue
@RunWith(DevSdkIgnoreRunner::class)
@@ -83,33 +87,10 @@
}
@Test
- fun testGetLegacyInt() {
- val ns = FullScore(50, 0L /* policy */, KEEP_CONNECTED_NONE)
- assertEquals(10, ns.legacyInt) // -40 penalty for not being validated
- assertEquals(50, ns.legacyIntAsValidated)
-
- val vpnNs = FullScore(101, 0L /* policy */, KEEP_CONNECTED_NONE).withPolicies(vpn = true)
- assertEquals(101, vpnNs.legacyInt) // VPNs are not subject to unvalidation penalty
- assertEquals(101, vpnNs.legacyIntAsValidated)
- assertEquals(101, vpnNs.withPolicies(validated = true).legacyInt)
- assertEquals(101, vpnNs.withPolicies(validated = true).legacyIntAsValidated)
-
- val validatedNs = ns.withPolicies(validated = true)
- assertEquals(50, validatedNs.legacyInt) // No penalty, this is validated
- assertEquals(50, validatedNs.legacyIntAsValidated)
-
- val chosenNs = ns.withPolicies(onceChosen = true)
- assertEquals(10, chosenNs.legacyInt)
- assertEquals(100, chosenNs.legacyIntAsValidated)
- assertEquals(10, chosenNs.withPolicies(acceptUnvalidated = true).legacyInt)
- assertEquals(50, chosenNs.withPolicies(acceptUnvalidated = true).legacyIntAsValidated)
- }
-
- @Test
fun testToString() {
- val string = FullScore(10, 0L /* policy */, KEEP_CONNECTED_NONE)
+ val string = FullScore(0L /* policy */, KEEP_CONNECTED_NONE)
.withPolicies(vpn = true, acceptUnvalidated = true).toString()
- assertTrue(string.contains("Score(10"), string)
+ assertTrue(string.contains("Score("), string)
assertTrue(string.contains("ACCEPT_UNVALIDATED"), string)
assertTrue(string.contains("IS_VPN"), string)
assertFalse(string.contains("IS_VALIDATED"), string)
@@ -131,7 +112,7 @@
@Test
fun testHasPolicy() {
- val ns = FullScore(50, 0L /* policy */, KEEP_CONNECTED_NONE)
+ val ns = FullScore(0L /* policy */, KEEP_CONNECTED_NONE)
assertFalse(ns.hasPolicy(POLICY_IS_VALIDATED))
assertFalse(ns.hasPolicy(POLICY_IS_VPN))
assertFalse(ns.hasPolicy(POLICY_EVER_USER_SELECTED))
@@ -148,12 +129,23 @@
val policies = getAllPolicies()
policies.forEach { policy ->
- assertTrue(policy.get() as Int >= FullScore.MIN_CS_MANAGED_POLICY)
- assertTrue(policy.get() as Int <= FullScore.MAX_CS_MANAGED_POLICY)
+ assertTrue(policy.get() as Int >= MIN_CS_MANAGED_POLICY)
+ assertTrue(policy.get() as Int <= MAX_CS_MANAGED_POLICY)
}
- assertEquals(FullScore.MIN_CS_MANAGED_POLICY,
- policies.minOfOrNull { it.get() as Int })
- assertEquals(FullScore.MAX_CS_MANAGED_POLICY,
- policies.maxOfOrNull { it.get() as Int })
+ assertEquals(MIN_CS_MANAGED_POLICY, policies.minOfOrNull { it.get() as Int })
+ assertEquals(MAX_CS_MANAGED_POLICY, policies.maxOfOrNull { it.get() as Int })
+ }
+
+ @Test
+ fun testEquals() {
+ val ns1 = FullScore(0L /* policy */, KEEP_CONNECTED_NONE)
+ val ns2 = FullScore(0L /* policy */, KEEP_CONNECTED_NONE)
+ val ns3 = FullScore(0L /* policy */, KEEP_CONNECTED_FOR_HANDOVER)
+ val ns4 = NetworkScore.Builder().setLegacyInt(50).build()
+ assertEquals(ns1, ns1)
+ assertEquals(ns2, ns1)
+ assertNotEquals(ns1.withPolicies(validated = true), ns1)
+ assertNotEquals(ns3, ns1)
+ assertFalse(ns1.equals(ns4))
}
}
diff --git a/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 063ccd3..ad8613f 100644
--- a/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -138,18 +138,16 @@
private void logDefaultNetworkEvent(long timeMs, NetworkAgentInfo nai,
NetworkAgentInfo oldNai) {
final Network network = (nai != null) ? nai.network() : null;
- final int score = (nai != null) ? nai.getCurrentScore() : 0;
final boolean validated = (nai != null) ? nai.lastValidated : false;
final LinkProperties lp = (nai != null) ? nai.linkProperties : null;
final NetworkCapabilities nc = (nai != null) ? nai.networkCapabilities : null;
final Network prevNetwork = (oldNai != null) ? oldNai.network() : null;
- final int prevScore = (oldNai != null) ? oldNai.getCurrentScore() : 0;
final LinkProperties prevLp = (oldNai != null) ? oldNai.linkProperties : null;
final NetworkCapabilities prevNc = (oldNai != null) ? oldNai.networkCapabilities : null;
- mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, network, score, validated,
- lp, nc, prevNetwork, prevScore, prevLp, prevNc);
+ mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, network, 0 /* legacyScore */,
+ validated, lp, nc, prevNetwork, 0 /* prevLegacyScore */, prevLp, prevNc);
}
@Test
public void testDefaultNetworkEvents() throws Exception {
@@ -158,15 +156,15 @@
NetworkAgentInfo[][] defaultNetworks = {
// nothing -> cell
- {null, makeNai(100, 10, false, true, cell)},
+ {null, makeNai(100, false, true, cell)},
// cell -> wifi
- {makeNai(100, 50, true, true, cell), makeNai(101, 20, true, false, wifi)},
+ {makeNai(100, true, true, cell), makeNai(101, true, false, wifi)},
// wifi -> nothing
- {makeNai(101, 60, true, false, wifi), null},
+ {makeNai(101, true, false, wifi), null},
// nothing -> cell
- {null, makeNai(102, 10, true, true, cell)},
+ {null, makeNai(102, true, true, cell)},
// cell -> wifi
- {makeNai(102, 50, true, true, cell), makeNai(103, 20, true, false, wifi)},
+ {makeNai(102, true, true, cell), makeNai(103, true, false, wifi)},
};
long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
@@ -204,8 +202,8 @@
" transports: 1",
" default_network_event <",
" default_network_duration_ms: 2002",
- " final_score: 50",
- " initial_score: 10",
+ " final_score: 0",
+ " initial_score: 0",
" ip_support: 3",
" no_default_network_duration_ms: 0",
" previous_default_network_link_layer: 0",
@@ -221,8 +219,8 @@
" transports: 2",
" default_network_event <",
" default_network_duration_ms: 4004",
- " final_score: 60",
- " initial_score: 20",
+ " final_score: 0",
+ " initial_score: 0",
" ip_support: 1",
" no_default_network_duration_ms: 0",
" previous_default_network_link_layer: 2",
@@ -255,8 +253,8 @@
" transports: 1",
" default_network_event <",
" default_network_duration_ms: 16016",
- " final_score: 50",
- " initial_score: 10",
+ " final_score: 0",
+ " initial_score: 0",
" ip_support: 3",
" no_default_network_duration_ms: 0",
" previous_default_network_link_layer: 4",
@@ -348,8 +346,8 @@
long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
- NetworkAgentInfo cellNai = makeNai(100, 50, false, true, cell);
- NetworkAgentInfo wifiNai = makeNai(101, 60, true, false, wifi);
+ final NetworkAgentInfo cellNai = makeNai(100, false, true, cell);
+ final NetworkAgentInfo wifiNai = makeNai(101, true, false, wifi);
logDefaultNetworkEvent(timeMs + 200L, cellNai, null);
logDefaultNetworkEvent(timeMs + 300L, wifiNai, cellNai);
@@ -463,8 +461,8 @@
" transports: 1",
" default_network_event <",
" default_network_duration_ms: 100",
- " final_score: 50",
- " initial_score: 50",
+ " final_score: 0",
+ " initial_score: 0",
" ip_support: 2",
" no_default_network_duration_ms: 0",
" previous_default_network_link_layer: 0",
@@ -611,10 +609,9 @@
mNetdListener.onWakeupEvent(prefix, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now);
}
- NetworkAgentInfo makeNai(int netId, int score, boolean ipv4, boolean ipv6, long transports) {
+ NetworkAgentInfo makeNai(int netId, boolean ipv4, boolean ipv6, long transports) {
NetworkAgentInfo nai = mock(NetworkAgentInfo.class);
when(nai.network()).thenReturn(new Network(netId));
- when(nai.getCurrentScore()).thenReturn(score);
nai.linkProperties = new LinkProperties();
nai.networkCapabilities = new NetworkCapabilities();
nai.lastValidated = true;
diff --git a/tests/unit/java/com/android/server/connectivity/NetworkOfferTest.kt b/tests/unit/java/com/android/server/connectivity/NetworkOfferTest.kt
index d03c567..f9a0927 100644
--- a/tests/unit/java/com/android/server/connectivity/NetworkOfferTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/NetworkOfferTest.kt
@@ -42,7 +42,7 @@
@Test
fun testOfferNeededUnneeded() {
- val score = FullScore(50, POLICY_NONE, KEEP_CONNECTED_NONE)
+ val score = FullScore(POLICY_NONE, KEEP_CONNECTED_NONE)
val offer = NetworkOffer(score, NetworkCapabilities.Builder().build(), mockCallback,
1 /* providerId */)
val request1 = mock(NetworkRequest::class.java)
diff --git a/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt b/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
index 4408958..6f9f430 100644
--- a/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
@@ -33,7 +33,7 @@
import org.junit.runner.RunWith
import kotlin.test.assertEquals
-private fun score(vararg policies: Int) = FullScore(0,
+private fun score(vararg policies: Int) = FullScore(
policies.fold(0L) { acc, e -> acc or (1L shl e) }, KEEP_CONNECTED_NONE)
private fun caps(transport: Int) = NetworkCapabilities.Builder().addTransportType(transport).build()
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index 484d717..f64e35b 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -16,6 +16,7 @@
package com.android.server.net;
+import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.app.usage.NetworkStatsManager.PREFIX_DEV;
@@ -156,7 +157,10 @@
import org.mockito.MockitoAnnotations;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Clock;
@@ -283,6 +287,7 @@
case PERMISSION_MAINLINE_NETWORK_STACK:
case READ_NETWORK_USAGE_HISTORY:
case UPDATE_DEVICE_STATS:
+ case DUMP:
return PERMISSION_GRANTED;
default:
return PERMISSION_DENIED;
@@ -857,7 +862,7 @@
incrementCurrentTime(MINUTE_IN_MILLIS);
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 12L, 18L, 14L, 1L, 0L)));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12L, 18L, 14L, 1L, 0L)));
forcePollAndWaitForIdle();
// Verify 3g templates gets stats.
@@ -872,10 +877,10 @@
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
// Append more traffic on existing 3g stats entry.
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 16L, 22L, 17L, 2L, 0L))
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 16L, 22L, 17L, 2L, 0L))
// Add entry that is new on 4g.
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
- 33L, 27L, 8L, 10L, 1L)));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 33L, 27L, 8L, 10L, 1L)));
forcePollAndWaitForIdle();
// Verify ALL_MOBILE template gets all. 3g template counters do not increase.
@@ -892,12 +897,12 @@
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
// Existing stats remains.
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 16L, 22L, 17L, 2L, 0L))
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 16L, 22L, 17L, 2L, 0L))
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
- 33L, 27L, 8L, 10L, 1L))
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 33L, 27L, 8L, 10L, 1L))
// Add some traffic on 5g.
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 5L, 13L, 31L, 9L, 2L)));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 5L, 13L, 31L, 9L, 2L)));
forcePollAndWaitForIdle();
// Verify ALL_MOBILE template gets all.
@@ -979,7 +984,7 @@
incrementCurrentTime(MINUTE_IN_MILLIS);
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 36L, 41L, 24L, 96L, 0L)));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 36L, 41L, 24L, 96L, 0L)));
forcePollAndWaitForIdle();
// OEM_PRIVATE network comes online.
@@ -994,7 +999,7 @@
incrementCurrentTime(MINUTE_IN_MILLIS);
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 49L, 71L, 72L, 48L, 0L)));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 49L, 71L, 72L, 48L, 0L)));
forcePollAndWaitForIdle();
// OEM_PAID + OEM_PRIVATE network comes online.
@@ -1010,7 +1015,7 @@
incrementCurrentTime(MINUTE_IN_MILLIS);
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 57L, 86L, 83L, 93L, 0L)));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 57L, 86L, 83L, 93L, 0L)));
forcePollAndWaitForIdle();
// OEM_NONE network comes online.
@@ -1024,7 +1029,7 @@
incrementCurrentTime(MINUTE_IN_MILLIS);
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 29L, 73L, 34L, 31L, 0L)));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 29L, 73L, 34L, 31L, 0L)));
forcePollAndWaitForIdle();
// Verify OEM_PAID template gets only relevant stats.
@@ -1135,7 +1140,8 @@
// Increase arbitrary time which does not align to the bucket edge, create some traffic.
incrementCurrentTime(1751000L);
NetworkStats.Entry entry = new NetworkStats.Entry(
- TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 50L, 5L, 51L, 1L, 3L);
+ TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50L, 5L, 51L, 1L, 3L);
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1).insertEntry(entry));
expectNetworkStatsUidDetail(buildEmptyStats());
forcePollAndWaitForIdle();
@@ -1169,11 +1175,14 @@
new UnderlyingNetworkInfo[0]);
NetworkStats.Entry entry1 = new NetworkStats.Entry(
- TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L);
+ TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50L, 5L, 50L, 5L, 0L);
NetworkStats.Entry entry2 = new NetworkStats.Entry(
- TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 50L, 5L, 50L, 5L, 0L);
+ TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 50L, 5L, 50L, 5L, 0L);
NetworkStats.Entry entry3 = new NetworkStats.Entry(
- TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xBEEF, 1024L, 8L, 512L, 4L, 0L);
+ TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xBEEF, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1024L, 8L, 512L, 4L, 0L);
incrementCurrentTime(HOUR_IN_MILLIS);
expectDefaultSettings();
@@ -1681,7 +1690,7 @@
incrementCurrentTime(MINUTE_IN_MILLIS);
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 12L, 18L, 14L, 1L, 0L)));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12L, 18L, 14L, 1L, 0L)));
forcePollAndWaitForIdle();
// Since CombineSubtypeEnabled is false by default in unit test, the generated traffic
@@ -1705,9 +1714,10 @@
// Append more traffic on existing snapshot.
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 12L + 4L, 18L + 4L, 14L + 3L, 1L + 1L, 0L))
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12L + 4L, 18L + 4L, 14L + 3L,
+ 1L + 1L, 0L))
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
- 35L, 29L, 7L, 11L, 1L)));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 35L, 29L, 7L, 11L, 1L)));
forcePollAndWaitForIdle();
// Verify 3G counters do not increase, while template with unknown RAT type gets new
@@ -1727,9 +1737,9 @@
// Append more traffic on existing snapshot.
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 22L, 26L, 19L, 5L, 0L))
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 22L, 26L, 19L, 5L, 0L))
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
- 35L, 29L, 7L, 11L, 1L)));
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 35L, 29L, 7L, 11L, 1L)));
forcePollAndWaitForIdle();
// Verify traffic is split by RAT type, no increase on template with unknown RAT type
@@ -2317,4 +2327,44 @@
assertTrue(mAppUidStatsMap.containsKey(new UidStatsMapKey(UID_RED)));
assertTrue(mUidCounterSetMap.containsKey(new U32(UID_RED)));
}
+
+ private void assertDumpContains(final String dump, final String message) {
+ assertTrue(String.format("dump(%s) does not contain '%s'", dump, message),
+ dump.contains(message));
+ }
+
+ private String getDump() {
+ final StringWriter sw = new StringWriter();
+ mService.dump(new FileDescriptor(), new PrintWriter(sw), new String[]{});
+ return sw.toString();
+ }
+
+ @Test
+ public void testDumpCookieTagMap() throws ErrnoException {
+ initBpfMapsWithTagData(UID_BLUE);
+
+ final String dump = getDump();
+ assertDumpContains(dump, "mCookieTagMap: OK");
+ assertDumpContains(dump, "cookie=2002 tag=0x1 uid=1002");
+ assertDumpContains(dump, "cookie=3002 tag=0x2 uid=1002");
+ }
+
+ @Test
+ public void testDumpUidCounterSetMap() throws ErrnoException {
+ initBpfMapsWithTagData(UID_BLUE);
+
+ final String dump = getDump();
+ assertDumpContains(dump, "mUidCounterSetMap: OK");
+ assertDumpContains(dump, "uid=1002 set=1");
+ }
+
+ @Test
+ public void testAppUidStatsMap() throws ErrnoException {
+ initBpfMapsWithTagData(UID_BLUE);
+
+ final String dump = getDump();
+ assertDumpContains(dump, "mAppUidStatsMap: OK");
+ assertDumpContains(dump, "uid rxBytes rxPackets txBytes txPackets");
+ assertDumpContains(dump, "1002 10000 10 6000 6");
+ }
}