Snap for 6306509 from b1f2e3d0211be00397dcacc36296bf71800d3bbd to mainline-release

Change-Id: I4901b261694118fa1e9e82f927236842c4600e0b
This commit is contained in:
android-build-team Robot
2020-03-18 07:16:05 +00:00
7 changed files with 329 additions and 56 deletions

View File

@@ -29,10 +29,10 @@ import android.net.ConnectivityManager;
import android.net.DataUsageRequest;
import android.net.INetworkStatsService;
import android.net.NetworkIdentity;
import android.net.NetworkStack;
import android.net.NetworkTemplate;
import android.net.netstats.provider.AbstractNetworkStatsProvider;
import android.net.netstats.provider.NetworkStatsProviderCallback;
import android.net.netstats.provider.NetworkStatsProviderWrapper;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.net.netstats.provider.NetworkStatsProvider;
import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
@@ -527,32 +527,53 @@ public class NetworkStatsManager {
/**
* Registers a custom provider of {@link android.net.NetworkStats} to provide network statistics
* to the system. To unregister, invoke {@link NetworkStatsProviderCallback#unregister()}.
* to the system. To unregister, invoke {@link #unregisterNetworkStatsProvider}.
* Note that no de-duplication of statistics between providers is performed, so each provider
* must only report network traffic that is not being reported by any other provider.
* must only report network traffic that is not being reported by any other provider. Also note
* that the provider cannot be re-registered after unregistering.
*
* @param tag a human readable identifier of the custom network stats provider. This is only
* used for debugging.
* @param provider the subclass of {@link AbstractNetworkStatsProvider} that needs to be
* @param provider the subclass of {@link NetworkStatsProvider} that needs to be
* registered to the system.
* @return a {@link NetworkStatsProviderCallback}, which can be used to report events to the
* system or unregister the provider.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
@NonNull public NetworkStatsProviderCallback registerNetworkStatsProvider(
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STATS_PROVIDER,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
@NonNull public void registerNetworkStatsProvider(
@NonNull String tag,
@NonNull AbstractNetworkStatsProvider provider) {
@NonNull NetworkStatsProvider provider) {
try {
final NetworkStatsProviderWrapper wrapper = new NetworkStatsProviderWrapper(provider);
return new NetworkStatsProviderCallback(
mService.registerNetworkStatsProvider(tag, wrapper));
if (provider.getProviderCallbackBinder() != null) {
throw new IllegalArgumentException("provider is already registered");
}
final INetworkStatsProviderCallback cbBinder =
mService.registerNetworkStatsProvider(tag, provider.getProviderBinder());
provider.setProviderCallbackBinder(cbBinder);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
/**
* Unregisters an instance of {@link NetworkStatsProvider}.
*
* @param provider the subclass of {@link NetworkStatsProvider} that needs to be
* unregistered to the system.
* @hide
*/
@SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STATS_PROVIDER,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
@NonNull public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) {
try {
provider.getProviderCallbackBinderOrThrow().unregister();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
// Unreachable code, but compiler doesn't know about it.
return null;
}
private static NetworkTemplate createTemplate(int networkType, String subscriberId) {

View File

@@ -21,7 +21,6 @@ import static android.os.Process.CLAT_UID;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
@@ -58,9 +57,12 @@ import java.util.function.Predicate;
public final class NetworkStats implements Parcelable {
private static final String TAG = "NetworkStats";
/** {@link #iface} value when interface details unavailable. */
@SuppressLint("CompileTimeConstant")
/**
* {@link #iface} value when interface details unavailable.
* @hide
*/
@Nullable public static final String IFACE_ALL = null;
/**
* Virtual network interface for video telephony. This is for VT data usage counting
* purpose.
@@ -248,7 +250,13 @@ public final class NetworkStats implements Parcelable {
@UnsupportedAppUsage
private long[] operations;
/** @hide */
/**
* Basic element of network statistics. Contains the number of packets and number of bytes
* transferred on both directions in a given set of conditions. See
* {@link Entry#Entry(String, int, int, int, int, int, int, long, long, long, long, long)}.
*
* @hide
*/
@SystemApi
public static class Entry {
/** @hide */
@@ -319,6 +327,35 @@ public final class NetworkStats implements Parcelable {
rxBytes, rxPackets, txBytes, txPackets, operations);
}
/**
* Construct a {@link Entry} object by giving statistics of packet and byte transferred on
* both direction, and associated with a set of given conditions.
*
* @param iface interface name of this {@link Entry}. Or null if not specified.
* @param uid uid of this {@link Entry}. {@link #UID_TETHERING} if this {@link Entry} is
* for tethering. Or {@link #UID_ALL} if this {@link NetworkStats} is only
* counting iface stats.
* @param set usage state of this {@link Entry}. Should be one of the following
* values: {@link #SET_DEFAULT}, {@link #SET_FOREGROUND}.
* @param tag tag of this {@link Entry}.
* @param metered metered state of this {@link Entry}. Should be one of the following
* values: {link #METERED_YES}, {link #METERED_NO}.
* @param roaming roaming state of this {@link Entry}. Should be one of the following
* values: {link #ROAMING_YES}, {link #ROAMING_NO}.
* @param defaultNetwork default network status of this {@link Entry}. Should be one
* of the following values: {link #DEFAULT_NETWORK_YES},
* {link #DEFAULT_NETWORK_NO}.
* @param rxBytes Number of bytes received for this {@link Entry}. Statistics should
* represent the contents of IP packets, including IP headers.
* @param rxPackets Number of packets received for this {@link Entry}. Statistics should
* represent the contents of IP packets, including IP headers.
* @param txBytes Number of bytes transmitted for this {@link Entry}. Statistics should
* represent the contents of IP packets, including IP headers.
* @param txPackets Number of bytes transmitted for this {@link Entry}. Statistics should
* represent the contents of IP packets, including IP headers.
* @param operations count of network operations performed for this {@link Entry}. This can
* be used to derive bytes-per-operation.
*/
public Entry(@Nullable String iface, int uid, @State int set, int tag,
@Meteredness int metered, @Roaming int roaming, @DefaultNetwork int defaultNetwork,
long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
@@ -466,7 +503,7 @@ public final class NetworkStats implements Parcelable {
NetworkStats.Entry entry = null;
for (int i = 0; i < size; i++) {
entry = getValues(i, entry);
clone.addEntry(entry);
clone.insertEntry(entry);
}
return clone;
}
@@ -493,26 +530,26 @@ public final class NetworkStats implements Parcelable {
/** @hide */
@VisibleForTesting
public NetworkStats addIfaceValues(
public NetworkStats insertEntry(
String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
return addEntry(
return insertEntry(
iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
}
/** @hide */
@VisibleForTesting
public NetworkStats addEntry(String iface, int uid, int set, int tag, long rxBytes,
public NetworkStats insertEntry(String iface, int uid, int set, int tag, long rxBytes,
long rxPackets, long txBytes, long txPackets, long operations) {
return addEntry(new Entry(
return insertEntry(new Entry(
iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
}
/** @hide */
@VisibleForTesting
public NetworkStats addEntry(String iface, int uid, int set, int tag, int metered, int roaming,
int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets,
long operations) {
return addEntry(new Entry(
public NetworkStats insertEntry(String iface, int uid, int set, int tag, int metered,
int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes,
long txPackets, long operations) {
return insertEntry(new Entry(
iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets,
txBytes, txPackets, operations));
}
@@ -522,7 +559,7 @@ public final class NetworkStats implements Parcelable {
* object can be recycled across multiple calls.
* @hide
*/
public NetworkStats addEntry(Entry entry) {
public NetworkStats insertEntry(Entry entry) {
if (size >= capacity) {
final int newLength = Math.max(size, 10) * 3 / 2;
iface = Arrays.copyOf(iface, newLength);
@@ -665,7 +702,7 @@ public final class NetworkStats implements Parcelable {
entry.roaming, entry.defaultNetwork);
if (i == -1) {
// only create new entry when positive contribution
addEntry(entry);
insertEntry(entry);
} else {
rxBytes[i] += entry.rxBytes;
rxPackets[i] += entry.rxPackets;
@@ -684,7 +721,7 @@ public final class NetworkStats implements Parcelable {
* @param entry the {@link Entry} to add.
* @return a new constructed {@link NetworkStats} object that contains the result.
*/
public @NonNull NetworkStats addValues(@NonNull Entry entry) {
public @NonNull NetworkStats addEntry(@NonNull Entry entry) {
return this.clone().combineValues(entry);
}
@@ -1003,7 +1040,7 @@ public final class NetworkStats implements Parcelable {
entry.operations = Math.max(entry.operations, 0);
}
result.addEntry(entry);
result.insertEntry(entry);
}
return result;

View File

@@ -22,7 +22,7 @@ package android.net.netstats.provider;
* @hide
*/
oneway interface INetworkStatsProvider {
void requestStatsUpdate(int token);
void setLimit(String iface, long quotaBytes);
void setAlert(long quotaBytes);
void onRequestStatsUpdate(int token);
void onSetLimit(String iface, long quotaBytes);
void onSetAlert(long quotaBytes);
}

View File

@@ -24,8 +24,8 @@ import android.net.NetworkStats;
* @hide
*/
oneway interface INetworkStatsProviderCallback {
void onStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats);
void onAlertReached();
void onLimitReached();
void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats);
void notifyAlertReached();
void notifyLimitReached();
void unregister();
}

View File

@@ -0,0 +1,195 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.netstats.provider;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.NetworkStats;
import android.os.RemoteException;
/**
* A base class that allows external modules to implement a custom network statistics provider.
* @hide
*/
@SystemApi
public abstract class NetworkStatsProvider {
/**
* A value used by {@link #onSetLimit} and {@link #onSetAlert} indicates there is no limit.
*/
public static final int QUOTA_UNLIMITED = -1;
@NonNull private final INetworkStatsProvider mProviderBinder =
new INetworkStatsProvider.Stub() {
@Override
public void onRequestStatsUpdate(int token) {
NetworkStatsProvider.this.onRequestStatsUpdate(token);
}
@Override
public void onSetLimit(String iface, long quotaBytes) {
NetworkStatsProvider.this.onSetLimit(iface, quotaBytes);
}
@Override
public void onSetAlert(long quotaBytes) {
NetworkStatsProvider.this.onSetAlert(quotaBytes);
}
};
// The binder given by the service when successfully registering. Only null before registering,
// never null once non-null.
@Nullable
private INetworkStatsProviderCallback mProviderCbBinder;
/**
* Return the binder invoked by the service and redirect function calls to the overridden
* methods.
* @hide
*/
@NonNull
public INetworkStatsProvider getProviderBinder() {
return mProviderBinder;
}
/**
* Store the binder that was returned by the service when successfully registering. Note that
* the provider cannot be re-registered. Hence this method can only be called once per provider.
*
* @hide
*/
public void setProviderCallbackBinder(@NonNull INetworkStatsProviderCallback binder) {
if (mProviderCbBinder != null) {
throw new IllegalArgumentException("provider is already registered");
}
mProviderCbBinder = binder;
}
/**
* Get the binder that was returned by the service when successfully registering. Or null if the
* provider was never registered.
*
* @hide
*/
@Nullable
public INetworkStatsProviderCallback getProviderCallbackBinder() {
return mProviderCbBinder;
}
/**
* Get the binder that was returned by the service when successfully registering. Throw an
* {@link IllegalStateException} if the provider is not registered.
*
* @hide
*/
@NonNull
public INetworkStatsProviderCallback getProviderCallbackBinderOrThrow() {
if (mProviderCbBinder == null) {
throw new IllegalStateException("the provider is not registered");
}
return mProviderCbBinder;
}
/**
* Notify the system of new network statistics.
*
* Send the network statistics recorded since the last call to {@link #notifyStatsUpdated}. Must
* be called as soon as possible after {@link NetworkStatsProvider#onRequestStatsUpdate(int)}
* being called. Responding later increases the probability stats will be dropped. The
* provider can also call this whenever it wants to reports new stats for any reason.
* Note that the system will not necessarily immediately propagate the statistics to
* reflect the update.
*
* @param token the token under which these stats were gathered. Providers can call this method
* with the current token as often as they want, until the token changes.
* {@see NetworkStatsProvider#onRequestStatsUpdate()}
* @param ifaceStats the {@link NetworkStats} per interface to be reported.
* The provider should not include any traffic that is already counted by
* kernel interface counters.
* @param uidStats the same stats as above, but counts {@link NetworkStats}
* per uid.
*/
public void notifyStatsUpdated(int token, @NonNull NetworkStats ifaceStats,
@NonNull NetworkStats uidStats) {
try {
getProviderCallbackBinderOrThrow().notifyStatsUpdated(token, ifaceStats, uidStats);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
/**
* Notify system that the quota set by {@code onSetAlert} has been reached.
*/
public void notifyAlertReached() {
try {
getProviderCallbackBinderOrThrow().notifyAlertReached();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
/**
* Notify system that the quota set by {@code onSetLimit} has been reached.
*/
public void notifyLimitReached() {
try {
getProviderCallbackBinderOrThrow().notifyLimitReached();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
/**
* Called by {@code NetworkStatsService} when it requires to know updated stats.
* The provider MUST respond by calling {@link #notifyStatsUpdated} as soon as possible.
* Responding later increases the probability stats will be dropped. Memory allowing, the
* system will try to take stats into account up to one minute after calling
* {@link #onRequestStatsUpdate}.
*
* @param token a positive number identifying the new state of the system under which
* {@link NetworkStats} have to be gathered from now on. When this is called,
* custom implementations of providers MUST tally and report the latest stats with
* the previous token, under which stats were being gathered so far.
*/
public abstract void onRequestStatsUpdate(int token);
/**
* Called by {@code NetworkStatsService} when setting the interface quota for the specified
* upstream interface. When this is called, the custom implementation should block all egress
* packets on the {@code iface} associated with the provider when {@code quotaBytes} bytes have
* been reached, and MUST respond to it by calling
* {@link NetworkStatsProvider#notifyLimitReached()}.
*
* @param iface the interface requiring the operation.
* @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.
*/
public abstract void onSetLimit(@NonNull String iface, long quotaBytes);
/**
* Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations
* MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes
* have been reached. Unlike {@link #onSetLimit(String, long)}, the custom implementation should
* not block all egress packets.
*
* @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 alert.
*/
public abstract void onSetAlert(long quotaBytes);
}

View File

@@ -229,7 +229,7 @@ public class NetworkStatsFactory {
entry.txPackets += reader.nextLong();
}
stats.addEntry(entry);
stats.insertEntry(entry);
reader.finishLine();
}
} catch (NullPointerException|NumberFormatException e) {
@@ -279,7 +279,7 @@ public class NetworkStatsFactory {
entry.txBytes = reader.nextLong();
entry.txPackets = reader.nextLong();
stats.addEntry(entry);
stats.insertEntry(entry);
reader.finishLine();
}
} catch (NullPointerException|NumberFormatException e) {
@@ -439,7 +439,7 @@ public class NetworkStatsFactory {
if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface))
&& (limitUid == UID_ALL || limitUid == entry.uid)
&& (limitTag == TAG_ALL || limitTag == entry.tag)) {
stats.addEntry(entry);
stats.insertEntry(entry);
}
reader.finishLine();

View File

@@ -17,12 +17,14 @@
package com.android.server.net;
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
import static android.Manifest.permission.NETWORK_STATS_PROVIDER;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.content.Intent.ACTION_SHUTDOWN;
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.ConnectivityManager.isNetworkTypeMobile;
import static android.net.NetworkStack.checkNetworkStackPermission;
@@ -101,7 +103,7 @@ import android.net.NetworkTemplate;
import android.net.TrafficStats;
import android.net.netstats.provider.INetworkStatsProvider;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.net.netstats.provider.NetworkStatsProviderCallback;
import android.net.netstats.provider.NetworkStatsProvider;
import android.os.BestClock;
import android.os.Binder;
import android.os.DropBoxManager;
@@ -556,7 +558,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
} catch (RemoteException e) {
// ignored; service lives in system_server
}
invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setAlert(mGlobalAlertBytes));
invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetAlert(mGlobalAlertBytes));
}
@Override
@@ -757,7 +759,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null);
final NetworkStats stats = new NetworkStats(end - start, 1);
stats.addEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE,
stats.insertEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE,
METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets,
entry.txBytes, entry.txPackets, entry.operations));
return stats;
@@ -1374,7 +1376,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate");
final int registeredCallbackCount = mStatsProviderCbList.getRegisteredCallbackCount();
mStatsProviderSem.drainPermits();
invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.requestStatsUpdate(0 /* unused */));
invokeForAllStatsProviderCallbacks(
(cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */));
try {
mStatsProviderSem.tryAcquire(registeredCallbackCount,
MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS, TimeUnit.MILLISECONDS);
@@ -1549,7 +1552,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public void setStatsProviderLimitAsync(@NonNull String iface, long quota) {
Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")");
invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setLimit(iface, quota));
invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota));
}
}
@@ -1793,6 +1796,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
}
// TODO: It is copied from ConnectivityService, consider refactor these check permission
// functions to a proper util.
private boolean checkAnyPermissionOf(String... permissions) {
for (String permission : permissions) {
if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
return true;
}
}
return false;
}
private void enforceAnyPermissionOf(String... permissions) {
if (!checkAnyPermissionOf(permissions)) {
throw new SecurityException("Requires one of the following permissions: "
+ String.join(", ", permissions) + ".");
}
}
/**
* Registers a custom provider of {@link android.net.NetworkStats} to combine the network
* statistics that cannot be seen by the kernel to system. To unregister, invoke the
@@ -1800,16 +1821,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
*
* @param tag a human readable identifier of the custom network stats provider.
* @param provider the {@link INetworkStatsProvider} binder corresponding to the
* {@link android.net.netstats.provider.AbstractNetworkStatsProvider} to be
* registered.
* {@link NetworkStatsProvider} to be registered.
*
* @return a binder interface of
* {@link android.net.netstats.provider.NetworkStatsProviderCallback}, which can be
* used to report events to the system.
* @return a {@link INetworkStatsProviderCallback} binder
* interface, which can be used to report events to the system.
*/
public @NonNull INetworkStatsProviderCallback registerNetworkStatsProvider(
@NonNull String tag, @NonNull INetworkStatsProvider provider) {
mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG);
enforceAnyPermissionOf(NETWORK_STATS_PROVIDER,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
Objects.requireNonNull(provider, "provider is null");
Objects.requireNonNull(tag, "tag is null");
try {
@@ -1910,7 +1930,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
@Override
public void onStatsUpdated(int token, @Nullable NetworkStats ifaceStats,
public void notifyStatsUpdated(int token, @Nullable NetworkStats ifaceStats,
@Nullable NetworkStats uidStats) {
// TODO: 1. Use token to map ifaces to correct NetworkIdentity.
// 2. Store the difference and store it directly to the recorder.
@@ -1922,12 +1942,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
@Override
public void onAlertReached() throws RemoteException {
public void notifyAlertReached() throws RemoteException {
mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */);
}
@Override
public void onLimitReached() {
public void notifyLimitReached() {
Log.d(TAG, mTag + ": onLimitReached");
LocalServices.getService(NetworkPolicyManagerInternal.class)
.onStatsProviderLimitReached(mTag);