diff options
16 files changed, 420 insertions, 329 deletions
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 90e3ffd550b4..381cfb61de88 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -39,9 +39,6 @@ interface INetworkStatsService { */ 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 @@ interface INetworkStatsService { /** 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 01b2b39213f9..16fb858a58c2 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -234,7 +234,7 @@ public class NetworkStats implements Parcelable { 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 @@ public class NetworkStats implements Parcelable { 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 @@ public class NetworkStats implements Parcelable { 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 433f9410cc6e..a13ad659e767 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -39,6 +39,8 @@ import android.util.proto.ProtoOutputStream; 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 @@ public class NetworkStatsHistory implements Parcelable { } /** + * 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 8efd39a7a785..74233fd990dc 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_PROXY; 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_ALL; 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.Arrays; 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 @@ public class NetworkTemplate implements Parcelable { */ 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 @@ public class NetworkTemplate implements Parcelable { 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 @@ public class NetworkTemplate implements Parcelable { * 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 class NetworkTemplate implements Parcelable { 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 @@ public class NetworkTemplate implements Parcelable { 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 @@ public class NetworkTemplate implements Parcelable { } /** - * 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 @@ public class NetworkTemplate implements Parcelable { 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 @@ public class NetworkTemplate implements Parcelable { } } - 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 f4be888e06ee..cadc3ffba41c 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3772,31 +3772,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> @@ -3804,9 +3796,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 fc4d4e71e24c..a2af57e8dbd5 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1971,10 +1971,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" /> @@ -1987,6 +1983,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 f201165a3989..be3168c3b208 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 android.view.WindowManager; 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 @@ public class NetworkOverLimitActivity extends Activity { 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 index 9e0a230b9250..296b9ac07b84 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.NetworkStats; 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 @@ public class MultipathPolicyTracker { 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 @@ public class MultipathPolicyTracker { // 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 class MultipathPolicyTracker { } 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 @@ public class MultipathPolicyTracker { // 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 @@ public class MultipathPolicyTracker { 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 @@ public class MultipathPolicyTracker { 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 @@ public class MultipathPolicyTracker { 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 @@ public class MultipathPolicyTracker { } 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 bd9ec55abc04..f29e0bba8ad5 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_UID_REMOVED; 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.isProcStateAllowedWhileOnRestrict 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.ACTION_CARRIER_CONFIG_CHANG 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.NetworkQuotaInfo; 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // 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 class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class); + mNetworkStats = LocalServices.getService(NetworkStatsManagerInternal.class); synchronized (mUidRulesFirstLock) { synchronized (mNetworkPoliciesSecondLock) { @@ -1063,9 +1065,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } /** + * 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } 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,18 +4378,29 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + @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); - return 0; - } catch (RemoteException e) { - // ignored; service lives in system_server + Slog.w(TAG, "Failed to read network stats: " + e); 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); + } + } + private boolean isBandwidthControlEnabled() { final long token = Binder.clearCallingIdentity(); try { diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 3cc4d83267cf..a5f8dc72d87c 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 @@ public class NetworkStatsCollection implements FileRotator.Reader { 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 000000000000..4843ede7219d --- /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 32e15c9d9c98..93c04fe2068c 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_DEV_ROTATE_AGE; 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.NetworkStats.NonMonotonicObserver; 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.DumpUtils; 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - @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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - @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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - @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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + 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 d24b3ee27545..5b5de0e94eca 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1088,8 +1088,8 @@ public final class SystemServer { 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 e1b4422c83c4..d31d550ae902 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_ALLOW_METERED_BACKGROUND; 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_LIMIT_SNOO 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.ConnectivityManager; 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.PowerManagerInternal; 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; 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 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { .setBatterySaverEnabled(false).build(); final PowerManagerInternal pmInternal = addLocalServiceMock(PowerManagerInternal.class); when(pmInternal.getLowPowerState(anyInt())).thenReturn(state); + + mStatsService = addLocalServiceMock(NetworkStatsManagerInternal.class); } @Before @@ -347,7 +353,7 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { LocalServices.removeServiceForTest(PowerManagerInternal.class); LocalServices.removeServiceForTest(DeviceIdleController.LocalService.class); LocalServices.removeServiceForTest(UsageStatsManagerInternal.class); + LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class); } @After @@ -515,7 +530,7 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { mService.updateRestrictBackgroundByLowPowerModeUL(stateOff); // RestrictBackground should be on, following its previous state - assertThat(mService.getRestrictBackground()).isTrue(); + assertTrue(mService.getRestrictBackground()); } @Test @@ -539,7 +554,7 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { mService.updateRestrictBackgroundByLowPowerModeUL(stateOff); // RestrictBackground should be off, following its previous state - assertThat(mService.getRestrictBackground()).isFalse(); + assertFalse(mService.getRestrictBackground()); } @Test @@ -562,7 +577,7 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { 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 class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { // 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 @@ public class NetworkPolicyManagerServiceTest { // 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 @@ public class NetworkPolicyManagerServiceTest { // 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 class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { // 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 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { 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 28f81220027c..2aea1d7011d5 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -914,8 +914,10 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { @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 b1b05e8b86ba..49b2643fa83e 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 android.telephony.TelephonyManager; 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 @@ public class NetworkStatsServiceTest { @After public void tearDown() throws Exception { + // Registered by NetworkStatsService's constructor. + LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class); + IoUtils.deleteContents(mStatsDir); mServiceContext = null; |