Fetch tethering offload stats.
Make tethering offload register an ITetheringStatsProvider and
fetch tethering stats from the hardware.
Currently we fetch stats in the following cases:
1. Just after changing upstreams, we fetch stats from the
previous upstream.
2. When we are polled by NetworkStatsService.
Bug: 29337859
Bug: 32163131
Test: builds, boots
Test: stats appear in tethering logs
Change-Id: If744f2e06cb6a3095a40199936b9afb76eff7b56
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index acf9e8f7..a115146 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -178,6 +178,7 @@
mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
mLooper.getLooper(), mSystemProperties,
mTetheringDependencies);
+ verify(mNMService).registerTetheringStatsProvider(any(), anyString());
}
@After
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
index 0e4a36c..dcb9723 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -16,26 +16,38 @@
package com.android.server.connectivity.tethering;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.TrafficStats.UID_TETHERING;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
+import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.net.ITetheringStatsProvider;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NetworkStats;
import android.net.RouteInfo;
import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.INetworkManagementService;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -66,11 +78,14 @@
@Mock private OffloadHardwareInterface mHardware;
@Mock private ApplicationInfo mApplicationInfo;
@Mock private Context mContext;
+ @Mock private INetworkManagementService mNMService;
private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
ArgumentCaptor.forClass(ArrayList.class);
+ private final ArgumentCaptor<ITetheringStatsProvider.Stub> mTetherStatsProviderCaptor =
+ ArgumentCaptor.forClass(ITetheringStatsProvider.Stub.class);
private MockContentResolver mContentResolver;
- @Before public void setUp() throws Exception {
+ @Before public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
when(mContext.getPackageName()).thenReturn("OffloadControllerTest");
@@ -88,14 +103,23 @@
when(mHardware.initOffloadConfig()).thenReturn(true);
when(mHardware.initOffloadControl(any(OffloadHardwareInterface.ControlCallback.class)))
.thenReturn(true);
+ when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats());
}
private void enableOffload() {
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
}
+ private OffloadController makeOffloadController() throws Exception {
+ OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()),
+ mHardware, mContentResolver, mNMService, new SharedLog("test"));
+ verify(mNMService).registerTetheringStatsProvider(
+ mTetherStatsProviderCaptor.capture(), anyString());
+ return offload;
+ }
+
@Test
- public void testNoSettingsValueDefaultDisabledDoesNotStart() {
+ public void testNoSettingsValueDefaultDisabledDoesNotStart() throws Exception {
setupFunctioningHardwareInterface();
when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1);
try {
@@ -103,8 +127,7 @@
fail();
} catch (SettingNotFoundException expected) {}
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -116,7 +139,7 @@
}
@Test
- public void testNoSettingsValueDefaultEnabledDoesStart() {
+ public void testNoSettingsValueDefaultEnabledDoesStart() throws Exception {
setupFunctioningHardwareInterface();
when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0);
try {
@@ -124,8 +147,7 @@
fail();
} catch (SettingNotFoundException expected) {}
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -137,12 +159,11 @@
}
@Test
- public void testSettingsAllowsStart() {
+ public void testSettingsAllowsStart() throws Exception {
setupFunctioningHardwareInterface();
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -154,12 +175,11 @@
}
@Test
- public void testSettingsDisablesStart() {
+ public void testSettingsDisablesStart() throws Exception {
setupFunctioningHardwareInterface();
Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 1);
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -174,8 +194,7 @@
setupFunctioningHardwareInterface();
enableOffload();
- final OffloadController offload =
- new OffloadController(null, mHardware, mContentResolver, new SharedLog("test"));
+ final OffloadController offload = makeOffloadController();
offload.start();
final InOrder inOrder = inOrder(mHardware);
@@ -240,6 +259,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(null), eq(null));
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
inOrder.verifyNoMoreInteractions();
final String ipv4Gateway = "192.0.2.1";
@@ -249,6 +269,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), eq(null));
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
inOrder.verifyNoMoreInteractions();
final String ipv6Gw1 = "fe80::cafe";
@@ -258,6 +279,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
ArrayList<String> v6gws = mStringArrayCaptor.getValue();
assertEquals(1, v6gws.size());
assertTrue(v6gws.contains(ipv6Gw1));
@@ -270,6 +292,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
v6gws = mStringArrayCaptor.getValue();
assertEquals(2, v6gws.size());
assertTrue(v6gws.contains(ipv6Gw1));
@@ -287,6 +310,7 @@
inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
v6gws = mStringArrayCaptor.getValue();
assertEquals(2, v6gws.size());
assertTrue(v6gws.contains(ipv6Gw1));
@@ -321,6 +345,7 @@
assertEquals(2, v6gws.size());
assertTrue(v6gws.contains(ipv6Gw1));
assertTrue(v6gws.contains(ipv6Gw2));
+ inOrder.verify(mHardware, times(1)).getForwardedStats(eq(testIfName));
inOrder.verifyNoMoreInteractions();
// Completely identical LinkProperties updates are de-duped.
@@ -331,4 +356,65 @@
anyObject(), anyObject(), anyObject(), anyObject());
inOrder.verifyNoMoreInteractions();
}
+
+ private void assertNetworkStats(String iface, ForwardedStats stats, NetworkStats.Entry entry) {
+ assertEquals(iface, entry.iface);
+ assertEquals(stats.rxBytes, entry.rxBytes);
+ assertEquals(stats.txBytes, entry.txBytes);
+ assertEquals(SET_DEFAULT, entry.set);
+ assertEquals(TAG_NONE, entry.tag);
+ assertEquals(UID_TETHERING, entry.uid);
+ }
+
+ @Test
+ public void testGetForwardedStats() throws Exception {
+ setupFunctioningHardwareInterface();
+ enableOffload();
+
+ final OffloadController offload = makeOffloadController();
+ offload.start();
+
+ final String ethernetIface = "eth1";
+ final String mobileIface = "rmnet_data0";
+
+ ForwardedStats ethernetStats = new ForwardedStats();
+ ethernetStats.rxBytes = 12345;
+ ethernetStats.txBytes = 54321;
+
+ ForwardedStats mobileStats = new ForwardedStats();
+ mobileStats.rxBytes = 999;
+ mobileStats.txBytes = 99999;
+
+ when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(ethernetStats);
+ when(mHardware.getForwardedStats(eq(mobileIface))).thenReturn(mobileStats);
+
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(ethernetIface);
+ offload.setUpstreamLinkProperties(lp);
+
+ lp.setInterfaceName(mobileIface);
+ offload.setUpstreamLinkProperties(lp);
+
+ lp.setInterfaceName(ethernetIface);
+ offload.setUpstreamLinkProperties(lp);
+
+ ethernetStats.rxBytes = 100000;
+ ethernetStats.txBytes = 100000;
+ offload.setUpstreamLinkProperties(null);
+
+ NetworkStats stats = mTetherStatsProviderCaptor.getValue().getTetherStats();
+ assertEquals(2, stats.size());
+
+ NetworkStats.Entry entry = null;
+ int ethernetPosition = ethernetIface.equals(stats.getValues(0, entry).iface) ? 0 : 1;
+ int mobilePosition = 1 - ethernetPosition;
+
+ entry = stats.getValues(mobilePosition, entry);
+ assertNetworkStats(mobileIface, mobileStats, entry);
+
+ ethernetStats.rxBytes = 12345 + 100000;
+ ethernetStats.txBytes = 54321 + 100000;
+ entry = stats.getValues(ethernetPosition, entry);
+ assertNetworkStats(ethernetIface, ethernetStats, entry);
+ }
}