am 673eb677: am 15884007: Merge "464xlat: use a gatewayed route, not point-to-point"
* commit '673eb677a27b6d761bd358edfc46ed64eedbb167':
464xlat: use a gatewayed route, not point-to-point
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 697bde9..1dbe34e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -355,11 +355,17 @@
*/
public static final int TYPE_WIFI_P2P = 13;
- /** {@hide} */
- public static final int MAX_RADIO_TYPE = TYPE_WIFI_P2P;
+ /**
+ * The network to use for initially attaching to the network
+ * {@hide}
+ */
+ public static final int TYPE_MOBILE_IA = 14;
/** {@hide} */
- public static final int MAX_NETWORK_TYPE = TYPE_WIFI_P2P;
+ public static final int MAX_RADIO_TYPE = TYPE_MOBILE_IA;
+
+ /** {@hide} */
+ public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_IA;
/**
* If you want to set the default network preference,you can directly
@@ -436,6 +442,8 @@
return "MOBILE_CBS";
case TYPE_WIFI_P2P:
return "WIFI_P2P";
+ case TYPE_MOBILE_IA:
+ return "MOBILE_IA";
default:
return Integer.toString(type);
}
@@ -458,6 +466,39 @@
case TYPE_MOBILE_FOTA:
case TYPE_MOBILE_IMS:
case TYPE_MOBILE_CBS:
+ case TYPE_MOBILE_IA:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given network type is backed by a Wi-Fi radio.
+ *
+ * @hide
+ */
+ public static boolean isNetworkTypeWifi(int networkType) {
+ switch (networkType) {
+ case TYPE_WIFI:
+ case TYPE_WIFI_P2P:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given network type should be exempt from VPN routing rules
+ *
+ * @hide
+ */
+ public static boolean isNetworkTypeExempt(int networkType) {
+ switch (networkType) {
+ case TYPE_MOBILE_MMS:
+ case TYPE_MOBILE_SUPL:
+ case TYPE_MOBILE_HIPRI:
+ case TYPE_MOBILE_IA:
return true;
default:
return false;
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 4600c1a..b0f7fc6 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -37,6 +37,9 @@
/** {@hide} */
interface IConnectivityManager
{
+ // Keep this in sync with framework/native/services/connectivitymanager/ConnectivityManager.h
+ void markSocketAsUser(in ParcelFileDescriptor socket, int uid);
+
void setNetworkPreference(int pref);
int getNetworkPreference();
@@ -121,6 +124,8 @@
ParcelFileDescriptor establishVpn(in VpnConfig config);
+ VpnConfig getVpnConfig();
+
void startLegacyVpn(in VpnProfile profile);
LegacyVpnInfo getLegacyVpnInfo();
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 4ab479e..b24d396 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -21,6 +21,7 @@
import java.net.Inet6Address;
import java.net.UnknownHostException;
import java.util.Collection;
+import java.util.Locale;
import android.util.Log;
@@ -103,6 +104,11 @@
public native static String getDhcpError();
/**
+ * Set the SO_MARK of {@code socketfd} to {@code mark}
+ */
+ public native static void markSocket(int socketfd, int mark);
+
+ /**
* Convert a IPv4 address from an integer to an InetAddress.
* @param hostAddress an int corresponding to the IPv4 address in network byte order
*/
@@ -223,7 +229,7 @@
public static InetAddress hexToInet6Address(String addrHexString)
throws IllegalArgumentException {
try {
- return numericToInetAddress(String.format("%s:%s:%s:%s:%s:%s:%s:%s",
+ return numericToInetAddress(String.format(Locale.US, "%s:%s:%s:%s:%s:%s:%s:%s",
addrHexString.substring(0,4), addrHexString.substring(4,8),
addrHexString.substring(8,12), addrHexString.substring(12,16),
addrHexString.substring(16,20), addrHexString.substring(20,24),
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index faae11e..526159f 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "NetUtils"
#include "jni.h"
+#include "JNIHelp.h"
#include <utils/misc.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
@@ -239,6 +240,13 @@
return env->NewStringUTF(::dhcp_get_errmsg());
}
+static void android_net_utils_markSocket(JNIEnv *env, jobject thiz, jint socket, jint mark)
+{
+ if (setsockopt(socket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Error marking socket");
+ }
+}
+
// ----------------------------------------------------------------------------
/*
@@ -255,6 +263,7 @@
{ "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp },
{ "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease },
{ "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
+ { "markSocket", "(II)V", (void*) android_net_utils_markSocket },
};
int register_android_net_NetworkUtils(JNIEnv* env)
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index cb4e89c..9615ff5 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -97,6 +97,7 @@
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.Xml;
@@ -110,6 +111,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
import com.android.server.am.BatteryStatsService;
+import com.android.server.connectivity.DataConnectionStats;
import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
@@ -118,6 +120,8 @@
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
+import com.android.internal.annotations.GuardedBy;
+
import dalvik.system.DexClassLoader;
import org.xmlpull.v1.XmlPullParser;
@@ -178,7 +182,8 @@
private KeyStore mKeyStore;
- private Vpn mVpn;
+ @GuardedBy("mVpns")
+ private final SparseArray<Vpn> mVpns = new SparseArray<Vpn>();
private VpnCallback mVpnCallback = new VpnCallback();
private boolean mLockdownEnabled;
@@ -230,7 +235,6 @@
private Object mDnsLock = new Object();
private int mNumDnsEntries;
- private boolean mDnsOverridden = false;
private boolean mTestMode;
private static ConnectivityService sServiceInstance;
@@ -247,6 +251,9 @@
private static final boolean TO_DEFAULT_TABLE = true;
private static final boolean TO_SECONDARY_TABLE = false;
+ private static final boolean EXEMPT = true;
+ private static final boolean UNEXEMPT = false;
+
/**
* used internally as a delayed event to make us switch back to the
* default network
@@ -302,28 +309,22 @@
private static final int EVENT_SET_DEPENDENCY_MET = 10;
/**
- * used internally to restore DNS properties back to the
- * default network
- */
- private static final int EVENT_RESTORE_DNS = 11;
-
- /**
* used internally to send a sticky broadcast delayed.
*/
- private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 12;
+ private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 11;
/**
* Used internally to
* {@link NetworkStateTracker#setPolicyDataEnable(boolean)}.
*/
- private static final int EVENT_SET_POLICY_DATA_ENABLE = 13;
+ private static final int EVENT_SET_POLICY_DATA_ENABLE = 12;
- private static final int EVENT_VPN_STATE_CHANGED = 14;
+ private static final int EVENT_VPN_STATE_CHANGED = 13;
/**
* Used internally to disable fail fast of mobile data
*/
- private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 15;
+ private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14;
/** Handler used for internal events. */
private InternalHandler mHandler;
@@ -344,10 +345,19 @@
private InetAddress mDefaultDns;
+ // Lock for protecting access to mAddedRoutes and mExemptAddresses
+ private final Object mRoutesLock = new Object();
+
// this collection is used to refcount the added routes - if there are none left
// it's time to remove the route from the route table
+ @GuardedBy("mRoutesLock")
private Collection<RouteInfo> mAddedRoutes = new ArrayList<RouteInfo>();
+ // this collection corresponds to the entries of mAddedRoutes that have routing exemptions
+ // used to handle cleanup of exempt rules
+ @GuardedBy("mRoutesLock")
+ private Collection<LinkAddress> mExemptAddresses = new ArrayList<LinkAddress>();
+
// used in DBG mode to track inet condition reports
private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
private ArrayList mInetLog;
@@ -379,6 +389,7 @@
// the set of network types that can only be enabled by system/sig apps
List mProtectedNetworks;
+ private DataConnectionStats mDataConnectionStats;
private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0);
TelephonyManager mTelephonyManager;
@@ -461,6 +472,7 @@
com.android.internal.R.array.radioAttributes);
for (String raString : raStrings) {
RadioAttributes r = new RadioAttributes(raString);
+ if (VDBG) log("raString=" + raString + " r=" + r);
if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
loge("Error in radioAttributes - ignoring attempt to define type " + r.mType);
continue;
@@ -481,6 +493,7 @@
for (String naString : naStrings) {
try {
NetworkConfig n = new NetworkConfig(naString);
+ if (VDBG) log("naString=" + naString + " config=" + n);
if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
loge("Error in networkAttributes - ignoring attempt to define type " +
n.type);
@@ -507,6 +520,7 @@
// ignore it - leave the entry null
}
}
+ if (VDBG) log("mNetworksDefined=" + mNetworksDefined);
mProtectedNetworks = new ArrayList<Integer>();
int[] protectedNetworks = context.getResources().getIntArray(
@@ -589,9 +603,12 @@
mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper());
- mVpn = new Vpn(mContext, mVpnCallback, mNetd, this);
- mVpn.startMonitoring(mContext, mTrackerHandler);
-
+ //set up the listener for user state for creating user VPNs
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_USER_STARTING);
+ intentFilter.addAction(Intent.ACTION_USER_STOPPING);
+ mContext.registerReceiverAsUser(
+ mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
mClat = new Nat464Xlat(mContext, mNetd, this, mTrackerHandler);
try {
@@ -611,6 +628,9 @@
mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this);
loadGlobalProxy();
+
+ mDataConnectionStats = new DataConnectionStats(mContext);
+ mDataConnectionStats.startMonitoring();
}
/**
@@ -1458,7 +1478,7 @@
try {
InetAddress addr = InetAddress.getByAddress(hostAddress);
LinkProperties lp = tracker.getLinkProperties();
- boolean ok = addRouteToAddress(lp, addr);
+ boolean ok = addRouteToAddress(lp, addr, EXEMPT);
if (DBG) log("requestRouteToHostAddress ok=" + ok);
return ok;
} catch (UnknownHostException e) {
@@ -1470,24 +1490,25 @@
return false;
}
- private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
- return modifyRoute(p, r, 0, ADD, toDefaultTable);
+ private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable,
+ boolean exempt) {
+ return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt);
}
private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
- return modifyRoute(p, r, 0, REMOVE, toDefaultTable);
+ return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT);
}
- private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) {
- return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE);
+ private boolean addRouteToAddress(LinkProperties lp, InetAddress addr, boolean exempt) {
+ return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt);
}
private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) {
- return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE);
+ return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE, UNEXEMPT);
}
private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd,
- boolean toDefaultTable) {
+ boolean toDefaultTable, boolean exempt) {
RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr);
if (bestRoute == null) {
bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName());
@@ -1502,11 +1523,11 @@
bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface);
}
}
- return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable);
+ return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt);
}
private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd,
- boolean toDefaultTable) {
+ boolean toDefaultTable, boolean exempt) {
if ((lp == null) || (r == null)) {
if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r);
return false;
@@ -1535,15 +1556,25 @@
bestRoute.getGateway(),
ifaceName);
}
- modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable);
+ modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt);
}
}
if (doAdd) {
if (VDBG) log("Adding " + r + " for interface " + ifaceName);
try {
if (toDefaultTable) {
- mAddedRoutes.add(r); // only track default table - only one apps can effect
- mNetd.addRoute(ifaceName, r);
+ synchronized (mRoutesLock) {
+ // only track default table - only one apps can effect
+ mAddedRoutes.add(r);
+ mNetd.addRoute(ifaceName, r);
+ if (exempt) {
+ LinkAddress dest = r.getDestination();
+ if (!mExemptAddresses.contains(dest)) {
+ mNetd.setHostExemption(dest);
+ mExemptAddresses.add(dest);
+ }
+ }
+ }
} else {
mNetd.addSecondaryRoute(ifaceName, r);
}
@@ -1556,18 +1587,25 @@
// if we remove this one and there are no more like it, then refcount==0 and
// we can remove it from the table
if (toDefaultTable) {
- mAddedRoutes.remove(r);
- if (mAddedRoutes.contains(r) == false) {
- if (VDBG) log("Removing " + r + " for interface " + ifaceName);
- try {
- mNetd.removeRoute(ifaceName, r);
- } catch (Exception e) {
- // never crash - catch them all
- if (VDBG) loge("Exception trying to remove a route: " + e);
- return false;
+ synchronized (mRoutesLock) {
+ mAddedRoutes.remove(r);
+ if (mAddedRoutes.contains(r) == false) {
+ if (VDBG) log("Removing " + r + " for interface " + ifaceName);
+ try {
+ mNetd.removeRoute(ifaceName, r);
+ LinkAddress dest = r.getDestination();
+ if (mExemptAddresses.contains(dest)) {
+ mNetd.clearHostExemption(dest);
+ mExemptAddresses.remove(dest);
+ }
+ } catch (Exception e) {
+ // never crash - catch them all
+ if (VDBG) loge("Exception trying to remove a route: " + e);
+ return false;
+ }
+ } else {
+ if (VDBG) log("not removing " + r + " as it's still in use");
}
- } else {
- if (VDBG) log("not removing " + r + " as it's still in use");
}
} else {
if (VDBG) log("Removing " + r + " for interface " + ifaceName);
@@ -1744,6 +1782,16 @@
"ConnectivityService");
}
+ private void enforceMarkNetworkSocketPermission() {
+ //Media server special case
+ if (Binder.getCallingUid() == Process.MEDIA_UID) {
+ return;
+ }
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MARK_NETWORK_SOCKET,
+ "ConnectivityService");
+ }
+
/**
* Handle a {@code DISCONNECTED} event. If this pertains to the non-active
* network, we ignore it. If it is for the active network, we send out a
@@ -2238,6 +2286,7 @@
*/
private void handleConnectivityChange(int netType, boolean doReset) {
int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
+ boolean exempt = ConnectivityManager.isNetworkTypeExempt(netType);
/*
* If a non-default network is enabled, add the host routes that
@@ -2302,7 +2351,7 @@
}
}
mCurrentLinkProperties[netType] = newLp;
- boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault());
+ boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt);
if (resetMask != 0 || resetDns) {
if (curLp != null) {
@@ -2315,7 +2364,11 @@
// Tell VPN the interface is down. It is a temporary
// but effective fix to make VPN aware of the change.
if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) {
- mVpn.interfaceStatusChanged(iface, false);
+ synchronized(mVpns) {
+ for (int i = 0; i < mVpns.size(); i++) {
+ mVpns.valueAt(i).interfaceStatusChanged(iface, false);
+ }
+ }
}
}
if (resetDns) {
@@ -2374,7 +2427,7 @@
* returns a boolean indicating the routes changed
*/
private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp,
- boolean isLinkDefault) {
+ boolean isLinkDefault, boolean exempt) {
Collection<RouteInfo> routesToAdd = null;
CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
@@ -2410,7 +2463,7 @@
}
if (newLp != null) {
for (InetAddress newDns : newLp.getDnses()) {
- addRouteToAddress(newLp, newDns);
+ addRouteToAddress(newLp, newDns, exempt);
}
}
} else {
@@ -2419,28 +2472,30 @@
removeRouteToAddress(curLp, oldDns);
}
for (InetAddress newDns : dnsDiff.added) {
- addRouteToAddress(newLp, newDns);
+ addRouteToAddress(newLp, newDns, exempt);
}
}
}
for (RouteInfo r : routeDiff.added) {
if (isLinkDefault || ! r.isDefaultRoute()) {
- addRoute(newLp, r, TO_DEFAULT_TABLE);
+ addRoute(newLp, r, TO_DEFAULT_TABLE, exempt);
} else {
// add to a secondary route table
- addRoute(newLp, r, TO_SECONDARY_TABLE);
+ addRoute(newLp, r, TO_SECONDARY_TABLE, UNEXEMPT);
// many radios add a default route even when we don't want one.
// remove the default route unless somebody else has asked for it
String ifaceName = newLp.getInterfaceName();
- if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) {
- if (VDBG) log("Removing " + r + " for interface " + ifaceName);
- try {
- mNetd.removeRoute(ifaceName, r);
- } catch (Exception e) {
- // never crash - catch them all
- if (DBG) loge("Exception trying to remove a route: " + e);
+ synchronized (mRoutesLock) {
+ if (!TextUtils.isEmpty(ifaceName) && !mAddedRoutes.contains(r)) {
+ if (VDBG) log("Removing " + r + " for interface " + ifaceName);
+ try {
+ mNetd.removeRoute(ifaceName, r);
+ } catch (Exception e) {
+ // never crash - catch them all
+ if (DBG) loge("Exception trying to remove a route: " + e);
+ }
}
}
}
@@ -2560,7 +2615,7 @@
// Caller must grab mDnsLock.
private void updateDnsLocked(String network, String iface,
- Collection<InetAddress> dnses, String domains) {
+ Collection<InetAddress> dnses, String domains, boolean defaultDns) {
int last = 0;
if (dnses.size() == 0 && mDefaultDns != null) {
dnses = new ArrayList();
@@ -2572,7 +2627,10 @@
try {
mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains);
- mNetd.setDefaultInterfaceForDns(iface);
+ if (defaultDns) {
+ mNetd.setDefaultInterfaceForDns(iface);
+ }
+
for (InetAddress dns : dnses) {
++last;
String key = "net.dns" + last;
@@ -2599,9 +2657,7 @@
if (mNetConfigs[netType].isDefault()) {
String network = nt.getNetworkInfo().getTypeName();
synchronized (mDnsLock) {
- if (!mDnsOverridden) {
- updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains());
- }
+ updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains(), true);
}
} else {
try {
@@ -2854,13 +2910,6 @@
handleSetDependencyMet(msg.arg2, met);
break;
}
- case EVENT_RESTORE_DNS:
- {
- if (mActiveDefaultNetwork != -1) {
- handleDnsConfigurationChange(mActiveDefaultNetwork);
- }
- break;
- }
case EVENT_SEND_STICKY_BROADCAST_INTENT:
{
Intent intent = (Intent)msg.obj;
@@ -3205,6 +3254,10 @@
Settings.Global.HTTP_PROXY);
if (!TextUtils.isEmpty(proxy)) {
String data[] = proxy.split(":");
+ if (data.length == 0) {
+ return;
+ }
+
String proxyHost = data[0];
int proxyPort = 8080;
if (data.length > 1) {
@@ -3216,6 +3269,8 @@
}
ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
setGlobalProxy(p);
+ } else {
+ setGlobalProxy(null);
}
}
@@ -3315,8 +3370,12 @@
throwIfLockdownEnabled();
try {
int type = mActiveDefaultNetwork;
+ int user = UserHandle.getUserId(Binder.getCallingUid());
if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) {
- mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName());
+ synchronized(mVpns) {
+ mVpns.get(user).protect(socket,
+ mNetTrackers[type].getLinkProperties().getInterfaceName());
+ }
return true;
}
} catch (Exception e) {
@@ -3340,7 +3399,27 @@
@Override
public boolean prepareVpn(String oldPackage, String newPackage) {
throwIfLockdownEnabled();
- return mVpn.prepare(oldPackage, newPackage);
+ int user = UserHandle.getUserId(Binder.getCallingUid());
+ synchronized(mVpns) {
+ return mVpns.get(user).prepare(oldPackage, newPackage);
+ }
+ }
+
+ @Override
+ public void markSocketAsUser(ParcelFileDescriptor socket, int uid) {
+ enforceMarkNetworkSocketPermission();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ int mark = mNetd.getMarkForUid(uid);
+ // Clear the mark on the socket if no mark is needed to prevent socket reuse issues
+ if (mark == -1) {
+ mark = 0;
+ }
+ NetworkUtils.markSocket(socket.getFd(), mark);
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
/**
@@ -3353,7 +3432,10 @@
@Override
public ParcelFileDescriptor establishVpn(VpnConfig config) {
throwIfLockdownEnabled();
- return mVpn.establish(config);
+ int user = UserHandle.getUserId(Binder.getCallingUid());
+ synchronized(mVpns) {
+ return mVpns.get(user).establish(config);
+ }
}
/**
@@ -3367,7 +3449,10 @@
if (egress == null) {
throw new IllegalStateException("Missing active network connection");
}
- mVpn.startLegacyVpn(profile, mKeyStore, egress);
+ int user = UserHandle.getUserId(Binder.getCallingUid());
+ synchronized(mVpns) {
+ mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress);
+ }
}
/**
@@ -3379,7 +3464,24 @@
@Override
public LegacyVpnInfo getLegacyVpnInfo() {
throwIfLockdownEnabled();
- return mVpn.getLegacyVpnInfo();
+ int user = UserHandle.getUserId(Binder.getCallingUid());
+ synchronized(mVpns) {
+ return mVpns.get(user).getLegacyVpnInfo();
+ }
+ }
+
+ /**
+ * Returns the information of the ongoing VPN. This method is used by VpnDialogs and
+ * not available in ConnectivityManager.
+ * Permissions are checked in Vpn class.
+ * @hide
+ */
+ @Override
+ public VpnConfig getVpnConfig() {
+ int user = UserHandle.getUserId(Binder.getCallingUid());
+ synchronized(mVpns) {
+ return mVpns.get(user).getVpnConfig();
+ }
}
/**
@@ -3400,7 +3502,7 @@
mHandler.obtainMessage(EVENT_VPN_STATE_CHANGED, info).sendToTarget();
}
- public void override(List<String> dnsServers, List<String> searchDomains) {
+ public void override(String iface, List<String> dnsServers, List<String> searchDomains) {
if (dnsServers == null) {
restore();
return;
@@ -3432,8 +3534,7 @@
// Apply DNS changes.
synchronized (mDnsLock) {
- updateDnsLocked("VPN", "VPN", addresses, domains);
- mDnsOverridden = true;
+ updateDnsLocked("VPN", iface, addresses, domains, false);
}
// Temporarily disable the default proxy (not global).
@@ -3448,12 +3549,6 @@
}
public void restore() {
- synchronized (mDnsLock) {
- if (mDnsOverridden) {
- mDnsOverridden = false;
- mHandler.sendEmptyMessage(EVENT_RESTORE_DNS);
- }
- }
synchronized (mProxyLock) {
mDefaultProxyDisabled = false;
if (mGlobalProxy == null && mDefaultProxy != null) {
@@ -3461,6 +3556,67 @@
}
}
}
+
+ public void protect(ParcelFileDescriptor socket) {
+ try {
+ final int mark = mNetd.getMarkForProtect();
+ NetworkUtils.markSocket(socket.getFd(), mark);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public void setRoutes(String interfaze, List<RouteInfo> routes) {
+ for (RouteInfo route : routes) {
+ try {
+ mNetd.setMarkedForwardingRoute(interfaze, route);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ public void setMarkedForwarding(String interfaze) {
+ try {
+ mNetd.setMarkedForwarding(interfaze);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public void clearMarkedForwarding(String interfaze) {
+ try {
+ mNetd.clearMarkedForwarding(interfaze);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public void addUserForwarding(String interfaze, int uid) {
+ int uidStart = uid * UserHandle.PER_USER_RANGE;
+ int uidEnd = uidStart + UserHandle.PER_USER_RANGE - 1;
+ addUidForwarding(interfaze, uidStart, uidEnd);
+ }
+
+ public void clearUserForwarding(String interfaze, int uid) {
+ int uidStart = uid * UserHandle.PER_USER_RANGE;
+ int uidEnd = uidStart + UserHandle.PER_USER_RANGE - 1;
+ clearUidForwarding(interfaze, uidStart, uidEnd);
+ }
+
+ public void addUidForwarding(String interfaze, int uidStart, int uidEnd) {
+ try {
+ mNetd.setUidRangeRoute(interfaze,uidStart, uidEnd);
+ mNetd.setDnsInterfaceForUidRange(interfaze, uidStart, uidEnd);
+ } catch (RemoteException e) {
+ }
+
+ }
+
+ public void clearUidForwarding(String interfaze, int uidStart, int uidEnd) {
+ try {
+ mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd);
+ mNetd.clearDnsInterfaceForUidRange(uidStart, uidEnd);
+ } catch (RemoteException e) {
+ }
+
+ }
}
@Override
@@ -3481,7 +3637,11 @@
final String profileName = new String(mKeyStore.get(Credentials.LOCKDOWN_VPN));
final VpnProfile profile = VpnProfile.decode(
profileName, mKeyStore.get(Credentials.VPN + profileName));
- setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpn, profile));
+ int user = UserHandle.getUserId(Binder.getCallingUid());
+ synchronized(mVpns) {
+ setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpns.get(user),
+ profile));
+ }
} else {
setLockdownTracker(null);
}
@@ -3562,7 +3722,7 @@
}
@Override
- public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs,
+ public int checkMobileProvisioning(final boolean sendNotification, int suggestedTimeOutMs,
final ResultReceiver resultReceiver) {
log("checkMobileProvisioning: E sendNotification=" + sendNotification
+ " suggestedTimeOutMs=" + suggestedTimeOutMs
@@ -3597,6 +3757,10 @@
log("CheckMp.onComplete: send result");
resultReceiver.send(result, null);
}
+ if (!sendNotification) {
+ log("CheckMp.onComplete: done, not sending notification");
+ return;
+ }
NetworkInfo ni =
mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo();
switch(result) {
@@ -4117,4 +4281,43 @@
return url;
}
+
+ private void onUserStart(int userId) {
+ synchronized(mVpns) {
+ Vpn userVpn = mVpns.get(userId);
+ if (userVpn != null) {
+ loge("Starting user already has a VPN");
+ return;
+ }
+ userVpn = new Vpn(mContext, mVpnCallback, mNetd, this, userId);
+ mVpns.put(userId, userVpn);
+ userVpn.startMonitoring(mContext, mTrackerHandler);
+ }
+ }
+
+ private void onUserStop(int userId) {
+ synchronized(mVpns) {
+ Vpn userVpn = mVpns.get(userId);
+ if (userVpn == null) {
+ loge("Stopping user has no VPN");
+ return;
+ }
+ mVpns.delete(userId);
+ }
+ }
+
+ private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId == UserHandle.USER_NULL) return;
+
+ if (Intent.ACTION_USER_STARTING.equals(action)) {
+ onUserStart(userId);
+ } else if (Intent.ACTION_USER_STOPPING.equals(action)) {
+ onUserStop(userId);
+ }
+ }
+ };
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index cdc4d78..aca77b8 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -878,8 +878,7 @@
mAlarmManager.remove(isA(PendingIntent.class));
expectLastCall().anyTimes();
- mAlarmManager.setInexactRepeating(
- eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), isA(PendingIntent.class));
+ mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(), isA(PendingIntent.class));
expectLastCall().atLeastOnce();
mNetManager.setGlobalAlert(anyLong());