Merge changes I6c486303,I073934f3,I6ee66149,Ibbb4325c into mainline-prod
* changes: [SP29] Send interface warning bytes to NetworkStatsProvider [SP29.1] Simplify logic of calculating and applying data limit [SP28] Add API for set data warning NPMS lock improvement.
This commit is contained in:
@@ -23,6 +23,6 @@ package android.net.netstats.provider;
|
||||
*/
|
||||
oneway interface INetworkStatsProvider {
|
||||
void onRequestStatsUpdate(int token);
|
||||
void onSetLimit(String iface, long quotaBytes);
|
||||
void onSetAlert(long quotaBytes);
|
||||
void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,6 @@ import android.net.NetworkStats;
|
||||
oneway interface INetworkStatsProviderCallback {
|
||||
void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats);
|
||||
void notifyAlertReached();
|
||||
void notifyLimitReached();
|
||||
void notifyWarningOrLimitReached();
|
||||
void unregister();
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ import android.os.RemoteException;
|
||||
@SystemApi
|
||||
public abstract class NetworkStatsProvider {
|
||||
/**
|
||||
* A value used by {@link #onSetLimit} and {@link #onSetAlert} indicates there is no limit.
|
||||
* A value used by {@link #onSetLimit}, {@link #onSetAlert} and {@link #onSetWarningAndLimit}
|
||||
* indicates there is no limit.
|
||||
*/
|
||||
public static final int QUOTA_UNLIMITED = -1;
|
||||
|
||||
@@ -42,13 +43,13 @@ public abstract class NetworkStatsProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetLimit(String iface, long quotaBytes) {
|
||||
NetworkStatsProvider.this.onSetLimit(iface, quotaBytes);
|
||||
public void onSetAlert(long quotaBytes) {
|
||||
NetworkStatsProvider.this.onSetAlert(quotaBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetAlert(long quotaBytes) {
|
||||
NetworkStatsProvider.this.onSetAlert(quotaBytes);
|
||||
public void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes) {
|
||||
NetworkStatsProvider.this.onSetWarningAndLimit(iface, warningBytes, limitBytes);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -145,11 +146,28 @@ public abstract class NetworkStatsProvider {
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify system that the quota set by {@code onSetLimit} has been reached.
|
||||
* Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
// TODO: Expose as system API.
|
||||
public void notifyWarningReached() {
|
||||
try {
|
||||
// Reuse the code path to notify warning reached with limit reached
|
||||
// since framework handles them in the same way.
|
||||
getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify system that the quota set by {@link #onSetLimit} or limit set by
|
||||
* {@link #onSetWarningAndLimit} has been reached.
|
||||
*/
|
||||
public void notifyLimitReached() {
|
||||
try {
|
||||
getProviderCallbackBinderOrThrow().notifyLimitReached();
|
||||
getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
@@ -180,8 +198,34 @@ public abstract class NetworkStatsProvider {
|
||||
* @param quotaBytes the quota defined as the number of bytes, starting from zero and counting
|
||||
* from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit.
|
||||
*/
|
||||
// TODO: deprecate this once onSetWarningAndLimit is ready.
|
||||
public abstract void onSetLimit(@NonNull String iface, long quotaBytes);
|
||||
|
||||
/**
|
||||
* Called by {@code NetworkStatsService} when setting the interface quotas for the specified
|
||||
* upstream interface. If a provider implements {@link #onSetWarningAndLimit}, the system
|
||||
* will not call {@link #onSetLimit}. When this method is called, the implementation
|
||||
* should behave as follows:
|
||||
* 1. If {@code warningBytes} is reached on {@code iface}, block all further traffic on
|
||||
* {@code iface} and call {@link NetworkStatsProvider@notifyWarningReached()}.
|
||||
* 2. If {@code limitBytes} is reached on {@code iface}, block all further traffic on
|
||||
* {@code iface} and call {@link NetworkStatsProvider#notifyLimitReached()}.
|
||||
*
|
||||
* @param iface the interface requiring the operation.
|
||||
* @param warningBytes the warning defined as the number of bytes, starting from zero and
|
||||
* counting from now. A value of {@link #QUOTA_UNLIMITED} indicates
|
||||
* there is no warning.
|
||||
* @param limitBytes the limit defined as the number of bytes, starting from zero and counting
|
||||
* from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
// TODO: Expose as system API.
|
||||
public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) {
|
||||
// Backward compatibility for those who didn't override this function.
|
||||
onSetLimit(iface, limitBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations
|
||||
* MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes
|
||||
|
||||
@@ -131,9 +131,10 @@ public abstract class NetworkPolicyManagerInternal {
|
||||
|
||||
/**
|
||||
* Notifies that the specified {@link NetworkStatsProvider} has reached its quota
|
||||
* which was set through {@link NetworkStatsProvider#onSetLimit(String, long)}.
|
||||
* which was set through {@link NetworkStatsProvider#onSetLimit(String, long)} or
|
||||
* {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}.
|
||||
*
|
||||
* @param tag the human readable identifier of the custom network stats provider.
|
||||
*/
|
||||
public abstract void onStatsProviderLimitReached(@NonNull String tag);
|
||||
public abstract void onStatsProviderWarningOrLimitReached(@NonNull String tag);
|
||||
}
|
||||
|
||||
@@ -383,15 +383,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
private static final int MSG_LIMIT_REACHED = 5;
|
||||
private static final int MSG_RESTRICT_BACKGROUND_CHANGED = 6;
|
||||
private static final int MSG_ADVISE_PERSIST_THRESHOLD = 7;
|
||||
private static final int MSG_UPDATE_INTERFACE_QUOTA = 10;
|
||||
private static final int MSG_REMOVE_INTERFACE_QUOTA = 11;
|
||||
private static final int MSG_UPDATE_INTERFACE_QUOTAS = 10;
|
||||
private static final int MSG_REMOVE_INTERFACE_QUOTAS = 11;
|
||||
private static final int MSG_POLICIES_CHANGED = 13;
|
||||
private static final int MSG_RESET_FIREWALL_RULES_BY_UID = 15;
|
||||
private static final int MSG_SUBSCRIPTION_OVERRIDE = 16;
|
||||
private static final int MSG_METERED_RESTRICTED_PACKAGES_CHANGED = 17;
|
||||
private static final int MSG_SET_NETWORK_TEMPLATE_ENABLED = 18;
|
||||
private static final int MSG_SUBSCRIPTION_PLANS_CHANGED = 19;
|
||||
private static final int MSG_STATS_PROVIDER_LIMIT_REACHED = 20;
|
||||
private static final int MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED = 20;
|
||||
|
||||
private static final int UID_MSG_STATE_CHANGED = 100;
|
||||
private static final int UID_MSG_GONE = 101;
|
||||
@@ -518,8 +518,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
private final SparseBooleanArray mRestrictBackgroundWhitelistRevokedUids =
|
||||
new SparseBooleanArray();
|
||||
|
||||
final Object mMeteredIfacesLock = new Object();
|
||||
/** Set of ifaces that are metered. */
|
||||
@GuardedBy("mNetworkPoliciesSecondLock")
|
||||
@GuardedBy("mMeteredIfacesLock")
|
||||
private ArraySet<String> mMeteredIfaces = new ArraySet<>();
|
||||
/** Set of over-limit templates that have been notified. */
|
||||
@GuardedBy("mNetworkPoliciesSecondLock")
|
||||
@@ -1908,39 +1909,45 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
|
||||
final boolean hasWarning = policy.warningBytes != LIMIT_DISABLED;
|
||||
final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED;
|
||||
if (hasLimit || policy.metered) {
|
||||
final long quotaBytes;
|
||||
if (hasLimit && policy.hasCycle()) {
|
||||
final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager
|
||||
.cycleIterator(policy).next();
|
||||
final long start = cycle.first.toInstant().toEpochMilli();
|
||||
final long end = cycle.second.toInstant().toEpochMilli();
|
||||
final long totalBytes = getTotalBytes(policy.template, start, end);
|
||||
long limitBytes = Long.MAX_VALUE;
|
||||
long warningBytes = Long.MAX_VALUE;
|
||||
if ((hasLimit || hasWarning) && policy.hasCycle()) {
|
||||
final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager
|
||||
.cycleIterator(policy).next();
|
||||
final long start = cycle.first.toInstant().toEpochMilli();
|
||||
final long end = cycle.second.toInstant().toEpochMilli();
|
||||
final long totalBytes = getTotalBytes(policy.template, start, end);
|
||||
|
||||
if (policy.lastLimitSnooze >= start) {
|
||||
// snoozing past quota, but we still need to restrict apps,
|
||||
// so push really high quota.
|
||||
quotaBytes = Long.MAX_VALUE;
|
||||
} else {
|
||||
// remaining "quota" bytes are based on total usage in
|
||||
// current cycle. kernel doesn't like 0-byte rules, so we
|
||||
// set 1-byte quota and disable the radio later.
|
||||
quotaBytes = Math.max(1, policy.limitBytes - totalBytes);
|
||||
}
|
||||
} else {
|
||||
// metered network, but no policy limit; we still need to
|
||||
// restrict apps, so push really high quota.
|
||||
quotaBytes = Long.MAX_VALUE;
|
||||
// If the limit notification is not snoozed, the limit quota needs to be calculated.
|
||||
if (hasLimit && policy.lastLimitSnooze < start) {
|
||||
// remaining "quota" bytes are based on total usage in
|
||||
// current cycle. kernel doesn't like 0-byte rules, so we
|
||||
// set 1-byte quota and disable the radio later.
|
||||
limitBytes = Math.max(1, policy.limitBytes - totalBytes);
|
||||
}
|
||||
|
||||
// If the warning notification was snoozed by user, or the service already knows
|
||||
// it is over warning bytes, doesn't need to calculate warning bytes.
|
||||
if (hasWarning && policy.lastWarningSnooze < start
|
||||
&& !policy.isOverWarning(totalBytes)) {
|
||||
warningBytes = Math.max(1, policy.warningBytes - totalBytes);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasWarning || hasLimit || policy.metered) {
|
||||
if (matchingIfaces.size() > 1) {
|
||||
// TODO: switch to shared quota once NMS supports
|
||||
Slog.w(TAG, "shared quota unsupported; generating rule for each iface");
|
||||
}
|
||||
|
||||
// Set the interface warning and limit. For interfaces which has no cycle,
|
||||
// or metered with no policy quotas, or snoozed notification; we still need to put
|
||||
// iptables rule hooks to restrict apps for data saver, so push really high quota.
|
||||
// TODO: Push NetworkStatsProvider.QUOTA_UNLIMITED instead of Long.MAX_VALUE to
|
||||
// providers.
|
||||
for (int j = matchingIfaces.size() - 1; j >= 0; j--) {
|
||||
final String iface = matchingIfaces.valueAt(j);
|
||||
setInterfaceQuotaAsync(iface, quotaBytes);
|
||||
setInterfaceQuotasAsync(iface, warningBytes, limitBytes);
|
||||
newMeteredIfaces.add(iface);
|
||||
}
|
||||
}
|
||||
@@ -1964,7 +1971,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
for (int j = matchingIfaces.size() - 1; j >= 0; j--) {
|
||||
final String iface = matchingIfaces.valueAt(j);
|
||||
if (!newMeteredIfaces.contains(iface)) {
|
||||
setInterfaceQuotaAsync(iface, Long.MAX_VALUE);
|
||||
setInterfaceQuotasAsync(iface, Long.MAX_VALUE, Long.MAX_VALUE);
|
||||
newMeteredIfaces.add(iface);
|
||||
}
|
||||
}
|
||||
@@ -1972,13 +1979,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
}
|
||||
|
||||
// Remove quota from any interfaces that are no longer metered.
|
||||
for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
|
||||
final String iface = mMeteredIfaces.valueAt(i);
|
||||
if (!newMeteredIfaces.contains(iface)) {
|
||||
removeInterfaceQuotaAsync(iface);
|
||||
synchronized (mMeteredIfacesLock) {
|
||||
for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
|
||||
final String iface = mMeteredIfaces.valueAt(i);
|
||||
if (!newMeteredIfaces.contains(iface)) {
|
||||
removeInterfaceQuotasAsync(iface);
|
||||
}
|
||||
}
|
||||
mMeteredIfaces = newMeteredIfaces;
|
||||
}
|
||||
mMeteredIfaces = newMeteredIfaces;
|
||||
|
||||
final ContentResolver cr = mContext.getContentResolver();
|
||||
final boolean quotaEnabled = Settings.Global.getInt(cr,
|
||||
@@ -2030,7 +2039,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
mSubscriptionOpportunisticQuota.put(subId, quotaBytes);
|
||||
}
|
||||
|
||||
final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
|
||||
final String[] meteredIfaces;
|
||||
synchronized (mMeteredIfacesLock) {
|
||||
meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
|
||||
}
|
||||
mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
|
||||
|
||||
mHandler.obtainMessage(MSG_ADVISE_PERSIST_THRESHOLD, lowestRule).sendToTarget();
|
||||
@@ -3436,7 +3448,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
fout.print("Restrict background: "); fout.println(mRestrictBackground);
|
||||
fout.print("Restrict power: "); fout.println(mRestrictPower);
|
||||
fout.print("Device idle: "); fout.println(mDeviceIdleMode);
|
||||
fout.print("Metered ifaces: "); fout.println(mMeteredIfaces);
|
||||
synchronized (mMeteredIfacesLock) {
|
||||
fout.print("Metered ifaces: ");
|
||||
fout.println(mMeteredIfaces);
|
||||
}
|
||||
|
||||
fout.println();
|
||||
fout.print("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode);
|
||||
@@ -4618,7 +4633,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
mListeners.finishBroadcast();
|
||||
return true;
|
||||
}
|
||||
case MSG_STATS_PROVIDER_LIMIT_REACHED: {
|
||||
case MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED: {
|
||||
mNetworkStats.forceUpdate();
|
||||
|
||||
synchronized (mNetworkPoliciesSecondLock) {
|
||||
@@ -4632,7 +4647,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
}
|
||||
case MSG_LIMIT_REACHED: {
|
||||
final String iface = (String) msg.obj;
|
||||
synchronized (mNetworkPoliciesSecondLock) {
|
||||
synchronized (mMeteredIfacesLock) {
|
||||
// fast return if not needed.
|
||||
if (!mMeteredIfaces.contains(iface)) {
|
||||
return true;
|
||||
@@ -4689,19 +4704,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
mNetworkStats.advisePersistThreshold(persistThreshold);
|
||||
return true;
|
||||
}
|
||||
case MSG_UPDATE_INTERFACE_QUOTA: {
|
||||
final String iface = (String) msg.obj;
|
||||
// int params need to be stitched back into a long
|
||||
final long quota = ((long) msg.arg1 << 32) | (msg.arg2 & 0xFFFFFFFFL);
|
||||
removeInterfaceQuota(iface);
|
||||
setInterfaceQuota(iface, quota);
|
||||
mNetworkStats.setStatsProviderLimitAsync(iface, quota);
|
||||
case MSG_UPDATE_INTERFACE_QUOTAS: {
|
||||
final IfaceQuotas val = (IfaceQuotas) msg.obj;
|
||||
// TODO: Consider set a new limit before removing the original one.
|
||||
removeInterfaceLimit(val.iface);
|
||||
setInterfaceLimit(val.iface, val.limit);
|
||||
mNetworkStats.setStatsProviderWarningAndLimitAsync(val.iface, val.warning,
|
||||
val.limit);
|
||||
return true;
|
||||
}
|
||||
case MSG_REMOVE_INTERFACE_QUOTA: {
|
||||
case MSG_REMOVE_INTERFACE_QUOTAS: {
|
||||
final String iface = (String) msg.obj;
|
||||
removeInterfaceQuota(iface);
|
||||
mNetworkStats.setStatsProviderLimitAsync(iface, QUOTA_UNLIMITED);
|
||||
removeInterfaceLimit(iface);
|
||||
mNetworkStats.setStatsProviderWarningAndLimitAsync(iface, QUOTA_UNLIMITED,
|
||||
QUOTA_UNLIMITED);
|
||||
return true;
|
||||
}
|
||||
case MSG_RESET_FIREWALL_RULES_BY_UID: {
|
||||
@@ -4829,15 +4845,32 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void setInterfaceQuotaAsync(String iface, long quotaBytes) {
|
||||
// long quotaBytes split up into two ints to fit in message
|
||||
mHandler.obtainMessage(MSG_UPDATE_INTERFACE_QUOTA, (int) (quotaBytes >> 32),
|
||||
(int) (quotaBytes & 0xFFFFFFFF), iface).sendToTarget();
|
||||
private static final class IfaceQuotas {
|
||||
@NonNull public final String iface;
|
||||
// Warning and limit bytes of interface qutoas, could be QUOTA_UNLIMITED or Long.MAX_VALUE
|
||||
// if not set. 0 is not acceptable since kernel doesn't like 0-byte rules.
|
||||
public final long warning;
|
||||
public final long limit;
|
||||
|
||||
private IfaceQuotas(@NonNull String iface, long warning, long limit) {
|
||||
this.iface = iface;
|
||||
this.warning = warning;
|
||||
this.limit = limit;
|
||||
}
|
||||
}
|
||||
|
||||
private void setInterfaceQuota(String iface, long quotaBytes) {
|
||||
private void setInterfaceQuotasAsync(@NonNull String iface,
|
||||
long warningBytes, long limitBytes) {
|
||||
mHandler.obtainMessage(MSG_UPDATE_INTERFACE_QUOTAS,
|
||||
new IfaceQuotas(iface, warningBytes, limitBytes)).sendToTarget();
|
||||
}
|
||||
|
||||
private void setInterfaceLimit(String iface, long limitBytes) {
|
||||
try {
|
||||
mNetworkManager.setInterfaceQuota(iface, quotaBytes);
|
||||
// For legacy design the data warning is covered by global alert, where the
|
||||
// kernel will notify upper layer for a small amount of change of traffic
|
||||
// statistics. Thus, passing warning is not needed.
|
||||
mNetworkManager.setInterfaceQuota(iface, limitBytes);
|
||||
} catch (IllegalStateException e) {
|
||||
Log.wtf(TAG, "problem setting interface quota", e);
|
||||
} catch (RemoteException e) {
|
||||
@@ -4845,11 +4878,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void removeInterfaceQuotaAsync(String iface) {
|
||||
mHandler.obtainMessage(MSG_REMOVE_INTERFACE_QUOTA, iface).sendToTarget();
|
||||
private void removeInterfaceQuotasAsync(String iface) {
|
||||
mHandler.obtainMessage(MSG_REMOVE_INTERFACE_QUOTAS, iface).sendToTarget();
|
||||
}
|
||||
|
||||
private void removeInterfaceQuota(String iface) {
|
||||
private void removeInterfaceLimit(String iface) {
|
||||
try {
|
||||
mNetworkManager.removeInterfaceQuota(iface);
|
||||
} catch (IllegalStateException e) {
|
||||
@@ -5274,7 +5307,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
isBackgroundRestricted = mRestrictBackground;
|
||||
}
|
||||
final boolean isNetworkMetered;
|
||||
synchronized (mNetworkPoliciesSecondLock) {
|
||||
synchronized (mMeteredIfacesLock) {
|
||||
isNetworkMetered = mMeteredIfaces.contains(ifname);
|
||||
}
|
||||
final boolean ret = isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
|
||||
@@ -5361,9 +5394,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatsProviderLimitReached(@NonNull String tag) {
|
||||
Log.v(TAG, "onStatsProviderLimitReached: " + tag);
|
||||
mHandler.obtainMessage(MSG_STATS_PROVIDER_LIMIT_REACHED).sendToTarget();
|
||||
public void onStatsProviderWarningOrLimitReached(@NonNull String tag) {
|
||||
Log.v(TAG, "onStatsProviderWarningOrLimitReached: " + tag);
|
||||
mHandler.obtainMessage(MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,8 +37,9 @@ public abstract class NetworkStatsManagerInternal {
|
||||
public abstract void forceUpdate();
|
||||
|
||||
/**
|
||||
* Set the quota limit to all registered custom network stats providers.
|
||||
* Set the warning and limit to all registered custom network stats providers.
|
||||
* Note that invocation of any interface will be sent to all providers.
|
||||
*/
|
||||
public abstract void setStatsProviderLimitAsync(@NonNull String iface, long quota);
|
||||
public abstract void setStatsProviderWarningAndLimitAsync(@NonNull String iface, long warning,
|
||||
long limit);
|
||||
}
|
||||
|
||||
@@ -1658,9 +1658,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatsProviderLimitAsync(@NonNull String iface, long quota) {
|
||||
if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")");
|
||||
invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota));
|
||||
public void setStatsProviderWarningAndLimitAsync(
|
||||
@NonNull String iface, long warning, long limit) {
|
||||
if (LOGV) {
|
||||
Slog.v(TAG, "setStatsProviderWarningAndLimitAsync("
|
||||
+ iface + "," + warning + "," + limit + ")");
|
||||
}
|
||||
invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface,
|
||||
warning, limit));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2051,10 +2056,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyLimitReached() {
|
||||
Log.d(TAG, mTag + ": onLimitReached");
|
||||
public void notifyWarningOrLimitReached() {
|
||||
Log.d(TAG, mTag + ": notifyWarningOrLimitReached");
|
||||
LocalServices.getService(NetworkPolicyManagerInternal.class)
|
||||
.onStatsProviderLimitReached(mTag);
|
||||
.onStatsProviderWarningOrLimitReached(mTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1760,57 +1760,75 @@ public class NetworkPolicyManagerServiceTest {
|
||||
true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that when StatsProvider triggers limit reached, new limit will be calculated and
|
||||
* re-armed.
|
||||
*/
|
||||
@Test
|
||||
public void testStatsProviderLimitReached() throws Exception {
|
||||
final int CYCLE_DAY = 15;
|
||||
|
||||
final NetworkStats stats = new NetworkStats(0L, 1);
|
||||
private void increaseMockedTotalBytes(NetworkStats stats, long rxBytes, long txBytes) {
|
||||
stats.insertEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE,
|
||||
2999, 1, 2000, 1, 0);
|
||||
rxBytes, 1, txBytes, 1, 0);
|
||||
when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
|
||||
.thenReturn(stats.getTotalBytes());
|
||||
when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
|
||||
.thenReturn(stats);
|
||||
}
|
||||
|
||||
private void triggerOnStatsProviderWarningOrLimitReached() throws InterruptedException {
|
||||
final NetworkPolicyManagerInternal npmi = LocalServices
|
||||
.getService(NetworkPolicyManagerInternal.class);
|
||||
npmi.onStatsProviderWarningOrLimitReached("TEST");
|
||||
// Wait for processing of MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED.
|
||||
postMsgAndWaitForCompletion();
|
||||
verify(mStatsService).forceUpdate();
|
||||
// Wait for processing of MSG_*_INTERFACE_QUOTAS.
|
||||
postMsgAndWaitForCompletion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that when StatsProvider triggers warning and limit reached, new quotas will be
|
||||
* calculated and re-armed.
|
||||
*/
|
||||
@Test
|
||||
public void testStatsProviderWarningAndLimitReached() throws Exception {
|
||||
final int CYCLE_DAY = 15;
|
||||
|
||||
final NetworkStats stats = new NetworkStats(0L, 1);
|
||||
increaseMockedTotalBytes(stats, 2999, 2000);
|
||||
|
||||
// Get active mobile network in place
|
||||
expectMobileDefaults();
|
||||
mService.updateNetworks();
|
||||
verify(mStatsService).setStatsProviderLimitAsync(TEST_IFACE, Long.MAX_VALUE);
|
||||
verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, Long.MAX_VALUE,
|
||||
Long.MAX_VALUE);
|
||||
|
||||
// Set limit to 10KB.
|
||||
// Set warning to 7KB and limit to 10KB.
|
||||
setNetworkPolicies(new NetworkPolicy(
|
||||
sTemplateMobileAll, CYCLE_DAY, TIMEZONE_UTC, WARNING_DISABLED, 10000L,
|
||||
true));
|
||||
sTemplateMobileAll, CYCLE_DAY, TIMEZONE_UTC, 7000L, 10000L, true));
|
||||
postMsgAndWaitForCompletion();
|
||||
|
||||
// Verifies that remaining quota is set to providers.
|
||||
verify(mStatsService).setStatsProviderLimitAsync(TEST_IFACE, 10000L - 4999L);
|
||||
|
||||
// Verifies that remaining quotas are set to providers.
|
||||
verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, 2001L, 5001L);
|
||||
reset(mStatsService);
|
||||
|
||||
// Increase the usage.
|
||||
stats.insertEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE,
|
||||
1000, 1, 999, 1, 0);
|
||||
when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
|
||||
.thenReturn(stats.getTotalBytes());
|
||||
when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
|
||||
.thenReturn(stats);
|
||||
// Increase the usage and simulates that limit reached fires earlier by provider,
|
||||
// but actually the quota is not yet reached. Verifies that the limit reached leads to
|
||||
// a force update and new quotas should be set.
|
||||
increaseMockedTotalBytes(stats, 1000, 999);
|
||||
triggerOnStatsProviderWarningOrLimitReached();
|
||||
verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, 2L, 3002L);
|
||||
reset(mStatsService);
|
||||
|
||||
// Simulates that limit reached fires earlier by provider, but actually the quota is not
|
||||
// yet reached.
|
||||
final NetworkPolicyManagerInternal npmi = LocalServices
|
||||
.getService(NetworkPolicyManagerInternal.class);
|
||||
npmi.onStatsProviderLimitReached("TEST");
|
||||
// Increase the usage and simulate warning reached, the new warning should be unlimited
|
||||
// since service will disable warning quota to stop lower layer from keep triggering
|
||||
// warning reached event.
|
||||
increaseMockedTotalBytes(stats, 1000L, 1000);
|
||||
triggerOnStatsProviderWarningOrLimitReached();
|
||||
verify(mStatsService).setStatsProviderWarningAndLimitAsync(
|
||||
TEST_IFACE, Long.MAX_VALUE, 1002L);
|
||||
reset(mStatsService);
|
||||
|
||||
// Verifies that the limit reached leads to a force update and new limit should be set.
|
||||
postMsgAndWaitForCompletion();
|
||||
verify(mStatsService).forceUpdate();
|
||||
postMsgAndWaitForCompletion();
|
||||
verify(mStatsService).setStatsProviderLimitAsync(TEST_IFACE, 10000L - 4999L - 1999L);
|
||||
// Increase the usage that over the warning and limit, the new limit should set to 1 to
|
||||
// block the network traffic.
|
||||
increaseMockedTotalBytes(stats, 1000L, 1000);
|
||||
triggerOnStatsProviderWarningOrLimitReached();
|
||||
verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, Long.MAX_VALUE, 1L);
|
||||
reset(mStatsService);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user