Loading core/java/android/os/INetworkManagementService.aidl +15 −0 Original line number Diff line number Diff line Loading @@ -219,6 +219,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 **/ Loading services/core/java/com/android/server/NetworkManagementService.java +12 −0 Original line number Diff line number Diff line Loading @@ -550,6 +550,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; Loading services/core/java/com/android/server/connectivity/tethering/OffloadController.java +25 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } Loading Loading @@ -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 Loading tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java +16 −1 Original line number Diff line number Diff line Loading @@ -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() { Loading @@ -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()); } Loading Loading @@ -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()); } } Loading
core/java/android/os/INetworkManagementService.aidl +15 −0 Original line number Diff line number Diff line Loading @@ -219,6 +219,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 **/ Loading
services/core/java/com/android/server/NetworkManagementService.java +12 −0 Original line number Diff line number Diff line Loading @@ -550,6 +550,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; Loading
services/core/java/com/android/server/connectivity/tethering/OffloadController.java +25 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } Loading Loading @@ -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 Loading
tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java +16 −1 Original line number Diff line number Diff line Loading @@ -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() { Loading @@ -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()); } Loading Loading @@ -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()); } }