summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2017-08-17 09:06:57 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2017-08-17 09:06:57 +0000
commitc3e7f875b41f78de26d07f6c8ab8fe78747886c0 (patch)
treee4c491b67dccfcaf5d4d3db78068bce2e70ebc7b
parent8b2513e4399e8d96e9219b7de9f4c7aa9b8f3a44 (diff)
parentd66cf56ba662f10f2da1d0f844116632ad0a0dbb (diff)
Merge "Tell the system when tethering offload hits a limit." into oc-mr1-dev
-rw-r--r--core/java/android/os/INetworkManagementService.aidl15
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java12
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/OffloadController.java28
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java17
4 files changed, 68 insertions, 4 deletions
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index b916b4381a5d..e6e1da4a71c7 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -220,6 +220,21 @@ interface INetworkManagementService
void unregisterTetheringStatsProvider(ITetheringStatsProvider provider);
/**
+ * Reports that a tethering provider has reached a data limit.
+ *
+ * Currently triggers a global alert, which causes NetworkStatsService to poll counters and
+ * re-evaluate data usage.
+ *
+ * This does not take an interface name because:
+ * 1. The tethering offload stats provider cannot reliably determine the interface on which the
+ * limit was reached, because the HAL does not provide it.
+ * 2. Firing an interface-specific alert instead of a global alert isn't really useful since in
+ * all cases of interest, the system responds to both in the same way - it polls stats, and
+ * then notifies NetworkPolicyManagerService of the fact.
+ */
+ void tetherLimitReached(ITetheringStatsProvider provider);
+
+ /**
** PPPD
**/
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 3a4c9f805219..901e1e7c424d 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -547,6 +547,18 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
}
+ @Override
+ public void tetherLimitReached(ITetheringStatsProvider provider) {
+ mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+ synchronized(mTetheringStatsProviders) {
+ if (!mTetheringStatsProviders.containsKey(provider)) {
+ return;
+ }
+ // No current code examines the interface parameter in a global alert. Just pass null.
+ notifyLimitReached(LIMIT_GLOBAL_ALERT, null);
+ }
+ }
+
// Sync the state of the given chain with the native daemon.
private void syncFirewallChainLocked(int chain, String name) {
SparseIntArray rules;
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index 55e290a4215e..ad661d79767d 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -60,6 +60,8 @@ public class OffloadController {
private final Handler mHandler;
private final OffloadHardwareInterface mHwInterface;
private final ContentResolver mContentResolver;
+ private final INetworkManagementService mNms;
+ private final ITetheringStatsProvider mStatsProvider;
private final SharedLog mLog;
private boolean mConfigInitialized;
private boolean mControlInitialized;
@@ -89,13 +91,14 @@ public class OffloadController {
mHandler = h;
mHwInterface = hwi;
mContentResolver = contentResolver;
+ mNms = nms;
+ mStatsProvider = new OffloadTetheringStatsProvider();
mLog = log.forSubComponent(TAG);
mExemptPrefixes = new HashSet<>();
mLastLocalPrefixStrs = new HashSet<>();
try {
- nms.registerTetheringStatsProvider(
- new OffloadTetheringStatsProvider(), getClass().getSimpleName());
+ mNms.registerTetheringStatsProvider(mStatsProvider, getClass().getSimpleName());
} catch (RemoteException e) {
mLog.e("Cannot register offload stats provider: " + e);
}
@@ -150,7 +153,26 @@ public class OffloadController {
@Override
public void onStoppedLimitReached() {
mLog.log("onStoppedLimitReached");
- // Poll for statistics and notify NetworkStats
+
+ // We cannot reliably determine on which interface the limit was reached,
+ // because the HAL interface does not specify it. We cannot just use the
+ // current upstream, because that might have changed since the time that
+ // the HAL queued the callback.
+ // TODO: rev the HAL so that it provides an interface name.
+
+ // Fetch current stats, so that when our notification reaches
+ // NetworkStatsService and triggers a poll, we will respond with
+ // current data (which will be above the limit that was reached).
+ // Note that if we just changed upstream, this is unnecessary but harmless.
+ // The stats for the previous upstream were already updated on this thread
+ // just after the upstream was changed, so they are also up-to-date.
+ updateStatsForCurrentUpstream();
+
+ try {
+ mNms.tetherLimitReached(mStatsProvider);
+ } catch (RemoteException e) {
+ mLog.e("Cannot report data limit reached: " + e);
+ }
}
@Override
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 c4965a0b5cde..983e04d9930d 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -85,6 +85,8 @@ public class OffloadControllerTest {
ArgumentCaptor.forClass(ArrayList.class);
private final ArgumentCaptor<ITetheringStatsProvider.Stub> mTetherStatsProviderCaptor =
ArgumentCaptor.forClass(ITetheringStatsProvider.Stub.class);
+ private final ArgumentCaptor<OffloadHardwareInterface.ControlCallback> mControlCallbackCaptor =
+ ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class);
private MockContentResolver mContentResolver;
@Before public void setUp() {
@@ -103,7 +105,7 @@ public class OffloadControllerTest {
private void setupFunctioningHardwareInterface() {
when(mHardware.initOffloadConfig()).thenReturn(true);
- when(mHardware.initOffloadControl(any(OffloadHardwareInterface.ControlCallback.class)))
+ when(mHardware.initOffloadControl(mControlCallbackCaptor.capture()))
.thenReturn(true);
when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats());
}
@@ -489,4 +491,17 @@ public class OffloadControllerTest {
waitForIdle();
inOrder.verify(mHardware).stopOffloadControl();
}
+
+ @Test
+ public void testDataLimitCallback() throws Exception {
+ setupFunctioningHardwareInterface();
+ enableOffload();
+
+ final OffloadController offload = makeOffloadController();
+ offload.start();
+
+ OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
+ callback.onStoppedLimitReached();
+ verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue());
+ }
}