Notify policy listeners about metered ifaces. am: a47d7a1a70

Original change: undetermined

Change-Id: I5f6339f24fe7bebb550d27297c28cec952aee844
This commit is contained in:
Jeff Sharkey
2021-05-31 04:25:47 +00:00
committed by Automerger Merge Worker

View File

@@ -19,7 +19,7 @@ package com.android.server;
import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
import static android.net.ConnectivityManager.isNetworkTypeValid;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_PAID;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import android.bluetooth.BluetoothTetheringDataTracker;
import android.content.ContentResolver;
@@ -71,6 +71,7 @@ import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -78,8 +79,10 @@ import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -108,8 +111,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private Vpn mVpn;
/** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
private Object mRulesLock = new Object();
/** Currently active network rules by UID. */
private SparseIntArray mUidRules = new SparseIntArray();
/** Set of ifaces that are costly. */
private HashSet<String> mMeteredIfaces = Sets.newHashSet();
/**
* Sometimes we want to refer to the individual network state
@@ -570,31 +577,35 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
/**
* Check if UID is blocked from using the given {@link NetworkInfo}.
* Check if UID should be blocked from using the network represented by the
* given {@link NetworkStateTracker}.
*/
private boolean isNetworkBlocked(NetworkInfo info, int uid) {
synchronized (mUidRules) {
// TODO: expand definition of "paid" network to cover tethered or
// paid hotspot use cases.
final boolean networkIsPaid = info.getType() != ConnectivityManager.TYPE_WIFI;
final int uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
private boolean isNetworkBlocked(NetworkStateTracker tracker, int uid) {
final String iface = tracker.getLinkProperties().getInterfaceName();
if (networkIsPaid && (uidRules & RULE_REJECT_PAID) != 0) {
return true;
}
// no restrictive rules; network is visible
return false;
final boolean networkCostly;
final int uidRules;
synchronized (mRulesLock) {
networkCostly = mMeteredIfaces.contains(iface);
uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
}
if (networkCostly && (uidRules & RULE_REJECT_METERED) != 0) {
return true;
}
// no restrictive rules; network is visible
return false;
}
/**
* Return a filtered version of the given {@link NetworkInfo}, potentially
* marked {@link DetailedState#BLOCKED} based on
* {@link #isNetworkBlocked(NetworkInfo, int)}.
* Return a filtered {@link NetworkInfo}, potentially marked
* {@link DetailedState#BLOCKED} based on
* {@link #isNetworkBlocked(NetworkStateTracker, int)}.
*/
private NetworkInfo filterNetworkInfo(NetworkInfo info, int uid) {
if (isNetworkBlocked(info, uid)) {
private NetworkInfo getFilteredNetworkInfo(NetworkStateTracker tracker, int uid) {
NetworkInfo info = tracker.getNetworkInfo();
if (isNetworkBlocked(tracker, uid)) {
// network is blocked; clone and override state
info = new NetworkInfo(info);
info.setDetailedState(DetailedState.BLOCKED, null, null);
@@ -634,7 +645,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (isNetworkTypeValid(networkType)) {
final NetworkStateTracker tracker = mNetTrackers[networkType];
if (tracker != null) {
info = filterNetworkInfo(tracker.getNetworkInfo(), uid);
info = getFilteredNetworkInfo(tracker, uid);
}
}
return info;
@@ -645,10 +656,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
enforceAccessPermission();
final int uid = Binder.getCallingUid();
final ArrayList<NetworkInfo> result = Lists.newArrayList();
synchronized (mUidRules) {
synchronized (mRulesLock) {
for (NetworkStateTracker tracker : mNetTrackers) {
if (tracker != null) {
result.add(filterNetworkInfo(tracker.getNetworkInfo(), uid));
result.add(getFilteredNetworkInfo(tracker, uid));
}
}
}
@@ -685,10 +696,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
enforceAccessPermission();
final int uid = Binder.getCallingUid();
final ArrayList<NetworkState> result = Lists.newArrayList();
synchronized (mUidRules) {
synchronized (mRulesLock) {
for (NetworkStateTracker tracker : mNetTrackers) {
if (tracker != null) {
final NetworkInfo info = filterNetworkInfo(tracker.getNetworkInfo(), uid);
final NetworkInfo info = getFilteredNetworkInfo(tracker, uid);
result.add(new NetworkState(
info, tracker.getLinkProperties(), tracker.getLinkCapabilities()));
}
@@ -1139,15 +1150,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
@Override
public void onRulesChanged(int uid, int uidRules) {
public void onUidRulesChanged(int uid, int uidRules) {
// only someone like NPMS should only be calling us
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
if (LOGD_RULES) {
Slog.d(TAG, "onRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
Slog.d(TAG, "onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
}
synchronized (mUidRules) {
synchronized (mRulesLock) {
// skip update when we've already applied rules
final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL);
if (oldRules == uidRules) return;
@@ -1158,6 +1169,24 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// TODO: dispatch into NMS to push rules towards kernel module
// TODO: notify UID when it has requested targeted updates
}
@Override
public void onMeteredIfacesChanged(String[] meteredIfaces) {
// only someone like NPMS should only be calling us
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
if (LOGD_RULES) {
Slog.d(TAG,
"onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
}
synchronized (mRulesLock) {
mMeteredIfaces.clear();
for (String iface : meteredIfaces) {
mMeteredIfaces.add(iface);
}
}
}
};
/**