Merge changes from topic "sp06-offloadcontroller" am: 01d30a4ce0 am: b61116705a am: c6a841b77b

Change-Id: I4e7924ebb2d37ecffb8facce0ec51643afb12264
This commit is contained in:
Automerger Merge Worker
2020-01-15 05:33:32 +00:00
13 changed files with 255 additions and 198 deletions

View File

@@ -245,6 +245,7 @@ applications that come with the platform
<permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
<permission name="android.permission.TETHER_PRIVILEGED"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
<permission name="android.permission.UPDATE_DEVICE_STATS"/>
</privapp-permissions>
<privapp-permissions package="com.android.server.telecom">

View File

@@ -36,6 +36,7 @@
<uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
<uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<application

View File

@@ -26,7 +26,6 @@ import static android.net.util.TetheringMessageBase.BASE_IPSERVER;
import android.net.INetd;
import android.net.INetworkStackStatusCallback;
import android.net.INetworkStatsService;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -176,7 +175,6 @@ public class IpServer extends StateMachine {
private final SharedLog mLog;
private final INetd mNetd;
private final INetworkStatsService mStatsService;
private final Callback mCallback;
private final InterfaceController mInterfaceCtrl;
@@ -208,12 +206,10 @@ public class IpServer extends StateMachine {
public IpServer(
String ifaceName, Looper looper, int interfaceType, SharedLog log,
INetd netd, INetworkStatsService statsService, Callback callback,
boolean usingLegacyDhcp, Dependencies deps) {
INetd netd, Callback callback, boolean usingLegacyDhcp, Dependencies deps) {
super(ifaceName, looper);
mLog = log.forSubComponent(ifaceName);
mNetd = netd;
mStatsService = statsService;
mCallback = callback;
mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog);
mIfaceName = ifaceName;
@@ -881,12 +877,6 @@ public class IpServer extends StateMachine {
// Sometimes interfaces are gone before we get
// to remove their rules, which generates errors.
// Just do the best we can.
try {
// About to tear down NAT; gather remaining statistics.
mStatsService.forceUpdate();
} catch (Exception e) {
mLog.e("Exception in forceUpdate: " + e.toString());
}
try {
mNetd.ipfwdRemoveInterfaceForward(mIfaceName, upstreamIface);
} catch (RemoteException | ServiceSpecificException e) {

View File

@@ -16,35 +16,40 @@
package com.android.server.connectivity.tethering;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.METERED_NO;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.STATS_PER_UID;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_TETHERING;
import static android.net.NetworkStats.UID_TETHERING;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.usage.NetworkStatsManager;
import android.content.ContentResolver;
import android.net.ITetheringStatsProvider;
import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkStats;
import android.net.NetworkStats.Entry;
import android.net.RouteInfo;
import android.net.netlink.ConntrackMessage;
import android.net.netlink.NetlinkConstants;
import android.net.netlink.NetlinkSocket;
import android.net.netstats.provider.AbstractNetworkStatsProvider;
import android.net.netstats.provider.NetworkStatsProviderCallback;
import android.net.util.SharedLog;
import android.os.Handler;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
import android.system.ErrnoException;
import android.system.OsConstants;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats;
@@ -73,13 +78,19 @@ public class OffloadController {
private static final String ANYIP = "0.0.0.0";
private static final ForwardedStats EMPTY_STATS = new ForwardedStats();
@VisibleForTesting
enum StatsType {
STATS_PER_IFACE,
STATS_PER_UID,
}
private enum UpdateType { IF_NEEDED, FORCE };
private final Handler mHandler;
private final OffloadHardwareInterface mHwInterface;
private final ContentResolver mContentResolver;
private final INetworkManagementService mNms;
private final ITetheringStatsProvider mStatsProvider;
private final @NonNull OffloadTetheringStatsProvider mStatsProvider;
private final @Nullable NetworkStatsProviderCallback mStatsProviderCb;
private final SharedLog mLog;
private final HashMap<String, LinkProperties> mDownstreams;
private boolean mConfigInitialized;
@@ -109,22 +120,23 @@ public class OffloadController {
private int mNatUpdateNetlinkErrors;
public OffloadController(Handler h, OffloadHardwareInterface hwi,
ContentResolver contentResolver, INetworkManagementService nms, SharedLog log) {
ContentResolver contentResolver, NetworkStatsManager nsm, SharedLog log) {
mHandler = h;
mHwInterface = hwi;
mContentResolver = contentResolver;
mNms = nms;
mStatsProvider = new OffloadTetheringStatsProvider();
mLog = log.forSubComponent(TAG);
mDownstreams = new HashMap<>();
mExemptPrefixes = new HashSet<>();
mLastLocalPrefixStrs = new HashSet<>();
NetworkStatsProviderCallback providerCallback = null;
try {
mNms.registerTetheringStatsProvider(mStatsProvider, getClass().getSimpleName());
} catch (RemoteException e) {
mLog.e("Cannot register offload stats provider: " + e);
providerCallback = nsm.registerNetworkStatsProvider(
getClass().getSimpleName(), mStatsProvider);
} catch (RuntimeException e) {
Log.wtf(TAG, "Cannot register offload stats provider: " + e);
}
mStatsProviderCb = providerCallback;
}
/** Start hardware offload. */
@@ -173,7 +185,7 @@ public class OffloadController {
// and we need to synchronize stats and limits between
// software and hardware forwarding.
updateStatsForAllUpstreams();
forceTetherStatsPoll();
mStatsProvider.pushTetherStats();
}
@Override
@@ -186,7 +198,7 @@ public class OffloadController {
// limits set take into account any software tethering
// traffic that has been happening in the meantime.
updateStatsForAllUpstreams();
forceTetherStatsPoll();
mStatsProvider.pushTetherStats();
// [2] (Re)Push all state.
computeAndPushLocalPrefixes(UpdateType.FORCE);
pushAllDownstreamState();
@@ -204,14 +216,11 @@ public class OffloadController {
// 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();
forceTetherStatsPoll();
mStatsProvider.pushTetherStats();
// Push stats to service does not cause the service react to it immediately.
// Inform the service about limit reached.
if (mStatsProviderCb != null) mStatsProviderCb.onLimitReached();
}
@Override
@@ -253,42 +262,37 @@ public class OffloadController {
return mConfigInitialized && mControlInitialized;
}
private class OffloadTetheringStatsProvider extends ITetheringStatsProvider.Stub {
@Override
public NetworkStats getTetherStats(int how) {
// getTetherStats() is the only function in OffloadController that can be called from
// a different thread. Do not attempt to update stats by querying the offload HAL
// synchronously from a different thread than our Handler thread. http://b/64771555.
Runnable updateStats = () -> {
updateStatsForCurrentUpstream();
};
if (Looper.myLooper() == mHandler.getLooper()) {
updateStats.run();
} else {
mHandler.post(updateStats);
}
@VisibleForTesting
class OffloadTetheringStatsProvider extends AbstractNetworkStatsProvider {
// These stats must only ever be touched on the handler thread.
@NonNull
private NetworkStats mIfaceStats = new NetworkStats(0L, 0);
@NonNull
private NetworkStats mUidStats = new NetworkStats(0L, 0);
NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
NetworkStats.Entry entry = new NetworkStats.Entry();
entry.set = SET_DEFAULT;
entry.tag = TAG_NONE;
entry.uid = (how == STATS_PER_UID) ? UID_TETHERING : UID_ALL;
@VisibleForTesting
@NonNull
NetworkStats getTetherStats(@NonNull StatsType how) {
NetworkStats stats = new NetworkStats(0L, 0);
final int uid = (how == StatsType.STATS_PER_UID) ? UID_TETHERING : UID_ALL;
for (Map.Entry<String, ForwardedStats> kv : mForwardedStats.entrySet()) {
ForwardedStats value = kv.getValue();
entry.iface = kv.getKey();
entry.rxBytes = value.rxBytes;
entry.txBytes = value.txBytes;
stats.addEntry(entry);
for (final Map.Entry<String, ForwardedStats> kv : mForwardedStats.entrySet()) {
final ForwardedStats value = kv.getValue();
final Entry entry = new Entry(kv.getKey(), uid, SET_DEFAULT, TAG_NONE, METERED_NO,
ROAMING_NO, DEFAULT_NETWORK_NO, value.rxBytes, 0L, value.txBytes, 0L, 0L);
stats = stats.addValues(entry);
}
return stats;
}
@Override
public void setInterfaceQuota(String iface, long quotaBytes) {
public void setLimit(String iface, long quotaBytes) {
mLog.i("setLimit: " + iface + "," + quotaBytes);
// Listen for all iface is necessary since upstream might be changed after limit
// is set.
mHandler.post(() -> {
if (quotaBytes == ITetheringStatsProvider.QUOTA_UNLIMITED) {
if (quotaBytes == QUOTA_UNLIMITED) {
mInterfaceQuotas.remove(iface);
} else {
mInterfaceQuotas.put(iface, quotaBytes);
@@ -296,6 +300,42 @@ public class OffloadController {
maybeUpdateDataLimit(iface);
});
}
/**
* Push stats to service, but does not cause a force polling. Note that this can only be
* called on the handler thread.
*/
public void pushTetherStats() {
// TODO: remove the accumulated stats and report the diff from HAL directly.
if (null == mStatsProviderCb) return;
final NetworkStats ifaceDiff =
getTetherStats(StatsType.STATS_PER_IFACE).subtract(mIfaceStats);
final NetworkStats uidDiff =
getTetherStats(StatsType.STATS_PER_UID).subtract(mUidStats);
try {
mStatsProviderCb.onStatsUpdated(0 /* token */, ifaceDiff, uidDiff);
mIfaceStats = mIfaceStats.add(ifaceDiff);
mUidStats = mUidStats.add(uidDiff);
} catch (RuntimeException e) {
mLog.e("Cannot report network stats: ", e);
}
}
@Override
public void requestStatsUpdate(int token) {
mLog.i("requestStatsUpdate: " + token);
// Do not attempt to update stats by querying the offload HAL
// synchronously from a different thread than the Handler thread. http://b/64771555.
mHandler.post(() -> {
updateStatsForCurrentUpstream();
pushTetherStats();
});
}
@Override
public void setAlert(long quotaBytes) {
// TODO: Ask offload HAL to notify alert without stopping traffic.
}
}
private String currentUpstreamInterface() {
@@ -353,14 +393,6 @@ public class OffloadController {
}
}
private void forceTetherStatsPoll() {
try {
mNms.tetherLimitReached(mStatsProvider);
} catch (RemoteException e) {
mLog.e("Cannot report data limit reached: " + e);
}
}
/** Set current tethering upstream LinkProperties. */
public void setUpstreamLinkProperties(LinkProperties lp) {
if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return;

View File

@@ -29,6 +29,8 @@ import android.os.Handler;
import android.os.RemoteException;
import android.system.OsConstants;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
@@ -91,6 +93,12 @@ public class OffloadHardwareInterface {
txBytes = 0;
}
@VisibleForTesting
public ForwardedStats(long rxBytes, long txBytes) {
this.rxBytes = rxBytes;
this.txBytes = txBytes;
}
/** Add Tx/Rx bytes. */
public void add(ForwardedStats other) {
rxBytes += other.rxBytes;

View File

@@ -53,6 +53,7 @@ import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothProfile;
@@ -65,7 +66,6 @@ import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.INetd;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.ITetheringEventCallback;
import android.net.IpPrefix;
import android.net.LinkAddress;
@@ -176,7 +176,6 @@ public class Tethering {
private final Context mContext;
private final ArrayMap<String, TetherState> mTetherStates;
private final BroadcastReceiver mStateReceiver;
private final INetworkStatsService mStatsService;
private final INetworkPolicyManager mPolicyManager;
private final Looper mLooper;
private final StateMachine mTetherMasterSM;
@@ -212,7 +211,6 @@ public class Tethering {
mLog.mark("Tethering.constructed");
mDeps = deps;
mContext = mDeps.getContext();
mStatsService = mDeps.getINetworkStatsService();
mPolicyManager = mDeps.getINetworkPolicyManager();
mNetd = mDeps.getINetd(mContext);
mLooper = mDeps.getTetheringLooper();
@@ -224,10 +222,12 @@ public class Tethering {
mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps);
mTetherMasterSM.start();
final NetworkStatsManager statsManager =
(NetworkStatsManager) mContext.getSystemService(Context.NETWORK_STATS_SERVICE);
mHandler = mTetherMasterSM.getHandler();
mOffloadController = new OffloadController(mHandler,
mDeps.getOffloadHardwareInterface(mHandler, mLog), mContext.getContentResolver(),
mDeps.getINetworkManagementService(), mLog);
statsManager, mLog);
mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
mForwardedDownstreams = new HashSet<>();
@@ -264,7 +264,7 @@ public class Tethering {
}
final UserManager userManager = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
Context.USER_SERVICE);
mTetheringRestriction = new UserRestrictionActionListener(userManager, this);
final TetheringThreadExecutor executor = new TetheringThreadExecutor(mHandler);
mActiveDataSubIdListener = new ActiveDataSubIdListener(executor);
@@ -2054,7 +2054,7 @@ public class Tethering {
mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
final TetherState tetherState = new TetherState(
new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mStatsService,
new IpServer(iface, mLooper, interfaceType, mLog, mNetd,
makeControlCallback(), mConfig.enableLegacyDhcpServer,
mDeps.getIpServerDependencies()));
mTetherStates.put(iface, tetherState);

View File

@@ -19,7 +19,6 @@ package com.android.server.connectivity.tethering;
import android.content.Context;
import android.net.INetd;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.NetworkRequest;
import android.net.ip.IpServer;
import android.net.util.SharedLog;
@@ -106,15 +105,6 @@ public abstract class TetheringDependencies {
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
}
/**
* Get a reference to INetworkStatsService to force update tethering usage.
* Note: This should be removed in R development cycle.
*/
public INetworkStatsService getINetworkStatsService() {
return INetworkStatsService.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
}
/**
* Get a reference to INetworkPolicyManager to be used by tethering.
*/

View File

@@ -42,7 +42,6 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserManager;
import android.provider.Settings;
@@ -363,7 +362,7 @@ public class TetheringService extends Service {
IBinder connector;
try {
final long before = System.currentTimeMillis();
while ((connector = ServiceManager.getService(
while ((connector = (IBinder) mContext.getSystemService(
Context.NETWORK_STACK_SERVICE)) == null) {
if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector");

View File

@@ -52,7 +52,6 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.net.INetd;
import android.net.INetworkStatsService;
import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix;
import android.net.LinkAddress;
@@ -99,7 +98,6 @@ public class IpServerTest {
private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000;
@Mock private INetd mNetd;
@Mock private INetworkStatsService mStatsService;
@Mock private IpServer.Callback mCallback;
@Mock private SharedLog mSharedLog;
@Mock private IDhcpServer mDhcpServer;
@@ -139,13 +137,13 @@ public class IpServerTest {
mInterfaceConfiguration.prefixLength = BLUETOOTH_DHCP_PREFIX_LENGTH;
}
mIpServer = new IpServer(
IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, mStatsService,
IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd,
mCallback, usingLegacyDhcp, mDependencies);
mIpServer.start();
// Starting the state machine always puts us in a consistent state and notifies
// the rest of the world that we've changed from an unknown to available state.
mLooper.dispatchAll();
reset(mNetd, mStatsService, mCallback);
reset(mNetd, mCallback);
when(mRaDaemon.start()).thenReturn(true);
}
@@ -162,7 +160,7 @@ public class IpServerTest {
if (upstreamIface != null) {
dispatchTetherConnectionChanged(upstreamIface);
}
reset(mNetd, mStatsService, mCallback);
reset(mNetd, mCallback);
}
@Before public void setUp() throws Exception {
@@ -173,13 +171,13 @@ public class IpServerTest {
@Test
public void startsOutAvailable() {
mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog,
mNetd, mStatsService, mCallback, false /* usingLegacyDhcp */, mDependencies);
mNetd, mCallback, false /* usingLegacyDhcp */, mDependencies);
mIpServer.start();
mLooper.dispatchAll();
verify(mCallback).updateInterfaceState(
mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
verifyNoMoreInteractions(mCallback, mNetd, mStatsService);
verifyNoMoreInteractions(mCallback, mNetd);
}
@Test
@@ -198,7 +196,7 @@ public class IpServerTest {
// None of these commands should trigger us to request action from
// the rest of the system.
dispatchCommand(command);
verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
verifyNoMoreInteractions(mNetd, mCallback);
}
}
@@ -210,7 +208,7 @@ public class IpServerTest {
verify(mCallback).updateInterfaceState(
mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
verifyNoMoreInteractions(mNetd, mCallback);
}
@Test
@@ -228,7 +226,7 @@ public class IpServerTest {
mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), any(LinkProperties.class));
verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
verifyNoMoreInteractions(mNetd, mCallback);
}
@Test
@@ -236,7 +234,7 @@ public class IpServerTest {
initTetheredStateMachine(TETHERING_BLUETOOTH, null);
dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
InOrder inOrder = inOrder(mNetd, mStatsService, mCallback);
InOrder inOrder = inOrder(mNetd, mCallback);
inOrder.verify(mNetd).tetherApplyDnsInterfaces();
inOrder.verify(mNetd).tetherInterfaceRemove(IFACE_NAME);
inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
@@ -245,7 +243,7 @@ public class IpServerTest {
mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), any(LinkProperties.class));
verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
verifyNoMoreInteractions(mNetd, mCallback);
}
@Test
@@ -265,7 +263,7 @@ public class IpServerTest {
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), mLinkPropertiesCaptor.capture());
assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
verifyNoMoreInteractions(mNetd, mCallback);
}
@Test
@@ -285,7 +283,7 @@ public class IpServerTest {
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), mLinkPropertiesCaptor.capture());
assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
verifyNoMoreInteractions(mNetd, mCallback);
}
@Test
@@ -298,7 +296,7 @@ public class IpServerTest {
InOrder inOrder = inOrder(mNetd);
inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
verifyNoMoreInteractions(mNetd, mCallback);
}
@Test
@@ -306,13 +304,12 @@ public class IpServerTest {
initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
InOrder inOrder = inOrder(mNetd, mStatsService);
inOrder.verify(mStatsService).forceUpdate();
InOrder inOrder = inOrder(mNetd);
inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2);
verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
verifyNoMoreInteractions(mNetd, mCallback);
}
@Test
@@ -322,12 +319,10 @@ public class IpServerTest {
doThrow(RemoteException.class).when(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
InOrder inOrder = inOrder(mNetd, mStatsService);
inOrder.verify(mStatsService).forceUpdate();
InOrder inOrder = inOrder(mNetd);
inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mStatsService).forceUpdate();
inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE2);
}
@@ -340,13 +335,11 @@ public class IpServerTest {
IFACE_NAME, UPSTREAM_IFACE2);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
InOrder inOrder = inOrder(mNetd, mStatsService);
inOrder.verify(mStatsService).forceUpdate();
InOrder inOrder = inOrder(mNetd);
inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mStatsService).forceUpdate();
inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2);
inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE2);
}
@@ -356,8 +349,7 @@ public class IpServerTest {
initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
InOrder inOrder = inOrder(mNetd, mStatsService, mCallback);
inOrder.verify(mStatsService).forceUpdate();
InOrder inOrder = inOrder(mNetd, mCallback);
inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mNetd).tetherApplyDnsInterfaces();
@@ -368,7 +360,7 @@ public class IpServerTest {
mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), any(LinkProperties.class));
verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
verifyNoMoreInteractions(mNetd, mCallback);
}
@Test
@@ -435,11 +427,11 @@ public class IpServerTest {
public void ignoresDuplicateUpstreamNotifications() throws Exception {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
verifyNoMoreInteractions(mNetd, mCallback);
for (int i = 0; i < 5; i++) {
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
verifyNoMoreInteractions(mNetd, mStatsService, mCallback);
verifyNoMoreInteractions(mNetd, mCallback);
}
}

View File

@@ -16,21 +16,26 @@
package com.android.server.connectivity.tethering;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.METERED_NO;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.STATS_PER_IFACE;
import static android.net.NetworkStats.STATS_PER_UID;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStats.UID_TETHERING;
import static android.net.RouteInfo.RTN_UNICAST;
import static android.net.TrafficStats.UID_TETHERING;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
import static com.android.server.connectivity.tethering.OffloadController.StatsType.STATS_PER_IFACE;
import static com.android.server.connectivity.tethering.OffloadController.StatsType.STATS_PER_UID;
import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats;
import static com.android.testutils.MiscAssertsKt.assertContainsAll;
import static com.android.testutils.MiscAssertsKt.assertThrows;
import static com.android.testutils.NetworkStatsUtilsKt.orderInsensitiveEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyObject;
@@ -39,11 +44,14 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.clearInvocations;
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.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.net.ITetheringStatsProvider;
@@ -51,10 +59,12 @@ import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkStats;
import android.net.NetworkStats.Entry;
import android.net.RouteInfo;
import android.net.netstats.provider.AbstractNetworkStatsProvider;
import android.net.netstats.provider.NetworkStatsProviderCallback;
import android.net.util.SharedLog;
import android.os.Handler;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -97,11 +107,13 @@ public class OffloadControllerTest {
@Mock private OffloadHardwareInterface mHardware;
@Mock private ApplicationInfo mApplicationInfo;
@Mock private Context mContext;
@Mock private INetworkManagementService mNMService;
@Mock private NetworkStatsManager mStatsManager;
@Mock private NetworkStatsProviderCallback mTetherStatsProviderCb;
private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
ArgumentCaptor.forClass(ArrayList.class);
private final ArgumentCaptor<ITetheringStatsProvider.Stub> mTetherStatsProviderCaptor =
ArgumentCaptor.forClass(ITetheringStatsProvider.Stub.class);
private final ArgumentCaptor<OffloadController.OffloadTetheringStatsProvider>
mTetherStatsProviderCaptor =
ArgumentCaptor.forClass(OffloadController.OffloadTetheringStatsProvider.class);
private final ArgumentCaptor<OffloadHardwareInterface.ControlCallback> mControlCallbackCaptor =
ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class);
private MockContentResolver mContentResolver;
@@ -114,6 +126,8 @@ public class OffloadControllerTest {
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
when(mContext.getContentResolver()).thenReturn(mContentResolver);
FakeSettingsProvider.clearSettingsProvider();
when(mStatsManager.registerNetworkStatsProvider(anyString(), any()))
.thenReturn(mTetherStatsProviderCb);
}
@After public void tearDown() throws Exception {
@@ -139,9 +153,9 @@ public class OffloadControllerTest {
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());
mHardware, mContentResolver, mStatsManager, new SharedLog("test"));
verify(mStatsManager).registerNetworkStatsProvider(anyString(),
mTetherStatsProviderCaptor.capture());
return offload;
}
@@ -384,12 +398,11 @@ public class OffloadControllerTest {
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);
private static @NonNull Entry buildTestEntry(@NonNull OffloadController.StatsType how,
@NonNull String iface, long rxBytes, long txBytes) {
return new Entry(iface, how == STATS_PER_IFACE ? UID_ALL : UID_TETHERING, SET_DEFAULT,
TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes, 0L,
txBytes, 0L, 0L);
}
@Test
@@ -400,19 +413,16 @@ public class OffloadControllerTest {
final OffloadController offload = makeOffloadController();
offload.start();
final OffloadController.OffloadTetheringStatsProvider provider =
mTetherStatsProviderCaptor.getValue();
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);
when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(
new ForwardedStats(12345, 54321));
when(mHardware.getForwardedStats(eq(mobileIface))).thenReturn(
new ForwardedStats(999, 99999));
InOrder inOrder = inOrder(mHardware);
@@ -432,10 +442,35 @@ public class OffloadControllerTest {
// Expect that we fetch stats from the previous upstream.
inOrder.verify(mHardware, times(1)).getForwardedStats(eq(mobileIface));
ethernetStats = new ForwardedStats();
ethernetStats.rxBytes = 100000;
ethernetStats.txBytes = 100000;
when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(ethernetStats);
// Verify that the fetched stats are stored.
final NetworkStats ifaceStats = provider.getTetherStats(STATS_PER_IFACE);
final NetworkStats uidStats = provider.getTetherStats(STATS_PER_UID);
final NetworkStats expectedIfaceStats = new NetworkStats(0L, 2)
.addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999))
.addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 12345, 54321));
final NetworkStats expectedUidStats = new NetworkStats(0L, 2)
.addValues(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999))
.addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 12345, 54321));
assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStats));
assertTrue(orderInsensitiveEquals(expectedUidStats, uidStats));
final ArgumentCaptor<NetworkStats> ifaceStatsCaptor = ArgumentCaptor.forClass(
NetworkStats.class);
final ArgumentCaptor<NetworkStats> uidStatsCaptor = ArgumentCaptor.forClass(
NetworkStats.class);
// Force pushing stats update to verify the stats reported.
provider.pushTetherStats();
verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(),
ifaceStatsCaptor.capture(), uidStatsCaptor.capture());
assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStatsCaptor.getValue()));
assertTrue(orderInsensitiveEquals(expectedUidStats, uidStatsCaptor.getValue()));
when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(
new ForwardedStats(100000, 100000));
offload.setUpstreamLinkProperties(null);
// Expect that we first clear the HAL's upstream parameters.
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
@@ -443,37 +478,38 @@ public class OffloadControllerTest {
// Expect that we fetch stats from the previous upstream.
inOrder.verify(mHardware, times(1)).getForwardedStats(eq(ethernetIface));
ITetheringStatsProvider provider = mTetherStatsProviderCaptor.getValue();
NetworkStats stats = provider.getTetherStats(STATS_PER_IFACE);
NetworkStats perUidStats = provider.getTetherStats(STATS_PER_UID);
waitForIdle();
// There is no current upstream, so no stats are fetched.
inOrder.verify(mHardware, never()).getForwardedStats(any());
inOrder.verifyNoMoreInteractions();
assertEquals(2, stats.size());
assertEquals(2, perUidStats.size());
// Verify that the stored stats is accumulated.
final NetworkStats ifaceStatsAccu = provider.getTetherStats(STATS_PER_IFACE);
final NetworkStats uidStatsAccu = provider.getTetherStats(STATS_PER_UID);
final NetworkStats expectedIfaceStatsAccu = new NetworkStats(0L, 2)
.addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999))
.addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 112345, 154321));
NetworkStats.Entry entry = null;
for (int i = 0; i < stats.size(); i++) {
assertEquals(UID_ALL, stats.getValues(i, entry).uid);
assertEquals(UID_TETHERING, perUidStats.getValues(i, entry).uid);
}
final NetworkStats expectedUidStatsAccu = new NetworkStats(0L, 2)
.addValues(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999))
.addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 112345, 154321));
int ethernetPosition = ethernetIface.equals(stats.getValues(0, entry).iface) ? 0 : 1;
int mobilePosition = 1 - ethernetPosition;
assertTrue(orderInsensitiveEquals(expectedIfaceStatsAccu, ifaceStatsAccu));
assertTrue(orderInsensitiveEquals(expectedUidStatsAccu, uidStatsAccu));
entry = stats.getValues(mobilePosition, entry);
assertNetworkStats(mobileIface, mobileStats, entry);
entry = perUidStats.getValues(mobilePosition, entry);
assertNetworkStats(mobileIface, mobileStats, entry);
// Verify that only diff of stats is reported.
reset(mTetherStatsProviderCb);
provider.pushTetherStats();
final NetworkStats expectedIfaceStatsDiff = new NetworkStats(0L, 2)
.addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 0, 0))
.addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 100000, 100000));
ethernetStats.rxBytes = 12345 + 100000;
ethernetStats.txBytes = 54321 + 100000;
entry = stats.getValues(ethernetPosition, entry);
assertNetworkStats(ethernetIface, ethernetStats, entry);
entry = perUidStats.getValues(ethernetPosition, entry);
assertNetworkStats(ethernetIface, ethernetStats, entry);
final NetworkStats expectedUidStatsDiff = new NetworkStats(0L, 2)
.addValues(buildTestEntry(STATS_PER_UID, mobileIface, 0, 0))
.addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 100000, 100000));
verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(),
ifaceStatsCaptor.capture(), uidStatsCaptor.capture());
assertTrue(orderInsensitiveEquals(expectedIfaceStatsDiff, ifaceStatsCaptor.getValue()));
assertTrue(orderInsensitiveEquals(expectedUidStatsDiff, uidStatsCaptor.getValue()));
}
@Test
@@ -493,19 +529,19 @@ public class OffloadControllerTest {
lp.setInterfaceName(ethernetIface);
offload.setUpstreamLinkProperties(lp);
ITetheringStatsProvider provider = mTetherStatsProviderCaptor.getValue();
AbstractNetworkStatsProvider provider = mTetherStatsProviderCaptor.getValue();
final InOrder inOrder = inOrder(mHardware);
when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true);
when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true);
// Applying an interface quota to the current upstream immediately sends it to the hardware.
provider.setInterfaceQuota(ethernetIface, ethernetLimit);
provider.setLimit(ethernetIface, ethernetLimit);
waitForIdle();
inOrder.verify(mHardware).setDataLimit(ethernetIface, ethernetLimit);
inOrder.verifyNoMoreInteractions();
// Applying an interface quota to another upstream does not take any immediate action.
provider.setInterfaceQuota(mobileIface, mobileLimit);
provider.setLimit(mobileIface, mobileLimit);
waitForIdle();
inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong());
@@ -518,7 +554,7 @@ public class OffloadControllerTest {
// Setting a limit of ITetheringStatsProvider.QUOTA_UNLIMITED causes the limit to be set
// to Long.MAX_VALUE.
provider.setInterfaceQuota(mobileIface, ITetheringStatsProvider.QUOTA_UNLIMITED);
provider.setLimit(mobileIface, ITetheringStatsProvider.QUOTA_UNLIMITED);
waitForIdle();
inOrder.verify(mHardware).setDataLimit(mobileIface, Long.MAX_VALUE);
@@ -526,7 +562,7 @@ public class OffloadControllerTest {
when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(false);
lp.setInterfaceName(ethernetIface);
offload.setUpstreamLinkProperties(lp);
provider.setInterfaceQuota(mobileIface, mobileLimit);
provider.setLimit(mobileIface, mobileLimit);
waitForIdle();
inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong());
@@ -535,7 +571,7 @@ public class OffloadControllerTest {
when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(false);
lp.setInterfaceName(mobileIface);
offload.setUpstreamLinkProperties(lp);
provider.setInterfaceQuota(mobileIface, mobileLimit);
provider.setLimit(mobileIface, mobileLimit);
waitForIdle();
inOrder.verify(mHardware).getForwardedStats(ethernetIface);
inOrder.verify(mHardware).stopOffloadControl();
@@ -551,7 +587,7 @@ public class OffloadControllerTest {
OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
callback.onStoppedLimitReached();
verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue());
verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any());
}
@Test
@@ -654,9 +690,10 @@ public class OffloadControllerTest {
// Verify forwarded stats behaviour.
verify(mHardware, times(1)).getForwardedStats(eq(RMNET0));
verify(mHardware, times(1)).getForwardedStats(eq(WLAN0));
// TODO: verify the exact stats reported.
verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any());
verifyNoMoreInteractions(mTetherStatsProviderCb);
verifyNoMoreInteractions(mHardware);
verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue());
verifyNoMoreInteractions(mNMService);
}
@Test
@@ -719,8 +756,8 @@ public class OffloadControllerTest {
// Verify forwarded stats behaviour.
verify(mHardware, times(1)).getForwardedStats(eq(RMNET0));
verify(mHardware, times(1)).getForwardedStats(eq(WLAN0));
verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue());
verifyNoMoreInteractions(mNMService);
verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any());
verifyNoMoreInteractions(mTetherStatsProviderCb);
// TODO: verify local prefixes and downstreams are also pushed to the HAL.
verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());

View File

@@ -60,6 +60,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.usage.NetworkStatsManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -70,7 +71,6 @@ import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.INetd;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.ITetheringEventCallback;
import android.net.InetAddresses;
import android.net.InterfaceConfigurationParcel;
@@ -152,7 +152,7 @@ public class TetheringTest {
@Mock private ApplicationInfo mApplicationInfo;
@Mock private Context mContext;
@Mock private INetworkManagementService mNMService;
@Mock private INetworkStatsService mStatsService;
@Mock private NetworkStatsManager mStatsManager;
@Mock private INetworkPolicyManager mPolicyManager;
@Mock private OffloadHardwareInterface mOffloadHardwareInterface;
@Mock private Resources mResources;
@@ -217,6 +217,7 @@ public class TetheringTest {
if (Context.USB_SERVICE.equals(name)) return mUsbManager;
if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
if (Context.USER_SERVICE.equals(name)) return mUserManager;
if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager;
return super.getSystemService(name);
}
@@ -338,11 +339,6 @@ public class TetheringTest {
return mNMService;
}
@Override
public INetworkStatsService getINetworkStatsService() {
return mStatsService;
}
@Override
public INetworkPolicyManager getINetworkPolicyManager() {
return mPolicyManager;
@@ -457,7 +453,7 @@ public class TetheringTest {
mServiceContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(ACTION_TETHER_STATE_CHANGED));
mTethering = makeTethering();
verify(mNMService).registerTetheringStatsProvider(any(), anyString());
verify(mStatsManager, times(1)).registerNetworkStatsProvider(anyString(), any());
verify(mNetd).registerUnsolicitedEventListener(any());
final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor =
ArgumentCaptor.forClass(PhoneStateListener.class);

View File

@@ -4522,7 +4522,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
case MSG_STATS_PROVIDER_LIMIT_REACHED: {
mNetworkStats.forceUpdate();
synchronized (mNetworkPoliciesSecondLock) {
// Some providers might hit the limit reached event prior to others. Thus,
// re-calculate and update interface quota for every provider is needed.
updateNetworkRulesNL();
updateNetworkEnabledNL();
updateNotificationsNL();
}
@@ -4530,16 +4534,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
case MSG_LIMIT_REACHED: {
final String iface = (String) msg.obj;
synchronized (mNetworkPoliciesSecondLock) {
// fast return if not needed.
if (!mMeteredIfaces.contains(iface)) {
return true;
}
}
// force stats update to make sure the service have the numbers that caused
// alert to trigger.
mNetworkStats.forceUpdate();
synchronized (mNetworkPoliciesSecondLock) {
if (mMeteredIfaces.contains(iface)) {
// force stats update to make sure we have
// numbers that caused alert to trigger.
mNetworkStats.forceUpdate();
updateNetworkEnabledNL();
updateNotificationsNL();
}
updateNetworkRulesNL();
updateNetworkEnabledNL();
updateNotificationsNL();
}
return true;
}

View File

@@ -1804,9 +1804,11 @@ public class NetworkPolicyManagerServiceTest {
.getService(NetworkPolicyManagerInternal.class);
npmi.onStatsProviderLimitReached("TEST");
// Verifies that the limit reached leads to a force update.
// Verifies that the limit reached leads to a force update and new limit should be set.
postMsgAndWaitForCompletion();
verify(mStatsService).forceUpdate();
postMsgAndWaitForCompletion();
verify(mStatsService).setStatsProviderLimit(TEST_IFACE, 10000L - 4999L - 1999L);
}
/**