NetworkPolicyManagerServicepublic class NetworkPolicyManagerService extends INetworkPolicyManager.Stub Service that maintains low-level network policy rules, using
{@link NetworkStatsService} statistics to drive those rules.
Derives active rules by combining a given policy with other system status,
and delivers to listeners, such as {@link ConnectivityManager}, for
enforcement. |
Fields Summary |
---|
private static final String | TAG | private static final boolean | LOGD | private static final boolean | LOGV | private static final int | VERSION_INIT | private static final int | VERSION_ADDED_SNOOZE | private static final int | VERSION_ADDED_RESTRICT_BACKGROUND | private static final int | VERSION_ADDED_METERED | private static final int | VERSION_SPLIT_SNOOZE | private static final int | VERSION_ADDED_TIMEZONE | private static final int | VERSION_ADDED_INFERRED | private static final int | VERSION_SWITCH_APP_ID | private static final int | VERSION_ADDED_NETWORK_ID | private static final int | VERSION_SWITCH_UID | private static final int | VERSION_LATEST | public static final int | TYPE_WARNING | public static final int | TYPE_LIMIT | public static final int | TYPE_LIMIT_SNOOZED | private static final String | TAG_POLICY_LIST | private static final String | TAG_NETWORK_POLICY | private static final String | TAG_UID_POLICY | private static final String | TAG_APP_POLICY | private static final String | ATTR_VERSION | private static final String | ATTR_RESTRICT_BACKGROUND | private static final String | ATTR_NETWORK_TEMPLATE | private static final String | ATTR_SUBSCRIBER_ID | private static final String | ATTR_NETWORK_ID | private static final String | ATTR_CYCLE_DAY | private static final String | ATTR_CYCLE_TIMEZONE | private static final String | ATTR_WARNING_BYTES | private static final String | ATTR_LIMIT_BYTES | private static final String | ATTR_LAST_SNOOZE | private static final String | ATTR_LAST_WARNING_SNOOZE | private static final String | ATTR_LAST_LIMIT_SNOOZE | private static final String | ATTR_METERED | private static final String | ATTR_INFERRED | private static final String | ATTR_UID | private static final String | ATTR_APP_ID | private static final String | ATTR_POLICY | private static final String | TAG_ALLOW_BACKGROUND | private static final String | ACTION_ALLOW_BACKGROUND | private static final String | ACTION_SNOOZE_WARNING | private static final long | TIME_CACHE_MAX_AGE | private static final int | MSG_RULES_CHANGED | private static final int | MSG_METERED_IFACES_CHANGED | private static final int | MSG_LIMIT_REACHED | private static final int | MSG_RESTRICT_BACKGROUND_CHANGED | private static final int | MSG_ADVISE_PERSIST_THRESHOLD | private static final int | MSG_SCREEN_ON_CHANGED | private final android.content.Context | mContext | private final android.app.IActivityManager | mActivityManager | private final android.os.IPowerManager | mPowerManager | private final android.net.INetworkStatsService | mNetworkStats | private final android.os.INetworkManagementService | mNetworkManager | private final android.util.TrustedTime | mTime | private android.net.IConnectivityManager | mConnManager | private android.app.INotificationManager | mNotifManager | private android.os.PowerManagerInternal | mPowerManagerInternal | final Object | mRulesLock | volatile boolean | mScreenOn | volatile boolean | mRestrictBackground | volatile boolean | mRestrictPower | private final boolean | mSuppressDefaultPolicy | final android.util.ArrayMap | mNetworkPolicyDefined network policies. | final android.util.ArrayMap | mNetworkRulesCurrently active network rules for ifaces. | final android.util.SparseIntArray | mUidPolicyDefined UID policies. | final android.util.SparseIntArray | mUidRulesCurrently derived rules for each UID. | private final android.util.SparseBooleanArray | mPowerSaveWhitelistAppIdsUIDs that have been white-listed to always be able to have network access
in power save mode. | private android.util.ArraySet | mMeteredIfacesSet of ifaces that are metered. | private final android.util.ArraySet | mOverLimitNotifiedSet of over-limit templates that have been notified. | private final android.util.ArraySet | mActiveNotifsSet of currently active {@link Notification} tags. | final android.util.SparseIntArray | mUidStateForeground at both UID and PID granularity. | final android.util.SparseArray | mUidPidState | private int | mCurForegroundStateThe current maximum process state that we are considering to be foreground. | private final android.os.RemoteCallbackList | mListeners | final android.os.Handler | mHandler | private final android.util.AtomicFile | mPolicyFile | private android.app.IProcessObserver | mProcessObserver | private android.content.BroadcastReceiver | mScreenReceiver | private android.content.BroadcastReceiver | mPackageReceiver | private android.content.BroadcastReceiver | mUidRemovedReceiver | private android.content.BroadcastReceiver | mUserReceiver | private android.content.BroadcastReceiver | mStatsReceiverReceiver that watches for {@link INetworkStatsService} updates, which we
use to check against {@link NetworkPolicy#warningBytes}. | private android.content.BroadcastReceiver | mAllowReceiverReceiver that watches for {@link Notification} control of
{@link #mRestrictBackground}. | private android.content.BroadcastReceiver | mSnoozeWarningReceiverReceiver that watches for {@link Notification} control of
{@link NetworkPolicy#lastWarningSnooze}. | private android.content.BroadcastReceiver | mWifiConfigReceiverReceiver that watches for {@link WifiConfiguration} to be changed. | private android.content.BroadcastReceiver | mWifiStateReceiverReceiver that watches {@link WifiInfo} state changes to infer metered
state. Ignores hints when policy is user-defined. | private android.net.INetworkManagementEventObserver | mAlertObserverObserver that watches for {@link INetworkManagementService} alerts. | private android.content.BroadcastReceiver | mConnReceiverReceiver that watches for {@link IConnectivityManager} to claim network
interfaces. Used to apply {@link NetworkPolicy} to matching networks. | private Handler.Callback | mHandlerCallback |
Constructors Summary |
---|
public NetworkPolicyManagerService(android.content.Context context, android.app.IActivityManager activityManager, android.os.IPowerManager powerManager, android.net.INetworkStatsService networkStats, android.os.INetworkManagementService networkManagement)
// TODO: keep whitelist of system-critical services that should never have
// rules enforced, such as system, phone, and radio UIDs.
// TODO: migrate notifications to SystemUI
this(context, activityManager, powerManager, networkStats, networkManagement,
NtpTrustedTime.getInstance(context), getSystemDir(), false);
| public NetworkPolicyManagerService(android.content.Context context, android.app.IActivityManager activityManager, android.os.IPowerManager powerManager, android.net.INetworkStatsService networkStats, android.os.INetworkManagementService networkManagement, android.util.TrustedTime time, File systemDir, boolean suppressDefaultPolicy)
mContext = checkNotNull(context, "missing context");
mActivityManager = checkNotNull(activityManager, "missing activityManager");
mPowerManager = checkNotNull(powerManager, "missing powerManager");
mNetworkStats = checkNotNull(networkStats, "missing networkStats");
mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
mTime = checkNotNull(time, "missing TrustedTime");
HandlerThread thread = new HandlerThread(TAG);
thread.start();
mHandler = new Handler(thread.getLooper(), mHandlerCallback);
mSuppressDefaultPolicy = suppressDefaultPolicy;
mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
|
Methods Summary |
---|
public void | addIdleHandler(android.os.MessageQueue.IdleHandler handler)
mHandler.getLooper().getQueue().addIdleHandler(handler);
| void | addNetworkPolicyLocked(android.net.NetworkPolicy policy)
NetworkPolicy[] policies = getNetworkPolicies();
policies = ArrayUtils.appendElement(NetworkPolicy.class, policies, policy);
setNetworkPolicies(policies);
| public void | addUidPolicy(int uid, int policy)
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
if (!UserHandle.isApp(uid)) {
throw new IllegalArgumentException("cannot apply policy to UID " + uid);
}
synchronized (mRulesLock) {
final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
policy |= oldPolicy;
if (oldPolicy != policy) {
setUidPolicyUncheckedLocked(uid, policy, true);
}
}
| public void | bindConnectivityManager(android.net.IConnectivityManager connManager)
mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
| public void | bindNotificationManager(android.app.INotificationManager notifManager)
mNotifManager = checkNotNull(notifManager, "missing INotificationManager");
| private static android.content.Intent | buildAllowBackgroundDataIntent()
return new Intent(ACTION_ALLOW_BACKGROUND);
| private static android.content.Intent | buildNetworkOverLimitIntent(android.net.NetworkTemplate template)
final Intent intent = new Intent();
intent.setComponent(new ComponentName(
"com.android.systemui", "com.android.systemui.net.NetworkOverLimitActivity"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
return intent;
| private java.lang.String | buildNotificationTag(android.net.NetworkPolicy policy, int type)Build unique tag that identifies an active {@link NetworkPolicy}
notification of a specific type, like {@link #TYPE_LIMIT}.
return TAG + ":" + policy.template.hashCode() + ":" + type;
| private static android.content.Intent | buildSnoozeWarningIntent(android.net.NetworkTemplate template)
final Intent intent = new Intent(ACTION_SNOOZE_WARNING);
intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
return intent;
| private static android.content.Intent | buildViewDataUsageIntent(android.net.NetworkTemplate template)
final Intent intent = new Intent();
intent.setComponent(new ComponentName(
"com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
return intent;
| private void | cancelNotification(java.lang.String tag)
// TODO: move to NotificationManager once we can mock it
// XXX what to do about multi-user?
try {
final String packageName = mContext.getPackageName();
mNotifManager.cancelNotificationWithTag(
packageName, tag, 0x0, UserHandle.USER_OWNER);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
| private static void | collectKeys(android.util.SparseIntArray source, android.util.SparseBooleanArray target)
final int size = source.size();
for (int i = 0; i < size; i++) {
target.put(source.keyAt(i), true);
}
| void | computeUidStateLocked(int uid)Process state of PID changed; recompute state at UID level. If
changed, will trigger {@link #updateRulesForUidLocked(int)}.
final SparseIntArray pidState = mUidPidState.get(uid);
// current pid is dropping foreground; examine other pids
int uidState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
if (pidState != null) {
final int size = pidState.size();
for (int i = 0; i < size; i++) {
final int state = pidState.valueAt(i);
if (state < uidState) {
uidState = state;
}
}
}
final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
if (oldUidState != uidState) {
// state changed, push updated rules
mUidState.put(uid, uidState);
final boolean oldForeground = oldUidState <= mCurForegroundState;
final boolean newForeground = uidState <= mCurForegroundState;
if (oldForeground != newForeground) {
updateRulesForUidLocked(uid);
}
}
| private long | currentTimeMillis()
return mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
| protected void | dump(java.io.FileDescriptor fd, java.io.PrintWriter writer, java.lang.String[] args)
mContext.enforceCallingOrSelfPermission(DUMP, TAG);
final IndentingPrintWriter fout = new IndentingPrintWriter(writer, " ");
final ArraySet<String> argSet = new ArraySet<String>(args.length);
for (String arg : args) {
argSet.add(arg);
}
synchronized (mRulesLock) {
if (argSet.contains("--unsnooze")) {
for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
mNetworkPolicy.valueAt(i).clearSnooze();
}
normalizePoliciesLocked();
updateNetworkEnabledLocked();
updateNetworkRulesLocked();
updateNotificationsLocked();
writePolicyLocked();
fout.println("Cleared snooze timestamps");
return;
}
fout.print("Restrict background: "); fout.println(mRestrictBackground);
fout.print("Restrict power: "); fout.println(mRestrictPower);
fout.print("Current foreground state: "); fout.println(mCurForegroundState);
fout.println("Network policies:");
fout.increaseIndent();
for (int i = 0; i < mNetworkPolicy.size(); i++) {
fout.println(mNetworkPolicy.valueAt(i).toString());
}
fout.decreaseIndent();
fout.print("Metered ifaces: "); fout.println(String.valueOf(mMeteredIfaces));
fout.println("Policy for UIDs:");
fout.increaseIndent();
int size = mUidPolicy.size();
for (int i = 0; i < size; i++) {
final int uid = mUidPolicy.keyAt(i);
final int policy = mUidPolicy.valueAt(i);
fout.print("UID=");
fout.print(uid);
fout.print(" policy=");
dumpPolicy(fout, policy);
fout.println();
}
fout.decreaseIndent();
size = mPowerSaveWhitelistAppIds.size();
if (size > 0) {
fout.println("Power save whitelist app ids:");
fout.increaseIndent();
for (int i = 0; i < size; i++) {
fout.print("UID=");
fout.print(mPowerSaveWhitelistAppIds.keyAt(i));
fout.print(": ");
fout.print(mPowerSaveWhitelistAppIds.valueAt(i));
fout.println();
}
fout.decreaseIndent();
}
final SparseBooleanArray knownUids = new SparseBooleanArray();
collectKeys(mUidState, knownUids);
collectKeys(mUidRules, knownUids);
fout.println("Status for known UIDs:");
fout.increaseIndent();
size = knownUids.size();
for (int i = 0; i < size; i++) {
final int uid = knownUids.keyAt(i);
fout.print("UID=");
fout.print(uid);
int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
fout.print(" state=");
fout.print(state);
fout.print(state <= mCurForegroundState ? " (fg)" : " (bg)");
fout.print(" pids=");
final int foregroundIndex = mUidPidState.indexOfKey(uid);
if (foregroundIndex < 0) {
fout.print("UNKNOWN");
} else {
dumpSparseIntArray(fout, mUidPidState.valueAt(foregroundIndex));
}
fout.print(" rules=");
final int rulesIndex = mUidRules.indexOfKey(uid);
if (rulesIndex < 0) {
fout.print("UNKNOWN");
} else {
dumpRules(fout, mUidRules.valueAt(rulesIndex));
}
fout.println();
}
fout.decreaseIndent();
}
| private static void | dumpSparseIntArray(java.io.PrintWriter fout, android.util.SparseIntArray value)
fout.print("[");
final int size = value.size();
for (int i = 0; i < size; i++) {
fout.print(value.keyAt(i) + "=" + value.valueAt(i));
if (i < size - 1) fout.print(",");
}
fout.print("]");
| private void | enqueueNotification(android.net.NetworkPolicy policy, int type, long totalBytes)Show notification for combined {@link NetworkPolicy} and specific type,
like {@link #TYPE_LIMIT}. Okay to call multiple times.
final String tag = buildNotificationTag(policy, type);
final Notification.Builder builder = new Notification.Builder(mContext);
builder.setOnlyAlertOnce(true);
builder.setWhen(0L);
builder.setColor(mContext.getResources().getColor(
com.android.internal.R.color.system_notification_accent_color));
final Resources res = mContext.getResources();
switch (type) {
case TYPE_WARNING: {
final CharSequence title = res.getText(R.string.data_usage_warning_title);
final CharSequence body = res.getString(R.string.data_usage_warning_body);
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(
mContext, 0, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
final Intent viewIntent = buildViewDataUsageIntent(policy.template);
builder.setContentIntent(PendingIntent.getActivity(
mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT));
break;
}
case TYPE_LIMIT: {
final CharSequence 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:
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;
}
builder.setOngoing(true);
builder.setSmallIcon(icon);
builder.setTicker(title);
builder.setContentTitle(title);
builder.setContentText(body);
final Intent intent = buildNetworkOverLimitIntent(policy.template);
builder.setContentIntent(PendingIntent.getActivity(
mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
break;
}
case TYPE_LIMIT_SNOOZED: {
final long overBytes = totalBytes - policy.limitBytes;
final CharSequence 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:
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;
}
builder.setOngoing(true);
builder.setSmallIcon(R.drawable.stat_notify_error);
builder.setTicker(title);
builder.setContentTitle(title);
builder.setContentText(body);
final Intent intent = buildViewDataUsageIntent(policy.template);
builder.setContentIntent(PendingIntent.getActivity(
mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
break;
}
}
// TODO: move to NotificationManager once we can mock it
// XXX what to do about multi-user?
try {
final String packageName = mContext.getPackageName();
final int[] idReceived = new int[1];
mNotifManager.enqueueNotificationWithTag(
packageName, packageName, tag, 0x0, builder.getNotification(), idReceived,
UserHandle.USER_OWNER);
mActiveNotifs.add(tag);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
| private void | enqueueRestrictedNotification(java.lang.String tag)Show ongoing notification to reflect that {@link #mRestrictBackground}
has been enabled.
final Resources res = mContext.getResources();
final Notification.Builder builder = new Notification.Builder(mContext);
final CharSequence title = res.getText(R.string.data_usage_restricted_title);
final CharSequence body = res.getString(R.string.data_usage_restricted_body);
builder.setOnlyAlertOnce(true);
builder.setOngoing(true);
builder.setSmallIcon(R.drawable.stat_notify_error);
builder.setTicker(title);
builder.setContentTitle(title);
builder.setContentText(body);
builder.setColor(mContext.getResources().getColor(
com.android.internal.R.color.system_notification_accent_color));
final Intent intent = buildAllowBackgroundDataIntent();
builder.setContentIntent(
PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
// TODO: move to NotificationManager once we can mock it
// XXX what to do about multi-user?
try {
final String packageName = mContext.getPackageName();
final int[] idReceived = new int[1];
mNotifManager.enqueueNotificationWithTag(packageName, packageName, tag,
0x0, builder.getNotification(), idReceived, UserHandle.USER_OWNER);
mActiveNotifs.add(tag);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
| private void | ensureActiveMobilePolicyLocked()Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
have at least a default mobile policy defined.
if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()");
if (mSuppressDefaultPolicy) return;
final TelephonyManager tele = TelephonyManager.from(mContext);
final SubscriptionManager sub = SubscriptionManager.from(mContext);
final int[] subIds = sub.getActiveSubscriptionIdList();
for (int subId : subIds) {
final String subscriberId = tele.getSubscriberId(subId);
ensureActiveMobilePolicyLocked(subscriberId);
}
| private void | ensureActiveMobilePolicyLocked(java.lang.String subscriberId)
// Poke around to see if we already have a policy
final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false);
for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
final NetworkTemplate template = mNetworkPolicy.keyAt(i);
if (template.matches(probeIdent)) {
if (LOGD) {
Slog.d(TAG, "Found template " + template + " which matches subscriber "
+ NetworkIdentity.scrubSubscriberId(subscriberId));
}
return;
}
}
Slog.i(TAG, "No policy for subscriber " + NetworkIdentity.scrubSubscriberId(subscriberId)
+ "; generating default policy");
// Build default mobile policy, and assume usage cycle starts today
final long warningBytes = mContext.getResources().getInteger(
com.android.internal.R.integer.config_networkPolicyDefaultWarning) * MB_IN_BYTES;
final Time time = new Time();
time.setToNow();
final int cycleDay = time.monthDay;
final String cycleTimezone = time.timezone;
final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
final NetworkPolicy policy = new NetworkPolicy(template, cycleDay, cycleTimezone,
warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, true);
addNetworkPolicyLocked(policy);
| private android.net.NetworkPolicy | findPolicyForNetworkLocked(android.net.NetworkIdentity ident)
for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
NetworkPolicy policy = mNetworkPolicy.valueAt(i);
if (policy.template.matches(ident)) {
return policy;
}
}
return null;
| public android.net.NetworkPolicy[] | getNetworkPolicies()
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
synchronized (mRulesLock) {
final int size = mNetworkPolicy.size();
final NetworkPolicy[] policies = new NetworkPolicy[size];
for (int i = 0; i < size; i++) {
policies[i] = mNetworkPolicy.valueAt(i);
}
return policies;
}
| public android.net.NetworkQuotaInfo | getNetworkQuotaInfo(android.net.NetworkState state)
mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
// only returns usage summary, so we don't require caller to have
// READ_NETWORK_USAGE_HISTORY.
final long token = Binder.clearCallingIdentity();
try {
return getNetworkQuotaInfoUnchecked(state);
} finally {
Binder.restoreCallingIdentity(token);
}
| private android.net.NetworkQuotaInfo | getNetworkQuotaInfoUnchecked(android.net.NetworkState state)
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
final NetworkPolicy policy;
synchronized (mRulesLock) {
policy = findPolicyForNetworkLocked(ident);
}
if (policy == null || !policy.hasCycle()) {
// missing policy means we can't derive useful quota info
return null;
}
final long currentTime = currentTimeMillis();
// find total bytes used under policy
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
final long totalBytes = getTotalBytes(policy.template, start, end);
// report soft and hard limits under policy
final long softLimitBytes = policy.warningBytes != WARNING_DISABLED ? policy.warningBytes
: NetworkQuotaInfo.NO_LIMIT;
final long hardLimitBytes = policy.limitBytes != LIMIT_DISABLED ? policy.limitBytes
: NetworkQuotaInfo.NO_LIMIT;
return new NetworkQuotaInfo(totalBytes, softLimitBytes, hardLimitBytes);
| public int[] | getPowerSaveAppIdWhitelist()
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
synchronized (mRulesLock) {
int size = mPowerSaveWhitelistAppIds.size();
int[] appids = new int[size];
for (int i = 0; i < size; i++) {
appids[i] = mPowerSaveWhitelistAppIds.keyAt(i);
}
return appids;
}
| public boolean | getRestrictBackground()
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
synchronized (mRulesLock) {
return mRestrictBackground;
}
| private static java.io.File | getSystemDir()
return new File(Environment.getDataDirectory(), "system");
| private long | getTotalBytes(android.net.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
return 0;
}
| public int | getUidPolicy(int uid)
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
synchronized (mRulesLock) {
return mUidPolicy.get(uid, POLICY_NONE);
}
| public int[] | getUidsWithPolicy(int policy)
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
int[] uids = new int[0];
synchronized (mRulesLock) {
for (int i = 0; i < mUidPolicy.size(); i++) {
final int uid = mUidPolicy.keyAt(i);
final int uidPolicy = mUidPolicy.valueAt(i);
if (uidPolicy == policy) {
uids = appendInt(uids, uid);
}
}
}
return uids;
| private boolean | isBandwidthControlEnabled()
final long token = Binder.clearCallingIdentity();
try {
return mNetworkManager.isBandwidthControlEnabled();
} catch (RemoteException e) {
// ignored; service lives in system_server
return false;
} finally {
Binder.restoreCallingIdentity(token);
}
| public boolean | isNetworkMetered(android.net.NetworkState state)
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
// roaming networks are always considered metered
if (ident.getRoaming()) {
return true;
}
final NetworkPolicy policy;
synchronized (mRulesLock) {
policy = findPolicyForNetworkLocked(ident);
}
if (policy != null) {
return policy.metered;
} else {
final int type = state.networkInfo.getType();
if (isNetworkTypeMobile(type) || type == TYPE_WIMAX) {
return true;
}
return false;
}
| private boolean | isTemplateRelevant(android.net.NetworkTemplate template)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
data connection status.
if (template.isMatchRuleMobile()) {
final TelephonyManager tele = TelephonyManager.from(mContext);
final SubscriptionManager sub = SubscriptionManager.from(mContext);
// Mobile template is relevant when any active subscriber matches
final int[] subIds = sub.getActiveSubscriptionIdList();
for (int subId : subIds) {
final String subscriberId = tele.getSubscriberId(subId);
final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false);
if (template.matches(probeIdent)) {
return true;
}
}
return false;
} else {
return true;
}
| public boolean | isUidForeground(int uid)
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
synchronized (mRulesLock) {
return isUidForegroundLocked(uid);
}
| boolean | isUidForegroundLocked(int uid)
// only really in foreground when screen is also on
return mScreenOn && mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY)
<= mCurForegroundState;
| private static boolean | isUidValidForRules(int uid)
// allow rules on specific system services, and any apps
if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID
|| UserHandle.isApp(uid)) {
return true;
}
return false;
| void | maybeRefreshTrustedTime()Try refreshing {@link #mTime} when stale.
if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
mTime.forceRefresh();
}
| private void | normalizePoliciesLocked()
normalizePoliciesLocked(getNetworkPolicies());
| private void | normalizePoliciesLocked(android.net.NetworkPolicy[] policies)
final TelephonyManager tele = TelephonyManager.from(mContext);
final String[] merged = tele.getMergedSubscriberIds();
mNetworkPolicy.clear();
for (NetworkPolicy policy : policies) {
// When two normalized templates conflict, prefer the most
// restrictive policy
policy.template = NetworkTemplate.normalize(policy.template, merged);
final NetworkPolicy existing = mNetworkPolicy.get(policy.template);
if (existing == null || existing.compareTo(policy) > 0) {
if (existing != null) {
Slog.d(TAG, "Normalization replaced " + existing + " with " + policy);
}
mNetworkPolicy.put(policy.template, policy);
}
}
| private void | notifyOverLimitLocked(android.net.NetworkTemplate template)Notify that given {@link NetworkTemplate} is over
{@link NetworkPolicy#limitBytes}, potentially showing dialog to user.
if (!mOverLimitNotified.contains(template)) {
mContext.startActivity(buildNetworkOverLimitIntent(template));
mOverLimitNotified.add(template);
}
| private void | notifyUnderLimitLocked(android.net.NetworkTemplate template)
mOverLimitNotified.remove(template);
| void | performSnooze(android.net.NetworkTemplate template, int type)
maybeRefreshTrustedTime();
final long currentTime = currentTimeMillis();
synchronized (mRulesLock) {
// find and snooze local policy that matches
final NetworkPolicy policy = mNetworkPolicy.get(template);
if (policy == null) {
throw new IllegalArgumentException("unable to find policy for " + template);
}
switch (type) {
case TYPE_WARNING:
policy.lastWarningSnooze = currentTime;
break;
case TYPE_LIMIT:
policy.lastLimitSnooze = currentTime;
break;
default:
throw new IllegalArgumentException("unexpected type");
}
normalizePoliciesLocked();
updateNetworkEnabledLocked();
updateNetworkRulesLocked();
updateNotificationsLocked();
writePolicyLocked();
}
| private void | readPolicyLocked()
if (LOGV) Slog.v(TAG, "readPolicyLocked()");
// clear any existing policy and read from disk
mNetworkPolicy.clear();
mUidPolicy.clear();
FileInputStream fis = null;
try {
fis = mPolicyFile.openRead();
final XmlPullParser in = Xml.newPullParser();
in.setInput(fis, null);
int type;
int version = VERSION_INIT;
while ((type = in.next()) != END_DOCUMENT) {
final String tag = in.getName();
if (type == START_TAG) {
if (TAG_POLICY_LIST.equals(tag)) {
version = readIntAttribute(in, ATTR_VERSION);
if (version >= VERSION_ADDED_RESTRICT_BACKGROUND) {
mRestrictBackground = readBooleanAttribute(
in, ATTR_RESTRICT_BACKGROUND);
} else {
mRestrictBackground = false;
}
} else if (TAG_NETWORK_POLICY.equals(tag)) {
final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE);
final String subscriberId = in.getAttributeValue(null, ATTR_SUBSCRIBER_ID);
final String networkId;
if (version >= VERSION_ADDED_NETWORK_ID) {
networkId = in.getAttributeValue(null, ATTR_NETWORK_ID);
} else {
networkId = null;
}
final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
final String cycleTimezone;
if (version >= VERSION_ADDED_TIMEZONE) {
cycleTimezone = in.getAttributeValue(null, ATTR_CYCLE_TIMEZONE);
} else {
cycleTimezone = Time.TIMEZONE_UTC;
}
final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
final long lastLimitSnooze;
if (version >= VERSION_SPLIT_SNOOZE) {
lastLimitSnooze = readLongAttribute(in, ATTR_LAST_LIMIT_SNOOZE);
} else if (version >= VERSION_ADDED_SNOOZE) {
lastLimitSnooze = readLongAttribute(in, ATTR_LAST_SNOOZE);
} else {
lastLimitSnooze = SNOOZE_NEVER;
}
final boolean metered;
if (version >= VERSION_ADDED_METERED) {
metered = readBooleanAttribute(in, ATTR_METERED);
} else {
switch (networkTemplate) {
case MATCH_MOBILE_3G_LOWER:
case MATCH_MOBILE_4G:
case MATCH_MOBILE_ALL:
metered = true;
break;
default:
metered = false;
}
}
final long lastWarningSnooze;
if (version >= VERSION_SPLIT_SNOOZE) {
lastWarningSnooze = readLongAttribute(in, ATTR_LAST_WARNING_SNOOZE);
} else {
lastWarningSnooze = SNOOZE_NEVER;
}
final boolean inferred;
if (version >= VERSION_ADDED_INFERRED) {
inferred = readBooleanAttribute(in, ATTR_INFERRED);
} else {
inferred = false;
}
final NetworkTemplate template = new NetworkTemplate(networkTemplate,
subscriberId, networkId);
mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay,
cycleTimezone, warningBytes, limitBytes, lastWarningSnooze,
lastLimitSnooze, metered, inferred));
} else if (TAG_UID_POLICY.equals(tag)) {
final int uid = readIntAttribute(in, ATTR_UID);
final int policy = readIntAttribute(in, ATTR_POLICY);
if (UserHandle.isApp(uid)) {
setUidPolicyUncheckedLocked(uid, policy, false);
} else {
Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
}
} else if (TAG_APP_POLICY.equals(tag)) {
final int appId = readIntAttribute(in, ATTR_APP_ID);
final int policy = readIntAttribute(in, ATTR_POLICY);
// TODO: set for other users during upgrade
final int uid = UserHandle.getUid(UserHandle.USER_OWNER, appId);
if (UserHandle.isApp(uid)) {
setUidPolicyUncheckedLocked(uid, policy, false);
} else {
Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
}
}
}
}
} catch (FileNotFoundException e) {
// missing policy is okay, probably first boot
upgradeLegacyBackgroundData();
} catch (IOException e) {
Log.wtf(TAG, "problem reading network policy", e);
} catch (XmlPullParserException e) {
Log.wtf(TAG, "problem reading network policy", e);
} finally {
IoUtils.closeQuietly(fis);
}
| public void | registerListener(android.net.INetworkPolicyListener listener)
// TODO: create permission for observing network policy
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
mListeners.register(listener);
// TODO: consider dispatching existing rules to new listeners
| private void | removeInterfaceQuota(java.lang.String iface)
try {
mNetworkManager.removeInterfaceQuota(iface);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem removing interface quota", e);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
| void | removePoliciesForUserLocked(int userId)Remove any policies associated with given {@link UserHandle}, persisting
if any changes are made.
if (LOGV) Slog.v(TAG, "removePoliciesForUserLocked()");
int[] uids = new int[0];
for (int i = 0; i < mUidPolicy.size(); i++) {
final int uid = mUidPolicy.keyAt(i);
if (UserHandle.getUserId(uid) == userId) {
uids = appendInt(uids, uid);
}
}
if (uids.length > 0) {
for (int uid : uids) {
mUidPolicy.delete(uid);
updateRulesForUidLocked(uid);
}
writePolicyLocked();
}
| public void | removeUidPolicy(int uid, int policy)
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
if (!UserHandle.isApp(uid)) {
throw new IllegalArgumentException("cannot apply policy to UID " + uid);
}
synchronized (mRulesLock) {
final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
policy = oldPolicy & ~policy;
if (oldPolicy != policy) {
setUidPolicyUncheckedLocked(uid, policy, true);
}
}
| private void | setInterfaceQuota(java.lang.String iface, long quotaBytes)
try {
mNetworkManager.setInterfaceQuota(iface, quotaBytes);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting interface quota", e);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
| public void | setNetworkPolicies(android.net.NetworkPolicy[] policies)
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
maybeRefreshTrustedTime();
synchronized (mRulesLock) {
normalizePoliciesLocked(policies);
updateNetworkEnabledLocked();
updateNetworkRulesLocked();
updateNotificationsLocked();
writePolicyLocked();
}
| private void | setNetworkTemplateEnabled(android.net.NetworkTemplate template, boolean enabled)Proactively disable networks that match the given
{@link NetworkTemplate}.
// TODO: reach into ConnectivityManager to proactively disable bringing
// up this network, since we know that traffic will be blocked.
| public void | setRestrictBackground(boolean restrictBackground)
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
maybeRefreshTrustedTime();
synchronized (mRulesLock) {
mRestrictBackground = restrictBackground;
updateRulesForGlobalChangeLocked(false);
updateNotificationsLocked();
writePolicyLocked();
}
mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED, restrictBackground ? 1 : 0, 0)
.sendToTarget();
| private void | setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces)
try {
mNetworkManager.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting uid rules", e);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
| public void | setUidPolicy(int uid, int policy)
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
if (!UserHandle.isApp(uid)) {
throw new IllegalArgumentException("cannot apply policy to UID " + uid);
}
synchronized (mRulesLock) {
final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
if (oldPolicy != policy) {
setUidPolicyUncheckedLocked(uid, policy, true);
}
}
| private void | setUidPolicyUncheckedLocked(int uid, int policy, boolean persist)
mUidPolicy.put(uid, policy);
// uid policy changed, recompute rules and persist policy.
updateRulesForUidLocked(uid);
if (persist) {
writePolicyLocked();
}
| public void | snoozeLimit(android.net.NetworkTemplate template)
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
final long token = Binder.clearCallingIdentity();
try {
performSnooze(template, TYPE_LIMIT);
} finally {
Binder.restoreCallingIdentity(token);
}
| public void | systemReady()
if (!isBandwidthControlEnabled()) {
Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
return;
}
final PackageManager pm = mContext.getPackageManager();
synchronized (mRulesLock) {
SystemConfig sysConfig = SystemConfig.getInstance();
ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
for (int i=0; i<allowPower.size(); i++) {
String pkg = allowPower.valueAt(i);
try {
ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
mPowerSaveWhitelistAppIds.put(UserHandle.getAppId(ai.uid), true);
}
} catch (PackageManager.NameNotFoundException e) {
}
}
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mPowerManagerInternal.registerLowPowerModeObserver(
new PowerManagerInternal.LowPowerModeListener() {
@Override
public void onLowPowerModeChanged(boolean enabled) {
synchronized (mRulesLock) {
if (mRestrictPower != enabled) {
mRestrictPower = enabled;
updateRulesForGlobalChangeLocked(true);
}
}
}
});
mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
// read policy from disk
readPolicyLocked();
if (mRestrictBackground || mRestrictPower) {
updateRulesForGlobalChangeLocked(true);
updateNotificationsLocked();
}
}
updateScreenOn();
try {
mActivityManager.registerProcessObserver(mProcessObserver);
mNetworkManager.registerObserver(mAlertObserver);
} catch (RemoteException e) {
// ignored; both services live in system_server
}
// TODO: traverse existing processes to know foreground state, or have
// activitymanager dispatch current state when new observer attached.
final IntentFilter screenFilter = new IntentFilter();
screenFilter.addAction(Intent.ACTION_SCREEN_ON);
screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
mContext.registerReceiver(mScreenReceiver, screenFilter);
// watch for network interfaces to be claimed
final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE);
mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
// listen for package changes to update policy
final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(ACTION_PACKAGE_ADDED);
packageFilter.addDataScheme("package");
mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
// listen for UID changes to update policy
mContext.registerReceiver(
mUidRemovedReceiver, new IntentFilter(ACTION_UID_REMOVED), null, mHandler);
// listen for user changes to update policy
final IntentFilter userFilter = new IntentFilter();
userFilter.addAction(ACTION_USER_ADDED);
userFilter.addAction(ACTION_USER_REMOVED);
mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
// listen for stats update events
final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
mContext.registerReceiver(
mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
// listen for restrict background changes from notifications
final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);
// listen for snooze warning from notifications
final IntentFilter snoozeWarningFilter = new IntentFilter(ACTION_SNOOZE_WARNING);
mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter,
MANAGE_NETWORK_POLICY, mHandler);
// listen for configured wifi networks to be removed
final IntentFilter wifiConfigFilter = new IntentFilter(CONFIGURED_NETWORKS_CHANGED_ACTION);
mContext.registerReceiver(mWifiConfigReceiver, wifiConfigFilter, null, mHandler);
// listen for wifi state changes to catch metered hint
final IntentFilter wifiStateFilter = new IntentFilter(
WifiManager.NETWORK_STATE_CHANGED_ACTION);
mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
| public void | unregisterListener(android.net.INetworkPolicyListener listener)
// TODO: create permission for observing network policy
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
mListeners.unregister(listener);
| void | updateNetworkEnabledLocked()Proactively control network data connections when they exceed
{@link NetworkPolicy#limitBytes}.
if (LOGV) Slog.v(TAG, "updateNetworkEnabledLocked()");
// TODO: reset any policy-disabled networks when any policy is removed
// completely, which is currently rare case.
final long currentTime = currentTimeMillis();
for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
// shortcut when policy has no limit
if (policy.limitBytes == LIMIT_DISABLED || !policy.hasCycle()) {
setNetworkTemplateEnabled(policy.template, true);
continue;
}
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
final long totalBytes = getTotalBytes(policy.template, start, end);
// disable data connection when over limit and not snoozed
final boolean overLimitWithoutSnooze = policy.isOverLimit(totalBytes)
&& policy.lastLimitSnooze < start;
final boolean networkEnabled = !overLimitWithoutSnooze;
setNetworkTemplateEnabled(policy.template, networkEnabled);
}
| void | updateNetworkRulesLocked()Examine all connected {@link NetworkState}, looking for
{@link NetworkPolicy} that need to be enforced. When matches found, set
remaining quota based on usage cycle and historical stats.
if (LOGV) Slog.v(TAG, "updateNetworkRulesLocked()");
final NetworkState[] states;
try {
states = mConnManager.getAllNetworkState();
} catch (RemoteException e) {
// ignored; service lives in system_server
return;
}
// If we are in restrict power mode, we want to treat all interfaces
// as metered, to restrict access to the network by uid. However, we
// will not have a bandwidth limit. Also only do this if restrict
// background data use is *not* enabled, since that takes precendence
// use over those networks can have a cost associated with it).
final boolean powerSave = mRestrictPower && !mRestrictBackground;
// First, generate identities of all connected networks so we can
// quickly compare them against all defined policies below.
final ArrayList<Pair<String, NetworkIdentity>> connIdents = new ArrayList<>(states.length);
final ArraySet<String> connIfaces = new ArraySet<String>(states.length);
for (NetworkState state : states) {
if (state.networkInfo.isConnected()) {
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
final String baseIface = state.linkProperties.getInterfaceName();
if (baseIface != null) {
connIdents.add(Pair.create(baseIface, ident));
if (powerSave) {
connIfaces.add(baseIface);
}
}
// Stacked interfaces are considered to have same identity as
// their parent network.
final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks();
for (LinkProperties stackedLink : stackedLinks) {
final String stackedIface = stackedLink.getInterfaceName();
if (stackedIface != null) {
connIdents.add(Pair.create(stackedIface, ident));
if (powerSave) {
connIfaces.add(stackedIface);
}
}
}
}
}
// Apply policies against all connected interfaces found above
mNetworkRules.clear();
final ArrayList<String> ifaceList = Lists.newArrayList();
for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
ifaceList.clear();
for (int j = connIdents.size() - 1; j >= 0; j--) {
final Pair<String, NetworkIdentity> ident = connIdents.get(j);
if (policy.template.matches(ident.second)) {
ifaceList.add(ident.first);
}
}
if (ifaceList.size() > 0) {
final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]);
mNetworkRules.put(policy, ifaces);
}
}
long lowestRule = Long.MAX_VALUE;
final ArraySet<String> newMeteredIfaces = new ArraySet<String>(states.length);
// apply each policy that we found ifaces for; compute remaining data
// based on current cycle and historical stats, and push to kernel.
final long currentTime = currentTimeMillis();
for (int i = mNetworkRules.size()-1; i >= 0; i--) {
final NetworkPolicy policy = mNetworkRules.keyAt(i);
final String[] ifaces = mNetworkRules.valueAt(i);
final long start;
final long totalBytes;
if (policy.hasCycle()) {
start = computeLastCycleBoundary(currentTime, policy);
totalBytes = getTotalBytes(policy.template, start, currentTime);
} else {
start = Long.MAX_VALUE;
totalBytes = 0;
}
if (LOGD) {
Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces "
+ Arrays.toString(ifaces));
}
final boolean hasWarning = policy.warningBytes != LIMIT_DISABLED;
final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED;
if (hasLimit || policy.metered) {
final long quotaBytes;
if (!hasLimit) {
// metered network, but no policy limit; we still need to
// restrict apps, so push really high quota.
quotaBytes = Long.MAX_VALUE;
} else if (policy.lastLimitSnooze >= start) {
// snoozing past quota, but we still need to restrict apps,
// so push really high quota.
quotaBytes = Long.MAX_VALUE;
} else {
// remaining "quota" bytes are based on total usage in
// current cycle. kernel doesn't like 0-byte rules, so we
// set 1-byte quota and disable the radio later.
quotaBytes = Math.max(1, policy.limitBytes - totalBytes);
}
if (ifaces.length > 1) {
// TODO: switch to shared quota once NMS supports
Slog.w(TAG, "shared quota unsupported; generating rule for each iface");
}
for (String iface : ifaces) {
removeInterfaceQuota(iface);
setInterfaceQuota(iface, quotaBytes);
newMeteredIfaces.add(iface);
if (powerSave) {
connIfaces.remove(iface);
}
}
}
// keep track of lowest warning or limit of active policies
if (hasWarning && policy.warningBytes < lowestRule) {
lowestRule = policy.warningBytes;
}
if (hasLimit && policy.limitBytes < lowestRule) {
lowestRule = policy.limitBytes;
}
}
for (int i = connIfaces.size()-1; i >= 0; i--) {
String iface = connIfaces.valueAt(i);
removeInterfaceQuota(iface);
setInterfaceQuota(iface, Long.MAX_VALUE);
newMeteredIfaces.add(iface);
}
mHandler.obtainMessage(MSG_ADVISE_PERSIST_THRESHOLD, lowestRule).sendToTarget();
// remove quota on any trailing interfaces
for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
final String iface = mMeteredIfaces.valueAt(i);
if (!newMeteredIfaces.contains(iface)) {
removeInterfaceQuota(iface);
}
}
mMeteredIfaces = newMeteredIfaces;
final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
| void | updateNotificationsLocked()Check {@link NetworkPolicy} against current {@link INetworkStatsService}
to show visible notifications as needed.
if (LOGV) Slog.v(TAG, "updateNotificationsLocked()");
// keep track of previously active notifications
final ArraySet<String> beforeNotifs = new ArraySet<String>(mActiveNotifs);
mActiveNotifs.clear();
// TODO: when switching to kernel notifications, compute next future
// cycle boundary to recompute notifications.
// examine stats for each active policy
final long currentTime = currentTimeMillis();
for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
// ignore policies that aren't relevant to user
if (!isTemplateRelevant(policy.template)) continue;
if (!policy.hasCycle()) continue;
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
final long totalBytes = getTotalBytes(policy.template, start, end);
if (policy.isOverLimit(totalBytes)) {
if (policy.lastLimitSnooze >= start) {
enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
} else {
enqueueNotification(policy, TYPE_LIMIT, totalBytes);
notifyOverLimitLocked(policy.template);
}
} else {
notifyUnderLimitLocked(policy.template);
if (policy.isOverWarning(totalBytes) && policy.lastWarningSnooze < start) {
enqueueNotification(policy, TYPE_WARNING, totalBytes);
}
}
}
// ongoing notification when restricting background data
if (mRestrictBackground) {
enqueueRestrictedNotification(TAG_ALLOW_BACKGROUND);
}
// cancel stale notifications that we didn't renew above
for (int i = beforeNotifs.size()-1; i >= 0; i--) {
final String tag = beforeNotifs.valueAt(i);
if (!mActiveNotifs.contains(tag)) {
cancelNotification(tag);
}
}
| void | updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged)Update rules that might be changed by {@link #mRestrictBackground}
or {@link #mRestrictPower} value.
final PackageManager pm = mContext.getPackageManager();
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
// If we are in restrict power mode, we allow all important apps
// to have data access. Otherwise, we restrict data access to only
// the top apps.
mCurForegroundState = (!mRestrictBackground && mRestrictPower)
? ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
: ActivityManager.PROCESS_STATE_TOP;
// update rules for all installed applications
final List<UserInfo> users = um.getUsers();
final List<ApplicationInfo> apps = pm.getInstalledApplications(
PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS);
for (UserInfo user : users) {
for (ApplicationInfo app : apps) {
final int uid = UserHandle.getUid(user.id, app.uid);
updateRulesForUidLocked(uid);
}
}
// limit data usage for some internal system services
updateRulesForUidLocked(android.os.Process.MEDIA_UID);
updateRulesForUidLocked(android.os.Process.DRM_UID);
// If the set of restricted networks may have changed, re-evaluate those.
if (restrictedNetworksChanged) {
normalizePoliciesLocked();
updateNetworkRulesLocked();
}
| private void | updateRulesForScreenLocked()Update rules that might be changed by {@link #mScreenOn} value.
// only update rules for anyone with foreground activities
final int size = mUidState.size();
for (int i = 0; i < size; i++) {
if (mUidState.valueAt(i) <= mCurForegroundState) {
final int uid = mUidState.keyAt(i);
updateRulesForUidLocked(uid);
}
}
| void | updateRulesForUidLocked(int uid)
if (!isUidValidForRules(uid)) return;
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
final boolean uidForeground = isUidForegroundLocked(uid);
// derive active rules based on policy and active state
int uidRules = RULE_ALLOW_ALL;
if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
// uid in background, and policy says to block metered data
uidRules = RULE_REJECT_METERED;
} else if (mRestrictBackground) {
if (!uidForeground) {
// uid in background, and global background disabled
uidRules = RULE_REJECT_METERED;
}
} else if (mRestrictPower) {
final boolean whitelisted = mPowerSaveWhitelistAppIds.get(UserHandle.getAppId(uid));
if (!whitelisted && !uidForeground
&& (uidPolicy & POLICY_ALLOW_BACKGROUND_BATTERY_SAVE) == 0) {
// uid is in background, restrict power use mode is on (so we want to
// restrict all background network access), and this uid is not on the
// white list of those allowed background access.
uidRules = RULE_REJECT_METERED;
}
}
// TODO: only dispatch when rules actually change
if (uidRules == RULE_ALLOW_ALL) {
mUidRules.delete(uid);
} else {
mUidRules.put(uid, uidRules);
}
final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
setUidNetworkRules(uid, rejectMetered);
// dispatch changed rule to existing listeners
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
try {
// adjust stats accounting based on foreground status
mNetworkStats.setUidForeground(uid, uidForeground);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
| private void | updateScreenOn()
synchronized (mRulesLock) {
try {
mScreenOn = mPowerManager.isInteractive();
} catch (RemoteException e) {
// ignored; service lives in system_server
}
updateRulesForScreenLocked();
}
| private void | upgradeLegacyBackgroundData()Upgrade legacy background data flags, notifying listeners of one last
change to always-true.
mRestrictBackground = Settings.Secure.getInt(
mContext.getContentResolver(), Settings.Secure.BACKGROUND_DATA, 1) != 1;
// kick off one last broadcast if restricted
if (mRestrictBackground) {
final Intent broadcast = new Intent(
ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
mContext.sendBroadcastAsUser(broadcast, UserHandle.ALL);
}
| void | writePolicyLocked()
if (LOGV) Slog.v(TAG, "writePolicyLocked()");
FileOutputStream fos = null;
try {
fos = mPolicyFile.startWrite();
XmlSerializer out = new FastXmlSerializer();
out.setOutput(fos, "utf-8");
out.startDocument(null, true);
out.startTag(null, TAG_POLICY_LIST);
writeIntAttribute(out, ATTR_VERSION, VERSION_LATEST);
writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);
// write all known network policies
for (int i = 0; i < mNetworkPolicy.size(); i++) {
final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
final NetworkTemplate template = policy.template;
out.startTag(null, TAG_NETWORK_POLICY);
writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule());
final String subscriberId = template.getSubscriberId();
if (subscriberId != null) {
out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId);
}
final String networkId = template.getNetworkId();
if (networkId != null) {
out.attribute(null, ATTR_NETWORK_ID, networkId);
}
writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
out.attribute(null, ATTR_CYCLE_TIMEZONE, policy.cycleTimezone);
writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
writeLongAttribute(out, ATTR_LAST_WARNING_SNOOZE, policy.lastWarningSnooze);
writeLongAttribute(out, ATTR_LAST_LIMIT_SNOOZE, policy.lastLimitSnooze);
writeBooleanAttribute(out, ATTR_METERED, policy.metered);
writeBooleanAttribute(out, ATTR_INFERRED, policy.inferred);
out.endTag(null, TAG_NETWORK_POLICY);
}
// write all known uid policies
for (int i = 0; i < mUidPolicy.size(); i++) {
final int uid = mUidPolicy.keyAt(i);
final int policy = mUidPolicy.valueAt(i);
// skip writing empty policies
if (policy == POLICY_NONE) continue;
out.startTag(null, TAG_UID_POLICY);
writeIntAttribute(out, ATTR_UID, uid);
writeIntAttribute(out, ATTR_POLICY, policy);
out.endTag(null, TAG_UID_POLICY);
}
out.endTag(null, TAG_POLICY_LIST);
out.endDocument();
mPolicyFile.finishWrite(fos);
} catch (IOException e) {
if (fos != null) {
mPolicyFile.failWrite(fos);
}
}
|
|