Merge "Query HTTP proxy for network via a new API to avoid permissions exceptions" into mnc-dev
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 1c67f31..e175e9a 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -496,6 +496,8 @@
* Tests if a given integer represents a valid network type.
* @param networkType the type to be tested
* @return a boolean. {@code true} if the type is valid, else {@code false}
+ * @deprecated All APIs accepting a network type are deprecated. There should be no need to
+ * validate a network type.
*/
public static boolean isNetworkTypeValid(int networkType) {
return networkType >= 0 && networkType <= MAX_NETWORK_TYPE;
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 397e47b..89d23a2 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -106,13 +106,13 @@
ProxyInfo getProxyForNetwork(in Network nework);
- boolean prepareVpn(String oldPackage, String newPackage);
+ boolean prepareVpn(String oldPackage, String newPackage, int userId);
- void setVpnPackageAuthorization(boolean authorized);
+ void setVpnPackageAuthorization(String packageName, int userId, boolean authorized);
ParcelFileDescriptor establishVpn(in VpnConfig config);
- VpnConfig getVpnConfig();
+ VpnConfig getVpnConfig(int userId);
void startLegacyVpn(in VpnProfile profile);
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index ab70485..cf747cf 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -619,6 +619,7 @@
case NET_CAPABILITY_NOT_RESTRICTED: capabilities += "NOT_RESTRICTED"; break;
case NET_CAPABILITY_TRUSTED: capabilities += "TRUSTED"; break;
case NET_CAPABILITY_NOT_VPN: capabilities += "NOT_VPN"; break;
+ case NET_CAPABILITY_VALIDATED: capabilities += "VALIDATED"; break;
}
if (++i < types.length) capabilities += "&";
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index eceac51..7ac2655 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -23,6 +23,10 @@
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeValid;
+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_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
@@ -190,7 +194,7 @@
/** Set of ifaces that are costly. */
private HashSet<String> mMeteredIfaces = Sets.newHashSet();
- private Context mContext;
+ final private Context mContext;
private int mNetworkPreference;
// 0 is full bad, 100 is full good
private int mDefaultInetConditionPublished = 0;
@@ -344,6 +348,11 @@
*/
private static final int EVENT_PROMPT_UNVALIDATED = 29;
+ /**
+ * used internally to (re)configure mobile data always-on settings.
+ */
+ private static final int EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON = 30;
+
/** Handler used for internal events. */
final private InternalHandler mHandler;
/** Handler used for incoming {@link NetworkStateTracker} events. */
@@ -374,7 +383,7 @@
private PacManager mPacManager = null;
- private SettingsObserver mSettingsObserver;
+ final private SettingsObserver mSettingsObserver;
private UserManager mUserManager;
@@ -458,11 +467,12 @@
}
}
- private void maybeLogBroadcast(NetworkAgentInfo nai, boolean connected, int type) {
+ private void maybeLogBroadcast(NetworkAgentInfo nai, boolean connected, int type,
+ boolean isDefaultNetwork) {
if (DBG) {
log("Sending " + (connected ? "connected" : "disconnected") +
" broadcast for type " + type + " " + nai.name() +
- " isDefaultNetwork=" + isDefaultNetwork(nai));
+ " isDefaultNetwork=" + isDefaultNetwork);
}
}
@@ -482,43 +492,45 @@
list.add(nai);
// Send a broadcast if this is the first network of its type or if it's the default.
- if (list.size() == 1 || isDefaultNetwork(nai)) {
- maybeLogBroadcast(nai, true, type);
+ final boolean isDefaultNetwork = isDefaultNetwork(nai);
+ if (list.size() == 1 || isDefaultNetwork) {
+ maybeLogBroadcast(nai, true, type, isDefaultNetwork);
sendLegacyNetworkBroadcast(nai, true, type);
}
}
/** Removes the given network from the specified legacy type list. */
- public void remove(int type, NetworkAgentInfo nai) {
+ public void remove(int type, NetworkAgentInfo nai, boolean wasDefault) {
ArrayList<NetworkAgentInfo> list = mTypeLists[type];
if (list == null || list.isEmpty()) {
return;
}
- boolean wasFirstNetwork = list.get(0).equals(nai);
+ final boolean wasFirstNetwork = list.get(0).equals(nai);
if (!list.remove(nai)) {
return;
}
- if (wasFirstNetwork || isDefaultNetwork(nai)) {
- maybeLogBroadcast(nai, false, type);
+ if (wasFirstNetwork || wasDefault) {
+ maybeLogBroadcast(nai, false, type, wasDefault);
sendLegacyNetworkBroadcast(nai, false, type);
}
if (!list.isEmpty() && wasFirstNetwork) {
if (DBG) log("Other network available for type " + type +
", sending connected broadcast");
- maybeLogBroadcast(list.get(0), false, type);
- sendLegacyNetworkBroadcast(list.get(0), false, type);
+ final NetworkAgentInfo replacement = list.get(0);
+ maybeLogBroadcast(replacement, false, type, isDefaultNetwork(replacement));
+ sendLegacyNetworkBroadcast(replacement, false, type);
}
}
/** Removes the given network from all legacy type lists. */
- public void remove(NetworkAgentInfo nai) {
- if (VDBG) log("Removing agent " + nai);
+ public void remove(NetworkAgentInfo nai, boolean wasDefault) {
+ if (VDBG) log("Removing agent " + nai + " wasDefault=" + wasDefault);
for (int type = 0; type < mTypeLists.length; type++) {
- remove(type, nai);
+ remove(type, nai, wasDefault);
}
}
@@ -555,13 +567,12 @@
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
if (DBG) log("ConnectivityService starting up");
- NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
- mDefaultRequest = new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId());
- NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(),
- NetworkRequestInfo.REQUEST);
- mNetworkRequests.put(mDefaultRequest, nri);
+ mDefaultRequest = createInternetRequestForTransport(-1);
+ mNetworkRequests.put(mDefaultRequest, new NetworkRequestInfo(
+ null, mDefaultRequest, new Binder(), NetworkRequestInfo.REQUEST));
+
+ mDefaultMobileDataRequest = createInternetRequestForTransport(
+ NetworkCapabilities.TRANSPORT_CELLULAR);
HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
handlerThread.start();
@@ -696,8 +707,8 @@
mInetLog = new ArrayList();
}
- mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
- mSettingsObserver.observe(mContext);
+ mSettingsObserver = new SettingsObserver(mContext, mHandler);
+ registerSettingsCallbacks();
mDataConnectionStats = new DataConnectionStats(mContext);
mDataConnectionStats.startMonitoring();
@@ -707,6 +718,44 @@
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
}
+ private NetworkRequest createInternetRequestForTransport(int transportType) {
+ NetworkCapabilities netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ if (transportType > -1) {
+ netCap.addTransportType(transportType);
+ }
+ return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId());
+ }
+
+ private void handleMobileDataAlwaysOn() {
+ final boolean enable = (Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.MOBILE_DATA_ALWAYS_ON, 0) == 1);
+ final boolean isEnabled = (mNetworkRequests.get(mDefaultMobileDataRequest) != null);
+ if (enable == isEnabled) {
+ return; // Nothing to do.
+ }
+
+ if (enable) {
+ handleRegisterNetworkRequest(new NetworkRequestInfo(
+ null, mDefaultMobileDataRequest, new Binder(), NetworkRequestInfo.REQUEST));
+ } else {
+ handleReleaseNetworkRequest(mDefaultMobileDataRequest, Process.SYSTEM_UID);
+ }
+ }
+
+ private void registerSettingsCallbacks() {
+ // Watch for global HTTP proxy changes.
+ mSettingsObserver.observe(
+ Settings.Global.getUriFor(Settings.Global.HTTP_PROXY),
+ EVENT_APPLY_GLOBAL_HTTP_PROXY);
+
+ // Watch for whether or not to keep mobile data always on.
+ mSettingsObserver.observe(
+ Settings.Global.getUriFor(Settings.Global.MOBILE_DATA_ALWAYS_ON),
+ EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON);
+ }
+
private synchronized int nextNetworkRequestId() {
return mNextNetworkRequestId++;
}
@@ -1022,23 +1071,6 @@
}
}
- private NetworkCapabilities getNetworkCapabilitiesAndValidation(NetworkAgentInfo nai) {
- if (nai != null) {
- synchronized (nai) {
- if (nai.created) {
- NetworkCapabilities nc = new NetworkCapabilities(nai.networkCapabilities);
- if (nai.lastValidated) {
- nc.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
- } else {
- nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
- }
- return nc;
- }
- }
- }
- return null;
- }
-
@Override
public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
// The basic principle is: if an app's traffic could possibly go over a
@@ -1060,7 +1092,7 @@
HashMap<Network, NetworkCapabilities> result = new HashMap<Network, NetworkCapabilities>();
NetworkAgentInfo nai = getDefaultNetwork();
- NetworkCapabilities nc = getNetworkCapabilitiesAndValidation(getDefaultNetwork());
+ NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
if (nc != null) {
result.put(nai.network, nc);
}
@@ -1073,9 +1105,9 @@
if (networks != null) {
for (Network network : networks) {
nai = getNetworkAgentInfoForNetwork(network);
- nc = getNetworkCapabilitiesAndValidation(nai);
+ nc = getNetworkCapabilitiesInternal(nai);
if (nc != null) {
- result.put(nai.network, nc);
+ result.put(network, nc);
}
}
}
@@ -1135,25 +1167,24 @@
return null;
}
- @Override
- public NetworkCapabilities getNetworkCapabilities(Network network) {
- enforceAccessPermission();
- NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
if (nai != null) {
synchronized (nai) {
- NetworkCapabilities nc = new NetworkCapabilities(nai.networkCapabilities);
- if (nai.lastValidated) {
- nc.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
- } else {
- nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+ if (nai.networkCapabilities != null) {
+ return new NetworkCapabilities(nai.networkCapabilities);
}
- return nc;
}
}
return null;
}
@Override
+ public NetworkCapabilities getNetworkCapabilities(Network network) {
+ enforceAccessPermission();
+ return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
+ }
+
+ @Override
public NetworkState[] getAllNetworkState() {
// Require internal since we're handing out IMSI details
enforceConnectivityInternalPermission();
@@ -1361,6 +1392,22 @@
}
};
+ /**
+ * Require that the caller is either in the same user or has appropriate permission to interact
+ * across users.
+ *
+ * @param userId Target user for whatever operation the current IPC is supposed to perform.
+ */
+ private void enforceCrossUserPermission(int userId) {
+ if (userId == UserHandle.getCallingUserId()) {
+ // Not a cross-user call.
+ return;
+ }
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "ConnectivityService");
+ }
+
private void enforceInternetPermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERNET,
@@ -1491,6 +1538,9 @@
mContext.registerReceiver(mUserPresentReceiver, filter);
}
+ // Configure whether mobile data is always on.
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON));
+
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_READY));
mPermissionMonitor.startMonitoring();
@@ -1898,11 +1948,14 @@
}
case NetworkMonitor.EVENT_NETWORK_TESTED: {
NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
- if (isLiveNetworkAgent(nai, "EVENT_NETWORK_VALIDATED")) {
- boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
+ if (isLiveNetworkAgent(nai, "EVENT_NETWORK_TESTED")) {
+ final boolean valid =
+ (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
+ final boolean validationChanged = (valid != nai.lastValidated);
nai.lastValidated = valid;
if (valid) {
if (DBG) log("Validated " + nai.name());
+ nai.networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
if (!nai.everValidated) {
nai.everValidated = true;
rematchNetworkAndRequests(nai, NascentState.JUST_VALIDATED,
@@ -1910,6 +1963,8 @@
// If score has changed, rebroadcast to NetworkFactories. b/17726566
sendUpdatedScoreToFactories(nai);
}
+ } else {
+ nai.networkCapabilities.removeCapability(NET_CAPABILITY_VALIDATED);
}
updateInetCondition(nai);
// Let the NetworkAgent know the state of its network
@@ -1918,8 +1973,9 @@
(valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
0, null);
- // TODO: trigger a NetworkCapabilities update so that the dialog can know
- // that the network is now validated and close itself.
+ if (validationChanged) {
+ notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
+ }
}
break;
}
@@ -1934,7 +1990,7 @@
if (msg.arg1 == 0) {
setProvNotificationVisibleIntent(false, msg.arg2, 0, null, null);
} else {
- NetworkAgentInfo nai = null;
+ final NetworkAgentInfo nai;
synchronized (mNetworkForNetId) {
nai = mNetworkForNetId.get(msg.arg2);
}
@@ -1942,6 +1998,7 @@
loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
break;
}
+ nai.captivePortalDetected = true;
setProvNotificationVisibleIntent(true, msg.arg2, nai.networkInfo.getType(),
nai.networkInfo.getExtraInfo(), (PendingIntent)msg.obj);
}
@@ -1991,12 +2048,13 @@
loge("Error connecting NetworkAgent");
NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo);
if (nai != null) {
+ final boolean wasDefault = isDefaultNetwork(nai);
synchronized (mNetworkForNetId) {
mNetworkForNetId.remove(nai.network.netId);
mNetIdInUse.delete(nai.network.netId);
}
// Just in case.
- mLegacyTypeTracker.remove(nai);
+ mLegacyTypeTracker.remove(nai, wasDefault);
}
}
}
@@ -2026,7 +2084,8 @@
nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
null, null);
}
- if (isDefaultNetwork(nai)) {
+ final boolean wasDefault = isDefaultNetwork(nai);
+ if (wasDefault) {
mDefaultInetConditionPublished = 0;
}
notifyIfacesChanged();
@@ -2034,7 +2093,6 @@
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
mNetworkAgentInfos.remove(msg.replyTo);
updateClat(null, nai.linkProperties, nai);
- mLegacyTypeTracker.remove(nai);
synchronized (mNetworkForNetId) {
mNetworkForNetId.remove(nai.network.netId);
mNetIdInUse.delete(nai.network.netId);
@@ -2073,6 +2131,7 @@
notifyLockdownVpn(nai);
requestNetworkTransitionWakelock(nai.name());
}
+ mLegacyTypeTracker.remove(nai, wasDefault);
for (NetworkAgentInfo networkToActivate : toActivate) {
unlinger(networkToActivate);
rematchNetworkAndRequests(networkToActivate, NascentState.NOT_JUST_VALIDATED,
@@ -2107,12 +2166,10 @@
+ nri.request + " because their intents matched.");
handleReleaseNetworkRequest(existingRequest.request, getCallingUid());
}
- handleRegisterNetworkRequest(msg);
+ handleRegisterNetworkRequest(nri);
}
- private void handleRegisterNetworkRequest(Message msg) {
- final NetworkRequestInfo nri = (NetworkRequestInfo) (msg.obj);
-
+ private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {
mNetworkRequests.put(nri.request, nri);
// TODO: This logic may be better replaced with a call to rematchNetworkAndRequests
@@ -2264,7 +2321,7 @@
}
if (doRemove) {
- mLegacyTypeTracker.remove(nri.request.legacyType, nai);
+ mLegacyTypeTracker.remove(nri.request.legacyType, nai, false);
}
}
@@ -2336,7 +2393,8 @@
// Only prompt if the network is unvalidated and was explicitly selected by the user, and if
// we haven't already been told to switch to it regardless of whether it validated or not.
- if (nai == null || nai.everValidated ||
+ // Also don't prompt on captive portals because we're already prompting the user to sign in.
+ if (nai == null || nai.everValidated || nai.captivePortalDetected ||
!nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated) {
return;
}
@@ -2423,7 +2481,7 @@
}
case EVENT_REGISTER_NETWORK_REQUEST:
case EVENT_REGISTER_NETWORK_LISTENER: {
- handleRegisterNetworkRequest(msg);
+ handleRegisterNetworkRequest((NetworkRequestInfo) msg.obj);
break;
}
case EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT: {
@@ -2446,6 +2504,10 @@
handlePromptUnvalidated((Network) msg.obj);
break;
}
+ case EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON: {
+ handleMobileDataAlwaysOn();
+ break;
+ }
case EVENT_SYSTEM_READY: {
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
nai.networkMonitor.systemReady = true;
@@ -2853,23 +2915,36 @@
}
private static class SettingsObserver extends ContentObserver {
- private int mWhat;
- private Handler mHandler;
- SettingsObserver(Handler handler, int what) {
- super(handler);
+ final private HashMap<Uri, Integer> mUriEventMap;
+ final private Context mContext;
+ final private Handler mHandler;
+
+ SettingsObserver(Context context, Handler handler) {
+ super(null);
+ mUriEventMap = new HashMap<Uri, Integer>();
+ mContext = context;
mHandler = handler;
- mWhat = what;
}
- void observe(Context context) {
- ContentResolver resolver = context.getContentResolver();
- resolver.registerContentObserver(Settings.Global.getUriFor(
- Settings.Global.HTTP_PROXY), false, this);
+ void observe(Uri uri, int what) {
+ mUriEventMap.put(uri, what);
+ final ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(uri, false, this);
}
@Override
public void onChange(boolean selfChange) {
- mHandler.obtainMessage(mWhat).sendToTarget();
+ Slog.wtf(TAG, "Should never be reached.");
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ final Integer what = mUriEventMap.get(uri);
+ if (what != null) {
+ mHandler.obtainMessage(what.intValue()).sendToTarget();
+ } else {
+ loge("No matching event to send for URI=" + uri);
+ }
}
}
@@ -2890,29 +2965,48 @@
/**
* Prepare for a VPN application.
- * Permissions are checked in Vpn class.
+ * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
+ * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+ *
+ * @param oldPackage Package name of the application which currently controls VPN, which will
+ * be replaced. If there is no such application, this should should either be
+ * {@code null} or {@link VpnConfig.LEGACY_VPN}.
+ * @param newPackage Package name of the application which should gain control of VPN, or
+ * {@code null} to disable.
+ * @param userId User for whom to prepare the new VPN.
+ *
* @hide
*/
@Override
- public boolean prepareVpn(String oldPackage, String newPackage) {
+ public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage,
+ int userId) {
+ enforceCrossUserPermission(userId);
throwIfLockdownEnabled();
- int user = UserHandle.getUserId(Binder.getCallingUid());
+
synchronized(mVpns) {
- return mVpns.get(user).prepare(oldPackage, newPackage);
+ return mVpns.get(userId).prepare(oldPackage, newPackage);
}
}
/**
- * Set whether the current VPN package has the ability to launch VPNs without
- * user intervention. This method is used by system-privileged apps.
- * Permissions are checked in Vpn class.
+ * Set whether the VPN package has the ability to launch VPNs without user intervention.
+ * This method is used by system-privileged apps.
+ * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
+ * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+ *
+ * @param packageName The package for which authorization state should change.
+ * @param userId User for whom {@code packageName} is installed.
+ * @param authorized {@code true} if this app should be able to start a VPN connection without
+ * explicit user approval, {@code false} if not.
+ *
* @hide
*/
@Override
- public void setVpnPackageAuthorization(boolean authorized) {
- int user = UserHandle.getUserId(Binder.getCallingUid());
+ public void setVpnPackageAuthorization(String packageName, int userId, boolean authorized) {
+ enforceCrossUserPermission(userId);
+
synchronized(mVpns) {
- mVpns.get(user).setPackageAuthorization(authorized);
+ mVpns.get(userId).setPackageAuthorization(packageName, authorized);
}
}
@@ -3014,16 +3108,16 @@
}
/**
- * Returns the information of the ongoing VPN. This method is used by VpnDialogs and
- * not available in ConnectivityManager.
+ * Returns the information of the ongoing VPN for {@code userId}. 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());
+ public VpnConfig getVpnConfig(int userId) {
+ enforceCrossUserPermission(userId);
synchronized(mVpns) {
- return mVpns.get(user).getVpnConfig();
+ return mVpns.get(userId).getVpnConfig();
}
}
@@ -3479,8 +3573,7 @@
}
private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities) {
- if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- == false) {
+ if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) == false) {
enforceConnectivityInternalPermission();
} else {
enforceChangePermission();
@@ -3507,8 +3600,7 @@
private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) {
// if UID is restricted, don't allow them to bring up metered APNs
- if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
- == false) {
+ if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED) == false) {
final int uidRules;
final int uid = Binder.getCallingUid();
synchronized(mRulesLock) {
@@ -3517,7 +3609,7 @@
if ((uidRules & (RULE_REJECT_METERED | RULE_REJECT_ALL)) != 0) {
// we could silently fail or we can filter the available nets to only give
// them those they have access to. Chose the more useful
- networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
}
}
}
@@ -3659,6 +3751,10 @@
// Note: if mDefaultRequest is changed, NetworkMonitor needs to be updated.
private final NetworkRequest mDefaultRequest;
+ // Request used to optionally keep mobile data active even when higher
+ // priority networks like Wi-Fi are active.
+ private final NetworkRequest mDefaultMobileDataRequest;
+
private NetworkAgentInfo getDefaultNetwork() {
return mNetworkForRequestId.get(mDefaultRequest.requestId);
}
@@ -3719,7 +3815,7 @@
// TODO: deprecate and remove mDefaultDns when we can do so safely.
// For now, use it only when the network has Internet access. http://b/18327075
final boolean useDefaultDns = networkAgent.networkCapabilities.hasCapability(
- NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ NET_CAPABILITY_INTERNET);
final boolean flushDns = updateRoutes(newLp, oldLp, netId);
updateDnses(newLp, oldLp, netId, flushDns, useDefaultDns);
@@ -3875,6 +3971,11 @@
synchronized (networkAgent) {
networkAgent.networkCapabilities = networkCapabilities;
}
+ if (networkAgent.lastValidated) {
+ networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
+ // There's no need to remove the capability if we think the network is unvalidated,
+ // because NetworkAgents don't set the validated capability.
+ }
rematchAllNetworksAndRequests(networkAgent, networkAgent.getCurrentScore());
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
@@ -4142,7 +4243,7 @@
// the new one connected.
if (oldDefaultNetwork != null) {
mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
- oldDefaultNetwork);
+ oldDefaultNetwork, true);
}
mDefaultInetConditionPublished = newNetwork.everValidated ? 100 : 0;
mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
@@ -4501,6 +4602,8 @@
@Override
public void factoryReset() {
enforceConnectivityInternalPermission();
+ final int userId = UserHandle.getCallingUserId();
+
// Turn airplane mode off
setAirplaneMode(false);
@@ -4510,16 +4613,16 @@
}
// Turn VPN off
- VpnConfig vpnConfig = getVpnConfig();
+ VpnConfig vpnConfig = getVpnConfig(userId);
if (vpnConfig != null) {
if (vpnConfig.legacy) {
- prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
+ prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, userId);
} else {
- // Prevent this app from initiating VPN connections in the future without
- // user intervention.
- setVpnPackageAuthorization(false);
+ // Prevent this app (packagename = vpnConfig.user) from initiating VPN connections
+ // in the future without user intervention.
+ setVpnPackageAuthorization(vpnConfig.user, userId, false);
- prepareVpn(vpnConfig.user, VpnConfig.LEGACY_VPN);
+ prepareVpn(vpnConfig.user, VpnConfig.LEGACY_VPN, userId);
}
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 8a7c902..eac748f 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -50,12 +50,11 @@
public final NetworkMisc networkMisc;
// Indicates if netd has been told to create this Network. Once created the appropriate routing
// rules are setup and routes are added so packets can begin flowing over the Network.
- // NOTE: This is a sticky bit; once set it is never cleared.
+ // This is a sticky bit; once set it is never cleared.
public boolean created;
// Set to true if this Network successfully passed validation or if it did not satisfy the
// default NetworkRequest in which case validation will not be attempted.
- // NOTE: This is a sticky bit; once set it is never cleared even if future validation attempts
- // fail.
+ // This is a sticky bit; once set it is never cleared even if future validation attempts fail.
public boolean everValidated;
// The result of the last validation attempt on this network (true if validated, false if not).
@@ -65,6 +64,10 @@
// TODO: Fix the network scoring code, remove this, and rename everValidated to validated.
public boolean lastValidated;
+ // Whether a captive portal was ever detected on this network.
+ // This is a sticky bit; once set it is never cleared.
+ public boolean captivePortalDetected;
+
// This represents the last score received from the NetworkAgent.
private int currentScore;
// Penalty applied to scores of Networks that have not been validated.
@@ -101,9 +104,6 @@
currentScore = score;
networkMonitor = new NetworkMonitor(context, handler, this, defaultRequest);
networkMisc = misc;
- created = false;
- everValidated = false;
- lastValidated = false;
}
public void addRequest(NetworkRequest networkRequest) {
@@ -166,6 +166,7 @@
"created{" + created + "} " +
"explicitlySelected{" + networkMisc.explicitlySelected + "} " +
"acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} " +
+ "captivePortalDetected{" + captivePortalDetected + "} " +
"}";
}