Name specific app for rapid data usage.
When a single app is responsible for more than half of the data usage
that caused us to trigger a "rapid usage" alert, name that app in the
notification. Tests to verify.
Move NPMS->NSS direct calls to "Internal" pattern, following
best-practices to avoid unnecessary AIDL exposure.
Remove 3G/4G split mobile plan support, which has been deprecated for
years and was never supported in a shipping product.
Move MultipathPolicyTracker in tree to reflect its package name.
Test: bit FrameworksNetTests:*
Test: bit FrameworksServicesTests:com.android.server.NetworkPolicyManagerServiceTest
Bug: 69263587, 64221505, 73431080, 72746951
Exempt-From-Owner-Approval: approved in previous PS
Change-Id: I3e4ec1ae2222d51b232f76f32faca93d4f8cd272
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 90e3ffd..381cfb6 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -39,9 +39,6 @@
*/
INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage);
- /** Return network layer usage total for traffic that matches template. */
- long getNetworkTotalBytes(in NetworkTemplate template, long start, long end);
-
/** Return data layer snapshot of UID network usage. */
NetworkStats getDataLayerSnapshotForUid(int uid);
/** Return set of any ifaces associated with mobile networks since boot. */
@@ -50,17 +47,11 @@
/** Increment data layer count of operations performed for UID and tag. */
void incrementOperationCount(int uid, int tag, int operationCount);
- /** Mark given UID as being in foreground for stats purposes. */
- void setUidForeground(int uid, boolean uidForeground);
-
/** Force update of ifaces. */
void forceUpdateIfaces(in Network[] defaultNetworks);
/** Force update of statistics. */
void forceUpdate();
- /** Advise persistance threshold; may be overridden internally. */
- void advisePersistThreshold(long thresholdBytes);
-
/** Registers a callback on data usage. */
DataUsageRequest registerUsageCallback(String callingPackage,
in DataUsageRequest request, in Messenger messenger, in IBinder binder);
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 01b2b39..16fb858 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -234,7 +234,7 @@
public NetworkStats(long elapsedRealtime, int initialSize) {
this.elapsedRealtime = elapsedRealtime;
this.size = 0;
- if (initialSize >= 0) {
+ if (initialSize > 0) {
this.capacity = initialSize;
this.iface = new String[initialSize];
this.uid = new int[initialSize];
@@ -250,19 +250,7 @@
this.operations = new long[initialSize];
} else {
// Special case for use by NetworkStatsFactory to start out *really* empty.
- this.capacity = 0;
- this.iface = EmptyArray.STRING;
- this.uid = EmptyArray.INT;
- this.set = EmptyArray.INT;
- this.tag = EmptyArray.INT;
- this.metered = EmptyArray.INT;
- this.roaming = EmptyArray.INT;
- this.defaultNetwork = EmptyArray.INT;
- this.rxBytes = EmptyArray.LONG;
- this.rxPackets = EmptyArray.LONG;
- this.txBytes = EmptyArray.LONG;
- this.txPackets = EmptyArray.LONG;
- this.operations = EmptyArray.LONG;
+ clear();
}
}
@@ -314,6 +302,25 @@
return clone;
}
+ /**
+ * Clear all data stored in this object.
+ */
+ public void clear() {
+ this.capacity = 0;
+ this.iface = EmptyArray.STRING;
+ this.uid = EmptyArray.INT;
+ this.set = EmptyArray.INT;
+ this.tag = EmptyArray.INT;
+ this.metered = EmptyArray.INT;
+ this.roaming = EmptyArray.INT;
+ this.defaultNetwork = EmptyArray.INT;
+ this.rxBytes = EmptyArray.LONG;
+ this.rxPackets = EmptyArray.LONG;
+ this.txBytes = EmptyArray.LONG;
+ this.txPackets = EmptyArray.LONG;
+ this.operations = EmptyArray.LONG;
+ }
+
@VisibleForTesting
public NetworkStats addIfaceValues(
String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 433f941..a13ad65 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -39,6 +39,8 @@
import com.android.internal.util.IndentingPrintWriter;
+import libcore.util.EmptyArray;
+
import java.io.CharArrayWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -459,6 +461,21 @@
}
/**
+ * Clear all data stored in this object.
+ */
+ public void clear() {
+ bucketStart = EmptyArray.LONG;
+ if (activeTime != null) activeTime = EmptyArray.LONG;
+ if (rxBytes != null) rxBytes = EmptyArray.LONG;
+ if (rxPackets != null) rxPackets = EmptyArray.LONG;
+ if (txBytes != null) txBytes = EmptyArray.LONG;
+ if (txPackets != null) txPackets = EmptyArray.LONG;
+ if (operations != null) operations = EmptyArray.LONG;
+ bucketCount = 0;
+ totalBytes = 0;
+ }
+
+ /**
* Remove buckets older than requested cutoff.
*/
@Deprecated
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 8efd39a..74233fd 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -23,7 +23,6 @@
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.ConnectivityManager.TYPE_WIMAX;
-import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
@@ -34,11 +33,6 @@
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.ROAMING_YES;
import static android.net.wifi.WifiInfo.removeDoubleQuotes;
-import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
-import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
-import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
-import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN;
-import static android.telephony.TelephonyManager.getNetworkClass;
import android.os.Parcel;
import android.os.Parcelable;
@@ -55,8 +49,8 @@
import java.util.Objects;
/**
- * Template definition used to generically match {@link NetworkIdentity},
- * usually when collecting statistics.
+ * Predicate used to match {@link NetworkIdentity}, usually when collecting
+ * statistics. (It should probably have been named {@code NetworkPredicate}.)
*
* @hide
*/
@@ -68,13 +62,7 @@
*/
private static final int BACKUP_VERSION = 1;
- public static final int MATCH_MOBILE_ALL = 1;
- /** @deprecated don't use this any more */
- @Deprecated
- public static final int MATCH_MOBILE_3G_LOWER = 2;
- /** @deprecated don't use this any more */
- @Deprecated
- public static final int MATCH_MOBILE_4G = 3;
+ public static final int MATCH_MOBILE = 1;
public static final int MATCH_WIFI = 4;
public static final int MATCH_ETHERNET = 5;
public static final int MATCH_MOBILE_WILDCARD = 6;
@@ -84,9 +72,7 @@
private static boolean isKnownMatchRule(final int rule) {
switch (rule) {
- case MATCH_MOBILE_ALL:
- case MATCH_MOBILE_3G_LOWER:
- case MATCH_MOBILE_4G:
+ case MATCH_MOBILE:
case MATCH_WIFI:
case MATCH_ETHERNET:
case MATCH_MOBILE_WILDCARD:
@@ -111,25 +97,7 @@
* the given IMSI.
*/
public static NetworkTemplate buildTemplateMobileAll(String subscriberId) {
- return new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId, null);
- }
-
- /**
- * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
- * the given IMSI that roughly meet a "3G" definition, or lower.
- */
- @Deprecated
- public static NetworkTemplate buildTemplateMobile3gLower(String subscriberId) {
- return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId, null);
- }
-
- /**
- * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
- * the given IMSI that roughly meet a "4G" definition.
- */
- @Deprecated
- public static NetworkTemplate buildTemplateMobile4g(String subscriberId) {
- return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId, null);
+ return new NetworkTemplate(MATCH_MOBILE, subscriberId, null);
}
/**
@@ -307,9 +275,7 @@
public boolean isMatchRuleMobile() {
switch (mMatchRule) {
- case MATCH_MOBILE_3G_LOWER:
- case MATCH_MOBILE_4G:
- case MATCH_MOBILE_ALL:
+ case MATCH_MOBILE:
case MATCH_MOBILE_WILDCARD:
return true;
default:
@@ -348,12 +314,8 @@
if (!matchesDefaultNetwork(ident)) return false;
switch (mMatchRule) {
- case MATCH_MOBILE_ALL:
+ case MATCH_MOBILE:
return matchesMobile(ident);
- case MATCH_MOBILE_3G_LOWER:
- return matchesMobile3gLower(ident);
- case MATCH_MOBILE_4G:
- return matchesMobile4g(ident);
case MATCH_WIFI:
return matchesWifi(ident);
case MATCH_ETHERNET:
@@ -410,43 +372,6 @@
}
/**
- * Check if mobile network classified 3G or lower with matching IMSI.
- */
- @Deprecated
- private boolean matchesMobile3gLower(NetworkIdentity ident) {
- ensureSubtypeAvailable();
- if (ident.mType == TYPE_WIMAX) {
- return false;
- } else if (matchesMobile(ident)) {
- switch (getNetworkClass(ident.mSubType)) {
- case NETWORK_CLASS_UNKNOWN:
- case NETWORK_CLASS_2_G:
- case NETWORK_CLASS_3_G:
- return true;
- }
- }
- return false;
- }
-
- /**
- * Check if mobile network classified 4G with matching IMSI.
- */
- @Deprecated
- private boolean matchesMobile4g(NetworkIdentity ident) {
- ensureSubtypeAvailable();
- if (ident.mType == TYPE_WIMAX) {
- // TODO: consider matching against WiMAX subscriber identity
- return true;
- } else if (matchesMobile(ident)) {
- switch (getNetworkClass(ident.mSubType)) {
- case NETWORK_CLASS_4_G:
- return true;
- }
- }
- return false;
- }
-
- /**
* Check if matches Wi-Fi network template.
*/
private boolean matchesWifi(NetworkIdentity ident) {
@@ -506,12 +431,8 @@
private static String getMatchRuleName(int matchRule) {
switch (matchRule) {
- case MATCH_MOBILE_3G_LOWER:
- return "MOBILE_3G_LOWER";
- case MATCH_MOBILE_4G:
- return "MOBILE_4G";
- case MATCH_MOBILE_ALL:
- return "MOBILE_ALL";
+ case MATCH_MOBILE:
+ return "MOBILE";
case MATCH_WIFI:
return "WIFI";
case MATCH_ETHERNET:
@@ -529,13 +450,6 @@
}
}
- private static void ensureSubtypeAvailable() {
- if (COMBINE_SUBTYPE_ENABLED) {
- throw new IllegalArgumentException(
- "Unable to enforce 3G_LOWER template on combined data.");
- }
- }
-
/**
* Examine the given template and normalize if it refers to a "merged"
* mobile subscriber. We pick the "lowest" merged subscriber as the primary
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e6186023..bf28414 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3768,31 +3768,23 @@
<string name="extract_edit_menu_button">Edit</string>
<!-- Notification title when data usage has exceeded warning threshold. [CHAR LIMIT=50] -->
- <string name="data_usage_warning_title">Data usage alert</string>
+ <string name="data_usage_warning_title">Data warning</string>
<!-- Notification body when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
- <string name="data_usage_warning_body">Tap to view usage and settings.</string>
+ <string name="data_usage_warning_body">You've used <xliff:g id="app" example="3.8GB">%s</xliff:g> of data</string>
- <!-- Notification title when 2G-3G data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
- <string name="data_usage_3g_limit_title">2G-3G data limit reached</string>
- <!-- Notification title when 4G data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
- <string name="data_usage_4g_limit_title">4G data limit reached</string>
<!-- Notification title when mobile data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=50] -->
<string name="data_usage_mobile_limit_title">Mobile data limit reached</string>
<!-- Notification title when Wi-Fi data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
<string name="data_usage_wifi_limit_title">Wi-Fi data limit reached</string>
<!-- Notification body when data usage has exceeded limit threshold, and has been disabled. -->
- <string name="data_usage_limit_body">Data paused for rest of cycle</string>
+ <string name="data_usage_limit_body">Data paused for the rest of your cycle</string>
- <!-- Notification title when 2G-3G data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
- <string name="data_usage_3g_limit_snoozed_title">2G-3G data limit exceeded</string>
- <!-- Notification title when 4G data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
- <string name="data_usage_4g_limit_snoozed_title">4G data limit exceeded</string>
<!-- Notification title when mobile data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
- <string name="data_usage_mobile_limit_snoozed_title">Mobile data limit exceeded</string>
+ <string name="data_usage_mobile_limit_snoozed_title">Over your mobile data limit</string>
<!-- Notification title when Wi-Fi data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
- <string name="data_usage_wifi_limit_snoozed_title">Wi-Fi data limit exceeded</string>
+ <string name="data_usage_wifi_limit_snoozed_title">Over your Wi-Fi data limit</string>
<!-- Notification body when data usage has exceeded limit threshold. -->
- <string name="data_usage_limit_snoozed_body"><xliff:g id="size" example="3.8GB">%s</xliff:g> over specified limit.</string>
+ <string name="data_usage_limit_snoozed_body">You've gone <xliff:g id="size" example="3.8GB">%s</xliff:g> over your set limit</string>
<!-- Notification title when background data usage is limited. [CHAR LIMIT=32] -->
<string name="data_usage_restricted_title">Background data restricted</string>
@@ -3800,9 +3792,11 @@
<string name="data_usage_restricted_body">Tap to remove restriction.</string>
<!-- Notification title when there has been recent excessive data usage. [CHAR LIMIT=32] -->
- <string name="data_usage_rapid_title">Large data usage</string>
+ <string name="data_usage_rapid_title">High mobile data usage</string>
<!-- Notification body when there has been recent excessive data usage. [CHAR LIMIT=128] -->
- <string name="data_usage_rapid_body">Your data usage over the last few days is larger than normal. Tap to view usage and settings.</string>
+ <string name="data_usage_rapid_body">Your apps have used more data than usual</string>
+ <!-- Notification body when there has been recent excessive data usage by a specific app. [CHAR LIMIT=128] -->
+ <string name="data_usage_rapid_app_body"><xliff:g id="app" example="Calculator">%s</xliff:g> has used more data than usual</string>
<!-- SSL Certificate dialogs -->
<!-- Title for an SSL Certificate dialog -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0493c2b..81af8c5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1970,10 +1970,6 @@
<java-symbol type="string" name="config_wimaxServiceClassname" />
<java-symbol type="string" name="config_wimaxServiceJarLocation" />
<java-symbol type="string" name="config_wimaxStateTrackerClassname" />
- <java-symbol type="string" name="data_usage_3g_limit_snoozed_title" />
- <java-symbol type="string" name="data_usage_3g_limit_title" />
- <java-symbol type="string" name="data_usage_4g_limit_snoozed_title" />
- <java-symbol type="string" name="data_usage_4g_limit_title" />
<java-symbol type="string" name="data_usage_limit_body" />
<java-symbol type="string" name="data_usage_limit_snoozed_body" />
<java-symbol type="string" name="data_usage_mobile_limit_snoozed_title" />
@@ -1986,6 +1982,7 @@
<java-symbol type="string" name="data_usage_wifi_limit_title" />
<java-symbol type="string" name="data_usage_rapid_title" />
<java-symbol type="string" name="data_usage_rapid_body" />
+ <java-symbol type="string" name="data_usage_rapid_app_body" />
<java-symbol type="string" name="default_wallpaper_component" />
<java-symbol type="string" name="device_storage_monitor_notification_channel" />
<java-symbol type="string" name="dlg_ok" />
diff --git a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
index f201165..be3168c 100644
--- a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
@@ -16,6 +16,9 @@
package com.android.systemui.net;
+import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
+import static android.net.NetworkTemplate.MATCH_MOBILE;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -32,11 +35,6 @@
import com.android.systemui.R;
-import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
-import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
-import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
-import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
-
/**
* Notify user that a {@link NetworkTemplate} is over its
* {@link NetworkPolicy#limitBytes}, giving them the choice of acknowledging or
@@ -85,11 +83,7 @@
private static int getLimitedDialogTitleForTemplate(NetworkTemplate template) {
switch (template.getMatchRule()) {
- case MATCH_MOBILE_3G_LOWER:
- return R.string.data_usage_disabled_dialog_3g_title;
- case MATCH_MOBILE_4G:
- return R.string.data_usage_disabled_dialog_4g_title;
- case MATCH_MOBILE_ALL:
+ case MATCH_MOBILE:
return R.string.data_usage_disabled_dialog_mobile_title;
default:
return R.string.data_usage_disabled_dialog_title;
diff --git a/services/core/java/com/android/server/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
similarity index 85%
rename from services/core/java/com/android/server/MultipathPolicyTracker.java
rename to services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 9e0a230..296b9ac 100644
--- a/services/core/java/com/android/server/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -16,11 +16,17 @@
package com.android.server.connectivity;
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER;
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
+import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH;
+
import android.app.usage.NetworkStatsManager;
import android.app.usage.NetworkStatsManager.UsageCallback;
import android.content.Context;
-import android.net.INetworkStatsService;
-import android.net.INetworkPolicyManager;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
@@ -31,29 +37,17 @@
import android.net.NetworkTemplate;
import android.net.StringNetworkSpecifier;
import android.os.Handler;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.telephony.TelephonyManager;
import android.util.DebugUtils;
import android.util.Slog;
-import java.util.Calendar;
-import java.util.concurrent.ConcurrentHashMap;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.net.NetworkStatsManagerInternal;
-import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER;
-import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
-import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
-import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH;
+import java.util.Calendar;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Manages multipath data budgets.
@@ -76,10 +70,8 @@
private final Handler mHandler;
private ConnectivityManager mCM;
- private NetworkStatsManager mStatsManager;
private NetworkPolicyManager mNPM;
- private TelephonyManager mTelephonyManager;
- private INetworkStatsService mStatsService;
+ private NetworkStatsManager mStatsManager;
private NetworkCallback mMobileNetworkCallback;
private NetworkPolicyManager.Listener mPolicyListener;
@@ -87,8 +79,6 @@
// STOPSHIP: replace this with a configurable mechanism.
private static final long DEFAULT_DAILY_MULTIPATH_QUOTA = 2_500_000;
- private volatile int mMeteredMultipathPreference;
-
public MultipathPolicyTracker(Context ctx, Handler handler) {
mContext = ctx;
mHandler = handler;
@@ -97,12 +87,9 @@
}
public void start() {
- mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- mNPM = (NetworkPolicyManager) mContext.getSystemService(Context.NETWORK_POLICY_SERVICE);
- mStatsManager = (NetworkStatsManager) mContext.getSystemService(
- Context.NETWORK_STATS_SERVICE);
- mStatsService = INetworkStatsService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+ mCM = mContext.getSystemService(ConnectivityManager.class);
+ mNPM = mContext.getSystemService(NetworkPolicyManager.class);
+ mStatsManager = mContext.getSystemService(NetworkStatsManager.class);
registerTrackMobileCallback();
registerNetworkPolicyListener();
@@ -119,6 +106,9 @@
// Called on an arbitrary binder thread.
public Integer getMultipathPreference(Network network) {
+ if (network == null) {
+ return null;
+ }
MultipathTracker t = mMultipathTrackers.get(network);
if (t != null) {
return t.getMultipathPreference();
@@ -149,8 +139,7 @@
network, nc, e.getMessage()));
}
- TelephonyManager tele = (TelephonyManager) mContext.getSystemService(
- Context.TELEPHONY_SERVICE);
+ TelephonyManager tele = mContext.getSystemService(TelephonyManager.class);
if (tele == null) {
throw new IllegalStateException(String.format("Missing TelephonyManager"));
}
@@ -162,7 +151,7 @@
subscriberId = tele.getSubscriberId();
mNetworkTemplate = new NetworkTemplate(
- NetworkTemplate.MATCH_MOBILE_ALL, subscriberId, new String[] { subscriberId },
+ NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId },
null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
NetworkStats.DEFAULT_NETWORK_NO);
mUsageCallback = new UsageCallback() {
@@ -185,26 +174,21 @@
start.set(Calendar.SECOND, 0);
start.set(Calendar.MILLISECOND, 0);
- long bytes;
try {
- // TODO: Consider using NetworkStatsManager.getSummaryForDevice instead.
- bytes = mStatsService.getNetworkTotalBytes(mNetworkTemplate,
- start.getTimeInMillis(), end.getTimeInMillis());
- if (DBG) Slog.w(TAG, "Non-default data usage: " + bytes);
- } catch (RemoteException e) {
- Slog.w(TAG, "Can't fetch daily data usage: " + e);
- bytes = -1;
- } catch (IllegalStateException e) {
- // Bandwidth control disabled?
- bytes = -1;
+ final long bytes = LocalServices.getService(NetworkStatsManagerInternal.class)
+ .getNetworkTotalBytes(mNetworkTemplate, start.getTimeInMillis(),
+ end.getTimeInMillis());
+ if (DBG) Slog.d(TAG, "Non-default data usage: " + bytes);
+ return bytes;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failed to get data usage: " + e);
+ return -1;
}
- return bytes;
}
void updateMultipathBudget() {
- NetworkPolicyManagerInternal npms = LocalServices.getService(
- NetworkPolicyManagerInternal.class);
- long quota = npms.getSubscriptionOpportunisticQuota(this.network, QUOTA_TYPE_MULTIPATH);
+ long quota = LocalServices.getService(NetworkPolicyManagerInternal.class)
+ .getSubscriptionOpportunisticQuota(this.network, QUOTA_TYPE_MULTIPATH);
if (DBG) Slog.d(TAG, "Opportunistic quota from data plan: " + quota + " bytes");
if (quota == 0) {
@@ -223,8 +207,10 @@
}
mQuota = quota;
- long usage = getDailyNonDefaultDataUsage();
- long budget = Math.max(0, quota - usage);
+ // If we can't get current usage, assume the worst and don't give
+ // ourselves any budget to work with.
+ final long usage = getDailyNonDefaultDataUsage();
+ final long budget = (usage == -1) ? 0 : Math.max(0, quota - usage);
if (budget > 0) {
if (DBG) Slog.d(TAG, "Setting callback for " + budget +
" bytes on network " + network);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index bd9ec55..f29e0bb 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -28,6 +28,11 @@
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_UID;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
@@ -61,9 +66,7 @@
import static android.net.NetworkPolicyManager.resolveNetworkId;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
import static android.net.NetworkPolicyManager.uidRulesToString;
-import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
-import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
-import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
+import static android.net.NetworkTemplate.MATCH_MOBILE;
import static android.net.NetworkTemplate.MATCH_WIFI;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.TrafficStats.MB_IN_BYTES;
@@ -71,7 +74,6 @@
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -139,15 +141,16 @@
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.NetworkState;
+import android.net.NetworkStats;
import android.net.NetworkTemplate;
import android.net.StringNetworkSpecifier;
import android.net.TrafficStats;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
+import android.os.BestClock;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
-import android.os.BestClock;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IDeviceIdleController;
@@ -359,7 +362,7 @@
private final Context mContext;
private final IActivityManager mActivityManager;
- private final INetworkStatsService mNetworkStats;
+ private NetworkStatsManagerInternal mNetworkStats;
private final INetworkManagementService mNetworkManager;
private UsageStatsManagerInternal mUsageStats;
private final Clock mClock;
@@ -516,10 +519,9 @@
// TODO: migrate notifications to SystemUI
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
- INetworkStatsService networkStats, INetworkManagementService networkManagement) {
- this(context, activityManager, networkStats, networkManagement,
- AppGlobals.getPackageManager(), getDefaultClock(), getDefaultSystemDir(),
- false);
+ INetworkManagementService networkManagement) {
+ this(context, activityManager, networkManagement, AppGlobals.getPackageManager(),
+ getDefaultClock(), getDefaultSystemDir(), false);
}
private static @NonNull File getDefaultSystemDir() {
@@ -532,11 +534,10 @@
}
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
- INetworkStatsService networkStats, INetworkManagementService networkManagement,
- IPackageManager pm, Clock clock, File systemDir, boolean suppressDefaultPolicy) {
+ INetworkManagementService networkManagement, IPackageManager pm, Clock clock,
+ File systemDir, boolean suppressDefaultPolicy) {
mContext = checkNotNull(context, "missing context");
mActivityManager = checkNotNull(activityManager, "missing activityManager");
- mNetworkStats = checkNotNull(networkStats, "missing networkStats");
mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
mDeviceIdleController = IDeviceIdleController.Stub.asInterface(ServiceManager.getService(
Context.DEVICE_IDLE_CONTROLLER));
@@ -660,6 +661,7 @@
}
mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+ mNetworkStats = LocalServices.getService(NetworkStatsManagerInternal.class);
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
@@ -1063,9 +1065,9 @@
if (policy.isOverLimit(totalBytes)) {
final boolean snoozedThisCycle = policy.lastLimitSnooze >= cycleStart;
if (snoozedThisCycle) {
- enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
+ enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes, null);
} else {
- enqueueNotification(policy, TYPE_LIMIT, totalBytes);
+ enqueueNotification(policy, TYPE_LIMIT, totalBytes, null);
notifyOverLimitNL(policy.template);
}
@@ -1074,7 +1076,7 @@
final boolean snoozedThisCycle = policy.lastWarningSnooze >= cycleStart;
if (policy.isOverWarning(totalBytes) && !snoozedThisCycle) {
- enqueueNotification(policy, TYPE_WARNING, totalBytes);
+ enqueueNotification(policy, TYPE_WARNING, totalBytes, null);
}
}
@@ -1082,7 +1084,9 @@
// far past the plan limits.
if (policy.limitBytes != LIMIT_DISABLED) {
final long recentDuration = TimeUnit.DAYS.toMillis(4);
- final long recentBytes = getTotalBytes(policy.template, now - recentDuration, now);
+ final long recentStart = now - recentDuration;
+ final long recentEnd = now;
+ final long recentBytes = getTotalBytes(policy.template, recentStart, recentEnd);
final long cycleDuration = cycleEnd - cycleStart;
final long projectedBytes = (recentBytes * cycleDuration) / recentDuration;
@@ -1096,7 +1100,8 @@
final boolean snoozedRecently = policy.lastRapidSnooze >= now
- DateUtils.DAY_IN_MILLIS;
if (projectedBytes > alertBytes && !snoozedRecently) {
- enqueueNotification(policy, TYPE_RAPID, 0);
+ enqueueNotification(policy, TYPE_RAPID, 0,
+ findRapidBlame(policy.template, recentStart, recentEnd));
}
}
}
@@ -1111,6 +1116,45 @@
}
/**
+ * Attempt to find a specific app to blame for rapid data usage during the
+ * given time period.
+ */
+ private @Nullable ApplicationInfo findRapidBlame(NetworkTemplate template,
+ long start, long end) {
+ long totalBytes = 0;
+ long maxBytes = 0;
+ int maxUid = 0;
+
+ final NetworkStats stats = getNetworkUidBytes(template, start, end);
+ NetworkStats.Entry entry = null;
+ for (int i = 0; i < stats.size(); i++) {
+ entry = stats.getValues(i, entry);
+ final long bytes = entry.rxBytes + entry.txBytes;
+ totalBytes += bytes;
+ if (bytes > maxBytes) {
+ maxBytes = bytes;
+ maxUid = entry.uid;
+ }
+ }
+
+ // Only point blame if the majority of usage was done by a single app.
+ // TODO: support shared UIDs
+ if (maxBytes > 0 && maxBytes > totalBytes / 2) {
+ final String[] packageNames = mContext.getPackageManager().getPackagesForUid(maxUid);
+ if (packageNames.length == 1) {
+ try {
+ return mContext.getPackageManager().getApplicationInfo(packageNames[0],
+ MATCH_ANY_USER | MATCH_DISABLED_COMPONENTS | MATCH_DIRECT_BOOT_AWARE
+ | MATCH_DIRECT_BOOT_UNAWARE | MATCH_UNINSTALLED_PACKAGES);
+ } catch (NameNotFoundException ignored) {
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
* Test if given {@link NetworkTemplate} is relevant to user based on
* current device state, such as when
* {@link TelephonyManager#getSubscriberId()} matches. This is regardless of
@@ -1157,7 +1201,8 @@
* Show notification for combined {@link NetworkPolicy} and specific type,
* like {@link #TYPE_LIMIT}. Okay to call multiple times.
*/
- private void enqueueNotification(NetworkPolicy policy, int type, long totalBytes) {
+ private void enqueueNotification(NetworkPolicy policy, int type, long totalBytes,
+ ApplicationInfo rapidBlame) {
final NotificationId notificationId = new NotificationId(policy, type);
final Notification.Builder builder =
new Notification.Builder(mContext, SystemNotificationChannels.NETWORK_ALERTS);
@@ -1167,16 +1212,15 @@
com.android.internal.R.color.system_notification_accent_color));
final Resources res = mContext.getResources();
- CharSequence body = null;
+ final CharSequence title;
+ final CharSequence body;
switch (type) {
case TYPE_WARNING: {
- final CharSequence title = res.getText(R.string.data_usage_warning_title);
- body = res.getString(R.string.data_usage_warning_body);
+ title = res.getText(R.string.data_usage_warning_title);
+ body = res.getString(R.string.data_usage_warning_body,
+ Formatter.formatFileSize(mContext, totalBytes));
builder.setSmallIcon(R.drawable.stat_notify_error);
- builder.setTicker(title);
- builder.setContentTitle(title);
- builder.setContentText(body);
final Intent snoozeIntent = buildSnoozeWarningIntent(policy.template);
builder.setDeleteIntent(PendingIntent.getBroadcast(
@@ -1189,34 +1233,20 @@
break;
}
case TYPE_LIMIT: {
- body = res.getText(R.string.data_usage_limit_body);
-
- final CharSequence title;
- int icon = R.drawable.stat_notify_disabled_data;
switch (policy.template.getMatchRule()) {
- case MATCH_MOBILE_3G_LOWER:
- title = res.getText(R.string.data_usage_3g_limit_title);
- break;
- case MATCH_MOBILE_4G:
- title = res.getText(R.string.data_usage_4g_limit_title);
- break;
- case MATCH_MOBILE_ALL:
+ case MATCH_MOBILE:
title = res.getText(R.string.data_usage_mobile_limit_title);
break;
case MATCH_WIFI:
title = res.getText(R.string.data_usage_wifi_limit_title);
- icon = R.drawable.stat_notify_error;
break;
default:
- title = null;
- break;
+ return;
}
+ body = res.getText(R.string.data_usage_limit_body);
builder.setOngoing(true);
- builder.setSmallIcon(icon);
- builder.setTicker(title);
- builder.setContentTitle(title);
- builder.setContentText(body);
+ builder.setSmallIcon(R.drawable.stat_notify_disabled_data);
final Intent intent = buildNetworkOverLimitIntent(res, policy.template);
builder.setContentIntent(PendingIntent.getActivity(
@@ -1224,34 +1254,22 @@
break;
}
case TYPE_LIMIT_SNOOZED: {
- final long overBytes = totalBytes - policy.limitBytes;
- body = res.getString(R.string.data_usage_limit_snoozed_body,
- Formatter.formatFileSize(mContext, overBytes));
-
- final CharSequence title;
switch (policy.template.getMatchRule()) {
- case MATCH_MOBILE_3G_LOWER:
- title = res.getText(R.string.data_usage_3g_limit_snoozed_title);
- break;
- case MATCH_MOBILE_4G:
- title = res.getText(R.string.data_usage_4g_limit_snoozed_title);
- break;
- case MATCH_MOBILE_ALL:
+ case MATCH_MOBILE:
title = res.getText(R.string.data_usage_mobile_limit_snoozed_title);
break;
case MATCH_WIFI:
title = res.getText(R.string.data_usage_wifi_limit_snoozed_title);
break;
default:
- title = null;
- break;
+ return;
}
+ final long overBytes = totalBytes - policy.limitBytes;
+ body = res.getString(R.string.data_usage_limit_snoozed_body,
+ Formatter.formatFileSize(mContext, overBytes));
builder.setOngoing(true);
builder.setSmallIcon(R.drawable.stat_notify_error);
- builder.setTicker(title);
- builder.setContentTitle(title);
- builder.setContentText(body);
builder.setChannelId(SystemNotificationChannels.NETWORK_STATUS);
final Intent intent = buildViewDataUsageIntent(res, policy.template);
@@ -1260,13 +1278,15 @@
break;
}
case TYPE_RAPID: {
- final CharSequence title = res.getText(R.string.data_usage_rapid_title);
- body = res.getText(R.string.data_usage_rapid_body);
+ title = res.getText(R.string.data_usage_rapid_title);
+ if (rapidBlame != null) {
+ body = res.getString(R.string.data_usage_rapid_app_body,
+ rapidBlame.loadLabel(mContext.getPackageManager()));
+ } else {
+ body = res.getString(R.string.data_usage_rapid_body);
+ }
builder.setSmallIcon(R.drawable.stat_notify_error);
- builder.setTicker(title);
- builder.setContentTitle(title);
- builder.setContentText(body);
final Intent snoozeIntent = buildSnoozeRapidIntent(policy.template);
builder.setDeleteIntent(PendingIntent.getBroadcast(
@@ -1277,11 +1297,15 @@
mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT));
break;
}
+ default: {
+ return;
+ }
}
- if (!TextUtils.isEmpty(body)) {
- builder.setStyle(new Notification.BigTextStyle().bigText(body));
- }
+ builder.setTicker(title);
+ builder.setContentTitle(title);
+ builder.setContentText(body);
+ builder.setStyle(new Notification.BigTextStyle().bigText(body));
mContext.getSystemService(NotificationManager.class).notifyAsUser(notificationId.getTag(),
notificationId.getId(), builder.build(), UserHandle.ALL);
@@ -1537,7 +1561,7 @@
// TODO: reach into ConnectivityManager to proactively disable bringing
// up this network, since we know that traffic will be blocked.
- if (template.getMatchRule() == MATCH_MOBILE_ALL) {
+ if (template.getMatchRule() == MATCH_MOBILE) {
// If mobile data usage hits the limit or if the user resumes the data, we need to
// notify telephony.
final SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class);
@@ -1954,9 +1978,7 @@
metered = readBooleanAttribute(in, ATTR_METERED);
} else {
switch (networkTemplate) {
- case MATCH_MOBILE_3G_LOWER:
- case MATCH_MOBILE_4G:
- case MATCH_MOBILE_ALL:
+ case MATCH_MOBILE:
metered = true;
break;
default:
@@ -3243,8 +3265,6 @@
}
try {
mNetworkStats.setUidForeground(uid, uidForeground);
- } catch (RemoteException e) {
- // ignored; service lives in system_server
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
@@ -4028,13 +4048,9 @@
synchronized (mNetworkPoliciesSecondLock) {
if (mMeteredIfaces.contains(iface)) {
- try {
- // force stats update to make sure we have
- // numbers that caused alert to trigger.
- mNetworkStats.forceUpdate();
- } catch (RemoteException e) {
- // ignored; service lives in system_server
- }
+ // force stats update to make sure we have
+ // numbers that caused alert to trigger.
+ mNetworkStats.forceUpdate();
updateNetworkEnabledNL();
updateNotificationsNL();
@@ -4075,14 +4091,10 @@
}
case MSG_ADVISE_PERSIST_THRESHOLD: {
final long lowestRule = (Long) msg.obj;
- try {
- // make sure stats are recorded frequently enough; we aim
- // for 2MB threshold for 2GB/month rules.
- final long persistThreshold = lowestRule / 1000;
- mNetworkStats.advisePersistThreshold(persistThreshold);
- } catch (RemoteException e) {
- // ignored; service lives in system_server
- }
+ // make sure stats are recorded frequently enough; we aim
+ // for 2MB threshold for 2GB/month rules.
+ final long persistThreshold = lowestRule / 1000;
+ mNetworkStats.advisePersistThreshold(persistThreshold);
return true;
}
case MSG_UPDATE_INTERFACE_QUOTA: {
@@ -4366,15 +4378,26 @@
}
}
+ @Deprecated
private long getTotalBytes(NetworkTemplate template, long start, long end) {
+ return getNetworkTotalBytes(template, start, end);
+ }
+
+ private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
try {
return mNetworkStats.getNetworkTotalBytes(template, start, end);
} catch (RuntimeException e) {
- Slog.w(TAG, "problem reading network stats: " + e);
+ Slog.w(TAG, "Failed to read network stats: " + e);
return 0;
- } catch (RemoteException e) {
- // ignored; service lives in system_server
- return 0;
+ }
+ }
+
+ private NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) {
+ try {
+ return mNetworkStats.getNetworkUidBytes(template, start, end);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failed to read network stats: " + e);
+ return new NetworkStats(SystemClock.elapsedRealtime(), 0);
}
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 3cc4d83..a5f8dc7 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -106,6 +106,10 @@
reset();
}
+ public void clear() {
+ reset();
+ }
+
public void reset() {
mStats.clear();
mStartMillis = Long.MAX_VALUE;
diff --git a/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java b/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java
new file mode 100644
index 0000000..4843ede
--- /dev/null
+++ b/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 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 com.android.server.net;
+
+import android.net.NetworkStats;
+import android.net.NetworkTemplate;
+
+public abstract class NetworkStatsManagerInternal {
+ /** Return network layer usage total for traffic that matches template. */
+ public abstract long getNetworkTotalBytes(NetworkTemplate template, long start, long end);
+
+ /** Return network layer usage per-UID for traffic that matches template. */
+ public abstract NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end);
+
+ /** Mark given UID as being in foreground for stats purposes. */
+ public abstract void setUidForeground(int uid, boolean uidForeground);
+
+ /** Advise persistance threshold; may be overridden internally. */
+ public abstract void advisePersistThreshold(long thresholdBytes);
+
+ /** Force update of statistics. */
+ public abstract void forceUpdate();
+}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 32e15c9..93c04fe 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -49,7 +49,6 @@
import static android.provider.Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES;
import static android.provider.Settings.Global.NETSTATS_POLL_INTERVAL;
import static android.provider.Settings.Global.NETSTATS_SAMPLE_ENABLED;
-import static android.provider.Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE;
import static android.provider.Settings.Global.NETSTATS_UID_BUCKET_DURATION;
import static android.provider.Settings.Global.NETSTATS_UID_DELETE_AGE;
import static android.provider.Settings.Global.NETSTATS_UID_PERSIST_BYTES;
@@ -95,10 +94,10 @@
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TrafficStats;
+import android.os.BestClock;
import android.os.Binder;
import android.os.DropBoxManager;
import android.os.Environment;
-import android.os.BestClock;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -134,6 +133,7 @@
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
import com.android.server.connectivity.Tethering;
import java.io.File;
@@ -333,6 +333,9 @@
mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers");
mSystemDir = checkNotNull(systemDir, "missing systemDir");
mBaseDir = checkNotNull(baseDir, "missing baseDir");
+
+ LocalServices.addService(NetworkStatsManagerInternal.class,
+ new NetworkStatsManagerInternalImpl());
}
@VisibleForTesting
@@ -640,7 +643,7 @@
private SubscriptionPlan resolveSubscriptionPlan(NetworkTemplate template, int flags) {
SubscriptionPlan plan = null;
if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0
- && (template.getMatchRule() == NetworkTemplate.MATCH_MOBILE_ALL)
+ && (template.getMatchRule() == NetworkTemplate.MATCH_MOBILE)
&& mSettings.getAugmentEnabled()) {
if (LOGD) Slog.d(TAG, "Resolving plan for " + template);
final long token = Binder.clearCallingIdentity();
@@ -701,12 +704,8 @@
}
}
- @Override
- public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
- // Special case - since this is for internal use only, don't worry about
- // a full access level check and just require the signature/privileged
- // permission.
- mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+ private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
+ assertSystemReady();
assertBandwidthControlEnabled();
// NOTE: if callers want to get non-augmented data, they should go
@@ -716,6 +715,18 @@
NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotalBytes();
}
+ private NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) {
+ assertSystemReady();
+ assertBandwidthControlEnabled();
+
+ final NetworkStatsCollection uidComplete;
+ synchronized (mStatsLock) {
+ uidComplete = mUidRecorder.getOrLoadCompleteLocked();
+ }
+ return uidComplete.getSummary(template, start, end, NetworkStatsAccess.Level.DEVICE,
+ android.os.Process.SYSTEM_UID);
+ }
+
@Override
public NetworkStats getDataLayerSnapshotForUid(int uid) throws RemoteException {
if (Binder.getCallingUid() != uid) {
@@ -777,10 +788,8 @@
}
}
- @Override
- public void setUidForeground(int uid, boolean uidForeground) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
+ @VisibleForTesting
+ void setUidForeground(int uid, boolean uidForeground) {
synchronized (mStatsLock) {
final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT;
final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT);
@@ -817,9 +826,7 @@
}
}
- @Override
- public void advisePersistThreshold(long thresholdBytes) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ private void advisePersistThreshold(long thresholdBytes) {
assertBandwidthControlEnabled();
// clamp threshold into safe range
@@ -1330,6 +1337,33 @@
removeUidsLocked(uids);
}
+ private class NetworkStatsManagerInternalImpl extends NetworkStatsManagerInternal {
+ @Override
+ public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
+ return NetworkStatsService.this.getNetworkTotalBytes(template, start, end);
+ }
+
+ @Override
+ public NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) {
+ return NetworkStatsService.this.getNetworkUidBytes(template, start, end);
+ }
+
+ @Override
+ public void setUidForeground(int uid, boolean uidForeground) {
+ NetworkStatsService.this.setUidForeground(uid, uidForeground);
+ }
+
+ @Override
+ public void advisePersistThreshold(long thresholdBytes) {
+ NetworkStatsService.this.advisePersistThreshold(thresholdBytes);
+ }
+
+ @Override
+ public void forceUpdate() {
+ NetworkStatsService.this.forceUpdate();
+ }
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, rawWriter)) return;
@@ -1550,6 +1584,12 @@
}
}
+ private void assertSystemReady() {
+ if (!mSystemReady) {
+ throw new IllegalStateException("System not ready");
+ }
+ }
+
private void assertBandwidthControlEnabled() {
if (!isBandwidthControlEnabled()) {
throw new IllegalStateException("Bandwidth module disabled");
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 61c8b79..b53b10f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1088,8 +1088,8 @@
traceBeginAndSlog("StartNetworkPolicyManagerService");
try {
- networkPolicy = new NetworkPolicyManagerService(context,
- mActivityManagerService, networkStats, networkManagement);
+ networkPolicy = new NetworkPolicyManagerService(context, mActivityManagerService,
+ networkManagement);
ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
} catch (Throwable e) {
reportWtf("starting NetworkPolicy Service", e);
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index e1b4422..d31d550 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -26,6 +26,9 @@
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
+import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.SET_ALL;
+import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
@@ -42,8 +45,6 @@
import static com.android.server.net.NetworkPolicyManagerService.TYPE_RAPID;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
-import static com.google.common.truth.Truth.assertThat;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -86,7 +87,6 @@
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
-import android.net.INetworkStatsService;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -105,6 +105,7 @@
import android.os.PowerSaveState;
import android.os.RemoteException;
import android.os.SimpleClock;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
@@ -125,6 +126,7 @@
import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.net.NetworkPolicyManagerService;
+import com.android.server.net.NetworkStatsManagerInternal;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -214,7 +216,6 @@
private String mNetpolicyXml;
private @Mock IActivityManager mActivityManager;
- private @Mock INetworkStatsService mStatsService;
private @Mock INetworkManagementService mNetworkManager;
private @Mock IConnectivityManager mConnManager;
private @Mock NotificationManager mNotifManager;
@@ -224,7 +225,8 @@
private @Mock CarrierConfigManager mCarrierConfigManager;
private @Mock TelephonyManager mTelephonyManager;
- private static ActivityManagerInternal mActivityManagerInternal;
+ private ActivityManagerInternal mActivityManagerInternal;
+ private NetworkStatsManagerInternal mStatsService;
private IUidObserver mUidObserver;
private INetworkManagementEventObserver mNetworkObserver;
@@ -264,6 +266,8 @@
private static final int UID_F = UserHandle.getUid(USER_ID, APP_ID_F);
private static final String PKG_NAME_A = "name.is.A,pkg.A";
+ private static final String PKG_NAME_B = "name.is.B,pkg.B";
+ private static final String PKG_NAME_C = "name.is.C,pkg.C";
public final @Rule NetPolicyMethodRule mNetPolicyXmlRule = new NetPolicyMethodRule();
@@ -287,6 +291,8 @@
.setBatterySaverEnabled(false).build();
final PowerManagerInternal pmInternal = addLocalServiceMock(PowerManagerInternal.class);
when(pmInternal.getLowPowerState(anyInt())).thenReturn(state);
+
+ mStatsService = addLocalServiceMock(NetworkStatsManagerInternal.class);
}
@Before
@@ -347,7 +353,7 @@
eq(ActivityManager.PROCESS_STATE_UNKNOWN), isNull(String.class));
mFutureIntent = newRestrictBackgroundChangedFuture();
- mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService,
+ mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager,
mNetworkManager, mIpm, mClock, mPolicyDir, true);
mService.bindConnectivityManager(mConnManager);
mPolicyListener = new NetworkPolicyListenerAnswer(mService);
@@ -375,6 +381,14 @@
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
.thenReturn(new ApplicationInfo());
when(mPackageManager.getPackagesForUid(UID_A)).thenReturn(new String[] {PKG_NAME_A});
+ when(mPackageManager.getPackagesForUid(UID_B)).thenReturn(new String[] {PKG_NAME_B});
+ when(mPackageManager.getPackagesForUid(UID_C)).thenReturn(new String[] {PKG_NAME_C});
+ when(mPackageManager.getApplicationInfo(eq(PKG_NAME_A), anyInt()))
+ .thenReturn(buildApplicationInfo(PKG_NAME_A));
+ when(mPackageManager.getApplicationInfo(eq(PKG_NAME_B), anyInt()))
+ .thenReturn(buildApplicationInfo(PKG_NAME_B));
+ when(mPackageManager.getApplicationInfo(eq(PKG_NAME_C), anyInt()))
+ .thenReturn(buildApplicationInfo(PKG_NAME_C));
when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true);
when(mNetworkManager.setDataSaverModeEnabled(anyBoolean())).thenReturn(true);
@@ -409,6 +423,7 @@
LocalServices.removeServiceForTest(PowerManagerInternal.class);
LocalServices.removeServiceForTest(DeviceIdleController.LocalService.class);
LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
+ LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class);
}
@After
@@ -515,7 +530,7 @@
mService.updateRestrictBackgroundByLowPowerModeUL(stateOn);
// RestrictBackground should be on even though battery saver want to turn it off
- assertThat(mService.getRestrictBackground()).isTrue();
+ assertTrue(mService.getRestrictBackground());
PowerSaveState stateOff = new PowerSaveState.Builder()
.setGlobalBatterySaverEnabled(false)
@@ -524,7 +539,7 @@
mService.updateRestrictBackgroundByLowPowerModeUL(stateOff);
// RestrictBackground should be on, following its previous state
- assertThat(mService.getRestrictBackground()).isTrue();
+ assertTrue(mService.getRestrictBackground());
}
@Test
@@ -539,7 +554,7 @@
mService.updateRestrictBackgroundByLowPowerModeUL(stateOn);
// RestrictBackground should be turned on because of battery saver
- assertThat(mService.getRestrictBackground()).isTrue();
+ assertTrue(mService.getRestrictBackground());
PowerSaveState stateOff = new PowerSaveState.Builder()
.setGlobalBatterySaverEnabled(false)
@@ -548,7 +563,7 @@
mService.updateRestrictBackgroundByLowPowerModeUL(stateOff);
// RestrictBackground should be off, following its previous state
- assertThat(mService.getRestrictBackground()).isFalse();
+ assertFalse(mService.getRestrictBackground());
}
@Test
@@ -562,7 +577,7 @@
mService.updateRestrictBackgroundByLowPowerModeUL(stateOn);
// RestrictBackground should still be on
- assertThat(mService.getRestrictBackground()).isTrue();
+ assertTrue(mService.getRestrictBackground());
// User turns off RestrictBackground manually
setRestrictBackground(false);
@@ -571,7 +586,7 @@
mService.updateRestrictBackgroundByLowPowerModeUL(stateOff);
// RestrictBackground should be off because user changes it manually
- assertThat(mService.getRestrictBackground()).isFalse();
+ assertFalse(mService.getRestrictBackground());
}
private void removeRestrictBackgroundWhitelist(boolean expectIntent) throws Exception {
@@ -974,6 +989,7 @@
public void testNotificationWarningLimitSnooze() throws Exception {
// Create a place to store fake usage
final NetworkStatsHistory history = new NetworkStatsHistory(TimeUnit.HOURS.toMillis(1));
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
.thenAnswer(new Answer<Long>() {
@Override
@@ -983,6 +999,13 @@
return entry.rxBytes + entry.txBytes;
}
});
+ when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
+ .thenAnswer(new Answer<NetworkStats>() {
+ @Override
+ public NetworkStats answer(InvocationOnMock invocation) throws Throwable {
+ return stats;
+ }
+ });
// Get active mobile network in place
expectMobileDefaults();
@@ -1003,7 +1026,7 @@
// Normal usage means no notification
{
- history.removeBucketsBefore(Long.MAX_VALUE);
+ history.clear();
history.recordData(start, end,
new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(360), 0L, 0L, 0L, 0));
@@ -1020,7 +1043,7 @@
// Push over warning
{
- history.removeBucketsBefore(Long.MAX_VALUE);
+ history.clear();
history.recordData(start, end,
new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1799), 0L, 0L, 0L, 0));
@@ -1038,7 +1061,7 @@
// Push over limit
{
- history.removeBucketsBefore(Long.MAX_VALUE);
+ history.clear();
history.recordData(start, end,
new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1810), 0L, 0L, 0L, 0));
@@ -1073,6 +1096,7 @@
public void testNotificationRapid() throws Exception {
// Create a place to store fake usage
final NetworkStatsHistory history = new NetworkStatsHistory(TimeUnit.HOURS.toMillis(1));
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
.thenAnswer(new Answer<Long>() {
@Override
@@ -1082,6 +1106,13 @@
return entry.rxBytes + entry.txBytes;
}
});
+ when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
+ .thenAnswer(new Answer<NetworkStats>() {
+ @Override
+ public NetworkStats answer(InvocationOnMock invocation) throws Throwable {
+ return stats;
+ }
+ });
// Get active mobile network in place
expectMobileDefaults();
@@ -1102,7 +1133,7 @@
// Using 20% data in 20% time is normal
{
- history.removeBucketsBefore(Long.MAX_VALUE);
+ history.clear();
history.recordData(start, end,
new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(360), 0L, 0L, 0L, 0));
@@ -1111,16 +1142,58 @@
verify(mNotifManager, never()).notifyAsUser(any(), anyInt(), any(), any());
}
- // Using 80% data in 20% time is alarming
+ // Using 80% data in 20% time is alarming; but spread equally among
+ // three UIDs means we get generic alert
{
- history.removeBucketsBefore(Long.MAX_VALUE);
+ history.clear();
history.recordData(start, end,
new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0));
+ stats.clear();
+ stats.addValues(IFACE_ALL, UID_A, SET_ALL, TAG_ALL,
+ DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
+ stats.addValues(IFACE_ALL, UID_B, SET_ALL, TAG_ALL,
+ DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
+ stats.addValues(IFACE_ALL, UID_C, SET_ALL, TAG_ALL,
+ DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
reset(mNotifManager);
mService.updateNetworks();
+
+ final ArgumentCaptor<Notification> notif = ArgumentCaptor.forClass(Notification.class);
verify(mNotifManager, atLeastOnce()).notifyAsUser(any(), eq(TYPE_RAPID),
- isA(Notification.class), eq(UserHandle.ALL));
+ notif.capture(), eq(UserHandle.ALL));
+
+ final String text = notif.getValue().extras.getCharSequence(Notification.EXTRA_TEXT)
+ .toString();
+ assertFalse(text.contains(PKG_NAME_A));
+ assertFalse(text.contains(PKG_NAME_B));
+ assertFalse(text.contains(PKG_NAME_C));
+ }
+
+ // Using 80% data in 20% time is alarming; but mostly done by one UID
+ // means we get specific alert
+ {
+ history.clear();
+ history.recordData(start, end,
+ new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0));
+ stats.clear();
+ stats.addValues(IFACE_ALL, UID_A, SET_ALL, TAG_ALL,
+ DataUnit.MEGABYTES.toBytes(960), 0, 0, 0, 0);
+ stats.addValues(IFACE_ALL, UID_B, SET_ALL, TAG_ALL,
+ DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
+
+ reset(mNotifManager);
+ mService.updateNetworks();
+
+ final ArgumentCaptor<Notification> notif = ArgumentCaptor.forClass(Notification.class);
+ verify(mNotifManager, atLeastOnce()).notifyAsUser(any(), eq(TYPE_RAPID),
+ notif.capture(), eq(UserHandle.ALL));
+
+ final String text = notif.getValue().extras.getCharSequence(Notification.EXTRA_TEXT)
+ .toString();
+ assertTrue(text.contains(PKG_NAME_A));
+ assertFalse(text.contains(PKG_NAME_B));
+ assertFalse(text.contains(PKG_NAME_C));
}
}
@@ -1411,6 +1484,12 @@
true);
}
+ private ApplicationInfo buildApplicationInfo(String label) {
+ final ApplicationInfo ai = new ApplicationInfo();
+ ai.nonLocalizedLabel = label;
+ return ai;
+ }
+
private NetworkInfo buildNetworkInfo() {
final NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_MOBILE,
TelephonyManager.NETWORK_TYPE_LTE, null, null);
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 28f8122..2aea1d7 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -914,8 +914,10 @@
mock(INetworkPolicyManager.class),
mock(IpConnectivityLog.class));
- mService.systemReady();
+ // Create local CM before sending system ready so that we can answer
+ // getSystemService() correctly.
mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
+ mService.systemReady();
mCm.bindProcessToNetwork(null);
// Ensure that the default setting for Captive Portals is used for most tests
@@ -3412,8 +3414,10 @@
@Test
public void testNetworkCallbackMaximum() {
- final int MAX_REQUESTS = 100;
- final int CALLBACKS = 90;
+ // We can only have 99 callbacks, because MultipathPolicyTracker is
+ // already one of them.
+ final int MAX_REQUESTS = 99;
+ final int CALLBACKS = 89;
final int INTENTS = 10;
assertEquals(MAX_REQUESTS, CALLBACKS + INTENTS);
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index b1b05e8..49b2643 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -95,6 +95,7 @@
import com.android.internal.net.VpnInfo;
import com.android.internal.util.test.BroadcastInterceptingContext;
+import com.android.server.LocalServices;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
@@ -221,6 +222,9 @@
@After
public void tearDown() throws Exception {
+ // Registered by NetworkStatsService's constructor.
+ LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class);
+
IoUtils.deleteContents(mStatsDir);
mServiceContext = null;