diff options
| author | 2017-08-17 09:06:57 +0000 | |
|---|---|---|
| committer | 2017-08-17 09:06:57 +0000 | |
| commit | c3e7f875b41f78de26d07f6c8ab8fe78747886c0 (patch) | |
| tree | e4c491b67dccfcaf5d4d3db78068bce2e70ebc7b | |
| parent | 8b2513e4399e8d96e9219b7de9f4c7aa9b8f3a44 (diff) | |
| parent | d66cf56ba662f10f2da1d0f844116632ad0a0dbb (diff) | |
Merge "Tell the system when tethering offload hits a limit." into oc-mr1-dev
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()); + } } |