Merge "Tell the system when tethering offload hits a limit." into oc-mr1-dev

This commit is contained in:
TreeHugger Robot
2017-08-17 09:06:57 +00:00
committed by Android (Google) Code Review
4 changed files with 68 additions and 4 deletions

View File

@@ -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
**/

View File

@@ -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;

View File

@@ -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

View File

@@ -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());
}
}