Loading core/java/android/net/INetworkPolicyManager.aidl +0 −3 Original line number Original line Diff line number Diff line Loading @@ -38,9 +38,6 @@ interface INetworkPolicyManager { boolean isUidForeground(int uid); boolean isUidForeground(int uid); /** Higher priority listener before general event dispatch */ void setConnectivityListener(INetworkPolicyListener listener); void registerListener(INetworkPolicyListener listener); void registerListener(INetworkPolicyListener listener); void unregisterListener(INetworkPolicyListener listener); void unregisterListener(INetworkPolicyListener listener); Loading services/core/java/com/android/server/ConnectivityService.java +30 −143 Original line number Original line Diff line number Diff line Loading @@ -29,13 +29,6 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED; import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED; import static android.net.NetworkPolicyManager.uidRulesToString; import android.annotation.Nullable; import android.annotation.Nullable; import android.app.BroadcastOptions; import android.app.BroadcastOptions; Loading Loading @@ -104,7 +97,6 @@ import android.security.Credentials; import android.security.KeyStore; import android.security.KeyStore; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.text.TextUtils; import android.util.ArraySet; import android.util.LocalLog; import android.util.LocalLog; import android.util.LocalLog.ReadOnlyLocalLog; import android.util.LocalLog.ReadOnlyLocalLog; import android.util.Log; import android.util.Log; Loading @@ -130,6 +122,7 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; import com.android.internal.util.MessageUtils; import com.android.internal.util.WakeupMessage; import com.android.internal.util.WakeupMessage; import com.android.internal.util.XmlUtils; import com.android.internal.util.XmlUtils; import com.android.server.LocalServices; import com.android.server.am.BatteryStatsService; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.KeepaliveTracker; import com.android.server.connectivity.KeepaliveTracker; Loading @@ -147,6 +140,7 @@ import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.android.server.connectivity.Vpn; import com.android.server.net.BaseNetworkObserver; import com.android.server.net.BaseNetworkObserver; import com.android.server.net.LockdownVpnTracker; import com.android.server.net.LockdownVpnTracker; import com.android.server.net.NetworkPolicyManagerInternal; import com.google.android.collect.Lists; import com.google.android.collect.Lists; Loading Loading @@ -221,18 +215,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private boolean mLockdownEnabled; private boolean mLockdownEnabled; private LockdownVpnTracker mLockdownTracker; private LockdownVpnTracker mLockdownTracker; /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */ private Object mRulesLock = new Object(); /** Currently active network rules by UID. */ @GuardedBy("mRulesLock") private SparseIntArray mUidRules = new SparseIntArray(); /** Set of ifaces that are costly. */ @GuardedBy("mRulesLock") private ArraySet<String> mMeteredIfaces = new ArraySet<>(); /** Flag indicating if background data is restricted. */ @GuardedBy("mRulesLock") private boolean mRestrictBackground; final private Context mContext; final private Context mContext; private int mNetworkPreference; private int mNetworkPreference; // 0 is full bad, 100 is full good // 0 is full bad, 100 is full good Loading @@ -246,6 +228,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private INetworkManagementService mNetd; private INetworkManagementService mNetd; private INetworkStatsService mStatsService; private INetworkStatsService mStatsService; private INetworkPolicyManager mPolicyManager; private INetworkPolicyManager mPolicyManager; private NetworkPolicyManagerInternal mPolicyManagerInternal; private String mCurrentTcpBufferSizes; private String mCurrentTcpBufferSizes; Loading Loading @@ -715,12 +698,15 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetd = checkNotNull(netManager, "missing INetworkManagementService"); mNetd = checkNotNull(netManager, "missing INetworkManagementService"); mStatsService = checkNotNull(statsService, "missing INetworkStatsService"); mStatsService = checkNotNull(statsService, "missing INetworkStatsService"); mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager"); mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager"); mPolicyManagerInternal = checkNotNull( LocalServices.getService(NetworkPolicyManagerInternal.class), "missing NetworkPolicyManagerInternal"); mKeyStore = KeyStore.getInstance(); mKeyStore = KeyStore.getInstance(); mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); try { try { mPolicyManager.setConnectivityListener(mPolicyListener); mPolicyManager.registerListener(mPolicyListener); mRestrictBackground = mPolicyManager.getRestrictBackground(); } catch (RemoteException e) { } catch (RemoteException e) { // ouch, no rules updates means some processes may never get network // ouch, no rules updates means some processes may never get network loge("unable to register INetworkPolicyListener" + e); loge("unable to register INetworkPolicyListener" + e); Loading Loading @@ -991,51 +977,22 @@ public class ConnectivityService extends IConnectivityManager.Stub private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid, private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid, boolean ignoreBlocked) { boolean ignoreBlocked) { // Networks aren't blocked when ignoring blocked status // Networks aren't blocked when ignoring blocked status if (ignoreBlocked) return false; if (ignoreBlocked) { return false; } // Networks are never blocked for system services // Networks are never blocked for system services if (isSystem(uid)) return false; // TODO: consider moving this check to NetworkPolicyManagerInternal.isUidNetworkingBlocked. if (isSystem(uid)) { final boolean networkMetered; return false; final int uidRules; } synchronized (mVpns) { synchronized (mVpns) { final Vpn vpn = mVpns.get(UserHandle.getUserId(uid)); final Vpn vpn = mVpns.get(UserHandle.getUserId(uid)); if (vpn != null && vpn.isBlockingUid(uid)) { if (vpn != null && vpn.isBlockingUid(uid)) { return true; return true; } } } } final String iface = (lp == null ? "" : lp.getInterfaceName()); final String iface = (lp == null ? "" : lp.getInterfaceName()); synchronized (mRulesLock) { return mPolicyManagerInternal.isUidNetworkingBlocked(uid, iface); networkMetered = mMeteredIfaces.contains(iface); uidRules = mUidRules.get(uid, RULE_NONE); } boolean allowed = true; // Check Data Saver Mode first... if (networkMetered) { if ((uidRules & RULE_REJECT_METERED) != 0) { if (LOGD_RULES) Log.d(TAG, "uid " + uid + " is blacklisted"); // Explicitly blacklisted. allowed = false; } else { allowed = !mRestrictBackground || (uidRules & RULE_ALLOW_METERED) != 0 || (uidRules & RULE_TEMPORARY_ALLOW_METERED) != 0; if (LOGD_RULES) Log.d(TAG, "allowed status for uid " + uid + " when" + " mRestrictBackground=" + mRestrictBackground + ", whitelisted=" + ((uidRules & RULE_ALLOW_METERED) != 0) + ", tempWhitelist= + ((uidRules & RULE_TEMPORARY_ALLOW_METERED) != 0)" + ": " + allowed); } } // ...then power restrictions. if (allowed) { allowed = (uidRules & RULE_REJECT_ALL) == 0; if (LOGD_RULES) Log.d(TAG, "allowed status for uid " + uid + " when" + " rule is " + uidRulesToString(uidRules) + ": " + allowed); } return !allowed; } } private void maybeLogBlockedNetworkInfo(NetworkInfo ni, int uid) { private void maybeLogBlockedNetworkInfo(NetworkInfo ni, int uid) { Loading Loading @@ -1481,67 +1438,24 @@ public class ConnectivityService extends IConnectivityManager.Stub return true; return true; } } private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { @Override @Override public void onUidRulesChanged(int uid, int uidRules) { public void onUidRulesChanged(int uid, int uidRules) { // caller is NPMS, since we only register with them if (LOGD_RULES) { log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")"); } synchronized (mRulesLock) { // skip update when we've already applied rules final int oldRules = mUidRules.get(uid, RULE_NONE); if (oldRules == uidRules) return; if (uidRules == RULE_NONE) { mUidRules.delete(uid); } else { mUidRules.put(uid, uidRules); } } // TODO: notify UID when it has requested targeted updates // TODO: notify UID when it has requested targeted updates } } @Override @Override public void onMeteredIfacesChanged(String[] meteredIfaces) { public void onMeteredIfacesChanged(String[] meteredIfaces) { // caller is NPMS, since we only register with them if (LOGD_RULES) { log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")"); } synchronized (mRulesLock) { mMeteredIfaces.clear(); for (String iface : meteredIfaces) { mMeteredIfaces.add(iface); } } } } @Override @Override public void onRestrictBackgroundChanged(boolean restrictBackground) { public void onRestrictBackgroundChanged(boolean restrictBackground) { // caller is NPMS, since we only register with them // TODO: relocate this specific callback in Tethering. if (LOGD_RULES) { log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")"); } synchronized (mRulesLock) { mRestrictBackground = restrictBackground; } if (restrictBackground) { if (restrictBackground) { log("onRestrictBackgroundChanged(true): disabling tethering"); log("onRestrictBackgroundChanged(true): disabling tethering"); mTethering.untetherAll(); mTethering.untetherAll(); } } } } @Override @Override public void onUidPoliciesChanged(int uid, int uidPolicies) { public void onUidPoliciesChanged(int uid, int uidPolicies) { // caller is NPMS, since we only register with them if (LOGD_RULES) { log("onUidRulesChanged(uid=" + uid + ", uidPolicies=" + uidPolicies + ")"); } } } }; }; Loading Loading @@ -1976,33 +1890,6 @@ public class ConnectivityService extends IConnectivityManager.Stub pw.decreaseIndent(); pw.decreaseIndent(); pw.println(); pw.println(); pw.println("Metered Interfaces:"); pw.increaseIndent(); for (String value : mMeteredIfaces) { pw.println(value); } pw.decreaseIndent(); pw.println(); pw.print("Restrict background: "); pw.println(mRestrictBackground); pw.println(); pw.println("Status for known UIDs:"); pw.increaseIndent(); final int size = mUidRules.size(); for (int i = 0; i < size; i++) { final int uid = mUidRules.keyAt(i); pw.print("UID="); pw.print(uid); final int uidRules = mUidRules.get(uid, RULE_NONE); pw.print(" rules="); pw.print(uidRulesToString(uidRules)); pw.println(); } pw.println(); pw.decreaseIndent(); pw.println("Network Requests:"); pw.println("Network Requests:"); pw.increaseIndent(); pw.increaseIndent(); for (NetworkRequestInfo nri : mNetworkRequests.values()) { for (NetworkRequestInfo nri : mNetworkRequests.values()) { Loading Loading @@ -3437,6 +3324,10 @@ public class ConnectivityService extends IConnectivityManager.Stub Slog.e(TAG, s); Slog.e(TAG, s); } } private static void loge(String s, Throwable t) { Slog.e(TAG, s, t); } private static <T> T checkNotNull(T value, String message) { private static <T> T checkNotNull(T value, String message) { if (value == null) { if (value == null) { throw new NullPointerException(message); throw new NullPointerException(message); Loading Loading @@ -4197,22 +4088,18 @@ public class ConnectivityService extends IConnectivityManager.Stub private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) { private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) { final int uid = Binder.getCallingUid(); final int uid = Binder.getCallingUid(); if (isSystem(uid)) { if (isSystem(uid)) { // Exemption for system uid. return; return; } } // if UID is restricted, don't allow them to bring up metered APNs if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) { if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED) == false) { // Policy already enforced. final int uidRules; return; synchronized(mRulesLock) { uidRules = mUidRules.get(uid, RULE_ALLOW_ALL); } } if (mRestrictBackground && (uidRules & RULE_ALLOW_METERED) == 0 if (mPolicyManagerInternal.isUidRestrictedOnMeteredNetworks(uid)) { && (uidRules & RULE_TEMPORARY_ALLOW_METERED) == 0) { // If UID is restricted, don't allow them to bring up metered APNs. // we could silently fail or we can filter the available nets to only give // them those they have access to. Chose the more useful option. networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED); networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED); } } } } } @Override @Override public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities, public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities, Loading services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java +11 −0 Original line number Original line Diff line number Diff line Loading @@ -27,4 +27,15 @@ public abstract class NetworkPolicyManagerInternal { * Resets all policies associated with a given user. * Resets all policies associated with a given user. */ */ public abstract void resetUserState(int userId); public abstract void resetUserState(int userId); /** * @return true if the given uid is restricted from doing networking on metered networks. */ public abstract boolean isUidRestrictedOnMeteredNetworks(int uid); /** * @return true if networking is blocked on the given interface for the given uid according * to current networking policies. */ public abstract boolean isUidNetworkingBlocked(int uid, String ifname); } } services/core/java/com/android/server/net/NetworkPolicyManagerService.java +70 −18 Original line number Original line Diff line number Diff line Loading @@ -248,8 +248,8 @@ import java.util.concurrent.TimeUnit; */ */ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { static final String TAG = "NetworkPolicy"; static final String TAG = "NetworkPolicy"; private static final boolean LOGD = false; private static final boolean LOGD = true; // UNDO private static final boolean LOGV = false; private static final boolean LOGV = true; // UNDO private static final int VERSION_INIT = 1; private static final int VERSION_INIT = 1; private static final int VERSION_ADDED_SNOOZE = 2; private static final int VERSION_ADDED_SNOOZE = 2; Loading Loading @@ -428,9 +428,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") @GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidState = new SparseIntArray(); final SparseIntArray mUidState = new SparseIntArray(); /** Higher priority listener before general event dispatch */ private INetworkPolicyListener mConnectivityListener; private final RemoteCallbackList<INetworkPolicyListener> private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<>(); mListeners = new RemoteCallbackList<>(); Loading Loading @@ -2236,15 +2233,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return changed; return changed; } } @Override public void setConnectivityListener(INetworkPolicyListener listener) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); if (mConnectivityListener != null) { throw new IllegalStateException("Connectivity listener already registered"); } mConnectivityListener = listener; } @Override @Override public void registerListener(INetworkPolicyListener listener) { public void registerListener(INetworkPolicyListener listener) { // TODO: create permission for observing network policy // TODO: create permission for observing network policy Loading Loading @@ -3556,7 +3544,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { case MSG_RULES_CHANGED: { case MSG_RULES_CHANGED: { final int uid = msg.arg1; final int uid = msg.arg1; final int uidRules = msg.arg2; final int uidRules = msg.arg2; dispatchUidRulesChanged(mConnectivityListener, uid, uidRules); final int length = mListeners.beginBroadcast(); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); Loading @@ -3567,7 +3554,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } case MSG_METERED_IFACES_CHANGED: { case MSG_METERED_IFACES_CHANGED: { final String[] meteredIfaces = (String[]) msg.obj; final String[] meteredIfaces = (String[]) msg.obj; dispatchMeteredIfacesChanged(mConnectivityListener, meteredIfaces); final int length = mListeners.beginBroadcast(); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); Loading Loading @@ -3598,7 +3584,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } case MSG_RESTRICT_BACKGROUND_CHANGED: { case MSG_RESTRICT_BACKGROUND_CHANGED: { final boolean restrictBackground = msg.arg1 != 0; final boolean restrictBackground = msg.arg1 != 0; dispatchRestrictBackgroundChanged(mConnectivityListener, restrictBackground); final int length = mListeners.beginBroadcast(); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); Loading @@ -3616,7 +3601,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final int policy = msg.arg2; final int policy = msg.arg2; final Boolean notifyApp = (Boolean) msg.obj; final Boolean notifyApp = (Boolean) msg.obj; // First notify internal listeners... // First notify internal listeners... dispatchUidPoliciesChanged(mConnectivityListener, uid, policy); final int length = mListeners.beginBroadcast(); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); Loading Loading @@ -4049,6 +4033,74 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } } } } } /** * @return true if the given uid is restricted from doing networking on metered networks. */ @Override public boolean isUidRestrictedOnMeteredNetworks(int uid) { final int uidRules; final boolean isBackgroundRestricted; synchronized (mUidRulesFirstLock) { uidRules = mUidRules.get(uid, RULE_ALLOW_ALL); isBackgroundRestricted = mRestrictBackground; } return isBackgroundRestricted && !hasRule(uidRules, RULE_ALLOW_METERED) && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED); } /** * @return true if networking is blocked on the given interface for the given uid according * to current networking policies. */ @Override public boolean isUidNetworkingBlocked(int uid, String ifname) { final int uidRules; final boolean isBackgroundRestricted; final boolean isNetworkMetered; synchronized (mUidRulesFirstLock) { uidRules = mUidRules.get(uid, RULE_NONE); isBackgroundRestricted = mRestrictBackground; synchronized (mNetworkPoliciesSecondLock) { isNetworkMetered = mMeteredIfaces.contains(ifname); } } if (hasRule(uidRules, RULE_REJECT_ALL)) { if (LOGV) logUidStatus(uid, "blocked by power restrictions"); return true; } if (!isNetworkMetered) { if (LOGV) logUidStatus(uid, "allowed on unmetered network"); return false; } if (hasRule(uidRules, RULE_REJECT_METERED)) { if (LOGV) logUidStatus(uid, "blacklisted on metered network"); return true; } if (hasRule(uidRules, RULE_ALLOW_METERED)) { if (LOGV) logUidStatus(uid, "whitelisted on metered network"); return false; } if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) { if (LOGV) logUidStatus(uid, "temporary whitelisted on metered network"); return false; } if (isBackgroundRestricted) { if (LOGV) logUidStatus(uid, "blocked when background is restricted"); return true; } if (LOGV) logUidStatus(uid, "allowed by default"); return false; } } private static boolean hasRule(int uidRules, int rule) { return (uidRules & rule) != 0; } private static void logUidStatus(int uid, String descr) { Slog.d(TAG, String.format("uid %d is %s", uid, descr)); } } /** /** Loading tests/net/java/com/android/server/ConnectivityServiceTest.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -80,6 +80,7 @@ import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkMonitor; import com.android.server.connectivity.NetworkMonitor; import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult; import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult; import com.android.server.net.NetworkPinner; import com.android.server.net.NetworkPinner; import com.android.server.net.NetworkPolicyManagerInternal; import java.net.InetAddress; import java.net.InetAddress; import java.util.ArrayList; import java.util.ArrayList; Loading Loading @@ -713,6 +714,9 @@ public class ConnectivityServiceTest extends AndroidTestCase { } } mServiceContext = new MockContext(getContext()); mServiceContext = new MockContext(getContext()); LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class); LocalServices.addService( NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class)); mService = new WrappedConnectivityService(mServiceContext, mService = new WrappedConnectivityService(mServiceContext, mock(INetworkManagementService.class), mock(INetworkManagementService.class), mock(INetworkStatsService.class), mock(INetworkStatsService.class), Loading Loading
core/java/android/net/INetworkPolicyManager.aidl +0 −3 Original line number Original line Diff line number Diff line Loading @@ -38,9 +38,6 @@ interface INetworkPolicyManager { boolean isUidForeground(int uid); boolean isUidForeground(int uid); /** Higher priority listener before general event dispatch */ void setConnectivityListener(INetworkPolicyListener listener); void registerListener(INetworkPolicyListener listener); void registerListener(INetworkPolicyListener listener); void unregisterListener(INetworkPolicyListener listener); void unregisterListener(INetworkPolicyListener listener); Loading
services/core/java/com/android/server/ConnectivityService.java +30 −143 Original line number Original line Diff line number Diff line Loading @@ -29,13 +29,6 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED; import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED; import static android.net.NetworkPolicyManager.uidRulesToString; import android.annotation.Nullable; import android.annotation.Nullable; import android.app.BroadcastOptions; import android.app.BroadcastOptions; Loading Loading @@ -104,7 +97,6 @@ import android.security.Credentials; import android.security.KeyStore; import android.security.KeyStore; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.text.TextUtils; import android.util.ArraySet; import android.util.LocalLog; import android.util.LocalLog; import android.util.LocalLog.ReadOnlyLocalLog; import android.util.LocalLog.ReadOnlyLocalLog; import android.util.Log; import android.util.Log; Loading @@ -130,6 +122,7 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; import com.android.internal.util.MessageUtils; import com.android.internal.util.WakeupMessage; import com.android.internal.util.WakeupMessage; import com.android.internal.util.XmlUtils; import com.android.internal.util.XmlUtils; import com.android.server.LocalServices; import com.android.server.am.BatteryStatsService; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.KeepaliveTracker; import com.android.server.connectivity.KeepaliveTracker; Loading @@ -147,6 +140,7 @@ import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.android.server.connectivity.Vpn; import com.android.server.net.BaseNetworkObserver; import com.android.server.net.BaseNetworkObserver; import com.android.server.net.LockdownVpnTracker; import com.android.server.net.LockdownVpnTracker; import com.android.server.net.NetworkPolicyManagerInternal; import com.google.android.collect.Lists; import com.google.android.collect.Lists; Loading Loading @@ -221,18 +215,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private boolean mLockdownEnabled; private boolean mLockdownEnabled; private LockdownVpnTracker mLockdownTracker; private LockdownVpnTracker mLockdownTracker; /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */ private Object mRulesLock = new Object(); /** Currently active network rules by UID. */ @GuardedBy("mRulesLock") private SparseIntArray mUidRules = new SparseIntArray(); /** Set of ifaces that are costly. */ @GuardedBy("mRulesLock") private ArraySet<String> mMeteredIfaces = new ArraySet<>(); /** Flag indicating if background data is restricted. */ @GuardedBy("mRulesLock") private boolean mRestrictBackground; final private Context mContext; final private Context mContext; private int mNetworkPreference; private int mNetworkPreference; // 0 is full bad, 100 is full good // 0 is full bad, 100 is full good Loading @@ -246,6 +228,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private INetworkManagementService mNetd; private INetworkManagementService mNetd; private INetworkStatsService mStatsService; private INetworkStatsService mStatsService; private INetworkPolicyManager mPolicyManager; private INetworkPolicyManager mPolicyManager; private NetworkPolicyManagerInternal mPolicyManagerInternal; private String mCurrentTcpBufferSizes; private String mCurrentTcpBufferSizes; Loading Loading @@ -715,12 +698,15 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetd = checkNotNull(netManager, "missing INetworkManagementService"); mNetd = checkNotNull(netManager, "missing INetworkManagementService"); mStatsService = checkNotNull(statsService, "missing INetworkStatsService"); mStatsService = checkNotNull(statsService, "missing INetworkStatsService"); mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager"); mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager"); mPolicyManagerInternal = checkNotNull( LocalServices.getService(NetworkPolicyManagerInternal.class), "missing NetworkPolicyManagerInternal"); mKeyStore = KeyStore.getInstance(); mKeyStore = KeyStore.getInstance(); mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); try { try { mPolicyManager.setConnectivityListener(mPolicyListener); mPolicyManager.registerListener(mPolicyListener); mRestrictBackground = mPolicyManager.getRestrictBackground(); } catch (RemoteException e) { } catch (RemoteException e) { // ouch, no rules updates means some processes may never get network // ouch, no rules updates means some processes may never get network loge("unable to register INetworkPolicyListener" + e); loge("unable to register INetworkPolicyListener" + e); Loading Loading @@ -991,51 +977,22 @@ public class ConnectivityService extends IConnectivityManager.Stub private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid, private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid, boolean ignoreBlocked) { boolean ignoreBlocked) { // Networks aren't blocked when ignoring blocked status // Networks aren't blocked when ignoring blocked status if (ignoreBlocked) return false; if (ignoreBlocked) { return false; } // Networks are never blocked for system services // Networks are never blocked for system services if (isSystem(uid)) return false; // TODO: consider moving this check to NetworkPolicyManagerInternal.isUidNetworkingBlocked. if (isSystem(uid)) { final boolean networkMetered; return false; final int uidRules; } synchronized (mVpns) { synchronized (mVpns) { final Vpn vpn = mVpns.get(UserHandle.getUserId(uid)); final Vpn vpn = mVpns.get(UserHandle.getUserId(uid)); if (vpn != null && vpn.isBlockingUid(uid)) { if (vpn != null && vpn.isBlockingUid(uid)) { return true; return true; } } } } final String iface = (lp == null ? "" : lp.getInterfaceName()); final String iface = (lp == null ? "" : lp.getInterfaceName()); synchronized (mRulesLock) { return mPolicyManagerInternal.isUidNetworkingBlocked(uid, iface); networkMetered = mMeteredIfaces.contains(iface); uidRules = mUidRules.get(uid, RULE_NONE); } boolean allowed = true; // Check Data Saver Mode first... if (networkMetered) { if ((uidRules & RULE_REJECT_METERED) != 0) { if (LOGD_RULES) Log.d(TAG, "uid " + uid + " is blacklisted"); // Explicitly blacklisted. allowed = false; } else { allowed = !mRestrictBackground || (uidRules & RULE_ALLOW_METERED) != 0 || (uidRules & RULE_TEMPORARY_ALLOW_METERED) != 0; if (LOGD_RULES) Log.d(TAG, "allowed status for uid " + uid + " when" + " mRestrictBackground=" + mRestrictBackground + ", whitelisted=" + ((uidRules & RULE_ALLOW_METERED) != 0) + ", tempWhitelist= + ((uidRules & RULE_TEMPORARY_ALLOW_METERED) != 0)" + ": " + allowed); } } // ...then power restrictions. if (allowed) { allowed = (uidRules & RULE_REJECT_ALL) == 0; if (LOGD_RULES) Log.d(TAG, "allowed status for uid " + uid + " when" + " rule is " + uidRulesToString(uidRules) + ": " + allowed); } return !allowed; } } private void maybeLogBlockedNetworkInfo(NetworkInfo ni, int uid) { private void maybeLogBlockedNetworkInfo(NetworkInfo ni, int uid) { Loading Loading @@ -1481,67 +1438,24 @@ public class ConnectivityService extends IConnectivityManager.Stub return true; return true; } } private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { @Override @Override public void onUidRulesChanged(int uid, int uidRules) { public void onUidRulesChanged(int uid, int uidRules) { // caller is NPMS, since we only register with them if (LOGD_RULES) { log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")"); } synchronized (mRulesLock) { // skip update when we've already applied rules final int oldRules = mUidRules.get(uid, RULE_NONE); if (oldRules == uidRules) return; if (uidRules == RULE_NONE) { mUidRules.delete(uid); } else { mUidRules.put(uid, uidRules); } } // TODO: notify UID when it has requested targeted updates // TODO: notify UID when it has requested targeted updates } } @Override @Override public void onMeteredIfacesChanged(String[] meteredIfaces) { public void onMeteredIfacesChanged(String[] meteredIfaces) { // caller is NPMS, since we only register with them if (LOGD_RULES) { log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")"); } synchronized (mRulesLock) { mMeteredIfaces.clear(); for (String iface : meteredIfaces) { mMeteredIfaces.add(iface); } } } } @Override @Override public void onRestrictBackgroundChanged(boolean restrictBackground) { public void onRestrictBackgroundChanged(boolean restrictBackground) { // caller is NPMS, since we only register with them // TODO: relocate this specific callback in Tethering. if (LOGD_RULES) { log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")"); } synchronized (mRulesLock) { mRestrictBackground = restrictBackground; } if (restrictBackground) { if (restrictBackground) { log("onRestrictBackgroundChanged(true): disabling tethering"); log("onRestrictBackgroundChanged(true): disabling tethering"); mTethering.untetherAll(); mTethering.untetherAll(); } } } } @Override @Override public void onUidPoliciesChanged(int uid, int uidPolicies) { public void onUidPoliciesChanged(int uid, int uidPolicies) { // caller is NPMS, since we only register with them if (LOGD_RULES) { log("onUidRulesChanged(uid=" + uid + ", uidPolicies=" + uidPolicies + ")"); } } } }; }; Loading Loading @@ -1976,33 +1890,6 @@ public class ConnectivityService extends IConnectivityManager.Stub pw.decreaseIndent(); pw.decreaseIndent(); pw.println(); pw.println(); pw.println("Metered Interfaces:"); pw.increaseIndent(); for (String value : mMeteredIfaces) { pw.println(value); } pw.decreaseIndent(); pw.println(); pw.print("Restrict background: "); pw.println(mRestrictBackground); pw.println(); pw.println("Status for known UIDs:"); pw.increaseIndent(); final int size = mUidRules.size(); for (int i = 0; i < size; i++) { final int uid = mUidRules.keyAt(i); pw.print("UID="); pw.print(uid); final int uidRules = mUidRules.get(uid, RULE_NONE); pw.print(" rules="); pw.print(uidRulesToString(uidRules)); pw.println(); } pw.println(); pw.decreaseIndent(); pw.println("Network Requests:"); pw.println("Network Requests:"); pw.increaseIndent(); pw.increaseIndent(); for (NetworkRequestInfo nri : mNetworkRequests.values()) { for (NetworkRequestInfo nri : mNetworkRequests.values()) { Loading Loading @@ -3437,6 +3324,10 @@ public class ConnectivityService extends IConnectivityManager.Stub Slog.e(TAG, s); Slog.e(TAG, s); } } private static void loge(String s, Throwable t) { Slog.e(TAG, s, t); } private static <T> T checkNotNull(T value, String message) { private static <T> T checkNotNull(T value, String message) { if (value == null) { if (value == null) { throw new NullPointerException(message); throw new NullPointerException(message); Loading Loading @@ -4197,22 +4088,18 @@ public class ConnectivityService extends IConnectivityManager.Stub private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) { private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) { final int uid = Binder.getCallingUid(); final int uid = Binder.getCallingUid(); if (isSystem(uid)) { if (isSystem(uid)) { // Exemption for system uid. return; return; } } // if UID is restricted, don't allow them to bring up metered APNs if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) { if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED) == false) { // Policy already enforced. final int uidRules; return; synchronized(mRulesLock) { uidRules = mUidRules.get(uid, RULE_ALLOW_ALL); } } if (mRestrictBackground && (uidRules & RULE_ALLOW_METERED) == 0 if (mPolicyManagerInternal.isUidRestrictedOnMeteredNetworks(uid)) { && (uidRules & RULE_TEMPORARY_ALLOW_METERED) == 0) { // If UID is restricted, don't allow them to bring up metered APNs. // we could silently fail or we can filter the available nets to only give // them those they have access to. Chose the more useful option. networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED); networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED); } } } } } @Override @Override public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities, public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities, Loading
services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java +11 −0 Original line number Original line Diff line number Diff line Loading @@ -27,4 +27,15 @@ public abstract class NetworkPolicyManagerInternal { * Resets all policies associated with a given user. * Resets all policies associated with a given user. */ */ public abstract void resetUserState(int userId); public abstract void resetUserState(int userId); /** * @return true if the given uid is restricted from doing networking on metered networks. */ public abstract boolean isUidRestrictedOnMeteredNetworks(int uid); /** * @return true if networking is blocked on the given interface for the given uid according * to current networking policies. */ public abstract boolean isUidNetworkingBlocked(int uid, String ifname); } }
services/core/java/com/android/server/net/NetworkPolicyManagerService.java +70 −18 Original line number Original line Diff line number Diff line Loading @@ -248,8 +248,8 @@ import java.util.concurrent.TimeUnit; */ */ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { static final String TAG = "NetworkPolicy"; static final String TAG = "NetworkPolicy"; private static final boolean LOGD = false; private static final boolean LOGD = true; // UNDO private static final boolean LOGV = false; private static final boolean LOGV = true; // UNDO private static final int VERSION_INIT = 1; private static final int VERSION_INIT = 1; private static final int VERSION_ADDED_SNOOZE = 2; private static final int VERSION_ADDED_SNOOZE = 2; Loading Loading @@ -428,9 +428,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") @GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidState = new SparseIntArray(); final SparseIntArray mUidState = new SparseIntArray(); /** Higher priority listener before general event dispatch */ private INetworkPolicyListener mConnectivityListener; private final RemoteCallbackList<INetworkPolicyListener> private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<>(); mListeners = new RemoteCallbackList<>(); Loading Loading @@ -2236,15 +2233,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return changed; return changed; } } @Override public void setConnectivityListener(INetworkPolicyListener listener) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); if (mConnectivityListener != null) { throw new IllegalStateException("Connectivity listener already registered"); } mConnectivityListener = listener; } @Override @Override public void registerListener(INetworkPolicyListener listener) { public void registerListener(INetworkPolicyListener listener) { // TODO: create permission for observing network policy // TODO: create permission for observing network policy Loading Loading @@ -3556,7 +3544,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { case MSG_RULES_CHANGED: { case MSG_RULES_CHANGED: { final int uid = msg.arg1; final int uid = msg.arg1; final int uidRules = msg.arg2; final int uidRules = msg.arg2; dispatchUidRulesChanged(mConnectivityListener, uid, uidRules); final int length = mListeners.beginBroadcast(); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); Loading @@ -3567,7 +3554,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } case MSG_METERED_IFACES_CHANGED: { case MSG_METERED_IFACES_CHANGED: { final String[] meteredIfaces = (String[]) msg.obj; final String[] meteredIfaces = (String[]) msg.obj; dispatchMeteredIfacesChanged(mConnectivityListener, meteredIfaces); final int length = mListeners.beginBroadcast(); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); Loading Loading @@ -3598,7 +3584,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } case MSG_RESTRICT_BACKGROUND_CHANGED: { case MSG_RESTRICT_BACKGROUND_CHANGED: { final boolean restrictBackground = msg.arg1 != 0; final boolean restrictBackground = msg.arg1 != 0; dispatchRestrictBackgroundChanged(mConnectivityListener, restrictBackground); final int length = mListeners.beginBroadcast(); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); Loading @@ -3616,7 +3601,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final int policy = msg.arg2; final int policy = msg.arg2; final Boolean notifyApp = (Boolean) msg.obj; final Boolean notifyApp = (Boolean) msg.obj; // First notify internal listeners... // First notify internal listeners... dispatchUidPoliciesChanged(mConnectivityListener, uid, policy); final int length = mListeners.beginBroadcast(); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); Loading Loading @@ -4049,6 +4033,74 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } } } } } /** * @return true if the given uid is restricted from doing networking on metered networks. */ @Override public boolean isUidRestrictedOnMeteredNetworks(int uid) { final int uidRules; final boolean isBackgroundRestricted; synchronized (mUidRulesFirstLock) { uidRules = mUidRules.get(uid, RULE_ALLOW_ALL); isBackgroundRestricted = mRestrictBackground; } return isBackgroundRestricted && !hasRule(uidRules, RULE_ALLOW_METERED) && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED); } /** * @return true if networking is blocked on the given interface for the given uid according * to current networking policies. */ @Override public boolean isUidNetworkingBlocked(int uid, String ifname) { final int uidRules; final boolean isBackgroundRestricted; final boolean isNetworkMetered; synchronized (mUidRulesFirstLock) { uidRules = mUidRules.get(uid, RULE_NONE); isBackgroundRestricted = mRestrictBackground; synchronized (mNetworkPoliciesSecondLock) { isNetworkMetered = mMeteredIfaces.contains(ifname); } } if (hasRule(uidRules, RULE_REJECT_ALL)) { if (LOGV) logUidStatus(uid, "blocked by power restrictions"); return true; } if (!isNetworkMetered) { if (LOGV) logUidStatus(uid, "allowed on unmetered network"); return false; } if (hasRule(uidRules, RULE_REJECT_METERED)) { if (LOGV) logUidStatus(uid, "blacklisted on metered network"); return true; } if (hasRule(uidRules, RULE_ALLOW_METERED)) { if (LOGV) logUidStatus(uid, "whitelisted on metered network"); return false; } if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) { if (LOGV) logUidStatus(uid, "temporary whitelisted on metered network"); return false; } if (isBackgroundRestricted) { if (LOGV) logUidStatus(uid, "blocked when background is restricted"); return true; } if (LOGV) logUidStatus(uid, "allowed by default"); return false; } } private static boolean hasRule(int uidRules, int rule) { return (uidRules & rule) != 0; } private static void logUidStatus(int uid, String descr) { Slog.d(TAG, String.format("uid %d is %s", uid, descr)); } } /** /** Loading
tests/net/java/com/android/server/ConnectivityServiceTest.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -80,6 +80,7 @@ import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkMonitor; import com.android.server.connectivity.NetworkMonitor; import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult; import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult; import com.android.server.net.NetworkPinner; import com.android.server.net.NetworkPinner; import com.android.server.net.NetworkPolicyManagerInternal; import java.net.InetAddress; import java.net.InetAddress; import java.util.ArrayList; import java.util.ArrayList; Loading Loading @@ -713,6 +714,9 @@ public class ConnectivityServiceTest extends AndroidTestCase { } } mServiceContext = new MockContext(getContext()); mServiceContext = new MockContext(getContext()); LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class); LocalServices.addService( NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class)); mService = new WrappedConnectivityService(mServiceContext, mService = new WrappedConnectivityService(mServiceContext, mock(INetworkManagementService.class), mock(INetworkManagementService.class), mock(INetworkStatsService.class), mock(INetworkStatsService.class), Loading