diff options
Diffstat (limited to 'services/java/com/android/server/ConnectivityService.java')
| -rw-r--r-- | services/java/com/android/server/ConnectivityService.java | 207 |
1 files changed, 151 insertions, 56 deletions
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 55ce80b..dd76eb8 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -16,6 +16,11 @@ package com.android.server; +import static android.Manifest.permission.UPDATE_DEVICE_STATS; +import static android.net.ConnectivityManager.isNetworkTypeValid; +import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; +import static android.net.NetworkPolicyManager.RULE_REJECT_PAID; + import android.bluetooth.BluetoothTetheringDataTracker; import android.content.ContentResolver; import android.content.Context; @@ -26,11 +31,13 @@ import android.net.ConnectivityManager; import android.net.DummyDataStateTracker; import android.net.EthernetDataTracker; import android.net.IConnectivityManager; -import android.net.LinkAddress; +import android.net.INetworkPolicyListener; +import android.net.INetworkPolicyManager; import android.net.LinkProperties; import android.net.MobileDataStateTracker; import android.net.NetworkConfig; import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; import android.net.NetworkStateTracker; import android.net.NetworkUtils; import android.net.Proxy; @@ -39,6 +46,7 @@ import android.net.RouteInfo; import android.net.vpn.VpnManager; import android.net.wifi.WifiStateTracker; import android.os.Binder; +import android.os.FileUtils; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -53,22 +61,21 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.EventLog; import android.util.Slog; +import android.util.SparseIntArray; import com.android.internal.telephony.Phone; import com.android.server.connectivity.Tethering; import java.io.FileDescriptor; -import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.net.InetAddress; -import java.net.Inet4Address; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.GregorianCalendar; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; /** * @hide @@ -78,6 +85,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final boolean DBG = true; private static final String TAG = "ConnectivityService"; + private static final boolean LOGD_RULES = false; + // how long to wait before switching back to a radio's default network private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000; // system property that can override the above value @@ -91,6 +100,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { private Tethering mTethering; private boolean mTetheringConfigValid = false; + /** Currently active network rules by UID. */ + private SparseIntArray mUidRules = new SparseIntArray(); + /** * Sometimes we want to refer to the individual network state * trackers separately, and sometimes we just want to treat them @@ -128,6 +140,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private AtomicBoolean mBackgroundDataEnabled = new AtomicBoolean(true); private INetworkManagementService mNetd; + private INetworkPolicyManager mPolicyManager; private static final int ENABLED = 1; private static final int DISABLED = 0; @@ -250,14 +263,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } RadioAttributes[] mRadioAttributes; - public static synchronized ConnectivityService getInstance(Context context) { - if (sServiceInstance == null) { - sServiceInstance = new ConnectivityService(context); - } - return sServiceInstance; - } - - private ConnectivityService(Context context) { + public ConnectivityService( + Context context, INetworkManagementService netd, INetworkPolicyManager policyManager) { if (DBG) log("ConnectivityService starting up"); HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread"); @@ -290,9 +297,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { loge("Error setting defaultDns using " + dns); } - mContext = context; + mContext = checkNotNull(context, "missing Context"); + mNetd = checkNotNull(netd, "missing INetworkManagementService"); + mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager"); - PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); + try { + mPolicyManager.registerListener(mPolicyListener); + } catch (RemoteException e) { + // ouch, no rules updates means some processes may never get network + Slog.e(TAG, "unable to register INetworkPolicyListener", e); + } + + final PowerManager powerManager = (PowerManager) context.getSystemService( + Context.POWER_SERVICE); mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mNetTransitionWakeLockTimeout = mContext.getResources().getInteger( com.android.internal.R.integer.config_networkTransitionTimeout); @@ -430,7 +447,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - mTethering = new Tethering(mContext, mHandler.getLooper()); + IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b); + + mTethering = new Tethering(mContext, nmService, mHandler.getLooper()); mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) || !mTethering.isDunRequired()) && (mTethering.getTetherableUsbRegexs().length != 0 || @@ -533,32 +553,92 @@ public class ConnectivityService extends IConnectivityManager.Stub { } /** + * Check if UID is blocked from using the given {@link NetworkInfo}. + */ + private boolean isNetworkBlocked(NetworkInfo info, int uid) { + synchronized (mUidRules) { + return isNetworkBlockedLocked(info, uid); + } + } + + /** + * Check if UID is blocked from using the given {@link NetworkInfo}. + */ + private boolean isNetworkBlockedLocked(NetworkInfo info, int uid) { + // 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); + + if (networkIsPaid && (uidRules & RULE_REJECT_PAID) != 0) { + return true; + } + + // no restrictive rules; network is visible + return false; + } + + /** * Return NetworkInfo for the active (i.e., connected) network interface. * It is assumed that at most one network is active at a time. If more * than one is active, it is indeterminate which will be returned. * @return the info for the active network, or {@code null} if none is * active */ + @Override public NetworkInfo getActiveNetworkInfo() { - return getNetworkInfo(mActiveDefaultNetwork); + enforceAccessPermission(); + final int uid = Binder.getCallingUid(); + return getNetworkInfo(mActiveDefaultNetwork, uid); + } + + @Override + public NetworkInfo getActiveNetworkInfoForUid(int uid) { + enforceConnectivityInternalPermission(); + return getNetworkInfo(mActiveDefaultNetwork, uid); } + @Override public NetworkInfo getNetworkInfo(int networkType) { enforceAccessPermission(); - if (ConnectivityManager.isNetworkTypeValid(networkType)) { - NetworkStateTracker t = mNetTrackers[networkType]; - if (t != null) - return t.getNetworkInfo(); + final int uid = Binder.getCallingUid(); + return getNetworkInfo(networkType, uid); + } + + private NetworkInfo getNetworkInfo(int networkType, int uid) { + NetworkInfo info = null; + if (isNetworkTypeValid(networkType)) { + final NetworkStateTracker tracker = mNetTrackers[networkType]; + if (tracker != null) { + info = tracker.getNetworkInfo(); + if (isNetworkBlocked(info, uid)) { + // network is blocked; clone and override state + info = new NetworkInfo(info); + info.setDetailedState(DetailedState.BLOCKED, null, null); + } + } } - return null; + return info; } + @Override public NetworkInfo[] getAllNetworkInfo() { enforceAccessPermission(); - NetworkInfo[] result = new NetworkInfo[mNetworksDefined]; + final int uid = Binder.getCallingUid(); + final NetworkInfo[] result = new NetworkInfo[mNetworksDefined]; int i = 0; - for (NetworkStateTracker t : mNetTrackers) { - if(t != null) result[i++] = t.getNetworkInfo(); + synchronized (mUidRules) { + for (NetworkStateTracker tracker : mNetTrackers) { + if (tracker != null) { + NetworkInfo info = tracker.getNetworkInfo(); + if (isNetworkBlockedLocked(info, uid)) { + // network is blocked; clone and override state + info = new NetworkInfo(info); + info.setDetailedState(DetailedState.BLOCKED, null, null); + } + result[i++] = info; + } + } } return result; } @@ -571,15 +651,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { * @return the ip properties for the active network, or {@code null} if * none is active */ + @Override public LinkProperties getActiveLinkProperties() { return getLinkProperties(mActiveDefaultNetwork); } + @Override public LinkProperties getLinkProperties(int networkType) { enforceAccessPermission(); - if (ConnectivityManager.isNetworkTypeValid(networkType)) { - NetworkStateTracker t = mNetTrackers[networkType]; - if (t != null) return t.getLinkProperties(); + if (isNetworkTypeValid(networkType)) { + final NetworkStateTracker tracker = mNetTrackers[networkType]; + if (tracker != null) { + return tracker.getLinkProperties(); + } } return null; } @@ -1024,6 +1108,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { + @Override + public void onRulesChanged(int uid, int uidRules) { + // only someone like NPMS should only be calling us + // TODO: create permission for modifying data policy + mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); + + if (LOGD_RULES) { + Slog.d(TAG, "onRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")"); + } + + synchronized (mUidRules) { + // skip update when we've already applied rules + final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL); + if (oldRules == uidRules) return; + + mUidRules.put(uid, uidRules); + } + + // TODO: dispatch into NMS to push rules towards kernel module + // TODO: notify UID when it has requested targeted updates + } + }; + /** * @see ConnectivityManager#setMobileDataEnabled(boolean) */ @@ -1281,9 +1389,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } void systemReady() { - IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - mNetd = INetworkManagementService.Stub.asInterface(b); - synchronized(this) { mSystemReady = true; if (mInitialBroadcast != null) { @@ -1378,13 +1483,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { addDefaultRoute(mNetTrackers[netType]); } else { // many radios add a default route even when we don't want one. - // remove the default interface unless we need it for our active network + // remove the default route unless we need it for our active network if (mActiveDefaultNetwork != -1) { - LinkProperties linkProperties = + LinkProperties defaultLinkProperties = mNetTrackers[mActiveDefaultNetwork].getLinkProperties(); LinkProperties newLinkProperties = mNetTrackers[netType].getLinkProperties(); - String defaultIface = linkProperties.getInterfaceName(); + String defaultIface = defaultLinkProperties.getInterfaceName(); if (defaultIface != null && !defaultIface.equals(newLinkProperties.getInterfaceName())) { removeDefaultRoute(mNetTrackers[netType]); @@ -1549,12 +1654,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (values.length == 6) { final String prefix = "/sys/kernel/ipv4/tcp_"; - stringToFile(prefix + "rmem_min", values[0]); - stringToFile(prefix + "rmem_def", values[1]); - stringToFile(prefix + "rmem_max", values[2]); - stringToFile(prefix + "wmem_min", values[3]); - stringToFile(prefix + "wmem_def", values[4]); - stringToFile(prefix + "wmem_max", values[5]); + FileUtils.stringToFile(prefix + "rmem_min", values[0]); + FileUtils.stringToFile(prefix + "rmem_def", values[1]); + FileUtils.stringToFile(prefix + "rmem_max", values[2]); + FileUtils.stringToFile(prefix + "wmem_min", values[3]); + FileUtils.stringToFile(prefix + "wmem_def", values[4]); + FileUtils.stringToFile(prefix + "wmem_max", values[5]); } else { loge("Invalid buffersize string: " + bufferSizes); } @@ -1563,23 +1668,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - /** - * Writes string to file. Basically same as "echo -n $string > $filename" - * - * @param filename - * @param string - * @throws IOException - */ - private void stringToFile(String filename, String string) throws IOException { - FileWriter out = new FileWriter(filename); - try { - out.write(string); - } finally { - out.close(); - } - } - - /** * Adjust the per-process dns entries (net.dns<x>.<pid>) based * on the highest priority active net which this process requested. @@ -2269,4 +2357,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { } return networkType; } + + private static <T> T checkNotNull(T value, String message) { + if (value == null) { + throw new NullPointerException(message); + } + return value; + } } |
