From 23bff230fcd5a719e28bf30aaf763fb79d149314 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Tue, 28 May 2013 15:17:37 -0700 Subject: [PATCH 01/71] Fix parsing of global:http_proxy value. This caused a runtime restart for ':' and did not disable the proxy for "" before. Change-Id: Ib88b21e9eba5818a4968ae604abad8a3b3d1766f --- services/java/com/android/server/ConnectivityService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 37a8cb85c0..6f8c32351f 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3134,6 +3134,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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) { @@ -3145,6 +3149,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } ProxyProperties p = new ProxyProperties(data[0], proxyPort, ""); setGlobalProxy(p); + } else { + setGlobalProxy(null); } } From 79f3e029d41bf505ce42f1744718a71401e1c443 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 4 Jun 2013 12:29:00 -0700 Subject: [PATCH 02/71] Accumulate network statistics based on deltas. Network stats are now read out of the kernel in one sweep, instead of reading per-UID. We now accumulate the delta traffic between each stats snapshot using the well-tested SamplingCounter pattern. Since Wi-Fi and mobile traffic have different costs, track each separately. Avoids counting misc interfaces like loopback and ethernet under total. Bug: 5543387 Change-Id: I642004dc530113c27ef79f2abbae51d8af30117f --- core/java/android/net/ConnectivityManager.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 78bf9afcbb..ffcc2974cd 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -463,6 +463,21 @@ public class ConnectivityManager { } } + /** + * 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; + } + } + /** * Specifies the preferred network type. When the device has more * than one type available the preferred network type will be used. From a891d7bd005a7d90befae7801591c70388b44a83 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 11 Jun 2013 14:13:09 -0700 Subject: [PATCH 03/71] Explicit locale when formatting machine strings. Bug: 9390451 Change-Id: I3581c53407554a1dffd541fb42b06d68f20a7be0 --- core/java/android/net/NetworkUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 4ab479e239..333fcc67bc 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -21,6 +21,7 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.UnknownHostException; import java.util.Collection; +import java.util.Locale; import android.util.Log; @@ -223,7 +224,7 @@ public class NetworkUtils { 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), From 1f5cec7fdcf9978fe52d489f18a499db075f37a1 Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Mon, 24 Jun 2013 14:20:23 -0400 Subject: [PATCH 04/71] Move battery stats call from SystemUI to system server. The UPDATE_DEVICE_STATS permission is no longer required in sysui. Change-Id: Icc3120b7873563e3727e56bed9f3b4767da0606d --- services/java/com/android/server/ConnectivityService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 6f8c32351f..54f6118242 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -97,6 +97,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.IndentingPrintWriter; 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; @@ -346,6 +347,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // the set of network types that can only be enabled by system/sig apps List mProtectedNetworks; + private DataConnectionStats mDataConnectionStats; + public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -574,6 +577,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); loadGlobalProxy(); + + mDataConnectionStats = new DataConnectionStats(mContext); + mDataConnectionStats.startMonitoring(); } /** From d78d557cb86a5796d47b3257da603902ac1a66fa Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 17 Jun 2013 11:10:27 -0700 Subject: [PATCH 05/71] 464xlat: use a gatewayed route, not point-to-point Various applications such as Skype and our legacy VPN code do not understand routes pointed directly at point-to-point interfaces and require a default gateway IPv4 address in order to function. Grudgingly accept that routes without default gateways Are Hard and use gatewayed routes instead. This causes routing to go from: default dev clat4 scope link to: default via 192.0.0.4 dev clat4 scope link 192.0.0.4 dev clat4 scope link and those apps now work. Bug: 9597256 Bug: 9597516 Change-Id: I7b7890873802d3cb99affd6eb70b8ab75e7a2cf6 --- .../server/connectivity/Nat464Xlat.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/connectivity/Nat464Xlat.java b/services/java/com/android/server/connectivity/Nat464Xlat.java index 59403c559d..a15d678520 100644 --- a/services/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/java/com/android/server/connectivity/Nat464Xlat.java @@ -147,17 +147,24 @@ public class Nat464Xlat extends BaseNetworkObserver { " added, mIsRunning = " + mIsRunning + " -> true"); mIsRunning = true; - // Get the network configuration of the clat interface, store it - // in our link properties, and stack it on top of the interface - // it's running on. + // Create the LinkProperties for the clat interface by fetching the + // IPv4 address for the interface and adding an IPv4 default route, + // then stack the LinkProperties on top of the link it's running on. + // Although the clat interface is a point-to-point tunnel, we don't + // point the route directly at the interface because some apps don't + // understand routes without gateways (see, e.g., http://b/9597256 + // http://b/9597516). Instead, set the next hop of the route to the + // clat IPv4 address itself (for those apps, it doesn't matter what + // the IP of the gateway is, only that there is one). try { InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); + LinkAddress clatAddress = config.getLinkAddress(); mLP.clear(); mLP.setInterfaceName(iface); - RouteInfo ipv4Default = new RouteInfo(new LinkAddress(Inet4Address.ANY, 0), null, - iface); + RouteInfo ipv4Default = new RouteInfo(new LinkAddress(Inet4Address.ANY, 0), + clatAddress.getAddress(), iface); mLP.addRoute(ipv4Default); - mLP.addLinkAddress(config.getLinkAddress()); + mLP.addLinkAddress(clatAddress); mTracker.addStackedLink(mLP); Slog.i(TAG, "Adding stacked link. tracker LP: " + mTracker.getLinkProperties()); From 37302074650054778f890453f628caa30e7f2f5d Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 2 Jul 2013 12:41:31 -0700 Subject: [PATCH 06/71] am 6152916c: am db011499: am 753d754c: Merge "Fix NPE if mobile is not supported in checkMobileProvisioning." into jb-mr2-dev * commit '6152916c450942c6eeae8270eb2aed9a16639295': Fix NPE if mobile is not supported in checkMobileProvisioning. --- .../java/com/android/server/ConnectivityService.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index fc346a25b7..f2e0f2988e 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3564,6 +3564,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { timeOutMs = CheckMp.MAX_TIMEOUT_MS; } + // Check that mobile networks are supported + if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) + || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { + log("checkMobileProvisioning: X no mobile network"); + if (resultReceiver != null) { + resultReceiver.send(ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION, null); + } + return timeOutMs; + } + final long token = Binder.clearCallingIdentity(); try { CheckMp checkMp = new CheckMp(mContext, this); From 3f3b4e646263eb53cc90531b3d9cd32bb9a7b162 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Thu, 11 Jul 2013 13:30:36 -0700 Subject: [PATCH 07/71] Add NetworkUtil function for marking sockets Add NetworkUtil function for setting the SO_MARK field of sockets Change-Id: I94389b64296d87ee928293f24a26f8dd08c3bf37 --- core/java/android/net/NetworkUtils.java | 5 +++++ core/jni/android_net_NetUtils.cpp | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 333fcc67bc..b24d3969f7 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -103,6 +103,11 @@ public class NetworkUtils { */ 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 diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index faae11ec3b..526159f4f1 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 #include #include @@ -239,6 +240,13 @@ static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz) 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 @@ static JNINativeMethod gNetworkUtilMethods[] = { { "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) From b7652cde9deb742f2b218a49ae765158c4a18bf1 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Fri, 14 Jun 2013 11:16:51 -0700 Subject: [PATCH 08/71] Add per user VPN support VPNs are now per user instead of global. A VPN set by user A routes only user A's traffic and no other user can access it. Change-Id: Ia66463637b6bd088b05768076a1db897fe95c46c --- .../android/server/ConnectivityService.java | 158 ++++++++++++++++-- 1 file changed, 144 insertions(+), 14 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index b148b91219..a6344cafab 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.SparseIntArray; +import android.util.SparseArray; import com.android.internal.R; import com.android.internal.net.LegacyVpnInfo; @@ -116,6 +117,8 @@ import com.android.server.net.LockdownVpnTracker; import com.google.android.collect.Lists; import com.google.android.collect.Sets; +import com.android.internal.annotations.GuardedBy; + import dalvik.system.DexClassLoader; import java.io.FileDescriptor; @@ -171,7 +174,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private KeyStore mKeyStore; - private Vpn mVpn; + @GuardedBy("mVpns") + private final SparseArray mVpns = new SparseArray(); private VpnCallback mVpnCallback = new VpnCallback(); private boolean mLockdownEnabled; @@ -583,10 +587,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { mTethering.getTetherableWifiRegexs().length != 0 || mTethering.getTetherableBluetoothRegexs().length != 0) && mTethering.getUpstreamIfaceTypes().length != 0); + //set up the listener for user state for creating user VPNs - mVpn = new Vpn(mContext, mVpnCallback, mNetd, this); - mVpn.startMonitoring(mContext, mTrackerHandler); - + 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 { @@ -2313,7 +2320,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { // 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) { @@ -2570,7 +2581,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); - mNetd.setDefaultInterfaceForDns(iface); for (InetAddress dns : dnses) { ++last; String key = "net.dns" + last; @@ -3305,8 +3315,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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) { @@ -3330,7 +3344,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { @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); + } } /** @@ -3343,7 +3360,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { @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); + } } /** @@ -3357,7 +3377,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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); + } } /** @@ -3369,7 +3392,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public LegacyVpnInfo getLegacyVpnInfo() { throwIfLockdownEnabled(); - return mVpn.getLegacyVpnInfo(); + int user = UserHandle.getUserId(Binder.getCallingUid()); + synchronized(mVpns) { + return mVpns.get(user).getLegacyVpnInfo(); + } } /** @@ -3390,7 +3416,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mHandler.obtainMessage(EVENT_VPN_STATE_CHANGED, info).sendToTarget(); } - public void override(List dnsServers, List searchDomains) { + public void override(String iface, List dnsServers, List searchDomains) { if (dnsServers == null) { restore(); return; @@ -3422,7 +3448,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Apply DNS changes. synchronized (mDnsLock) { - updateDnsLocked("VPN", "VPN", addresses, domains); + updateDnsLocked("VPN", iface, addresses, domains); mDnsOverridden = true; } @@ -3451,6 +3477,67 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } + + 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 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 @@ -3471,7 +3558,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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); } @@ -4002,4 +4093,43 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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); + } + } + }; } From 11f2225c3dbd285d9f4d0033e85f67b2c9683afb Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Thu, 11 Jul 2013 13:29:30 -0700 Subject: [PATCH 09/71] Support routing sockets as another user Add support for routing sockets as if they were another user's. This is for services that handle delegated network tasks like MediaServer and DownloadManager. Change-Id: Id20efc1f5c2cce6f8838d777762f6c0a703a9437 --- .../android/net/IConnectivityManager.aidl | 2 ++ .../android/server/ConnectivityService.java | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 3dbe078313..7ee10c3f12 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -119,6 +119,8 @@ interface IConnectivityManager boolean prepareVpn(String oldPackage, String newPackage); + void markSocketAsUser(in ParcelFileDescriptor socket, int uid); + ParcelFileDescriptor establishVpn(in VpnConfig config); void startLegacyVpn(in VpnProfile profile); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index a6344cafab..476a6fdffb 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1749,6 +1749,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { "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 @@ -3350,6 +3360,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + @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); + } + } + /** * Configure a TUN interface and return its file descriptor. Parameters * are encoded and opaque to this class. This method is used by VpnBuilder From dc7e3ee3ad86e155284a73e5a2480cde2c793d28 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Tue, 16 Jul 2013 11:22:32 -0700 Subject: [PATCH 10/71] Move markSocketAsUser to the top of IConnectivityManager.aidl Move markSocketAsUser to the top of IConnectivityManager.aidl to make calls from framework/native/services/connectivitymanager less fragile Change-Id: Iba92c21dfef175b570521f34e7ee2732e5a0a9c9 --- core/java/android/net/IConnectivityManager.aidl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 7ee10c3f12..d537b32ff1 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -37,6 +37,9 @@ import com.android.internal.net.VpnProfile; /** {@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(); @@ -119,8 +122,6 @@ interface IConnectivityManager boolean prepareVpn(String oldPackage, String newPackage); - void markSocketAsUser(in ParcelFileDescriptor socket, int uid); - ParcelFileDescriptor establishVpn(in VpnConfig config); void startLegacyVpn(in VpnProfile profile); From 94f3c8c66d4330b3be137fa2d6cdb86b52b9e54a Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Tue, 16 Jul 2013 18:59:12 -0700 Subject: [PATCH 11/71] Support multiple Vpn ManageDialogs Move away from storing the configs in the Intent to prevent issues with PendingIntents and multiple configs. The Dialog now queries ConnectivityService for the configuration to display in the management dialog. Change-Id: I0e0ef52db840152914d117a24f776d8106e836ff --- core/java/android/net/IConnectivityManager.aidl | 2 ++ .../com/android/server/ConnectivityService.java | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index d537b32ff1..0a476eb88f 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -124,6 +124,8 @@ interface IConnectivityManager ParcelFileDescriptor establishVpn(in VpnConfig config); + VpnConfig getVpnConfig(); + void startLegacyVpn(in VpnProfile profile); LegacyVpnInfo getLegacyVpnInfo(); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 476a6fdffb..3a4b7e382f 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3425,6 +3425,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + /** + * 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(); + } + } + /** * Callback for VPN subsystem. Currently VPN is not adapted to the service * through NetworkStateTracker since it works differently. For example, it From 98b10cec42cab3698f1eb80f6ae57ee3e3de38f9 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Thu, 18 Jul 2013 18:23:57 -0700 Subject: [PATCH 12/71] Fix build & preserve DHCP scheduling as-is Change-Id: I4063b18532c476280f343658bf3641495e526ed4 --- .../src/com/android/server/NetworkStatsServiceTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index cdc4d784cf..ed74fdfccf 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 @@ public class NetworkStatsServiceTest extends AndroidTestCase { 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(), isA(PendingIntent.class), false); expectLastCall().atLeastOnce(); mNetManager.setGlobalAlert(anyLong()); From 99fedebaa111b760edf3de0afa108818f606becd Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Fri, 19 Jul 2013 09:27:56 -0700 Subject: [PATCH 13/71] checkMobileProvisioning is not using sendNotification. Change-Id: Ie5b98b462b29fe9339fcb8207d2d33e3028a155c --- services/java/com/android/server/ConnectivityService.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 476a6fdffb..d2bae28e38 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3670,7 +3670,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } @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 @@ -3703,6 +3703,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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) { From 49db4221002ae32cfb7b092b4eb30f90aad31e90 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Mon, 15 Jul 2013 16:34:04 -0700 Subject: [PATCH 14/71] Fix supplimentary network connections with VPNs Enables the use of supplimentary mobile networks like MMS, and HIPRI while VPNs are running. Change-Id: I313f57a905b4e16bd4322c68687cbff1cfbe9d3e --- .../java/android/net/ConnectivityManager.java | 16 +++ .../android/server/ConnectivityService.java | 107 ++++++++++++------ 2 files changed, 86 insertions(+), 37 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index f920874506..8bbe6c826b 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -479,6 +479,22 @@ public class ConnectivityManager { } } + /** + * 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: + return true; + default: + return false; + } + } + /** * Specifies the preferred network type. When the device has more * than one type available the preferred network type will be used. diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 0608b6a6f5..1e3f0ef89b 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -252,6 +252,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 @@ -349,10 +352,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 mAddedRoutes = new ArrayList(); + // this collection corresponds to the entries of mAddedRoutes that have routing exemptions + // used to handle cleanup of exempt rules + @GuardedBy("mRoutesLock") + private Collection mExemptAddresses = new ArrayList(); + // used in DBG mode to track inet condition reports private static final int INET_CONDITION_LOG_MAX_SIZE = 15; private ArrayList mInetLog; @@ -1470,7 +1482,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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) { @@ -1482,24 +1494,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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()); @@ -1514,11 +1527,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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; @@ -1547,15 +1560,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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); } @@ -1568,18 +1591,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { // 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); @@ -2260,6 +2290,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ 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 @@ -2324,7 +2355,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } 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) { @@ -2400,7 +2431,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * returns a boolean indicating the routes changed */ private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp, - boolean isLinkDefault) { + boolean isLinkDefault, boolean exempt) { Collection routesToAdd = null; CompareResult dnsDiff = new CompareResult(); CompareResult routeDiff = new CompareResult(); @@ -2436,7 +2467,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } if (newLp != null) { for (InetAddress newDns : newLp.getDnses()) { - addRouteToAddress(newLp, newDns); + addRouteToAddress(newLp, newDns, exempt); } } } else { @@ -2445,28 +2476,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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); + } } } } From a5e56e1223cfbfcfe87452ad05b84ba9db4900bd Mon Sep 17 00:00:00 2001 From: Guang Zhu Date: Sun, 21 Jul 2013 02:01:34 -0700 Subject: [PATCH 15/71] fix build Change-Id: Ie4bd7c3fe9320d22b7da2962e5e5a4abca510bd2 --- .../src/com/android/server/NetworkStatsServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index ed74fdfccf..aca77b8d87 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -878,7 +878,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mAlarmManager.remove(isA(PendingIntent.class)); expectLastCall().anyTimes(); - mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), isA(PendingIntent.class), false); + mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(), isA(PendingIntent.class)); expectLastCall().atLeastOnce(); mNetManager.setGlobalAlert(anyLong()); From 73652d07b898eaa734a5711851bfa8f2928d1ebf Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Tue, 23 Jul 2013 17:13:36 -0700 Subject: [PATCH 16/71] Fix default DNS not being set on network changes Change-Id: I3c45404cab34c77b20dadc1d8aee127aa08fd0bd --- .../java/com/android/server/ConnectivityService.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 0608b6a6f5..a3b3a1455d 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2586,7 +2586,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Caller must grab mDnsLock. private void updateDnsLocked(String network, String iface, - Collection dnses, String domains) { + Collection dnses, String domains, boolean defaultDns) { int last = 0; if (dnses.size() == 0 && mDefaultDns != null) { dnses = new ArrayList(); @@ -2598,6 +2598,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); + if (defaultDns) { + mNetd.setDefaultInterfaceForDns(iface); + } + for (InetAddress dns : dnses) { ++last; String key = "net.dns" + last; @@ -2625,7 +2629,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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 { @@ -3496,8 +3500,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Apply DNS changes. synchronized (mDnsLock) { - updateDnsLocked("VPN", iface, addresses, domains); - mDnsOverridden = true; + updateDnsLocked("VPN", iface, addresses, domains, false); } // Temporarily disable the default proxy (not global). From 5fdc14656cde61638c65630eef02e9508154a07d Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Tue, 23 Jul 2013 17:44:41 -0700 Subject: [PATCH 17/71] Remove unused mDnsOverridden mDnsOverridden is no longer used now that VPNs do not override the default DNS settings. Change-Id: I69495b9a6de7d60628813f357d3dbdf548695ada --- .../android/server/ConnectivityService.java | 32 +++---------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index a3b3a1455d..5681adfd71 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -235,7 +235,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private Object mDnsLock = new Object(); private int mNumDnsEntries; - private boolean mDnsOverridden = false; private boolean mTestMode; private static ConnectivityService sServiceInstance; @@ -306,29 +305,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ 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; @@ -2628,9 +2621,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mNetConfigs[netType].isDefault()) { String network = nt.getNetworkInfo().getTypeName(); synchronized (mDnsLock) { - if (!mDnsOverridden) { - updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains(), true); - } + updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains(), true); } } else { try { @@ -2883,13 +2874,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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; @@ -3515,12 +3499,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } public void restore() { - synchronized (mDnsLock) { - if (mDnsOverridden) { - mDnsOverridden = false; - mHandler.sendEmptyMessage(EVENT_RESTORE_DNS); - } - } synchronized (mProxyLock) { mDefaultProxyDisabled = false; if (mGlobalProxy == null && mDefaultProxy != null) { From 512c2204b1c2365451e3a62a8649a263acc5b7a8 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Mon, 29 Jul 2013 15:00:57 -0700 Subject: [PATCH 18/71] Add network type TYPE_MOBILE_IA. Add a network type for establishing connections to the apn used for the initial connection. Enable some debug for now. Bug: 8733613 Change-Id: Ia627ac0cf5715660b6d02bb13a83d46ec1727b87 --- core/java/android/net/ConnectivityManager.java | 16 +++++++++++++--- .../com/android/server/ConnectivityService.java | 3 +++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 8bbe6c826b..1dbe34e201 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -355,11 +355,17 @@ public class ConnectivityManager { */ 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 @@ public class ConnectivityManager { 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,7 @@ public class ConnectivityManager { case TYPE_MOBILE_FOTA: case TYPE_MOBILE_IMS: case TYPE_MOBILE_CBS: + case TYPE_MOBILE_IA: return true; default: return false; @@ -489,6 +498,7 @@ public class ConnectivityManager { case TYPE_MOBILE_MMS: case TYPE_MOBILE_SUPL: case TYPE_MOBILE_HIPRI: + case TYPE_MOBILE_IA: return true; default: return false; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index b341693245..9615ff5fb8 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -472,6 +472,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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; @@ -492,6 +493,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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); @@ -518,6 +520,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // ignore it - leave the entry null } } + if (VDBG) log("mNetworksDefined=" + mNetworksDefined); mProtectedNetworks = new ArrayList(); int[] protectedNetworks = context.getResources().getIntArray( From e1b474244259bbbe6adbdf780928f987cef51f24 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 31 Jul 2013 23:23:21 +0900 Subject: [PATCH 19/71] Add accessors for all addresses and clarify compare* methods 1. Add a method to return all addresses and all LinkAddresses on all links (both base links and stacked links). We already had one for routes, but did not yet have any for addresses. 2. Rename compareRoutes to compareAllRoutes, because unlike the other compare* methods, it looks at all interfaces. Update what appears to be its only caller. 3. Update the documentation of the compare* methods to match reality (they don't return lists) and clarify whether they look at all links or only the base link. Change-Id: Ie22e6c7f163d5de8e407248b45171dc28382d2d3 --- core/java/android/net/LinkProperties.java | 64 +++++++++++++------ .../src/android/net/LinkPropertiesTest.java | 27 ++++++-- .../android/server/ConnectivityService.java | 2 +- 3 files changed, 69 insertions(+), 24 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 75f8b5948b..6ab810c68d 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -128,6 +128,9 @@ public class LinkProperties implements Parcelable { return interfaceNames; } + /** + * Returns all the addresses on this link. + */ public Collection getAddresses() { Collection addresses = new ArrayList(); for (LinkAddress linkAddress : mLinkAddresses) { @@ -136,14 +139,43 @@ public class LinkProperties implements Parcelable { return Collections.unmodifiableCollection(addresses); } + /** + * Returns all the addresses on this link and all the links stacked above it. + */ + public Collection getAllAddresses() { + Collection addresses = new ArrayList(); + for (LinkAddress linkAddress : mLinkAddresses) { + addresses.add(linkAddress.getAddress()); + } + for (LinkProperties stacked: mStackedLinks.values()) { + addresses.addAll(stacked.getAllAddresses()); + } + return addresses; + } + public void addLinkAddress(LinkAddress address) { if (address != null) mLinkAddresses.add(address); } + /** + * Returns all the addresses on this link. + */ public Collection getLinkAddresses() { return Collections.unmodifiableCollection(mLinkAddresses); } + /** + * Returns all the addresses on this link and all the links stacked above it. + */ + public Collection getAllLinkAddresses() { + Collection addresses = new ArrayList(); + addresses.addAll(mLinkAddresses); + for (LinkProperties stacked: mStackedLinks.values()) { + addresses.addAll(stacked.getAllLinkAddresses()); + } + return addresses; + } + public void addDns(InetAddress dns) { if (dns != null) mDnses.add(dns); } @@ -426,13 +458,11 @@ public class LinkProperties implements Parcelable { } /** - * Return two lists, a list of addresses that would be removed from - * mLinkAddresses and a list of addresses that would be added to - * mLinkAddress which would then result in target and mLinkAddresses - * being the same list. + * Compares the addresses in this LinkProperties with another + * LinkProperties, examining only addresses on the base link. * - * @param target is a LinkProperties with the new list of addresses - * @return the removed and added lists. + * @param target a LinkProperties with the new list of addresses + * @return the differences between the addresses. */ public CompareResult compareAddresses(LinkProperties target) { /* @@ -456,13 +486,11 @@ public class LinkProperties implements Parcelable { } /** - * Return two lists, a list of dns addresses that would be removed from - * mDnses and a list of addresses that would be added to - * mDnses which would then result in target and mDnses - * being the same list. + * Compares the DNS addresses in this LinkProperties with another + * LinkProperties, examining only DNS addresses on the base link. * - * @param target is a LinkProperties with the new list of dns addresses - * @return the removed and added lists. + * @param target a LinkProperties with the new list of dns addresses + * @return the differences between the DNS addresses. */ public CompareResult compareDnses(LinkProperties target) { /* @@ -487,15 +515,13 @@ public class LinkProperties implements Parcelable { } /** - * Return two lists, a list of routes that would be removed from - * mRoutes and a list of routes that would be added to - * mRoutes which would then result in target and mRoutes - * being the same list. + * Compares all routes in this LinkProperties with another LinkProperties, + * examining both the the base link and all stacked links. * - * @param target is a LinkProperties with the new list of routes - * @return the removed and added lists. + * @param target a LinkProperties with the new list of routes + * @return the differences between the routes. */ - public CompareResult compareRoutes(LinkProperties target) { + public CompareResult compareAllRoutes(LinkProperties target) { /* * Duplicate the RouteInfos into removed, we will be removing * routes which are common between mRoutes and target diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index d6a7ee27a2..d8290f494b 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -273,28 +273,47 @@ public class LinkPropertiesTest extends TestCase { // Check comparisons work. LinkProperties lp2 = new LinkProperties(lp); assertAllRoutesHaveInterface("wlan0", lp); - assertEquals(0, lp.compareRoutes(lp2).added.size()); - assertEquals(0, lp.compareRoutes(lp2).removed.size()); + assertEquals(0, lp.compareAllRoutes(lp2).added.size()); + assertEquals(0, lp.compareAllRoutes(lp2).removed.size()); lp2.setInterfaceName("p2p0"); assertAllRoutesHaveInterface("p2p0", lp2); - assertEquals(3, lp.compareRoutes(lp2).added.size()); - assertEquals(3, lp.compareRoutes(lp2).removed.size()); + assertEquals(3, lp.compareAllRoutes(lp2).added.size()); + assertEquals(3, lp.compareAllRoutes(lp2).removed.size()); } @SmallTest public void testStackedInterfaces() { LinkProperties rmnet0 = new LinkProperties(); rmnet0.setInterfaceName("rmnet0"); + rmnet0.addLinkAddress(new LinkAddress( + NetworkUtils.numericToInetAddress(ADDRV6), 128)); LinkProperties clat4 = new LinkProperties(); clat4.setInterfaceName("clat4"); + clat4.addLinkAddress(new LinkAddress( + NetworkUtils.numericToInetAddress(ADDRV4), 32)); assertEquals(0, rmnet0.getStackedLinks().size()); + assertEquals(1, rmnet0.getAddresses().size()); + assertEquals(1, rmnet0.getLinkAddresses().size()); + assertEquals(1, rmnet0.getAllAddresses().size()); + assertEquals(1, rmnet0.getAllLinkAddresses().size()); + rmnet0.addStackedLink(clat4); assertEquals(1, rmnet0.getStackedLinks().size()); + assertEquals(1, rmnet0.getAddresses().size()); + assertEquals(1, rmnet0.getLinkAddresses().size()); + assertEquals(2, rmnet0.getAllAddresses().size()); + assertEquals(2, rmnet0.getAllLinkAddresses().size()); + rmnet0.addStackedLink(clat4); assertEquals(1, rmnet0.getStackedLinks().size()); + assertEquals(1, rmnet0.getAddresses().size()); + assertEquals(1, rmnet0.getLinkAddresses().size()); + assertEquals(2, rmnet0.getAllAddresses().size()); + assertEquals(2, rmnet0.getAllLinkAddresses().size()); + assertEquals(0, clat4.getStackedLinks().size()); // Modify an item in the returned collection to see what happens. diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 9615ff5fb8..af9fdffe88 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2433,7 +2433,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { CompareResult routeDiff = new CompareResult(); if (curLp != null) { // check for the delta between the current set and the new - routeDiff = curLp.compareRoutes(newLp); + routeDiff = curLp.compareAllRoutes(newLp); dnsDiff = curLp.compareDnses(newLp); } else if (newLp != null) { routeDiff.added = newLp.getAllRoutes(); From d28eef464a2c1e8a5f6964ff668587b34c87156c Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 31 Jul 2013 15:49:04 -0700 Subject: [PATCH 20/71] Fix excessive log spew. Bug: 10115060 Change-Id: I61fd83071da1224f38757b8d90f58c8d6c41d36b --- services/java/com/android/server/ConnectivityService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 9615ff5fb8..cdf9f213f5 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3909,8 +3909,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo.State state = mCs .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); if (state != NetworkInfo.State.CONNECTED) { - log("isMobileOk: not connected ni=" + + if (VDBG) { + log("isMobileOk: not connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); + } sleep(1); result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; continue; From fa9d82b877308b3c53576ddb3407c85e0c090ef4 Mon Sep 17 00:00:00 2001 From: David Christie Date: Fri, 26 Jul 2013 13:23:29 -0700 Subject: [PATCH 21/71] Add WorkSource capability to AlarmManager. Change-Id: I663ea3078d405f0fa667a04bdaa376ae6652e994 --- .../src/com/android/server/NetworkStatsServiceTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index aca77b8d87..5fa046aa4f 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -878,7 +878,8 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mAlarmManager.remove(isA(PendingIntent.class)); expectLastCall().anyTimes(); - mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(), isA(PendingIntent.class)); + mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(), + isA(PendingIntent.class), isA(WorkSource.class)); expectLastCall().atLeastOnce(); mNetManager.setGlobalAlert(anyLong()); From d201f880de31e4ab30f882c679de493158e3cca9 Mon Sep 17 00:00:00 2001 From: David Christie Date: Fri, 2 Aug 2013 10:54:55 -0700 Subject: [PATCH 22/71] Fix build breakage Change-Id: Ia684fb55db301fdadaa3aae93f82b2cdcfc200af --- .../src/com/android/server/NetworkStatsServiceTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index 5fa046aa4f..a9909b2ecf 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -63,6 +63,7 @@ import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.INetworkManagementService; +import android.os.WorkSource; import android.telephony.TelephonyManager; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; From 4bd59212450cc566126abb10af4e0fe139287ed5 Mon Sep 17 00:00:00 2001 From: David Christie Date: Fri, 2 Aug 2013 11:06:02 -0700 Subject: [PATCH 23/71] Fix broken unit test Change-Id: I4aa0035233749f6d585c151329436439ae9b2921 --- .../src/com/android/server/NetworkStatsServiceTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index a9909b2ecf..90a9b6a5f0 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -40,6 +40,7 @@ import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL; import static org.easymock.EasyMock.anyLong; +import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.aryEq; import static org.easymock.EasyMock.capture; import static org.easymock.EasyMock.createMock; @@ -880,7 +881,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectLastCall().anyTimes(); mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(), - isA(PendingIntent.class), isA(WorkSource.class)); + isA(PendingIntent.class), anyObject(WorkSource.class)); expectLastCall().atLeastOnce(); mNetManager.setGlobalAlert(anyLong()); From 1a168466464eb4c2a1a55b4d60542bd49ead5dfb Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Wed, 24 Jul 2013 17:42:56 -0700 Subject: [PATCH 24/71] dhcp: Get mtu property from dhcp results Change-Id: I1b032094e0945b27d98f7ac786247b7cc9d60131 Signed-off-by: Dmitry Shmidt --- core/jni/android_net_NetUtils.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 526159f4f1..7e70c7c5eb 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -37,7 +37,8 @@ int dhcp_do_request(const char * const ifname, const char *server, uint32_t *lease, const char *vendorInfo, - const char *domains); + const char *domains, + const char *mtu); int dhcp_do_request_renew(const char * const ifname, const char *ipaddr, @@ -47,7 +48,8 @@ int dhcp_do_request_renew(const char * const ifname, const char *server, uint32_t *lease, const char *vendorInfo, - const char *domains); + const char *domains, + const char *mtu); int dhcp_stop(const char *ifname); int dhcp_release_lease(const char *ifname); @@ -126,16 +128,17 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr uint32_t lease; char vendorInfo[PROPERTY_VALUE_MAX]; char domains[PROPERTY_VALUE_MAX]; + char mtu[PROPERTY_VALUE_MAX]; const char *nameStr = env->GetStringUTFChars(ifname, NULL); if (nameStr == NULL) return (jboolean)false; if (renew) { result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength, - dns, server, &lease, vendorInfo, domains); + dns, server, &lease, vendorInfo, domains, mtu); } else { result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength, - dns, server, &lease, vendorInfo, domains); + dns, server, &lease, vendorInfo, domains, mtu); } if (result != 0) { ALOGD("dhcp_do_request failed"); From 8432cf46212acd6542d48c45b31f0c5756b1a189 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Sat, 20 Jul 2013 20:31:59 -0700 Subject: [PATCH 25/71] Have CaptivePortalTracker use gservices updateable provisioning urls. After detecting there is a captive portal the url used in the notification for mobile networks should be updateable via gservices. These urls will be the same as used by CheckMp and is needed for carriers that have specific provisioning urls such as AT&T and Verizon. Bug: 9622647 Change-Id: Idcf4dabc72ece1dbbe1d5e5a21e550dd06fe16c7 --- core/java/android/net/ConnectivityManager.java | 14 +++++++++++++- core/java/android/net/IConnectivityManager.aidl | 2 ++ .../com/android/server/ConnectivityService.java | 9 ++++++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 697bde99a2..b6df2fa660 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1360,7 +1360,7 @@ public class ConnectivityManager { } /** - * Get the carrier provisioning url. + * Get the mobile provisioning url. * {@hide} */ public String getMobileProvisioningUrl() { @@ -1370,4 +1370,16 @@ public class ConnectivityManager { } return null; } + + /** + * Get the mobile redirected provisioning url. + * {@hide} + */ + public String getMobileRedirectedProvisioningUrl() { + try { + return mService.getMobileRedirectedProvisioningUrl(); + } catch (RemoteException e) { + } + return null; + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 4600c1a4dc..5daf39c60d 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -136,4 +136,6 @@ interface IConnectivityManager int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver); String getMobileProvisioningUrl(); + + String getMobileRedirectedProvisioningUrl(); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index cb4e89cc0f..6a90376557 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4086,7 +4086,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { return null; } - private String getMobileRedirectedProvisioningUrl() { + @Override + public String getMobileRedirectedProvisioningUrl() { + enforceConnectivityInternalPermission(); String url = getProvisioningUrlBaseFromFile(REDIRECTED_PROVISIONING); if (TextUtils.isEmpty(url)) { url = mContext.getResources().getString(R.string.mobile_redirected_provisioning_url); @@ -4094,14 +4096,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { return url; } + @Override public String getMobileProvisioningUrl() { enforceConnectivityInternalPermission(); String url = getProvisioningUrlBaseFromFile(PROVISIONING); if (TextUtils.isEmpty(url)) { url = mContext.getResources().getString(R.string.mobile_provisioning_url); - log("getProvisioningUrl: mobile_provisioining_url from resource =" + url); + log("getMobileProvisioningUrl: mobile_provisioining_url from resource =" + url); } else { - log("getProvisioningUrl: mobile_provisioning_url from File =" + url); + log("getMobileProvisioningUrl: mobile_provisioning_url from File =" + url); } // populate the iccid, imei and phone number in the provisioning url. if (!TextUtils.isEmpty(url)) { From d6085f847c7586e22148ce78c3962a51905554d5 Mon Sep 17 00:00:00 2001 From: David Christie Date: Tue, 6 Aug 2013 17:28:03 +0000 Subject: [PATCH 26/71] Revert "Fix broken unit test" This reverts commit 4bd59212450cc566126abb10af4e0fe139287ed5. Change-Id: I67f5e7227a8a874158c4f0954e62a77a317f1edd --- .../src/com/android/server/NetworkStatsServiceTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index 90a9b6a5f0..a9909b2ecf 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -40,7 +40,6 @@ import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL; import static org.easymock.EasyMock.anyLong; -import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.aryEq; import static org.easymock.EasyMock.capture; import static org.easymock.EasyMock.createMock; @@ -881,7 +880,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectLastCall().anyTimes(); mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(), - isA(PendingIntent.class), anyObject(WorkSource.class)); + isA(PendingIntent.class), isA(WorkSource.class)); expectLastCall().atLeastOnce(); mNetManager.setGlobalAlert(anyLong()); From 15f129209d65abb36643c91fa869f905a6d05a92 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 7 Aug 2013 11:02:57 -0700 Subject: [PATCH 27/71] Check that hipri has started. I needed to test the result of startUsingNetworkFeature, otherwise on mobile networks that are slow to come up, we won't detect warm SIMs after booting. Bug: 9962943 Change-Id: Ib638a4e43867ecaa85d6abff65643b77a63526b6 --- .../android/server/ConnectivityService.java | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index cb4e89cc0f..caab49ece7 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3732,11 +3732,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { // hipri connection so the default connection stays active. log("isMobileOk: start hipri url=" + params.mUrl); mCs.setEnableFailFastMobileData(DctConstants.ENABLED); - mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - Phone.FEATURE_ENABLE_HIPRI, new Binder()); // Continue trying to connect until time has run out long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs; + + // First wait until we can start using hipri + Binder binder = new Binder(); + while(SystemClock.elapsedRealtime() < endTime) { + int ret = mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + Phone.FEATURE_ENABLE_HIPRI, binder); + if ((ret == PhoneConstants.APN_ALREADY_ACTIVE) + || (ret == PhoneConstants.APN_REQUEST_STARTED)) { + log("isMobileOk: hipri started"); + break; + } + if (VDBG) log("isMobileOk: hipri not started yet"); + result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + sleep(1); + } + + // Continue trying to connect until time has run out while(SystemClock.elapsedRealtime() < endTime) { try { // Wait for hipri to connect. @@ -3745,8 +3760,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo.State state = mCs .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); if (state != NetworkInfo.State.CONNECTED) { - log("isMobileOk: not connected ni=" + + if (VDBG) { + log("isMobileOk: not connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); + } sleep(1); result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; continue; From 674777e622d33c48b068f7dc4c84aa6f0c24cdd1 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 7 Aug 2013 16:22:47 -0700 Subject: [PATCH 28/71] If in a mobile captive portal is detected enable fail fast. When captive portal checking completes pass back the result. This is used to enable/disable failing fast for mobile. When failing fast is enabled we don't check for data stalls and thus won't be continually trying to do recovery operations, such as restarting the radio. Bug: 9462512 Change-Id: I0dea0eee519f8ee7f94e79d40e82c18f30d7fe2e --- .../java/android/net/ConnectivityManager.java | 19 +++++++++++++++++++ .../android/net/IConnectivityManager.aidl | 2 ++ .../android/server/ConnectivityService.java | 11 +++++++++++ 3 files changed, 32 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 697bde99a2..855a2ef93b 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1282,6 +1282,25 @@ public class ConnectivityManager { } } + /** + * Signal that the captive portal check on the indicated network + * is complete and whether its a captive portal or not. + * + * @param info the {@link NetworkInfo} object for the networkType + * in question. + * @param isCaptivePortal true/false. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. + * {@hide} + */ + public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { + try { + mService.captivePortalCheckCompleted(info, isCaptivePortal); + } catch (RemoteException e) { + } + } + /** * Supply the backend messenger for a network tracker * diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 4600c1a4dc..45bb184e48 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -129,6 +129,8 @@ interface IConnectivityManager void captivePortalCheckComplete(in NetworkInfo info); + void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal); + void supplyMessenger(int networkType, in Messenger messenger); int findConnectionTypeForIface(in String iface); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index cb4e89cc0f..f3dc7257f9 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2169,15 +2169,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + if (DBG) log("handleCaptivePortalTrackerCheck: call captivePortalCheckComplete ni=" + info); thisNet.captivePortalCheckComplete(); } /** @hide */ + @Override public void captivePortalCheckComplete(NetworkInfo info) { enforceConnectivityInternalPermission(); + if (DBG) log("captivePortalCheckComplete: ni=" + info); mNetTrackers[info.getType()].captivePortalCheckComplete(); } + /** @hide */ + @Override + public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { + enforceConnectivityInternalPermission(); + if (DBG) log("captivePortalCheckCompleted: ni=" + info + " captive=" + isCaptivePortal); + mNetTrackers[info.getType()].captivePortalCheckCompleted(isCaptivePortal); + } + /** * Setup data activity tracking for the given network interface. * From a5bf2840cc81f7bd9a2b74a1ebb383c343edffc0 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Wed, 3 Jul 2013 17:04:33 -0400 Subject: [PATCH 29/71] Add PAC File support for proxy configuration PAC (Proxy auto-config) files contain a single javascript function, FindProxyForURL(url, host). It gets called to determine what proxy should be used for a specific request. This adds PAC support to the system. The ProxyProperties has been modified to hold the PAC file when one is present. The Proxy method setHttpProxySystemProperty has been modified to insert a PacProxySelector as the default ProxySelector when it is required. This new ProxySelector makes calls to the ConnectivityService to parse the PAC file. The ConnectivityService and the WifiConfigStore have been modified to support saving the extra PAC file data. The ConnectivityService now has a class attached (PacProxyNative) that interfaces to the native calls for PAC files. The parsing of the PAC file is handled by libpac (which is being added to external/) which utilizes libv8 to parse the javascript. As a fallback to applications that don't use the java ProxySelector, the proxy is setup to point to a local proxy server that will handle the pac parsing. bug:10182711 Change-Id: I5eb8df893c632fd3e1b732385cb7720ad646f401 --- core/java/android/net/ProxyProperties.java | 45 +++++++++++++++++-- .../android/server/ConnectivityService.java | 40 ++++++++++++----- 2 files changed, 71 insertions(+), 14 deletions(-) diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java index 9c4772b90f..76aea9f58e 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyProperties.java @@ -20,9 +20,7 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; -import android.util.Log; -import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.Locale; @@ -38,17 +36,30 @@ public class ProxyProperties implements Parcelable { private String mExclusionList; private String[] mParsedExclusionList; + private String mPacFileUrl; + public static final String LOCAL_EXCL_LIST = ""; + public static final int LOCAL_PORT = 8182; + public static final String LOCAL_HOST = "localhost"; + public ProxyProperties(String host, int port, String exclList) { mHost = host; mPort = port; setExclusionList(exclList); } + public ProxyProperties(String pacFileUrl) { + mHost = LOCAL_HOST; + mPort = LOCAL_PORT; + setExclusionList(LOCAL_EXCL_LIST); + mPacFileUrl = pacFileUrl; + } + private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) { mHost = host; mPort = port; mExclusionList = exclList; mParsedExclusionList = parsedExclList; + mPacFileUrl = null; } // copy constructor instead of clone @@ -56,6 +67,7 @@ public class ProxyProperties implements Parcelable { if (source != null) { mHost = source.getHost(); mPort = source.getPort(); + mPacFileUrl = source.getPacFileUrl(); mExclusionList = source.getExclusionList(); mParsedExclusionList = source.mParsedExclusionList; } @@ -69,6 +81,10 @@ public class ProxyProperties implements Parcelable { return inetSocketAddress; } + public String getPacFileUrl() { + return mPacFileUrl; + } + public String getHost() { return mHost; } @@ -130,7 +146,10 @@ public class ProxyProperties implements Parcelable { @Override public String toString() { StringBuilder sb = new StringBuilder(); - if (mHost != null) { + if (mPacFileUrl != null) { + sb.append("PAC Script: "); + sb.append(mPacFileUrl); + } else if (mHost != null) { sb.append("["); sb.append(mHost); sb.append("] "); @@ -148,6 +167,14 @@ public class ProxyProperties implements Parcelable { public boolean equals(Object o) { if (!(o instanceof ProxyProperties)) return false; ProxyProperties p = (ProxyProperties)o; + // If PAC URL is present in either then they must be equal. + // Other parameters will only be for fall back. + if (!TextUtils.isEmpty(mPacFileUrl)) { + return mPacFileUrl.equals(p.getPacFileUrl()); + } + if (!TextUtils.isEmpty(p.getPacFileUrl())) { + return false; + } if (mExclusionList != null && !mExclusionList.equals(p.getExclusionList())) return false; if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) { return false; @@ -181,6 +208,13 @@ public class ProxyProperties implements Parcelable { * @hide */ public void writeToParcel(Parcel dest, int flags) { + if (mPacFileUrl != null) { + dest.writeByte((byte)1); + dest.writeString(mPacFileUrl); + return; + } else { + dest.writeByte((byte)0); + } if (mHost != null) { dest.writeByte((byte)1); dest.writeString(mHost); @@ -201,7 +235,10 @@ public class ProxyProperties implements Parcelable { public ProxyProperties createFromParcel(Parcel in) { String host = null; int port = 0; - if (in.readByte() == 1) { + if (in.readByte() != 0) { + return new ProxyProperties(in.readString()); + } + if (in.readByte() != 0) { host = in.readString(); port = in.readInt(); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 17ae85f39a..3ae2eb542c 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -56,13 +56,11 @@ import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.LinkAddress; import android.net.LinkProperties; -import android.net.Uri; import android.net.LinkProperties.CompareResult; import android.net.MobileDataStateTracker; import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; -import android.net.NetworkInfo.State; import android.net.NetworkQuotaInfo; import android.net.NetworkState; import android.net.NetworkStateTracker; @@ -70,6 +68,7 @@ import android.net.NetworkUtils; import android.net.Proxy; import android.net.ProxyProperties; import android.net.RouteInfo; +import android.net.Uri; import android.net.wifi.WifiStateTracker; import android.net.wimax.WimaxManagerConstants; import android.os.AsyncTask; @@ -102,6 +101,7 @@ import android.util.SparseIntArray; import android.util.Xml; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; @@ -110,9 +110,11 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; +import com.android.net.IProxyService; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.Nat464Xlat; +import com.android.server.connectivity.PacManager; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.android.server.net.BaseNetworkObserver; @@ -120,8 +122,6 @@ import com.android.server.net.LockdownVpnTracker; 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; @@ -370,6 +370,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // track the global proxy. private ProxyProperties mGlobalProxy = null; + private PacManager mPacManager = null; + private SettingsObserver mSettingsObserver; NetworkConfig[] mNetConfigs; @@ -631,6 +633,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { mDataConnectionStats = new DataConnectionStats(mContext); mDataConnectionStats.startMonitoring(); + + mPacManager = new PacManager(mContext); } /** @@ -3168,13 +3172,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { // of proxy info to all the JVMs. // enforceAccessPermission(); synchronized (mProxyLock) { - if (mGlobalProxy != null) return mGlobalProxy; - return (mDefaultProxyDisabled ? null : mDefaultProxy); + ProxyProperties ret = mGlobalProxy; + if ((ret == null) && !mDefaultProxyDisabled) ret = mDefaultProxy; + return ret; } } public void setGlobalProxy(ProxyProperties proxyProperties) { enforceConnectivityInternalPermission(); + synchronized (mProxyLock) { if (proxyProperties == mGlobalProxy) return; if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return; @@ -3183,11 +3189,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { String host = ""; int port = 0; String exclList = ""; - if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) { + String pacFileUrl = ""; + if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) || + !TextUtils.isEmpty(proxyProperties.getPacFileUrl()))) { mGlobalProxy = new ProxyProperties(proxyProperties); host = mGlobalProxy.getHost(); port = mGlobalProxy.getPort(); exclList = mGlobalProxy.getExclusionList(); + if (proxyProperties.getPacFileUrl() != null) { + pacFileUrl = proxyProperties.getPacFileUrl(); + } } else { mGlobalProxy = null; } @@ -3198,6 +3209,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port); Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclList); + Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl); } finally { Binder.restoreCallingIdentity(token); } @@ -3215,8 +3227,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0); String exclList = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST); - if (!TextUtils.isEmpty(host)) { - ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList); + String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC); + if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) { + ProxyProperties proxyProperties; + if (!TextUtils.isEmpty(pacFileUrl)) { + proxyProperties = new ProxyProperties(pacFileUrl); + } else { + proxyProperties = new ProxyProperties(host, port, exclList); + } synchronized (mProxyLock) { mGlobalProxy = proxyProperties; } @@ -3234,7 +3252,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private void handleApplyDefaultProxy(ProxyProperties proxy) { - if (proxy != null && TextUtils.isEmpty(proxy.getHost())) { + if (proxy != null && TextUtils.isEmpty(proxy.getHost()) + && TextUtils.isEmpty(proxy.getPacFileUrl())) { proxy = null; } synchronized (mProxyLock) { @@ -3276,6 +3295,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void sendProxyBroadcast(ProxyProperties proxy) { if (proxy == null) proxy = new ProxyProperties("", 0, ""); + mPacManager.setCurrentProxyScriptUrl(proxy); if (DBG) log("sending Proxy Broadcast for " + proxy); Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | From a2dc69a8931e718c631f5a9a8fd30aef25de09e4 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 8 Aug 2013 10:56:22 +0900 Subject: [PATCH 30/71] Simplify LinkPropertiesTest. Instead of converting IP addresses to strings throughout the test, do so once at the beginning. Change-Id: I7f0dae5d2e9e2cdc6ec808e2cf71197ba6ade0a4 --- .../src/android/net/LinkPropertiesTest.java | 149 ++++++++---------- 1 file changed, 65 insertions(+), 84 deletions(-) diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index d8290f494b..9fdfd0e641 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -25,14 +25,18 @@ import java.net.InetAddress; import java.util.ArrayList; public class LinkPropertiesTest extends TestCase { - private static String ADDRV4 = "75.208.6.1"; - private static String ADDRV6 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; - private static String DNS1 = "75.208.7.1"; - private static String DNS2 = "69.78.7.1"; - private static String GATEWAY1 = "75.208.8.1"; - private static String GATEWAY2 = "69.78.8.1"; + private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1"); + private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress( + "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); + private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1"); + private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1"); + private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1"); + private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1"); private static String NAME = "qmi0"; + private static LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32); + private static LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128); + public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) { // Check implementation of equals(), element by element. assertTrue(source.isIdenticalInterfaceName(target)); @@ -76,43 +80,37 @@ public class LinkPropertiesTest extends TestCase { LinkProperties source = new LinkProperties(); source.setInterfaceName(NAME); // set 2 link addresses - source.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - source.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); + source.addLinkAddress(LINKADDRV4); + source.addLinkAddress(LINKADDRV6); // set 2 dnses - source.addDns(NetworkUtils.numericToInetAddress(DNS1)); - source.addDns(NetworkUtils.numericToInetAddress(DNS2)); + source.addDns(DNS1); + source.addDns(DNS2); // set 2 gateways - source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); - source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + source.addRoute(new RouteInfo(GATEWAY1)); + source.addRoute(new RouteInfo(GATEWAY2)); LinkProperties target = new LinkProperties(); // All fields are same target.setInterfaceName(NAME); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); - target.addDns(NetworkUtils.numericToInetAddress(DNS1)); - target.addDns(NetworkUtils.numericToInetAddress(DNS2)); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + target.addDns(DNS1); + target.addDns(DNS2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); assertLinkPropertiesEqual(source, target); target.clear(); // change Interface Name target.setInterfaceName("qmi1"); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); - target.addDns(NetworkUtils.numericToInetAddress(DNS1)); - target.addDns(NetworkUtils.numericToInetAddress(DNS2)); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + target.addDns(DNS1); + target.addDns(DNS2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); assertFalse(source.equals(target)); target.clear(); @@ -120,38 +118,33 @@ public class LinkPropertiesTest extends TestCase { // change link addresses target.addLinkAddress(new LinkAddress( NetworkUtils.numericToInetAddress("75.208.6.2"), 32)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); - target.addDns(NetworkUtils.numericToInetAddress(DNS1)); - target.addDns(NetworkUtils.numericToInetAddress(DNS2)); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + target.addLinkAddress(LINKADDRV6); + target.addDns(DNS1); + target.addDns(DNS2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); assertFalse(source.equals(target)); target.clear(); target.setInterfaceName(NAME); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); // change dnses target.addDns(NetworkUtils.numericToInetAddress("75.208.7.2")); - target.addDns(NetworkUtils.numericToInetAddress(DNS2)); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + target.addDns(DNS2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); assertFalse(source.equals(target)); target.clear(); target.setInterfaceName(NAME); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); - target.addDns(NetworkUtils.numericToInetAddress(DNS1)); - target.addDns(NetworkUtils.numericToInetAddress(DNS2)); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + target.addDns(DNS1); + target.addDns(DNS2); // change gateway target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2"))); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + target.addRoute(new RouteInfo(GATEWAY2)); assertFalse(source.equals(target)); } catch (Exception e) { @@ -166,28 +159,24 @@ public class LinkPropertiesTest extends TestCase { LinkProperties source = new LinkProperties(); source.setInterfaceName(NAME); // set 2 link addresses - source.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - source.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); + source.addLinkAddress(LINKADDRV4); + source.addLinkAddress(LINKADDRV6); // set 2 dnses - source.addDns(NetworkUtils.numericToInetAddress(DNS1)); - source.addDns(NetworkUtils.numericToInetAddress(DNS2)); + source.addDns(DNS1); + source.addDns(DNS2); // set 2 gateways - source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); - source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + source.addRoute(new RouteInfo(GATEWAY1)); + source.addRoute(new RouteInfo(GATEWAY2)); LinkProperties target = new LinkProperties(); // Exchange order target.setInterfaceName(NAME); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - target.addDns(NetworkUtils.numericToInetAddress(DNS2)); - target.addDns(NetworkUtils.numericToInetAddress(DNS1)); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); + target.addLinkAddress(LINKADDRV6); + target.addLinkAddress(LINKADDRV4); + target.addDns(DNS2); + target.addDns(DNS1); + target.addRoute(new RouteInfo(GATEWAY2)); + target.addRoute(new RouteInfo(GATEWAY1)); assertLinkPropertiesEqual(source, target); } catch (Exception e) { @@ -200,21 +189,15 @@ public class LinkPropertiesTest extends TestCase { try { LinkProperties source = new LinkProperties(); // set 3 link addresses, eg, [A, A, B] - source.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - source.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - source.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); + source.addLinkAddress(LINKADDRV4); + source.addLinkAddress(LINKADDRV4); + source.addLinkAddress(LINKADDRV6); LinkProperties target = new LinkProperties(); // set 3 link addresses, eg, [A, B, B] - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + target.addLinkAddress(LINKADDRV6); assertLinkPropertiesEqual(source, target); } catch (Exception e) { @@ -232,7 +215,7 @@ public class LinkPropertiesTest extends TestCase { public void testRouteInterfaces() { LinkAddress prefix = new LinkAddress( NetworkUtils.numericToInetAddress("2001:db8::"), 32); - InetAddress address = NetworkUtils.numericToInetAddress(ADDRV6); + InetAddress address = ADDRV6; // Add a route with no interface to a LinkProperties with no interface. No errors. LinkProperties lp = new LinkProperties(); @@ -265,7 +248,7 @@ public class LinkPropertiesTest extends TestCase { assertAllRoutesHaveInterface("wlan0", lp); // Routes with null interfaces are converted to wlan0. - r = RouteInfo.makeHostRoute(NetworkUtils.numericToInetAddress(ADDRV6), null); + r = RouteInfo.makeHostRoute(ADDRV6, null); lp.addRoute(r); assertEquals(3, lp.getRoutes().size()); assertAllRoutesHaveInterface("wlan0", lp); @@ -286,13 +269,11 @@ public class LinkPropertiesTest extends TestCase { public void testStackedInterfaces() { LinkProperties rmnet0 = new LinkProperties(); rmnet0.setInterfaceName("rmnet0"); - rmnet0.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); + rmnet0.addLinkAddress(LINKADDRV6); LinkProperties clat4 = new LinkProperties(); clat4.setInterfaceName("clat4"); - clat4.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); + clat4.addLinkAddress(LINKADDRV4); assertEquals(0, rmnet0.getStackedLinks().size()); assertEquals(1, rmnet0.getAddresses().size()); From e0fac27d4d02cb2c0b096b2fed4e34ba422d9e92 Mon Sep 17 00:00:00 2001 From: Vinit Deshapnde Date: Thu, 8 Aug 2013 10:38:53 -0700 Subject: [PATCH 31/71] Use a single socket to communicate with supplicant This helps to prepare for future updates from external sources. Bug: 9298955 Change-Id: I4c63ad5fc1ea3564aab38cfce955de19bad75c0c (cherry picked from commit fb40801ed8c217ae01082fb1cbd0c30bbf5532ac) --- core/jni/android_net_NetUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 7e70c7c5eb..6d23c32b33 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -141,7 +141,7 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr dns, server, &lease, vendorInfo, domains, mtu); } if (result != 0) { - ALOGD("dhcp_do_request failed"); + ALOGD("dhcp_do_request failed : %s (%s)", nameStr, renew ? "renew" : "new"); } env->ReleaseStringUTFChars(ifname, nameStr); From bd53d843fa4a179a1e9dcea2900350b75b2e94af Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 7 Aug 2013 11:02:57 -0700 Subject: [PATCH 32/71] Check that hipri has started. I needed to test the result of startUsingNetworkFeature, otherwise on mobile networks that are slow to come up, we won't detect warm SIMs after booting. Bug: 9962943 Change-Id: Ib638a4e43867ecaa85d6abff65643b77a63526b6 --- .../android/server/ConnectivityService.java | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index cb4e89cc0f..caab49ece7 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3732,11 +3732,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { // hipri connection so the default connection stays active. log("isMobileOk: start hipri url=" + params.mUrl); mCs.setEnableFailFastMobileData(DctConstants.ENABLED); - mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - Phone.FEATURE_ENABLE_HIPRI, new Binder()); // Continue trying to connect until time has run out long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs; + + // First wait until we can start using hipri + Binder binder = new Binder(); + while(SystemClock.elapsedRealtime() < endTime) { + int ret = mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + Phone.FEATURE_ENABLE_HIPRI, binder); + if ((ret == PhoneConstants.APN_ALREADY_ACTIVE) + || (ret == PhoneConstants.APN_REQUEST_STARTED)) { + log("isMobileOk: hipri started"); + break; + } + if (VDBG) log("isMobileOk: hipri not started yet"); + result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + sleep(1); + } + + // Continue trying to connect until time has run out while(SystemClock.elapsedRealtime() < endTime) { try { // Wait for hipri to connect. @@ -3745,8 +3760,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo.State state = mCs .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); if (state != NetworkInfo.State.CONNECTED) { - log("isMobileOk: not connected ni=" + + if (VDBG) { + log("isMobileOk: not connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); + } sleep(1); result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; continue; From 830e29b51bb65548a80dc86b6786f35031870cdd Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Sat, 20 Jul 2013 20:31:59 -0700 Subject: [PATCH 33/71] Have CaptivePortalTracker use gservices updateable provisioning urls. After detecting there is a captive portal the url used in the notification for mobile networks should be updateable via gservices. These urls will be the same as used by CheckMp and is needed for carriers that have specific provisioning urls such as AT&T and Verizon. Bug: 9622647 Change-Id: Idcf4dabc72ece1dbbe1d5e5a21e550dd06fe16c7 --- core/java/android/net/ConnectivityManager.java | 14 +++++++++++++- core/java/android/net/IConnectivityManager.aidl | 2 ++ .../com/android/server/ConnectivityService.java | 9 ++++++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 697bde99a2..b6df2fa660 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1360,7 +1360,7 @@ public class ConnectivityManager { } /** - * Get the carrier provisioning url. + * Get the mobile provisioning url. * {@hide} */ public String getMobileProvisioningUrl() { @@ -1370,4 +1370,16 @@ public class ConnectivityManager { } return null; } + + /** + * Get the mobile redirected provisioning url. + * {@hide} + */ + public String getMobileRedirectedProvisioningUrl() { + try { + return mService.getMobileRedirectedProvisioningUrl(); + } catch (RemoteException e) { + } + return null; + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 4600c1a4dc..5daf39c60d 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -136,4 +136,6 @@ interface IConnectivityManager int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver); String getMobileProvisioningUrl(); + + String getMobileRedirectedProvisioningUrl(); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index caab49ece7..68037e08d2 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4103,7 +4103,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { return null; } - private String getMobileRedirectedProvisioningUrl() { + @Override + public String getMobileRedirectedProvisioningUrl() { + enforceConnectivityInternalPermission(); String url = getProvisioningUrlBaseFromFile(REDIRECTED_PROVISIONING); if (TextUtils.isEmpty(url)) { url = mContext.getResources().getString(R.string.mobile_redirected_provisioning_url); @@ -4111,14 +4113,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { return url; } + @Override public String getMobileProvisioningUrl() { enforceConnectivityInternalPermission(); String url = getProvisioningUrlBaseFromFile(PROVISIONING); if (TextUtils.isEmpty(url)) { url = mContext.getResources().getString(R.string.mobile_provisioning_url); - log("getProvisioningUrl: mobile_provisioining_url from resource =" + url); + log("getMobileProvisioningUrl: mobile_provisioining_url from resource =" + url); } else { - log("getProvisioningUrl: mobile_provisioning_url from File =" + url); + log("getMobileProvisioningUrl: mobile_provisioning_url from File =" + url); } // populate the iccid, imei and phone number in the provisioning url. if (!TextUtils.isEmpty(url)) { From 11f99735ee7ca0d16c696997295c876947f1cabd Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 7 Aug 2013 16:22:47 -0700 Subject: [PATCH 34/71] If in a mobile captive portal is detected enable fail fast. When captive portal checking completes pass back the result. This is used to enable/disable failing fast for mobile. When failing fast is enabled we don't check for data stalls and thus won't be continually trying to do recovery operations, such as restarting the radio. Bug: 9462512 Change-Id: I0dea0eee519f8ee7f94e79d40e82c18f30d7fe2e --- .../java/android/net/ConnectivityManager.java | 19 +++++++++++++++++++ .../android/net/IConnectivityManager.aidl | 2 ++ .../android/server/ConnectivityService.java | 11 +++++++++++ 3 files changed, 32 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index b6df2fa660..aa2d4ce92e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1282,6 +1282,25 @@ public class ConnectivityManager { } } + /** + * Signal that the captive portal check on the indicated network + * is complete and whether its a captive portal or not. + * + * @param info the {@link NetworkInfo} object for the networkType + * in question. + * @param isCaptivePortal true/false. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. + * {@hide} + */ + public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { + try { + mService.captivePortalCheckCompleted(info, isCaptivePortal); + } catch (RemoteException e) { + } + } + /** * Supply the backend messenger for a network tracker * diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 5daf39c60d..3ac5f1367f 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -129,6 +129,8 @@ interface IConnectivityManager void captivePortalCheckComplete(in NetworkInfo info); + void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal); + void supplyMessenger(int networkType, in Messenger messenger); int findConnectionTypeForIface(in String iface); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 68037e08d2..00935f3472 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2169,15 +2169,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + if (DBG) log("handleCaptivePortalTrackerCheck: call captivePortalCheckComplete ni=" + info); thisNet.captivePortalCheckComplete(); } /** @hide */ + @Override public void captivePortalCheckComplete(NetworkInfo info) { enforceConnectivityInternalPermission(); + if (DBG) log("captivePortalCheckComplete: ni=" + info); mNetTrackers[info.getType()].captivePortalCheckComplete(); } + /** @hide */ + @Override + public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { + enforceConnectivityInternalPermission(); + if (DBG) log("captivePortalCheckCompleted: ni=" + info + " captive=" + isCaptivePortal); + mNetTrackers[info.getType()].captivePortalCheckCompleted(isCaptivePortal); + } + /** * Setup data activity tracking for the given network interface. * From 69e2de0a4e9973174eb890b88350eaa288646be5 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 13 Aug 2013 12:41:06 -0700 Subject: [PATCH 35/71] In isMobileOk don't execute finally if mobile data is not supported. Move the early return outside the try {} finally so we don't call setEnableFailFastMobileData(DctContants.DISABLED). Otherwise referencing counting is wrong and an exception is thrown in DcTrackerBase. Bug: 10304904 Change-Id: I5ba5121e473bada9f3daa8d6f3d3577cec8212fc --- .../java/com/android/server/ConnectivityService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index bb0d2483ae..a0e6dd1a87 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3916,13 +3916,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { Random rand = new Random(); mParams = params; - try { - if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { - log("isMobileOk: not mobile capable"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; - return result; - } + if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { + log("isMobileOk: not mobile capable"); + result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + return result; + } + try { // Enable fail fast as we'll do retries here and use a // hipri connection so the default connection stays active. log("isMobileOk: start hipri url=" + params.mUrl); From 884a8d284993412b83e167c09a488938d7761c75 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 13 Aug 2013 12:41:06 -0700 Subject: [PATCH 36/71] In isMobileOk don't execute finally if mobile data is not supported. Move the early return outside the try {} finally so we don't call setEnableFailFastMobileData(DctContants.DISABLED). Otherwise referencing counting is wrong and an exception is thrown in DcTrackerBase. Bug: 10304904 Change-Id: I5ba5121e473bada9f3daa8d6f3d3577cec8212fc --- .../java/com/android/server/ConnectivityService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index bb0d2483ae..a0e6dd1a87 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3916,13 +3916,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { Random rand = new Random(); mParams = params; - try { - if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { - log("isMobileOk: not mobile capable"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; - return result; - } + if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { + log("isMobileOk: not mobile capable"); + result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + return result; + } + try { // Enable fail fast as we'll do retries here and use a // hipri connection so the default connection stays active. log("isMobileOk: start hipri url=" + params.mUrl); From 54c5e16978b25a17d0bcc75f7040cab9ec920aeb Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 13 Aug 2013 12:41:06 -0700 Subject: [PATCH 37/71] In isMobileOk don't execute finally if mobile data is not supported. Move the early return outside the try {} finally so we don't call setEnableFailFastMobileData(DctContants.DISABLED). Otherwise referencing counting is wrong and an exception is thrown in DcTrackerBase. Bug: 10304904 Change-Id: I5ba5121e473bada9f3daa8d6f3d3577cec8212fc --- .../java/com/android/server/ConnectivityService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 00935f3472..fa016f4587 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3732,13 +3732,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { Random rand = new Random(); mParams = params; - try { - if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { - log("isMobileOk: not mobile capable"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; - return result; - } + if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { + log("isMobileOk: not mobile capable"); + result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + return result; + } + try { // Enable fail fast as we'll do retries here and use a // hipri connection so the default connection stays active. log("isMobileOk: start hipri url=" + params.mUrl); From d23fa090e9cd4e05f0c65492b055397a68f1f2cf Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Fri, 16 Aug 2013 17:17:28 -0700 Subject: [PATCH 38/71] DO NOT MERGE: MDST is not ready until connected to DcTracker. When the system becomes loaded the PhoneApp can be delayed significantly and a call to setEnableFailFastMobileData may not occur because the channel between the MobileDataStateTracker (MDST) and DcTracker (DCT) is not connected. Solution: Add a isReady to MDST and isMobileDataStateTrackerReady to ConnectivityService and call it from isMobileOk. Bug: 10351868 Change-Id: I92f9d58121b88186b636cd71c2fd2ef9a28f7cf6 --- .../android/server/ConnectivityService.java | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index fa016f4587..06708191d9 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3572,6 +3572,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { enabled)); } + private boolean isMobileDataStateTrackerReady() { + MobileDataStateTracker mdst = + (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + return (mdst != null) && (mdst.isReady()); + } + @Override public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, final ResultReceiver resultReceiver) { @@ -3739,14 +3745,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { } try { - // Enable fail fast as we'll do retries here and use a - // hipri connection so the default connection stays active. - log("isMobileOk: start hipri url=" + params.mUrl); - mCs.setEnableFailFastMobileData(DctConstants.ENABLED); - // Continue trying to connect until time has run out long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs; + if (!mCs.isMobileDataStateTrackerReady()) { + // Wait for MobileDataStateTracker to be ready. + if (DBG) log("isMobileOk: mdst is not ready"); + while(SystemClock.elapsedRealtime() < endTime) { + if (mCs.isMobileDataStateTrackerReady()) { + // Enable fail fast as we'll do retries here and use a + // hipri connection so the default connection stays active. + if (DBG) log("isMobileOk: mdst ready, enable fail fast of mobile data"); + mCs.setEnableFailFastMobileData(DctConstants.ENABLED); + break; + } + sleep(1); + } + } + + log("isMobileOk: start hipri url=" + params.mUrl); + // First wait until we can start using hipri Binder binder = new Binder(); while(SystemClock.elapsedRealtime() < endTime) { From b48bb0801ae26fd0d4c759df6aa05d51f05f9c31 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 8 Aug 2013 19:24:09 +0900 Subject: [PATCH 39/71] Add a string constructor to LinkAddress. This will allow us to do new LinkAddress("2001:db8::1/64"). Bug: 10232006 Change-Id: If479bdbab16826afe9d82732215141841c282299 --- core/java/android/net/LinkAddress.java | 41 ++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index f6a114c834..a390add89e 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -32,27 +32,56 @@ public class LinkAddress implements Parcelable { /** * IPv4 or IPv6 address. */ - private final InetAddress address; + private InetAddress address; /** * Network prefix length */ - private final int prefixLength; + private int prefixLength; - public LinkAddress(InetAddress address, int prefixLength) { + private void init(InetAddress address, int prefixLength) { if (address == null || prefixLength < 0 || ((address instanceof Inet4Address) && prefixLength > 32) || (prefixLength > 128)) { throw new IllegalArgumentException("Bad LinkAddress params " + address + - prefixLength); + "/" + prefixLength); } this.address = address; this.prefixLength = prefixLength; } + public LinkAddress(InetAddress address, int prefixLength) { + init(address, prefixLength); + } + public LinkAddress(InterfaceAddress interfaceAddress) { - this.address = interfaceAddress.getAddress(); - this.prefixLength = interfaceAddress.getNetworkPrefixLength(); + init(interfaceAddress.getAddress(), + interfaceAddress.getNetworkPrefixLength()); + } + + /** + * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or + * "2001:db8::1/64". + * @param string The string to parse. + */ + public LinkAddress(String address) { + InetAddress inetAddress = null; + int prefixLength = -1; + try { + String [] pieces = address.split("/", 2); + prefixLength = Integer.parseInt(pieces[1]); + inetAddress = InetAddress.parseNumericAddress(pieces[0]); + } catch (NullPointerException e) { // Null string. + } catch (ArrayIndexOutOfBoundsException e) { // No prefix length. + } catch (NumberFormatException e) { // Non-numeric prefix. + } catch (IllegalArgumentException e) { // Invalid IP address. + } + + if (inetAddress == null || prefixLength == -1) { + throw new IllegalArgumentException("Bad LinkAddress params " + address); + } + + init(inetAddress, prefixLength); } @Override From 09de418b17408ca907452a56a70e58bba70fb540 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 8 Aug 2013 11:00:12 +0900 Subject: [PATCH 40/71] Modify LinkProperties address update methods. 1. Make addLinkAddress a no-op if the address already exists. 2. Make addLinkAddress, addStackedLink and removeStackedLink return a boolean indicating whether something changed. 3. Add a removeLinkAddress method (currently there is no way of removing an address). 3. Move hasIPv6Address from ConnectivityService to LinkProperties, where it belongs. Bug: 9625448 Bug: 10232006 Change-Id: If641d0198432a7a505e358c059171f25bc9f13d5 --- core/java/android/net/LinkProperties.java | 53 ++++++++++++++++-- .../src/android/net/LinkPropertiesTest.java | 56 +++++++++++++++++++ .../android/server/ConnectivityService.java | 18 +----- 3 files changed, 105 insertions(+), 22 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 6ab810c68d..1f73c4ad71 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -23,6 +23,7 @@ import android.text.TextUtils; import java.net.InetAddress; import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.UnknownHostException; import java.util.ArrayList; @@ -153,8 +154,28 @@ public class LinkProperties implements Parcelable { return addresses; } - public void addLinkAddress(LinkAddress address) { - if (address != null) mLinkAddresses.add(address); + /** + * Adds a link address if it does not exist, or update it if it does. + * @param address The {@code LinkAddress} to add. + * @return true if the address was added, false if it already existed. + */ + public boolean addLinkAddress(LinkAddress address) { + // TODO: when the LinkAddress has other attributes beyond the + // address and the prefix length, update them here. + if (address != null && !mLinkAddresses.contains(address)) { + mLinkAddresses.add(address); + return true; + } + return false; + } + + /** + * Removes a link address. + * @param address The {@code LinkAddress} to remove. + * @return true if the address was removed, false if it did not exist. + */ + public boolean removeLinkAddress(LinkAddress toRemove) { + return mLinkAddresses.remove(toRemove); } /** @@ -245,11 +266,14 @@ public class LinkProperties implements Parcelable { * of stacked links. If link is null, nothing changes. * * @param link The link to add. + * @return true if the link was stacked, false otherwise. */ - public void addStackedLink(LinkProperties link) { + public boolean addStackedLink(LinkProperties link) { if (link != null && link.getInterfaceName() != null) { mStackedLinks.put(link.getInterfaceName(), link); + return true; } + return false; } /** @@ -258,12 +282,15 @@ public class LinkProperties implements Parcelable { * If there a stacked link with the same interfacename as link, it is * removed. Otherwise, nothing changes. * - * @param link The link to add. + * @param link The link to remove. + * @return true if the link was removed, false otherwise. */ - public void removeStackedLink(LinkProperties link) { + public boolean removeStackedLink(LinkProperties link) { if (link != null && link.getInterfaceName() != null) { - mStackedLinks.remove(link.getInterfaceName()); + LinkProperties removed = mStackedLinks.remove(link.getInterfaceName()); + return removed != null; } + return false; } /** @@ -339,6 +366,20 @@ public class LinkProperties implements Parcelable { return false; } + /** + * Returns true if this link has an IPv6 address. + * + * @return {@code true} if there is an IPv6 address, {@code false} otherwise. + */ + public boolean hasIPv6Address() { + for (LinkAddress address : mLinkAddresses) { + if (address.getAddress() instanceof Inet6Address) { + return true; + } + } + return false; + } + /** * Compares this {@code LinkProperties} interface name against the target * diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index 9fdfd0e641..a570802d29 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -306,5 +306,61 @@ public class LinkPropertiesTest extends TestCase { for (LinkProperties link : rmnet0.getStackedLinks()) { assertFalse("newname".equals(link.getInterfaceName())); } + + assertTrue(rmnet0.removeStackedLink(clat4)); + assertEquals(0, rmnet0.getStackedLinks().size()); + assertEquals(1, rmnet0.getAddresses().size()); + assertEquals(1, rmnet0.getLinkAddresses().size()); + assertEquals(1, rmnet0.getAllAddresses().size()); + assertEquals(1, rmnet0.getAllLinkAddresses().size()); + + assertFalse(rmnet0.removeStackedLink(clat4)); + } + + @SmallTest + public void testAddressMethods() { + LinkProperties lp = new LinkProperties(); + + // No addresses. + assertFalse(lp.hasIPv4Address()); + assertFalse(lp.hasIPv6Address()); + + // Addresses on stacked links don't count. + LinkProperties stacked = new LinkProperties(); + stacked.setInterfaceName("stacked"); + lp.addStackedLink(stacked); + stacked.addLinkAddress(LINKADDRV4); + stacked.addLinkAddress(LINKADDRV6); + assertTrue(stacked.hasIPv4Address()); + assertTrue(stacked.hasIPv6Address()); + assertFalse(lp.hasIPv4Address()); + assertFalse(lp.hasIPv6Address()); + lp.removeStackedLink(stacked); + assertFalse(lp.hasIPv4Address()); + assertFalse(lp.hasIPv6Address()); + + // Addresses on the base link. + // Check the return values of hasIPvXAddress and ensure the add/remove methods return true + // iff something changes. + assertTrue(lp.addLinkAddress(LINKADDRV6)); + assertFalse(lp.hasIPv4Address()); + assertTrue(lp.hasIPv6Address()); + + assertTrue(lp.removeLinkAddress(LINKADDRV6)); + assertTrue(lp.addLinkAddress(LINKADDRV4)); + assertTrue(lp.hasIPv4Address()); + assertFalse(lp.hasIPv6Address()); + + assertTrue(lp.addLinkAddress(LINKADDRV6)); + assertTrue(lp.hasIPv4Address()); + assertTrue(lp.hasIPv6Address()); + + // Adding an address twice has no effect. + // Removing an address that's not present has no effect. + assertFalse(lp.addLinkAddress(LINKADDRV4)); + assertTrue(lp.hasIPv4Address()); + assertTrue(lp.removeLinkAddress(LINKADDRV4)); + assertFalse(lp.hasIPv4Address()); + assertFalse(lp.removeLinkAddress(LINKADDRV4)); } } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index a0e6dd1a87..07a7fbab74 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3982,8 +3982,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Get the type of addresses supported by this link LinkProperties lp = mCs.getLinkProperties( ConnectivityManager.TYPE_MOBILE_HIPRI); - boolean linkHasIpv4 = hasIPv4Address(lp); - boolean linkHasIpv6 = hasIPv6Address(lp); + boolean linkHasIpv4 = lp.hasIPv4Address(); + boolean linkHasIpv6 = lp.hasIPv6Address(); log("isMobileOk: linkHasIpv4=" + linkHasIpv4 + " linkHasIpv6=" + linkHasIpv6); @@ -4129,20 +4129,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - public boolean hasIPv4Address(LinkProperties lp) { - return lp.hasIPv4Address(); - } - - // Not implemented in LinkProperties, do it here. - public boolean hasIPv6Address(LinkProperties lp) { - for (LinkAddress address : lp.getLinkAddresses()) { - if (address.getAddress() instanceof Inet6Address) { - return true; - } - } - return false; - } - private void log(String s) { Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s); } From 30ad254a1e10e1d410719496c8cfda794015795f Mon Sep 17 00:00:00 2001 From: Vinit Deshapnde Date: Wed, 21 Aug 2013 13:09:01 -0700 Subject: [PATCH 41/71] Introduce network link quality statistics This change starts tracking traffic quality data for WiFi and mobile networks. The quality is tracked based on incidental traffic, and not on specific measurements. Theoretical bandwidths are hard-coded, as well as sampling interval; although sampling interval can be changed by setting a system policy. Bugs filed to remove shortcomings of this change - 10342372 Change LinkInfo name to something better 10342318 Move hardcoded values of MobileLinkInfo to resources so they can be updated without changing code Bug: 10006249 Change-Id: I83d8c7594da20fe53abbd5e1f909b1f606b035bb --- .../java/android/net/ConnectivityManager.java | 39 +++++ .../android/net/IConnectivityManager.aidl | 8 + .../android/server/ConnectivityService.java | 150 +++++++++++++++++- 3 files changed, 194 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 1b418fa5f8..f6a3a4a772 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1442,4 +1442,43 @@ public class ConnectivityManager { } return null; } + + /** + * get the information about a specific network link + * @hide + */ + public LinkInfo getLinkInfo(int networkType) { + try { + LinkInfo li = mService.getLinkInfo(networkType); + return li; + } catch (RemoteException e) { + return null; + } + } + + /** + * get the information of currently active network link + * @hide + */ + public LinkInfo getActiveLinkInfo() { + try { + LinkInfo li = mService.getActiveLinkInfo(); + return li; + } catch (RemoteException e) { + return null; + } + } + + /** + * get the information of all network links + * @hide + */ + public LinkInfo[] getAllLinkInfo() { + try { + LinkInfo[] li = mService.getAllLinkInfo(); + return li; + } catch (RemoteException e) { + return null; + } + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 992ec37cda..bf2dade3bc 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -16,6 +16,7 @@ package android.net; +import android.net.LinkInfo; import android.net.LinkProperties; import android.net.NetworkInfo; import android.net.NetworkQuotaInfo; @@ -145,4 +146,11 @@ interface IConnectivityManager String getMobileProvisioningUrl(); String getMobileRedirectedProvisioningUrl(); + + LinkInfo getLinkInfo(int networkType); + + LinkInfo getActiveLinkInfo(); + + LinkInfo[] getAllLinkInfo(); + } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index a0e6dd1a87..27614d0f7d 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -31,6 +31,7 @@ import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; +import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -56,6 +57,7 @@ import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.LinkAddress; import android.net.LinkProperties; +import android.net.LinkInfo; import android.net.LinkProperties.CompareResult; import android.net.MobileDataStateTracker; import android.net.NetworkConfig; @@ -68,6 +70,7 @@ import android.net.NetworkUtils; import android.net.Proxy; import android.net.ProxyProperties; import android.net.RouteInfo; +import android.net.SamplingDataTracker; import android.net.Uri; import android.net.wifi.WifiStateTracker; import android.net.wimax.WimaxManagerConstants; @@ -144,8 +147,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.GregorianCalendar; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; @@ -174,6 +179,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final String FAIL_FAST_TIME_MS = "persist.radio.fail_fast_time_ms"; + private static final String ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED = + "android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED"; + + private static final int SAMPLE_INTERVAL_ELAPSED_REQURST_CODE = 0; + + private PendingIntent mSampleIntervalElapsedIntent; + + // Set network sampling interval at 12 minutes, this way, even if the timers get + // aggregated, it will fire at around 15 minutes, which should allow us to + // aggregate this timer with other timers (specially the socket keep alive timers) + private static final int DEFAULT_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 12 * 60); + + // start network sampling a minute after booting ... + private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 60); + + AlarmManager mAlarmManager; + // used in recursive route setting to add gateways for the host for which // a host route was requested. private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10; @@ -326,6 +348,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14; + /** + * user internally to indicate that data sampling interval is up + */ + private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15; + /** Handler used for internal events. */ private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ @@ -392,6 +419,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { List mProtectedNetworks; private DataConnectionStats mDataConnectionStats; + private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0); TelephonyManager mTelephonyManager; @@ -634,6 +662,29 @@ public class ConnectivityService extends IConnectivityManager.Stub { mDataConnectionStats = new DataConnectionStats(mContext); mDataConnectionStats.startMonitoring(); + // start network sampling .. + Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED, null); + mSampleIntervalElapsedIntent = PendingIntent.getBroadcast(mContext, + SAMPLE_INTERVAL_ELAPSED_REQURST_CODE, intent, 0); + + mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); + setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent); + + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED); + mContext.registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED)) { + mHandler.sendMessage(mHandler.obtainMessage + (EVENT_SAMPLE_INTERVAL_ELAPSED)); + } + } + }, + new IntentFilter(filter)); + mPacManager = new PacManager(mContext); } @@ -1911,6 +1962,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // if (mActiveDefaultNetwork != -1) { // currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority; // } + for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) { if (checkType == prevNetType) continue; if (mNetConfigs[checkType] == null) continue; @@ -1925,6 +1977,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // optimization should work and we need to investigate why it doesn't work. // This could be related to how DEACTIVATE_DATA_CALL is reporting its // complete before it is really complete. + // if (!mNetTrackers[checkType].isAvailable()) continue; // if (currentPriority >= mNetConfigs[checkType].mPriority) continue; @@ -2520,12 +2573,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { } - /** + /** * Reads the network specific TCP buffer sizes from SystemProperties * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system * wide use */ - private void updateNetworkSettings(NetworkStateTracker nt) { + private void updateNetworkSettings(NetworkStateTracker nt) { String key = nt.getTcpBufferSizesPropName(); String bufferSizes = key == null ? null : SystemProperties.get(key); @@ -2547,7 +2600,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - /** + /** * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max] * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem * @@ -2956,6 +3009,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { + " != tag:" + tag); } } + case EVENT_SAMPLE_INTERVAL_ELAPSED: + handleNetworkSamplingTimeout(); + break; } } } @@ -4371,4 +4427,92 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } }; + + @Override + public LinkInfo getLinkInfo(int networkType) { + enforceAccessPermission(); + if (isNetworkTypeValid(networkType)) { + return mNetTrackers[networkType].getLinkInfo(); + } else { + return null; + } + } + + @Override + public LinkInfo getActiveLinkInfo() { + enforceAccessPermission(); + if (isNetworkTypeValid(mActiveDefaultNetwork)) { + return mNetTrackers[mActiveDefaultNetwork].getLinkInfo(); + } else { + return null; + } + } + + @Override + public LinkInfo[] getAllLinkInfo() { + enforceAccessPermission(); + final ArrayList result = Lists.newArrayList(); + for (NetworkStateTracker tracker : mNetTrackers) { + if (tracker != null) { + LinkInfo li = tracker.getLinkInfo(); + if (li != null) { + result.add(li); + } + } + } + + return result.toArray(new LinkInfo[result.size()]); + } + + /* Infrastructure for network sampling */ + + private void handleNetworkSamplingTimeout() { + + log("Sampling interval elapsed, updating statistics .."); + + // initialize list of interfaces .. + Map mapIfaceToSample = + new HashMap(); + for (NetworkStateTracker tracker : mNetTrackers) { + if (tracker != null) { + String ifaceName = tracker.getNetworkInterfaceName(); + if (ifaceName != null) { + mapIfaceToSample.put(ifaceName, null); + } + } + } + + // Read samples for all interfaces + SamplingDataTracker.getSamplingSnapshots(mapIfaceToSample); + + // process samples for all networks + for (NetworkStateTracker tracker : mNetTrackers) { + if (tracker != null) { + String ifaceName = tracker.getNetworkInterfaceName(); + SamplingDataTracker.SamplingSnapshot ss = mapIfaceToSample.get(ifaceName); + if (ss != null) { + // end the previous sampling cycle + tracker.stopSampling(ss); + // start a new sampling cycle .. + tracker.startSampling(ss); + } + } + } + + log("Done."); + + int samplingIntervalInSeconds = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS, + DEFAULT_SAMPLING_INTERVAL_IN_SECONDS); + + if (DBG) log("Setting timer for " + String.valueOf(samplingIntervalInSeconds) + "seconds"); + + setAlarm(samplingIntervalInSeconds * 1000, mSampleIntervalElapsedIntent); + } + + void setAlarm(int timeoutInMilliseconds, PendingIntent intent) { + long wakeupTime = SystemClock.elapsedRealtime() + timeoutInMilliseconds; + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent); + } } + From 2337946b4f5f072a0d404183860365ce87a98bd2 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 20 Aug 2013 22:51:24 +0900 Subject: [PATCH 42/71] Add a simple test for NetworkManagementService. For now, this only tests network observers. It works by starting NetworkManagementService with a fake netd socket, feeding it inputs, and seeing if the appropriate observer methods are called. Bug: 10232006 Change-Id: I827681575642a4ee13ae48b81272521544b676bd --- .../server/NetworkManagementServiceTest.java | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java new file mode 100644 index 0000000000..56dd7c40df --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.content.Context; +import android.net.LocalSocket; +import android.net.LocalServerSocket; +import android.os.Binder; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import com.android.server.net.BaseNetworkObserver; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Tests for {@link NetworkManagementService}. + */ +@LargeTest +public class NetworkManagementServiceTest extends AndroidTestCase { + + private static final String SOCKET_NAME = "__test__NetworkManagementServiceTest"; + private NetworkManagementService mNMService; + private LocalServerSocket mServerSocket; + private LocalSocket mSocket; + private OutputStream mOutputStream; + + @Override + public void setUp() throws Exception { + super.setUp(); + // TODO: make this unnecessary. runtest might already make it unnecessary. + System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); + + // Set up a sheltered test environment. + BroadcastInterceptingContext context = new BroadcastInterceptingContext(getContext()); + mServerSocket = new LocalServerSocket(SOCKET_NAME); + + // Start the service and wait until it connects to our socket. + mNMService = NetworkManagementService.create(context, SOCKET_NAME); + mSocket = mServerSocket.accept(); + mOutputStream = mSocket.getOutputStream(); + } + + @Override + public void tearDown() throws Exception { + if (mSocket != null) mSocket.close(); + if (mServerSocket != null) mServerSocket.close(); + super.tearDown(); + } + + /** + * Sends a message on the netd socket and gives the events some time to make it back. + */ + private void sendMessage(String message) throws IOException { + // Strings are null-terminated, so add "\0" at the end. + mOutputStream.write((message + "\0").getBytes()); + } + + private static T expectSoon(T mock) { + return verify(mock, timeout(100)); + } + + /** + * Tests that network observers work properly. + */ + public void testNetworkObservers() throws Exception { + BaseNetworkObserver observer = mock(BaseNetworkObserver.class); + doReturn(new Binder()).when(observer).asBinder(); // Used by registerObserver. + mNMService.registerObserver(observer); + + // Forget everything that happened to the mock so far, so we can explicitly verify + // everything that happens and does not happen to it from now on. + reset(observer); + + // Now send NetworkManagementService messages and ensure that the observer methods are + // called. After every valid message we expect a callback soon after; to ensure that + // invalid messages don't cause any callbacks, we call verifyNoMoreInteractions at the end. + + /** + * Interface changes. + */ + sendMessage("600 Iface added rmnet12"); + expectSoon(observer).interfaceAdded("rmnet12"); + + sendMessage("600 Iface removed eth1"); + expectSoon(observer).interfaceRemoved("eth1"); + + sendMessage("607 Iface removed eth1"); + // Invalid code. + + sendMessage("600 Iface borked lo down"); + // Invalid event. + + sendMessage("600 Iface changed clat4 up again"); + // Extra tokens. + + sendMessage("600 Iface changed clat4 up"); + expectSoon(observer).interfaceStatusChanged("clat4", true); + + sendMessage("600 Iface linkstate rmnet0 down"); + expectSoon(observer).interfaceLinkStateChanged("rmnet0", false); + + sendMessage("600 IFACE linkstate clat4 up"); + // Invalid group. + + /** + * Bandwidth control events. + */ + sendMessage("601 limit alert data rmnet_usb0"); + expectSoon(observer).limitReached("data", "rmnet_usb0"); + + sendMessage("601 invalid alert data rmnet0"); + // Invalid group. + + sendMessage("601 limit increased data rmnet0"); + // Invalid event. + + + /** + * Interface class activity. + */ + sendMessage("613 IfaceClass active rmnet0"); + expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", true); + + sendMessage("613 IfaceClass idle eth0"); + expectSoon(observer).interfaceClassDataActivityChanged("eth0", false); + + sendMessage("613 IfaceClass reallyactive rmnet0"); + expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", false); + + sendMessage("613 InterfaceClass reallyactive rmnet0"); + // Invalid group. + + + /** + * IP address changes. + */ + sendMessage("614 Address updated fe80::1/64 wlan0 128 253"); + expectSoon(observer).addressUpdated("fe80::1/64", "wlan0", 128, 253); + + // There is no "added". + sendMessage("614 Address added fe80::1/64 wlan0 128 253"); + expectSoon(observer).addressRemoved("fe80::1/64", "wlan0", 128, 253); + + sendMessage("614 Address removed 2001:db8::1/64 wlan0 1 0"); + expectSoon(observer).addressRemoved("2001:db8::1/64", "wlan0", 1, 0); + + sendMessage("666 Address added 2001:db8::1/64 wlan0 1 0"); + // Invalid code. + + // Make sure nothing else was called. + verifyNoMoreInteractions(observer); + } +} From 01a790ad556662f09097ab59462c66e0fa6a6185 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Tue, 27 Aug 2013 10:51:24 -0400 Subject: [PATCH 43/71] Don't clear Global Proxy on boot. Doesn't clear the global proxy when a deprecated one is not found because there still may be a non-deprecated global proxy present. Bug: 10457179 Change-Id: I68e6d5aee7b4940f9315484060c7d82cb8ccfa70 --- services/java/com/android/server/ConnectivityService.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index ec6b063e82..136a85e0af 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3355,8 +3355,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } ProxyProperties p = new ProxyProperties(data[0], proxyPort, ""); setGlobalProxy(p); - } else { - setGlobalProxy(null); } } From 1b5a3acb8b1f303f14a330aa2a0616fb1612178e Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Tue, 27 Aug 2013 11:41:19 -0700 Subject: [PATCH 44/71] Minor fixes: Add a missing "break" and some cosmetic fixes. Change-Id: Ie614a7b47185fd511fdc3f064620e46ab7d6d8f8 --- .../android/server/ConnectivityService.java | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index ec6b063e82..5e0ee151ea 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -182,7 +182,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final String ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED = "android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED"; - private static final int SAMPLE_INTERVAL_ELAPSED_REQURST_CODE = 0; + private static final int SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE = 0; private PendingIntent mSampleIntervalElapsedIntent; @@ -665,7 +665,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // start network sampling .. Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED, null); mSampleIntervalElapsedIntent = PendingIntent.getBroadcast(mContext, - SAMPLE_INTERVAL_ELAPSED_REQURST_CODE, intent, 0); + SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE, intent, 0); mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent); @@ -2924,7 +2924,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { - case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: + case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: { String causedBy = null; synchronized (ConnectivityService.this) { if (msg.arg1 == mNetTransitionWakeLockSerialNumber && @@ -2937,49 +2937,44 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("NetTransition Wakelock for " + causedBy + " released by timeout"); } break; - case EVENT_RESTORE_DEFAULT_NETWORK: + } + case EVENT_RESTORE_DEFAULT_NETWORK: { FeatureUser u = (FeatureUser)msg.obj; u.expire(); break; - case EVENT_INET_CONDITION_CHANGE: - { + } + case EVENT_INET_CONDITION_CHANGE: { int netType = msg.arg1; int condition = msg.arg2; handleInetConditionChange(netType, condition); break; } - case EVENT_INET_CONDITION_HOLD_END: - { + case EVENT_INET_CONDITION_HOLD_END: { int netType = msg.arg1; int sequence = msg.arg2; handleInetConditionHoldEnd(netType, sequence); break; } - case EVENT_SET_NETWORK_PREFERENCE: - { + case EVENT_SET_NETWORK_PREFERENCE: { int preference = msg.arg1; handleSetNetworkPreference(preference); break; } - case EVENT_SET_MOBILE_DATA: - { + case EVENT_SET_MOBILE_DATA: { boolean enabled = (msg.arg1 == ENABLED); handleSetMobileData(enabled); break; } - case EVENT_APPLY_GLOBAL_HTTP_PROXY: - { + case EVENT_APPLY_GLOBAL_HTTP_PROXY: { handleDeprecatedGlobalHttpProxy(); break; } - case EVENT_SET_DEPENDENCY_MET: - { + case EVENT_SET_DEPENDENCY_MET: { boolean met = (msg.arg1 == ENABLED); handleSetDependencyMet(msg.arg2, met); break; } - case EVENT_SEND_STICKY_BROADCAST_INTENT: - { + case EVENT_SEND_STICKY_BROADCAST_INTENT: { Intent intent = (Intent)msg.obj; sendStickyBroadcast(intent); break; @@ -3008,10 +3003,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: stale arg1:" + msg.arg1 + " != tag:" + tag); } + break; } - case EVENT_SAMPLE_INTERVAL_ELAPSED: + case EVENT_SAMPLE_INTERVAL_ELAPSED: { handleNetworkSamplingTimeout(); break; + } } } } From 9a1a7ef57c704f58aac2f8c7c546e0b9d1b53dcc Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Thu, 29 Aug 2013 08:55:16 -0700 Subject: [PATCH 45/71] Add support for handling mobile provisioning networks. When a sim is new or it has expired it needs to be provisioned with the carrier. Basically provisioning is associating a sim with a user account. When a sim isn't provisioned then operators will restrict access to the network and only allow certain addresses or services to be used. This set of changes allows two types of provisioning networks to be recognized. The first is a network that causes all DNS lookups to be redirected to a different address than was intended. This is exemplified by how T-Mobile works. The second technique uses a special apn for provisioning. An example is AT&T where lwaactivate is the provisioning apn and broadband is the normal apn. We first try broadband and if we are unable to connect we try lwaactivate. When we see the activate we identify it as special and the ApnContext.isProvisioningApn will return true. In the future our plan is to create a new network type that can be added to the apn list, but for now it identified by name. Here is a list of significant changes: - CaptivePortalTracker now only test WiFi networks instead of all networks - checkMobileProvisioning checks for provisioning networks and doesn't try to ping. - IConnectivityManager.aidl changes: * getProvisioningOrActiveNetworkInfo was added to and used by Manage mobile plan in WirelessSettings so even when there is no active network it will still allow provisioning. Otherwise it would report no internet connection. * setSignInErrorNotificationVisible is used by both CaptiviePortalTracker and checkMobileProvisioning so they use the same code for the notifications. * checkMobileProvisioning was simplified to have only a timeout as returning the result is now harder as we abort simultaneous call otherwise we'd could get into loops because we now check every time we connect to mobile. - Enhanced MDST to handle the provisioning network. - Added CONNECTED_TO_PROVISIONING_NETWORK to NetworkInfo to make a new state so we don't announce to the world we're connected. - TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN is sent by the low level data connection code to notify Connectivity Service that a provisioning apn has connected. This allows CS to handle the connection differently than a normal connection. Bug: 10328264 Change-Id: I3925004011bb1243793c4c1b963d923dc2b00cb5 --- .../java/android/net/ConnectivityManager.java | 89 ++-- .../android/net/IConnectivityManager.aidl | 6 +- core/java/android/net/NetworkInfo.java | 7 + .../android/server/ConnectivityService.java | 451 ++++++++++++++---- 4 files changed, 410 insertions(+), 143 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index aa2d4ce92e..02a649401f 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -582,6 +582,29 @@ public class ConnectivityManager { } } + /** + * Returns details about the Provisioning or currently active default data network. When + * connected, this network is the default route for outgoing connections. + * You should always check {@link NetworkInfo#isConnected()} before initiating + * network traffic. This may return {@code null} when there is no default + * network. + * + * @return a {@link NetworkInfo} object for the current default network + * or {@code null} if no network default network is currently active + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * + * {@hide} + */ + public NetworkInfo getProvisioningOrActiveNetworkInfo() { + try { + return mService.getProvisioningOrActiveNetworkInfo(); + } catch (RemoteException e) { + return null; + } + } + /** * Returns the IP information for the current default network. * @@ -1316,63 +1339,19 @@ public class ConnectivityManager { } /** - * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE) - */ - - /** - * No connection was possible to the network. - * {@hide} - */ - public static final int CMP_RESULT_CODE_NO_CONNECTION = 0; - - /** - * A connection was made to the internet, all is well. - * {@hide} - */ - public static final int CMP_RESULT_CODE_CONNECTABLE = 1; - - /** - * A connection was made but there was a redirection, we appear to be in walled garden. - * This is an indication of a warm sim on a mobile network. - * {@hide} - */ - public static final int CMP_RESULT_CODE_REDIRECTED = 2; - - /** - * A connection was made but no dns server was available to resolve a name to address. - * This is an indication of a warm sim on a mobile network. + * Check mobile provisioning. * - * {@hide} - */ - public static final int CMP_RESULT_CODE_NO_DNS = 3; - - /** - * A connection was made but could not open a TCP connection. - * This is an indication of a warm sim on a mobile network. - * {@hide} - */ - public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4; - - /** - * Check mobile provisioning. The resultCode passed to - * onReceiveResult will be one of the CMP_RESULT_CODE_xxxx values above. - * This may take a minute or more to complete. - * - * @param sendNotificaiton, when true a notification will be sent to user. * @param suggestedTimeOutMs, timeout in milliseconds - * @param resultReceiver needs to be supplied to receive the result * * @return time out that will be used, maybe less that suggestedTimeOutMs * -1 if an error. * * {@hide} */ - public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, - ResultReceiver resultReceiver) { + public int checkMobileProvisioning(int suggestedTimeOutMs) { int timeOutMs = -1; try { - timeOutMs = mService.checkMobileProvisioning(sendNotification, suggestedTimeOutMs, - resultReceiver); + timeOutMs = mService.checkMobileProvisioning(suggestedTimeOutMs); } catch (RemoteException e) { } return timeOutMs; @@ -1401,4 +1380,20 @@ public class ConnectivityManager { } return null; } + + /** + * Set sign in error notification to visible or in visible + * + * @param visible + * @param networkType + * + * {@hide} + */ + public void setProvisioningNotificationVisible(boolean visible, int networkType, + String extraInfo, String url) { + try { + mService.setProvisioningNotificationVisible(visible, networkType, extraInfo, url); + } catch (RemoteException e) { + } + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 3ac5f1367f..a17b4f5f95 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -46,6 +46,8 @@ interface IConnectivityManager NetworkInfo getNetworkInfo(int networkType); NetworkInfo[] getAllNetworkInfo(); + NetworkInfo getProvisioningOrActiveNetworkInfo(); + boolean isNetworkSupported(int networkType); LinkProperties getActiveLinkProperties(); @@ -135,9 +137,11 @@ interface IConnectivityManager int findConnectionTypeForIface(in String iface); - int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver); + int checkMobileProvisioning(int suggestedTimeOutMs); String getMobileProvisioningUrl(); String getMobileRedirectedProvisioningUrl(); + + void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url); } diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 689dae5301..dabc73a716 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -84,6 +84,12 @@ public class NetworkInfo implements Parcelable { VERIFYING_POOR_LINK, /** Checking if network is a captive portal */ CAPTIVE_PORTAL_CHECK, + /** + * Network is connected to provisioning network + * TODO: Probably not needed when we add TYPE_PROVISIONING_NETWORK + * @hide + */ + CONNECTED_TO_PROVISIONING_NETWORK } /** @@ -108,6 +114,7 @@ public class NetworkInfo implements Parcelable { stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED); stateMap.put(DetailedState.FAILED, State.DISCONNECTED); stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED); + stateMap.put(DetailedState.CONNECTED_TO_PROVISIONING_NETWORK, State.CONNECTED); } private int mNetworkType; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 06708191d9..ee23b13d3f 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -35,6 +35,7 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.bluetooth.BluetoothTetheringDataTracker; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -143,6 +144,7 @@ import java.util.GregorianCalendar; import java.util.HashSet; import java.util.List; import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** @@ -383,9 +385,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { TelephonyManager mTelephonyManager; - // We only want one checkMobileProvisioning after booting. - volatile boolean mFirstProvisioningCheckStarted = false; - public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -609,8 +608,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY); mSettingsObserver.observe(mContext); - mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); - loadGlobalProxy(); + IntentFilter filter = new IntentFilter(); + filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); + mContext.registerReceiver(mProvisioningReceiver, filter); } /** @@ -879,6 +879,46 @@ public class ConnectivityService extends IConnectivityManager.Stub { return getNetworkInfo(mActiveDefaultNetwork, uid); } + /** + * Find the first Provisioning network. + * + * @return NetworkInfo or null if none. + */ + private NetworkInfo getProvisioningNetworkInfo() { + enforceAccessPermission(); + + // Find the first Provisioning Network + NetworkInfo provNi = null; + for (NetworkInfo ni : getAllNetworkInfo()) { + if (ni.getDetailedState() + == NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + provNi = ni; + break; + } + } + if (DBG) log("getProvisioningNetworkInfo: X provNi=" + provNi); + return provNi; + } + + /** + * Find the first Provisioning network or the ActiveDefaultNetwork + * if there is no Provisioning network + * + * @return NetworkInfo or null if none. + */ + @Override + public NetworkInfo getProvisioningOrActiveNetworkInfo() { + enforceAccessPermission(); + + NetworkInfo provNi = getProvisioningNetworkInfo(); + if (provNi == null) { + final int uid = Binder.getCallingUid(); + provNi = getNetworkInfo(mActiveDefaultNetwork, uid); + } + if (DBG) log("getProvisioningOrActiveNetworkInfo: X provNi=" + provNi); + return provNi; + } + public NetworkInfo getActiveNetworkInfoUnfiltered() { enforceAccessPermission(); if (isNetworkTypeValid(mActiveDefaultNetwork)) { @@ -1241,8 +1281,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { feature); } if (network.reconnect()) { + if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_STARTED"); return PhoneConstants.APN_REQUEST_STARTED; } else { + if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_FAILED"); return PhoneConstants.APN_REQUEST_FAILED; } } else { @@ -1254,9 +1296,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetRequestersPids[usedNetworkType].add(currentPid); } } + if (DBG) log("startUsingNetworkFeature X: return -1 unsupported feature."); return -1; } } + if (DBG) log("startUsingNetworkFeature X: return APN_TYPE_NOT_AVAILABLE"); return PhoneConstants.APN_TYPE_NOT_AVAILABLE; } finally { if (DBG) { @@ -1290,11 +1334,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } if (found && u != null) { + if (VDBG) log("stopUsingNetworkFeature: X"); // stop regardless of how many other time this proc had called start return stopUsingNetworkFeature(u, true); } else { // none found! - if (VDBG) log("stopUsingNetworkFeature - not a live request, ignoring"); + if (VDBG) log("stopUsingNetworkFeature: X not a live request, ignoring"); return 1; } } @@ -1849,6 +1894,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ if (mNetConfigs[prevNetType].isDefault()) { if (mActiveDefaultNetwork == prevNetType) { + if (DBG) { + log("tryFailover: set mActiveDefaultNetwork=-1, prevNetType=" + prevNetType); + } mActiveDefaultNetwork = -1; } @@ -2041,6 +2089,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } void systemReady() { + mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); + loadGlobalProxy(); + synchronized(this) { mSystemReady = true; if (mInitialBroadcast != null) { @@ -2071,10 +2122,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { }; private boolean isNewNetTypePreferredOverCurrentNetType(int type) { - if ((type != mNetworkPreference && - mNetConfigs[mActiveDefaultNetwork].priority > - mNetConfigs[type].priority) || - mNetworkPreference == mActiveDefaultNetwork) return false; + if (((type != mNetworkPreference) + && (mNetConfigs[mActiveDefaultNetwork].priority > mNetConfigs[type].priority)) + || (mNetworkPreference == mActiveDefaultNetwork)) { + return false; + } return true; } @@ -2088,6 +2140,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { final NetworkStateTracker thisNet = mNetTrackers[newNetType]; final String thisIface = thisNet.getLinkProperties().getInterfaceName(); + if (VDBG) { + log("handleConnect: E newNetType=" + newNetType + " thisIface=" + thisIface + + " isFailover" + isFailover); + } + // if this is a default net and other default is running // kill the one not preferred if (mNetConfigs[newNetType].isDefault()) { @@ -2249,6 +2306,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private void handleConnectivityChange(int netType, boolean doReset) { int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0; + if (VDBG) { + log("handleConnectivityChange: netType=" + netType + " doReset=" + doReset + + " resetMask=" + resetMask); + } /* * If a non-default network is enabled, add the host routes that @@ -2316,7 +2377,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault()); if (resetMask != 0 || resetDns) { + if (VDBG) log("handleConnectivityChange: resetting"); if (curLp != null) { + if (VDBG) log("handleConnectivityChange: resetting curLp=" + curLp); for (String iface : curLp.getAllInterfaceNames()) { if (TextUtils.isEmpty(iface) == false) { if (resetMask != 0) { @@ -2349,6 +2412,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Update 464xlat state. NetworkStateTracker tracker = mNetTrackers[netType]; if (mClat.requiresClat(netType, tracker)) { + // If the connection was previously using clat, but is not using it now, stop the clat // daemon. Normally, this happens automatically when the connection disconnects, but if // the disconnect is not reported, or if the connection's LinkProperties changed for @@ -2402,6 +2466,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { for (RouteInfo r : routeDiff.removed) { if (isLinkDefault || ! r.isDefaultRoute()) { + if (VDBG) log("updateRoutes: default remove route r=" + r); removeRoute(curLp, r, TO_DEFAULT_TABLE); } if (isLinkDefault == false) { @@ -2446,7 +2511,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { // 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) { @@ -2736,9 +2800,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { - case NetworkStateTracker.EVENT_STATE_CHANGED: + case NetworkStateTracker.EVENT_STATE_CHANGED: { info = (NetworkInfo) msg.obj; - int type = info.getType(); NetworkInfo.State state = info.getState(); if (VDBG || (state == NetworkInfo.State.CONNECTED) || @@ -2748,15 +2811,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { state + "/" + info.getDetailedState()); } - // After booting we'll check once for mobile provisioning - // if we've provisioned by and connected. - if (!mFirstProvisioningCheckStarted + // Since mobile has the notion of a network/apn that can be used for + // provisioning we need to check every time we're connected as + // CaptiveProtalTracker won't detected it because DCT doesn't report it + // as connected as ACTION_ANY_DATA_CONNECTION_STATE_CHANGED instead its + // reported as ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN. Which + // is received by MDST and sent here as EVENT_STATE_CHANGED. + if (ConnectivityManager.isNetworkTypeMobile(info.getType()) && (0 != Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0)) && (state == NetworkInfo.State.CONNECTED)) { - log("check provisioning after booting"); - mFirstProvisioningCheckStarted = true; - checkMobileProvisioning(true, CheckMp.MAX_TIMEOUT_MS, null); + checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS); } EventLogTags.writeConnectivityStateChanged( @@ -2768,6 +2833,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else if (info.getDetailedState() == DetailedState.CAPTIVE_PORTAL_CHECK) { handleCaptivePortalTrackerCheck(info); + } else if (info.getDetailedState() == + DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + /** + * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING + * for now its an in between network, its a network that + * is actually a default network but we don't want it to be + * announced as such to keep background applications from + * trying to use it. It turns out that some still try so we + * take the additional step of clearing any default routes + * to the link that may have incorrectly setup by the lower + * levels. + */ + LinkProperties lp = getLinkProperties(info.getType()); + if (DBG) { + log("EVENT_STATE_CHANGED: connected to provisioning network, lp=" + lp); + } + + // Clear any default routes setup by the radio so + // any activity by applications trying to use this + // connection will fail until the provisioning network + // is enabled. + for (RouteInfo r : lp.getRoutes()) { + removeRoute(lp, r, TO_DEFAULT_TABLE); + } } else if (state == NetworkInfo.State.DISCONNECTED) { handleDisconnect(info); } else if (state == NetworkInfo.State.SUSPENDED) { @@ -2786,18 +2875,21 @@ public class ConnectivityService extends IConnectivityManager.Stub { mLockdownTracker.onNetworkInfoChanged(info); } break; - case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: + } + case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: { info = (NetworkInfo) msg.obj; // TODO: Temporary allowing network configuration // change not resetting sockets. // @see bug/4455071 handleConnectivityChange(info.getType(), false); break; - case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: + } + case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: { info = (NetworkInfo) msg.obj; - type = info.getType(); + int type = info.getType(); updateNetworkSettings(mNetTrackers[type]); break; + } } } } @@ -3574,76 +3666,151 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean isMobileDataStateTrackerReady() { MobileDataStateTracker mdst = - (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; return (mdst != null) && (mdst.isReady()); } + /** + * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE) + */ + + /** + * No connection was possible to the network. + */ + public static final int CMP_RESULT_CODE_NO_CONNECTION = 0; + + /** + * A connection was made to the internet, all is well. + */ + public static final int CMP_RESULT_CODE_CONNECTABLE = 1; + + /** + * A connection was made but there was a redirection, we appear to be in walled garden. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_REDIRECTED = 2; + + /** + * A connection was made but no dns server was available to resolve a name to address. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_NO_DNS = 3; + + /** + * A connection was made but could not open a TCP connection. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4; + + /** + * The mobile network is a provisioning network. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5; + + AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false); + @Override - public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, - final ResultReceiver resultReceiver) { - log("checkMobileProvisioning: E sendNotification=" + sendNotification - + " suggestedTimeOutMs=" + suggestedTimeOutMs - + " resultReceiver=" + resultReceiver); - enforceChangePermission(); - - mFirstProvisioningCheckStarted = true; - - int timeOutMs = suggestedTimeOutMs; - if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { - timeOutMs = CheckMp.MAX_TIMEOUT_MS; - } - - // Check that mobile networks are supported - if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) - || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { - log("checkMobileProvisioning: X no mobile network"); - if (resultReceiver != null) { - resultReceiver.send(ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION, null); - } - return timeOutMs; - } + public int checkMobileProvisioning(int suggestedTimeOutMs) { + int timeOutMs = -1; + if (DBG) log("checkMobileProvisioning: E suggestedTimeOutMs=" + suggestedTimeOutMs); + enforceConnectivityInternalPermission(); final long token = Binder.clearCallingIdentity(); try { + timeOutMs = suggestedTimeOutMs; + if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { + timeOutMs = CheckMp.MAX_TIMEOUT_MS; + } + + // Check that mobile networks are supported + if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) + || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { + if (DBG) log("checkMobileProvisioning: X no mobile network"); + return timeOutMs; + } + + // If we're already checking don't do it again + // TODO: Add a queue of results... + if (mIsCheckingMobileProvisioning.getAndSet(true)) { + if (DBG) log("checkMobileProvisioning: X already checking ignore for the moment"); + return timeOutMs; + } + + // Start off with notification off + setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); + + // See if we've alreadying determined if we've got a provsioning connection + // if so we don't need to do anything active + MobileDataStateTracker mdstDefault = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork(); + + MobileDataStateTracker mdstHipri = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork(); + + if (isDefaultProvisioning || isHipriProvisioning) { + if (mIsNotificationVisible) { + if (DBG) { + log("checkMobileProvisioning: provisioning-ignore notification is visible"); + } + } else { + NetworkInfo ni = null; + if (isDefaultProvisioning) { + ni = mdstDefault.getNetworkInfo(); + } + if (isHipriProvisioning) { + ni = mdstHipri.getNetworkInfo(); + } + String url = getMobileProvisioningUrl(); + if ((ni != null) && (!TextUtils.isEmpty(url))) { + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), url); + } else { + if (DBG) log("checkMobileProvisioning: provisioning but no url, ignore"); + } + } + mIsCheckingMobileProvisioning.set(false); + return timeOutMs; + } + CheckMp checkMp = new CheckMp(mContext, this); CheckMp.CallBack cb = new CheckMp.CallBack() { @Override void onComplete(Integer result) { - log("CheckMp.onComplete: result=" + result); - if (resultReceiver != null) { - log("CheckMp.onComplete: send result"); - resultReceiver.send(result, null); - } + if (DBG) log("CheckMp.onComplete: result=" + result); NetworkInfo ni = mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo(); switch(result) { - case ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE: - case ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION: { - log("CheckMp.onComplete: ignore, connected or no connection"); + case CMP_RESULT_CODE_CONNECTABLE: + case CMP_RESULT_CODE_NO_CONNECTION: { + if (DBG) log("CheckMp.onComplete: ignore, connected or no connection"); break; } - case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: { - log("CheckMp.onComplete: warm sim"); + case CMP_RESULT_CODE_REDIRECTED: { + if (DBG) log("CheckMp.onComplete: warm sim"); String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url)) { url = getMobileRedirectedProvisioningUrl(); } if (TextUtils.isEmpty(url) == false) { - log("CheckMp.onComplete: warm sim (redirected), url=" + url); - setNotificationVisible(true, ni, url); + if (DBG) log("CheckMp.onComplete: warm (redirected), url=" + url); + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), + url); } else { - log("CheckMp.onComplete: warm sim (redirected), no url"); + if (DBG) log("CheckMp.onComplete: warm (redirected), no url"); } break; } - case ConnectivityManager.CMP_RESULT_CODE_NO_DNS: - case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: { + case CMP_RESULT_CODE_NO_DNS: + case CMP_RESULT_CODE_NO_TCP_CONNECTION: { String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url) == false) { - log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url); - setNotificationVisible(true, ni, url); + if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), url=" + url); + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), + url); } else { - log("CheckMp.onComplete: warm sim (no dns/tcp), no url"); + if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url"); } break; } @@ -3652,16 +3819,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } } + mIsCheckingMobileProvisioning.set(false); } }; CheckMp.Params params = new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb); - log("checkMobileProvisioning: params=" + params); - setNotificationVisible(false, null, null); + if (DBG) log("checkMobileProvisioning: params=" + params); checkMp.execute(params); } finally { Binder.restoreCallingIdentity(token); - log("checkMobileProvisioning: X"); + if (DBG) log("checkMobileProvisioning: X"); } return timeOutMs; } @@ -3733,14 +3900,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { * a known address that fetches the data we expect. */ private synchronized Integer isMobileOk(Params params) { - Integer result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + Integer result = CMP_RESULT_CODE_NO_CONNECTION; Uri orgUri = Uri.parse(params.mUrl); Random rand = new Random(); mParams = params; if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { log("isMobileOk: not mobile capable"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; return result; } @@ -3776,7 +3943,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } if (VDBG) log("isMobileOk: hipri not started yet"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; sleep(1); } @@ -3789,15 +3956,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo.State state = mCs .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); if (state != NetworkInfo.State.CONNECTED) { - if (VDBG) { + if (true/*VDBG*/) { log("isMobileOk: not connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); } sleep(1); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; continue; } + // Hipri has started check if this is a provisioning url + MobileDataStateTracker mdst = (MobileDataStateTracker) + mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + if (mdst.isProvisioningNetwork()) { + if (DBG) log("isMobileOk: isProvisioningNetwork is true, no TCP conn"); + result = CMP_RESULT_CODE_NO_TCP_CONNECTION; + return result; + } else { + if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue"); + } + // Get of the addresses associated with the url host. We need to use the // address otherwise HttpURLConnection object will use the name to get // the addresses and is will try every address but that will bypass the @@ -3808,7 +3986,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { addresses = InetAddress.getAllByName(orgUri.getHost()); } catch (UnknownHostException e) { log("isMobileOk: UnknownHostException"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_DNS; + result = CMP_RESULT_CODE_NO_DNS; return result; } log("isMobileOk: addresses=" + inetAddressesToString(addresses)); @@ -3873,9 +4051,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { urlConn.setRequestProperty("Connection", "close"); int responseCode = urlConn.getResponseCode(); if (responseCode == 204) { - result = ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE; + result = CMP_RESULT_CODE_CONNECTABLE; } else { - result = ConnectivityManager.CMP_RESULT_CODE_REDIRECTED; + result = CMP_RESULT_CODE_REDIRECTED; } log("isMobileOk: connected responseCode=" + responseCode); urlConn.disconnect(); @@ -3889,7 +4067,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } - result = ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION; + result = CMP_RESULT_CODE_NO_TCP_CONNECTION; log("isMobileOk: loops|timed out"); return result; } catch (Exception e) { @@ -3903,6 +4081,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { mCs.setEnableFailFastMobileData(DctConstants.DISABLED); mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_HIPRI); + + // Wait for hipri to disconnect. + long endTime = SystemClock.elapsedRealtime() + 5000; + + while(SystemClock.elapsedRealtime() < endTime) { + NetworkInfo.State state = mCs + .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); + if (state != NetworkInfo.State.DISCONNECTED) { + if (VDBG) { + log("isMobileOk: connected ni=" + + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); + } + sleep(1); + continue; + } + } + log("isMobileOk: X result=" + result); } return result; @@ -3982,10 +4177,55 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private static final String NOTIFICATION_ID = "CaptivePortal.Notification"; + // TODO: Move to ConnectivityManager and make public? + private static final String CONNECTED_TO_PROVISIONING_NETWORK_ACTION = + "com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION"; - private void setNotificationVisible(boolean visible, NetworkInfo networkInfo, String url) { - log("setNotificationVisible: E visible=" + visible + " ni=" + networkInfo + " url=" + url); + private BroadcastReceiver mProvisioningReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(CONNECTED_TO_PROVISIONING_NETWORK_ACTION)) { + handleMobileProvisioningAction(intent.getStringExtra("EXTRA_URL")); + } + } + }; + + private void handleMobileProvisioningAction(String url) { + // Notication mark notification as not visible + setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); + + // If provisioning network handle as a special case, + // otherwise launch browser with the intent directly. + NetworkInfo ni = getProvisioningNetworkInfo(); + if ((ni != null) && ni.getDetailedState() == + NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + if (DBG) log("handleMobileProvisioningAction: on provisioning network"); + MobileDataStateTracker mdst = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + mdst.enableMobileProvisioning(url); + } else { + if (DBG) log("handleMobileProvisioningAction: on default network"); + Intent newIntent = + new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mContext.startActivity(newIntent); + } catch (ActivityNotFoundException e) { + loge("handleMobileProvisioningAction: startActivity failed" + e); + } + } + } + + private static final String NOTIFICATION_ID = "CaptivePortal.Notification"; + private volatile boolean mIsNotificationVisible = false; + + private void setProvNotificationVisible(boolean visible, int networkType, String extraInfo, + String url) { + if (DBG) { + log("setProvNotificationVisible: E visible=" + visible + " networkType=" + networkType + + " extraInfo=" + extraInfo + " url=" + url); + } Resources r = Resources.getSystem(); NotificationManager notificationManager = (NotificationManager) mContext @@ -3995,50 +4235,64 @@ public class ConnectivityService extends IConnectivityManager.Stub { CharSequence title; CharSequence details; int icon; - switch (networkInfo.getType()) { + Intent intent; + Notification notification = new Notification(); + switch (networkType) { case ConnectivityManager.TYPE_WIFI: - log("setNotificationVisible: TYPE_WIFI"); title = r.getString(R.string.wifi_available_sign_in, 0); details = r.getString(R.string.network_available_sign_in_detailed, - networkInfo.getExtraInfo()); + extraInfo); icon = R.drawable.stat_notify_wifi_in_range; + intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); break; case ConnectivityManager.TYPE_MOBILE: case ConnectivityManager.TYPE_MOBILE_HIPRI: - log("setNotificationVisible: TYPE_MOBILE|HIPRI"); title = r.getString(R.string.network_available_sign_in, 0); // TODO: Change this to pull from NetworkInfo once a printable // name has been added to it details = mTelephonyManager.getNetworkOperatorName(); icon = R.drawable.stat_notify_rssi_in_range; + intent = new Intent(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); + intent.putExtra("EXTRA_URL", url); + intent.setFlags(0); + notification.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); break; default: - log("setNotificationVisible: other type=" + networkInfo.getType()); title = r.getString(R.string.network_available_sign_in, 0); details = r.getString(R.string.network_available_sign_in_detailed, - networkInfo.getExtraInfo()); + extraInfo); icon = R.drawable.stat_notify_rssi_in_range; + intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); break; } - Notification notification = new Notification(); notification.when = 0; notification.icon = icon; notification.flags = Notification.FLAG_AUTO_CANCEL; - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | - Intent.FLAG_ACTIVITY_NEW_TASK); - notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); notification.tickerText = title; notification.setLatestEventInfo(mContext, title, details, notification.contentIntent); - log("setNotificaitionVisible: notify notificaiton=" + notification); - notificationManager.notify(NOTIFICATION_ID, 1, notification); + try { + notificationManager.notify(NOTIFICATION_ID, 1, notification); + } catch (NullPointerException npe) { + loge("setNotificaitionVisible: visible notificationManager npe=" + npe); + npe.printStackTrace(); + } } else { - log("setNotificaitionVisible: cancel"); - notificationManager.cancel(NOTIFICATION_ID, 1); + try { + notificationManager.cancel(NOTIFICATION_ID, 1); + } catch (NullPointerException npe) { + loge("setNotificaitionVisible: cancel notificationManager npe=" + npe); + npe.printStackTrace(); + } } - log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url); + mIsNotificationVisible = visible; } /** Location to an updatable file listing carrier provisioning urls. @@ -4166,4 +4420,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { return url; } + + @Override + public void setProvisioningNotificationVisible(boolean visible, int networkType, + String extraInfo, String url) { + enforceConnectivityInternalPermission(); + setProvNotificationVisible(visible, networkType, extraInfo, url); + } } From 5fda0c1e0d3203ffb3708c664a2110b425d435a7 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Thu, 29 Aug 2013 14:57:08 -0700 Subject: [PATCH 46/71] Merge commit 'a37f06d7' into manualmerge * commit 'a37f06d7': Add support for handling mobile provisioning networks. Conflicts: core/java/android/net/CaptivePortalTracker.java core/java/android/net/ConnectivityManager.java core/java/android/net/IConnectivityManager.aidl core/java/android/net/MobileDataStateTracker.java core/res/AndroidManifest.xml services/java/com/android/server/ConnectivityService.java Change-Id: I3925004011bb1243793c4c1b963d923dc2b00cb5 --- .../java/android/net/ConnectivityManager.java | 89 ++-- .../android/net/IConnectivityManager.aidl | 5 +- core/java/android/net/NetworkInfo.java | 7 + .../android/server/ConnectivityService.java | 482 ++++++++++++++---- 4 files changed, 432 insertions(+), 151 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index f6a3a4a772..3874369fcc 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -623,6 +623,29 @@ public class ConnectivityManager { } } + /** + * Returns details about the Provisioning or currently active default data network. When + * connected, this network is the default route for outgoing connections. + * You should always check {@link NetworkInfo#isConnected()} before initiating + * network traffic. This may return {@code null} when there is no default + * network. + * + * @return a {@link NetworkInfo} object for the current default network + * or {@code null} if no network default network is currently active + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * + * {@hide} + */ + public NetworkInfo getProvisioningOrActiveNetworkInfo() { + try { + return mService.getProvisioningOrActiveNetworkInfo(); + } catch (RemoteException e) { + return null; + } + } + /** * Returns the IP information for the current default network. * @@ -1357,63 +1380,19 @@ public class ConnectivityManager { } /** - * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE) - */ - - /** - * No connection was possible to the network. - * {@hide} - */ - public static final int CMP_RESULT_CODE_NO_CONNECTION = 0; - - /** - * A connection was made to the internet, all is well. - * {@hide} - */ - public static final int CMP_RESULT_CODE_CONNECTABLE = 1; - - /** - * A connection was made but there was a redirection, we appear to be in walled garden. - * This is an indication of a warm sim on a mobile network. - * {@hide} - */ - public static final int CMP_RESULT_CODE_REDIRECTED = 2; - - /** - * A connection was made but no dns server was available to resolve a name to address. - * This is an indication of a warm sim on a mobile network. + * Check mobile provisioning. * - * {@hide} - */ - public static final int CMP_RESULT_CODE_NO_DNS = 3; - - /** - * A connection was made but could not open a TCP connection. - * This is an indication of a warm sim on a mobile network. - * {@hide} - */ - public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4; - - /** - * Check mobile provisioning. The resultCode passed to - * onReceiveResult will be one of the CMP_RESULT_CODE_xxxx values above. - * This may take a minute or more to complete. - * - * @param sendNotificaiton, when true a notification will be sent to user. * @param suggestedTimeOutMs, timeout in milliseconds - * @param resultReceiver needs to be supplied to receive the result * * @return time out that will be used, maybe less that suggestedTimeOutMs * -1 if an error. * * {@hide} */ - public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, - ResultReceiver resultReceiver) { + public int checkMobileProvisioning(int suggestedTimeOutMs) { int timeOutMs = -1; try { - timeOutMs = mService.checkMobileProvisioning(sendNotification, suggestedTimeOutMs, - resultReceiver); + timeOutMs = mService.checkMobileProvisioning(suggestedTimeOutMs); } catch (RemoteException e) { } return timeOutMs; @@ -1481,4 +1460,20 @@ public class ConnectivityManager { return null; } } + + /** + * Set sign in error notification to visible or in visible + * + * @param visible + * @param networkType + * + * {@hide} + */ + public void setProvisioningNotificationVisible(boolean visible, int networkType, + String extraInfo, String url) { + try { + mService.setProvisioningNotificationVisible(visible, networkType, extraInfo, url); + } catch (RemoteException e) { + } + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index bf2dade3bc..c07e900ba2 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -50,6 +50,8 @@ interface IConnectivityManager NetworkInfo getNetworkInfo(int networkType); NetworkInfo[] getAllNetworkInfo(); + NetworkInfo getProvisioningOrActiveNetworkInfo(); + boolean isNetworkSupported(int networkType); LinkProperties getActiveLinkProperties(); @@ -141,7 +143,7 @@ interface IConnectivityManager int findConnectionTypeForIface(in String iface); - int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver); + int checkMobileProvisioning(int suggestedTimeOutMs); String getMobileProvisioningUrl(); @@ -153,4 +155,5 @@ interface IConnectivityManager LinkInfo[] getAllLinkInfo(); + void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url); } diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 689dae5301..dabc73a716 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -84,6 +84,12 @@ public class NetworkInfo implements Parcelable { VERIFYING_POOR_LINK, /** Checking if network is a captive portal */ CAPTIVE_PORTAL_CHECK, + /** + * Network is connected to provisioning network + * TODO: Probably not needed when we add TYPE_PROVISIONING_NETWORK + * @hide + */ + CONNECTED_TO_PROVISIONING_NETWORK } /** @@ -108,6 +114,7 @@ public class NetworkInfo implements Parcelable { stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED); stateMap.put(DetailedState.FAILED, State.DISCONNECTED); stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED); + stateMap.put(DetailedState.CONNECTED_TO_PROVISIONING_NETWORK, State.CONNECTED); } private int mNetworkType; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 136a85e0af..9c146549a1 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -36,6 +36,7 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.bluetooth.BluetoothTetheringDataTracker; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -152,6 +153,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** @@ -424,9 +426,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { TelephonyManager mTelephonyManager; - // We only want one checkMobileProvisioning after booting. - volatile boolean mFirstProvisioningCheckStarted = false; - public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -656,9 +655,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY); mSettingsObserver.observe(mContext); - mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); - loadGlobalProxy(); - mDataConnectionStats = new DataConnectionStats(mContext); mDataConnectionStats.startMonitoring(); @@ -686,6 +682,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { new IntentFilter(filter)); mPacManager = new PacManager(mContext); + + filter = new IntentFilter(); + filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); + mContext.registerReceiver(mProvisioningReceiver, filter); } /** @@ -954,6 +954,46 @@ public class ConnectivityService extends IConnectivityManager.Stub { return getNetworkInfo(mActiveDefaultNetwork, uid); } + /** + * Find the first Provisioning network. + * + * @return NetworkInfo or null if none. + */ + private NetworkInfo getProvisioningNetworkInfo() { + enforceAccessPermission(); + + // Find the first Provisioning Network + NetworkInfo provNi = null; + for (NetworkInfo ni : getAllNetworkInfo()) { + if (ni.getDetailedState() + == NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + provNi = ni; + break; + } + } + if (DBG) log("getProvisioningNetworkInfo: X provNi=" + provNi); + return provNi; + } + + /** + * Find the first Provisioning network or the ActiveDefaultNetwork + * if there is no Provisioning network + * + * @return NetworkInfo or null if none. + */ + @Override + public NetworkInfo getProvisioningOrActiveNetworkInfo() { + enforceAccessPermission(); + + NetworkInfo provNi = getProvisioningNetworkInfo(); + if (provNi == null) { + final int uid = Binder.getCallingUid(); + provNi = getNetworkInfo(mActiveDefaultNetwork, uid); + } + if (DBG) log("getProvisioningOrActiveNetworkInfo: X provNi=" + provNi); + return provNi; + } + public NetworkInfo getActiveNetworkInfoUnfiltered() { enforceAccessPermission(); if (isNetworkTypeValid(mActiveDefaultNetwork)) { @@ -1316,8 +1356,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { feature); } if (network.reconnect()) { + if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_STARTED"); return PhoneConstants.APN_REQUEST_STARTED; } else { + if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_FAILED"); return PhoneConstants.APN_REQUEST_FAILED; } } else { @@ -1329,9 +1371,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetRequestersPids[usedNetworkType].add(currentPid); } } + if (DBG) log("startUsingNetworkFeature X: return -1 unsupported feature."); return -1; } } + if (DBG) log("startUsingNetworkFeature X: return APN_TYPE_NOT_AVAILABLE"); return PhoneConstants.APN_TYPE_NOT_AVAILABLE; } finally { if (DBG) { @@ -1365,11 +1409,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } if (found && u != null) { + if (VDBG) log("stopUsingNetworkFeature: X"); // stop regardless of how many other time this proc had called start return stopUsingNetworkFeature(u, true); } else { // none found! - if (VDBG) log("stopUsingNetworkFeature - not a live request, ignoring"); + if (VDBG) log("stopUsingNetworkFeature: X not a live request, ignoring"); return 1; } } @@ -1952,6 +1997,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ if (mNetConfigs[prevNetType].isDefault()) { if (mActiveDefaultNetwork == prevNetType) { + if (DBG) { + log("tryFailover: set mActiveDefaultNetwork=-1, prevNetType=" + prevNetType); + } mActiveDefaultNetwork = -1; } @@ -2146,6 +2194,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } void systemReady() { + mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); + loadGlobalProxy(); + synchronized(this) { mSystemReady = true; if (mInitialBroadcast != null) { @@ -2176,10 +2227,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { }; private boolean isNewNetTypePreferredOverCurrentNetType(int type) { - if ((type != mNetworkPreference && - mNetConfigs[mActiveDefaultNetwork].priority > - mNetConfigs[type].priority) || - mNetworkPreference == mActiveDefaultNetwork) return false; + if (((type != mNetworkPreference) + && (mNetConfigs[mActiveDefaultNetwork].priority > mNetConfigs[type].priority)) + || (mNetworkPreference == mActiveDefaultNetwork)) { + return false; + } return true; } @@ -2193,6 +2245,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { final NetworkStateTracker thisNet = mNetTrackers[newNetType]; final String thisIface = thisNet.getLinkProperties().getInterfaceName(); + if (VDBG) { + log("handleConnect: E newNetType=" + newNetType + " thisIface=" + thisIface + + " isFailover" + isFailover); + } + // if this is a default net and other default is running // kill the one not preferred if (mNetConfigs[newNetType].isDefault()) { @@ -2355,6 +2412,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleConnectivityChange(int netType, boolean doReset) { int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0; boolean exempt = ConnectivityManager.isNetworkTypeExempt(netType); + if (VDBG) { + log("handleConnectivityChange: netType=" + netType + " doReset=" + doReset + + " resetMask=" + resetMask); + } /* * If a non-default network is enabled, add the host routes that @@ -2422,7 +2483,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt); if (resetMask != 0 || resetDns) { + if (VDBG) log("handleConnectivityChange: resetting"); if (curLp != null) { + if (VDBG) log("handleConnectivityChange: resetting curLp=" + curLp); for (String iface : curLp.getAllInterfaceNames()) { if (TextUtils.isEmpty(iface) == false) { if (resetMask != 0) { @@ -2459,6 +2522,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Update 464xlat state. NetworkStateTracker tracker = mNetTrackers[netType]; if (mClat.requiresClat(netType, tracker)) { + // If the connection was previously using clat, but is not using it now, stop the clat // daemon. Normally, this happens automatically when the connection disconnects, but if // the disconnect is not reported, or if the connection's LinkProperties changed for @@ -2512,6 +2576,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { for (RouteInfo r : routeDiff.removed) { if (isLinkDefault || ! r.isDefaultRoute()) { + if (VDBG) log("updateRoutes: default remove route r=" + r); removeRoute(curLp, r, TO_DEFAULT_TABLE); } if (isLinkDefault == false) { @@ -2849,9 +2914,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { - case NetworkStateTracker.EVENT_STATE_CHANGED: + case NetworkStateTracker.EVENT_STATE_CHANGED: { info = (NetworkInfo) msg.obj; - int type = info.getType(); NetworkInfo.State state = info.getState(); if (VDBG || (state == NetworkInfo.State.CONNECTED) || @@ -2861,15 +2925,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { state + "/" + info.getDetailedState()); } - // After booting we'll check once for mobile provisioning - // if we've provisioned by and connected. - if (!mFirstProvisioningCheckStarted + // Since mobile has the notion of a network/apn that can be used for + // provisioning we need to check every time we're connected as + // CaptiveProtalTracker won't detected it because DCT doesn't report it + // as connected as ACTION_ANY_DATA_CONNECTION_STATE_CHANGED instead its + // reported as ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN. Which + // is received by MDST and sent here as EVENT_STATE_CHANGED. + if (ConnectivityManager.isNetworkTypeMobile(info.getType()) && (0 != Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0)) && (state == NetworkInfo.State.CONNECTED)) { - log("check provisioning after booting"); - mFirstProvisioningCheckStarted = true; - checkMobileProvisioning(true, CheckMp.MAX_TIMEOUT_MS, null); + checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS); } EventLogTags.writeConnectivityStateChanged( @@ -2881,6 +2947,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else if (info.getDetailedState() == DetailedState.CAPTIVE_PORTAL_CHECK) { handleCaptivePortalTrackerCheck(info); + } else if (info.getDetailedState() == + DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + /** + * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING + * for now its an in between network, its a network that + * is actually a default network but we don't want it to be + * announced as such to keep background applications from + * trying to use it. It turns out that some still try so we + * take the additional step of clearing any default routes + * to the link that may have incorrectly setup by the lower + * levels. + */ + LinkProperties lp = getLinkProperties(info.getType()); + if (DBG) { + log("EVENT_STATE_CHANGED: connected to provisioning network, lp=" + lp); + } + + // Clear any default routes setup by the radio so + // any activity by applications trying to use this + // connection will fail until the provisioning network + // is enabled. + for (RouteInfo r : lp.getRoutes()) { + removeRoute(lp, r, TO_DEFAULT_TABLE); + } } else if (state == NetworkInfo.State.DISCONNECTED) { handleDisconnect(info); } else if (state == NetworkInfo.State.SUSPENDED) { @@ -2899,18 +2989,21 @@ public class ConnectivityService extends IConnectivityManager.Stub { mLockdownTracker.onNetworkInfoChanged(info); } break; - case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: + } + case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: { info = (NetworkInfo) msg.obj; // TODO: Temporary allowing network configuration // change not resetting sockets. // @see bug/4455071 handleConnectivityChange(info.getType(), false); break; - case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: + } + case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: { info = (NetworkInfo) msg.obj; - type = info.getType(); + int type = info.getType(); updateNetworkSettings(mNetTrackers[type]); break; + } } } } @@ -3806,76 +3899,153 @@ public class ConnectivityService extends IConnectivityManager.Stub { enabled)); } + private boolean isMobileDataStateTrackerReady() { + MobileDataStateTracker mdst = + (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + return (mdst != null) && (mdst.isReady()); + } + + /** + * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE) + */ + + /** + * No connection was possible to the network. + */ + public static final int CMP_RESULT_CODE_NO_CONNECTION = 0; + + /** + * A connection was made to the internet, all is well. + */ + public static final int CMP_RESULT_CODE_CONNECTABLE = 1; + + /** + * A connection was made but there was a redirection, we appear to be in walled garden. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_REDIRECTED = 2; + + /** + * A connection was made but no dns server was available to resolve a name to address. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_NO_DNS = 3; + + /** + * A connection was made but could not open a TCP connection. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4; + + /** + * The mobile network is a provisioning network. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5; + + AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false); + @Override - public int checkMobileProvisioning(final boolean sendNotification, int suggestedTimeOutMs, - final ResultReceiver resultReceiver) { - log("checkMobileProvisioning: E sendNotification=" + sendNotification - + " suggestedTimeOutMs=" + suggestedTimeOutMs - + " resultReceiver=" + resultReceiver); - enforceChangePermission(); - - mFirstProvisioningCheckStarted = true; - - int timeOutMs = suggestedTimeOutMs; - if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { - timeOutMs = CheckMp.MAX_TIMEOUT_MS; - } - - // Check that mobile networks are supported - if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) - || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { - log("checkMobileProvisioning: X no mobile network"); - if (resultReceiver != null) { - resultReceiver.send(ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION, null); - } - return timeOutMs; - } + public int checkMobileProvisioning(int suggestedTimeOutMs) { + int timeOutMs = -1; + if (DBG) log("checkMobileProvisioning: E suggestedTimeOutMs=" + suggestedTimeOutMs); + enforceConnectivityInternalPermission(); final long token = Binder.clearCallingIdentity(); try { + timeOutMs = suggestedTimeOutMs; + if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { + timeOutMs = CheckMp.MAX_TIMEOUT_MS; + } + + // Check that mobile networks are supported + if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) + || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { + if (DBG) log("checkMobileProvisioning: X no mobile network"); + return timeOutMs; + } + + // If we're already checking don't do it again + // TODO: Add a queue of results... + if (mIsCheckingMobileProvisioning.getAndSet(true)) { + if (DBG) log("checkMobileProvisioning: X already checking ignore for the moment"); + return timeOutMs; + } + + // Start off with notification off + setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); + + // See if we've alreadying determined if we've got a provsioning connection + // if so we don't need to do anything active + MobileDataStateTracker mdstDefault = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork(); + + MobileDataStateTracker mdstHipri = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork(); + + if (isDefaultProvisioning || isHipriProvisioning) { + if (mIsNotificationVisible) { + if (DBG) { + log("checkMobileProvisioning: provisioning-ignore notification is visible"); + } + } else { + NetworkInfo ni = null; + if (isDefaultProvisioning) { + ni = mdstDefault.getNetworkInfo(); + } + if (isHipriProvisioning) { + ni = mdstHipri.getNetworkInfo(); + } + String url = getMobileProvisioningUrl(); + if ((ni != null) && (!TextUtils.isEmpty(url))) { + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), url); + } else { + if (DBG) log("checkMobileProvisioning: provisioning but no url, ignore"); + } + } + mIsCheckingMobileProvisioning.set(false); + return timeOutMs; + } + CheckMp checkMp = new CheckMp(mContext, this); CheckMp.CallBack cb = new CheckMp.CallBack() { @Override void onComplete(Integer result) { - log("CheckMp.onComplete: result=" + result); - if (resultReceiver != null) { - log("CheckMp.onComplete: send result"); - resultReceiver.send(result, null); - } - if (!sendNotification) { - log("CheckMp.onComplete: done, not sending notification"); - return; - } + if (DBG) log("CheckMp.onComplete: result=" + result); NetworkInfo ni = mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo(); switch(result) { - case ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE: - case ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION: { - log("CheckMp.onComplete: ignore, connected or no connection"); + case CMP_RESULT_CODE_CONNECTABLE: + case CMP_RESULT_CODE_NO_CONNECTION: { + if (DBG) log("CheckMp.onComplete: ignore, connected or no connection"); break; } - case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: { - log("CheckMp.onComplete: warm sim"); + case CMP_RESULT_CODE_REDIRECTED: { + if (DBG) log("CheckMp.onComplete: warm sim"); String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url)) { url = getMobileRedirectedProvisioningUrl(); } if (TextUtils.isEmpty(url) == false) { - log("CheckMp.onComplete: warm sim (redirected), url=" + url); - setNotificationVisible(true, ni, url); + if (DBG) log("CheckMp.onComplete: warm (redirected), url=" + url); + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), + url); } else { - log("CheckMp.onComplete: warm sim (redirected), no url"); + if (DBG) log("CheckMp.onComplete: warm (redirected), no url"); } break; } - case ConnectivityManager.CMP_RESULT_CODE_NO_DNS: - case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: { + case CMP_RESULT_CODE_NO_DNS: + case CMP_RESULT_CODE_NO_TCP_CONNECTION: { String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url) == false) { - log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url); - setNotificationVisible(true, ni, url); + if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), url=" + url); + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), + url); } else { - log("CheckMp.onComplete: warm sim (no dns/tcp), no url"); + if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url"); } break; } @@ -3884,16 +4054,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } } + mIsCheckingMobileProvisioning.set(false); } }; CheckMp.Params params = new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb); - log("checkMobileProvisioning: params=" + params); - setNotificationVisible(false, null, null); + if (DBG) log("checkMobileProvisioning: params=" + params); checkMp.execute(params); } finally { Binder.restoreCallingIdentity(token); - log("checkMobileProvisioning: X"); + if (DBG) log("checkMobileProvisioning: X"); } return timeOutMs; } @@ -3965,26 +4135,38 @@ public class ConnectivityService extends IConnectivityManager.Stub { * a known address that fetches the data we expect. */ private synchronized Integer isMobileOk(Params params) { - Integer result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + Integer result = CMP_RESULT_CODE_NO_CONNECTION; Uri orgUri = Uri.parse(params.mUrl); Random rand = new Random(); mParams = params; if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { log("isMobileOk: not mobile capable"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; return result; } try { - // Enable fail fast as we'll do retries here and use a - // hipri connection so the default connection stays active. - log("isMobileOk: start hipri url=" + params.mUrl); - mCs.setEnableFailFastMobileData(DctConstants.ENABLED); - // Continue trying to connect until time has run out long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs; + if (!mCs.isMobileDataStateTrackerReady()) { + // Wait for MobileDataStateTracker to be ready. + if (DBG) log("isMobileOk: mdst is not ready"); + while(SystemClock.elapsedRealtime() < endTime) { + if (mCs.isMobileDataStateTrackerReady()) { + // Enable fail fast as we'll do retries here and use a + // hipri connection so the default connection stays active. + if (DBG) log("isMobileOk: mdst ready, enable fail fast of mobile data"); + mCs.setEnableFailFastMobileData(DctConstants.ENABLED); + break; + } + sleep(1); + } + } + + log("isMobileOk: start hipri url=" + params.mUrl); + // First wait until we can start using hipri Binder binder = new Binder(); while(SystemClock.elapsedRealtime() < endTime) { @@ -3996,7 +4178,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } if (VDBG) log("isMobileOk: hipri not started yet"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; sleep(1); } @@ -4009,15 +4191,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo.State state = mCs .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); if (state != NetworkInfo.State.CONNECTED) { - if (VDBG) { + if (true/*VDBG*/) { log("isMobileOk: not connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); } sleep(1); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; continue; } + // Hipri has started check if this is a provisioning url + MobileDataStateTracker mdst = (MobileDataStateTracker) + mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + if (mdst.isProvisioningNetwork()) { + if (DBG) log("isMobileOk: isProvisioningNetwork is true, no TCP conn"); + result = CMP_RESULT_CODE_NO_TCP_CONNECTION; + return result; + } else { + if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue"); + } + // Get of the addresses associated with the url host. We need to use the // address otherwise HttpURLConnection object will use the name to get // the addresses and is will try every address but that will bypass the @@ -4028,7 +4221,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { addresses = InetAddress.getAllByName(orgUri.getHost()); } catch (UnknownHostException e) { log("isMobileOk: UnknownHostException"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_DNS; + result = CMP_RESULT_CODE_NO_DNS; return result; } log("isMobileOk: addresses=" + inetAddressesToString(addresses)); @@ -4093,9 +4286,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { urlConn.setRequestProperty("Connection", "close"); int responseCode = urlConn.getResponseCode(); if (responseCode == 204) { - result = ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE; + result = CMP_RESULT_CODE_CONNECTABLE; } else { - result = ConnectivityManager.CMP_RESULT_CODE_REDIRECTED; + result = CMP_RESULT_CODE_REDIRECTED; } log("isMobileOk: connected responseCode=" + responseCode); urlConn.disconnect(); @@ -4109,7 +4302,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } - result = ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION; + result = CMP_RESULT_CODE_NO_TCP_CONNECTION; log("isMobileOk: loops|timed out"); return result; } catch (Exception e) { @@ -4123,6 +4316,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { mCs.setEnableFailFastMobileData(DctConstants.DISABLED); mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_HIPRI); + + // Wait for hipri to disconnect. + long endTime = SystemClock.elapsedRealtime() + 5000; + + while(SystemClock.elapsedRealtime() < endTime) { + NetworkInfo.State state = mCs + .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); + if (state != NetworkInfo.State.DISCONNECTED) { + if (VDBG) { + log("isMobileOk: connected ni=" + + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); + } + sleep(1); + continue; + } + } + log("isMobileOk: X result=" + result); } return result; @@ -4188,10 +4398,55 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private static final String NOTIFICATION_ID = "CaptivePortal.Notification"; + // TODO: Move to ConnectivityManager and make public? + private static final String CONNECTED_TO_PROVISIONING_NETWORK_ACTION = + "com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION"; - private void setNotificationVisible(boolean visible, NetworkInfo networkInfo, String url) { - log("setNotificationVisible: E visible=" + visible + " ni=" + networkInfo + " url=" + url); + private BroadcastReceiver mProvisioningReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(CONNECTED_TO_PROVISIONING_NETWORK_ACTION)) { + handleMobileProvisioningAction(intent.getStringExtra("EXTRA_URL")); + } + } + }; + + private void handleMobileProvisioningAction(String url) { + // Notication mark notification as not visible + setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); + + // If provisioning network handle as a special case, + // otherwise launch browser with the intent directly. + NetworkInfo ni = getProvisioningNetworkInfo(); + if ((ni != null) && ni.getDetailedState() == + NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + if (DBG) log("handleMobileProvisioningAction: on provisioning network"); + MobileDataStateTracker mdst = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + mdst.enableMobileProvisioning(url); + } else { + if (DBG) log("handleMobileProvisioningAction: on default network"); + Intent newIntent = + new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mContext.startActivity(newIntent); + } catch (ActivityNotFoundException e) { + loge("handleMobileProvisioningAction: startActivity failed" + e); + } + } + } + + private static final String NOTIFICATION_ID = "CaptivePortal.Notification"; + private volatile boolean mIsNotificationVisible = false; + + private void setProvNotificationVisible(boolean visible, int networkType, String extraInfo, + String url) { + if (DBG) { + log("setProvNotificationVisible: E visible=" + visible + " networkType=" + networkType + + " extraInfo=" + extraInfo + " url=" + url); + } Resources r = Resources.getSystem(); NotificationManager notificationManager = (NotificationManager) mContext @@ -4201,50 +4456,64 @@ public class ConnectivityService extends IConnectivityManager.Stub { CharSequence title; CharSequence details; int icon; - switch (networkInfo.getType()) { + Intent intent; + Notification notification = new Notification(); + switch (networkType) { case ConnectivityManager.TYPE_WIFI: - log("setNotificationVisible: TYPE_WIFI"); title = r.getString(R.string.wifi_available_sign_in, 0); details = r.getString(R.string.network_available_sign_in_detailed, - networkInfo.getExtraInfo()); + extraInfo); icon = R.drawable.stat_notify_wifi_in_range; + intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); break; case ConnectivityManager.TYPE_MOBILE: case ConnectivityManager.TYPE_MOBILE_HIPRI: - log("setNotificationVisible: TYPE_MOBILE|HIPRI"); title = r.getString(R.string.network_available_sign_in, 0); // TODO: Change this to pull from NetworkInfo once a printable // name has been added to it details = mTelephonyManager.getNetworkOperatorName(); icon = R.drawable.stat_notify_rssi_in_range; + intent = new Intent(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); + intent.putExtra("EXTRA_URL", url); + intent.setFlags(0); + notification.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); break; default: - log("setNotificationVisible: other type=" + networkInfo.getType()); title = r.getString(R.string.network_available_sign_in, 0); details = r.getString(R.string.network_available_sign_in_detailed, - networkInfo.getExtraInfo()); + extraInfo); icon = R.drawable.stat_notify_rssi_in_range; + intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); break; } - Notification notification = new Notification(); notification.when = 0; notification.icon = icon; notification.flags = Notification.FLAG_AUTO_CANCEL; - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | - Intent.FLAG_ACTIVITY_NEW_TASK); - notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); notification.tickerText = title; notification.setLatestEventInfo(mContext, title, details, notification.contentIntent); - log("setNotificaitionVisible: notify notificaiton=" + notification); - notificationManager.notify(NOTIFICATION_ID, 1, notification); + try { + notificationManager.notify(NOTIFICATION_ID, 1, notification); + } catch (NullPointerException npe) { + loge("setNotificaitionVisible: visible notificationManager npe=" + npe); + npe.printStackTrace(); + } } else { - log("setNotificaitionVisible: cancel"); - notificationManager.cancel(NOTIFICATION_ID, 1); + try { + notificationManager.cancel(NOTIFICATION_ID, 1); + } catch (NullPointerException npe) { + loge("setNotificaitionVisible: cancel notificationManager npe=" + npe); + npe.printStackTrace(); + } } - log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url); + mIsNotificationVisible = visible; } /** Location to an updatable file listing carrier provisioning urls. @@ -4373,6 +4642,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { return url; } + @Override + public void setProvisioningNotificationVisible(boolean visible, int networkType, + String extraInfo, String url) { + enforceConnectivityInternalPermission(); + setProvNotificationVisible(visible, networkType, extraInfo, url); + } + private void onUserStart(int userId) { synchronized(mVpns) { Vpn userVpn = mVpns.get(userId); From 00d4b8a98723f0e1ed5cebe5292e48666f8da3af Mon Sep 17 00:00:00 2001 From: Vinit Deshapnde Date: Wed, 4 Sep 2013 14:11:24 -0700 Subject: [PATCH 47/71] Rename LinkInfo to LinkQualityInfo This change renames the LinkInfo objects to LinkQuailtyInfo. The API is still hidden; but it can be accessed via reflection. Bug: 10342372 Change-Id: Ieccea87c467ceae5d7f76298b137573f67396cd6 --- core/java/android/net/ConnectivityManager.java | 12 ++++++------ .../java/android/net/IConnectivityManager.aidl | 8 ++++---- .../android/server/ConnectivityService.java | 18 +++++++++--------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index f6a3a4a772..c3ff857240 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1447,9 +1447,9 @@ public class ConnectivityManager { * get the information about a specific network link * @hide */ - public LinkInfo getLinkInfo(int networkType) { + public LinkQualityInfo getLinkQualityInfo(int networkType) { try { - LinkInfo li = mService.getLinkInfo(networkType); + LinkQualityInfo li = mService.getLinkQualityInfo(networkType); return li; } catch (RemoteException e) { return null; @@ -1460,9 +1460,9 @@ public class ConnectivityManager { * get the information of currently active network link * @hide */ - public LinkInfo getActiveLinkInfo() { + public LinkQualityInfo getActiveLinkQualityInfo() { try { - LinkInfo li = mService.getActiveLinkInfo(); + LinkQualityInfo li = mService.getActiveLinkQualityInfo(); return li; } catch (RemoteException e) { return null; @@ -1473,9 +1473,9 @@ public class ConnectivityManager { * get the information of all network links * @hide */ - public LinkInfo[] getAllLinkInfo() { + public LinkQualityInfo[] getAllLinkQualityInfo() { try { - LinkInfo[] li = mService.getAllLinkInfo(); + LinkQualityInfo[] li = mService.getAllLinkQualityInfo(); return li; } catch (RemoteException e) { return null; diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index bf2dade3bc..1c383146b1 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -16,7 +16,7 @@ package android.net; -import android.net.LinkInfo; +import android.net.LinkQualityInfo; import android.net.LinkProperties; import android.net.NetworkInfo; import android.net.NetworkQuotaInfo; @@ -147,10 +147,10 @@ interface IConnectivityManager String getMobileRedirectedProvisioningUrl(); - LinkInfo getLinkInfo(int networkType); + LinkQualityInfo getLinkQualityInfo(int networkType); - LinkInfo getActiveLinkInfo(); + LinkQualityInfo getActiveLinkQualityInfo(); - LinkInfo[] getAllLinkInfo(); + LinkQualityInfo[] getAllLinkQualityInfo(); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 136a85e0af..c3fa41712b 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -57,7 +57,7 @@ import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.LinkAddress; import android.net.LinkProperties; -import android.net.LinkInfo; +import android.net.LinkQualityInfo; import android.net.LinkProperties.CompareResult; import android.net.MobileDataStateTracker; import android.net.NetworkConfig; @@ -4413,39 +4413,39 @@ public class ConnectivityService extends IConnectivityManager.Stub { }; @Override - public LinkInfo getLinkInfo(int networkType) { + public LinkQualityInfo getLinkQualityInfo(int networkType) { enforceAccessPermission(); if (isNetworkTypeValid(networkType)) { - return mNetTrackers[networkType].getLinkInfo(); + return mNetTrackers[networkType].getLinkQualityInfo(); } else { return null; } } @Override - public LinkInfo getActiveLinkInfo() { + public LinkQualityInfo getActiveLinkQualityInfo() { enforceAccessPermission(); if (isNetworkTypeValid(mActiveDefaultNetwork)) { - return mNetTrackers[mActiveDefaultNetwork].getLinkInfo(); + return mNetTrackers[mActiveDefaultNetwork].getLinkQualityInfo(); } else { return null; } } @Override - public LinkInfo[] getAllLinkInfo() { + public LinkQualityInfo[] getAllLinkQualityInfo() { enforceAccessPermission(); - final ArrayList result = Lists.newArrayList(); + final ArrayList result = Lists.newArrayList(); for (NetworkStateTracker tracker : mNetTrackers) { if (tracker != null) { - LinkInfo li = tracker.getLinkInfo(); + LinkQualityInfo li = tracker.getLinkQualityInfo(); if (li != null) { result.add(li); } } } - return result.toArray(new LinkInfo[result.size()]); + return result.toArray(new LinkQualityInfo[result.size()]); } /* Infrastructure for network sampling */ From 174782b0fccf5685f8ed0fb93305cf623e508518 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 23 Aug 2013 20:54:49 +0900 Subject: [PATCH 48/71] Add a function to replace all the link addresses. Bug: 10232006 Change-Id: I689ce4735999dac2ab5e1fae09d80b1f734292a1 --- core/java/android/net/LinkProperties.java | 10 ++++++++++ .../src/android/net/LinkPropertiesTest.java | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 1f73c4ad71..43d6b71598 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -197,6 +197,16 @@ public class LinkProperties implements Parcelable { return addresses; } + /** + * Replaces the LinkAddresses on this link with the given collection of addresses. + */ + public void setLinkAddresses(Collection addresses) { + mLinkAddresses.clear(); + for (LinkAddress address: addresses) { + addLinkAddress(address); + } + } + public void addDns(InetAddress dns) { if (dns != null) mDnses.add(dns); } diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index a570802d29..7e70c6b046 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -363,4 +363,19 @@ public class LinkPropertiesTest extends TestCase { assertFalse(lp.hasIPv4Address()); assertFalse(lp.removeLinkAddress(LINKADDRV4)); } + + @SmallTest + public void testSetLinkAddresses() { + LinkProperties lp = new LinkProperties(); + lp.addLinkAddress(LINKADDRV4); + lp.addLinkAddress(LINKADDRV6); + + LinkProperties lp2 = new LinkProperties(); + lp2.addLinkAddress(LINKADDRV6); + + assertFalse(lp.equals(lp2)); + + lp2.setLinkAddresses(lp.getLinkAddresses()); + assertTrue(lp.equals(lp)); + } } From b1a3202e79f1e13f6b4ddd43155e71cbf4a61dd9 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Thu, 5 Sep 2013 12:02:25 -0700 Subject: [PATCH 49/71] Do not change NetworkInfo.DetailedState. I'd changed DetailedState to force ConnectivityService to treat provisioning apn's specially. In particular so that they wouldn't be identified they were fully connected until the provisioning actually started. The problem is that DetailedState is a public enum that has a CTS test and just changing the CTS to allow for the new state (CONNECTED_TO_PROVISIONING_NETWORK) was inappropriate. Instead I've added a new mIsConnectedToProvisioningNetwork variable and used the DetailedState.SUSPENDED as the intermediate state. Bug: 10620248 Change-Id: Id4a842398cad67455541ce629959351c27d83639 --- core/java/android/net/NetworkInfo.java | 35 ++++++++++++++----- .../android/server/ConnectivityService.java | 15 ++++---- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index dabc73a716..4d2a70ddf1 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -83,13 +83,7 @@ public class NetworkInfo implements Parcelable { /** Link has poor connectivity. */ VERIFYING_POOR_LINK, /** Checking if network is a captive portal */ - CAPTIVE_PORTAL_CHECK, - /** - * Network is connected to provisioning network - * TODO: Probably not needed when we add TYPE_PROVISIONING_NETWORK - * @hide - */ - CONNECTED_TO_PROVISIONING_NETWORK + CAPTIVE_PORTAL_CHECK } /** @@ -114,7 +108,6 @@ public class NetworkInfo implements Parcelable { stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED); stateMap.put(DetailedState.FAILED, State.DISCONNECTED); stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED); - stateMap.put(DetailedState.CONNECTED_TO_PROVISIONING_NETWORK, State.CONNECTED); } private int mNetworkType; @@ -127,6 +120,8 @@ public class NetworkInfo implements Parcelable { private String mExtraInfo; private boolean mIsFailover; private boolean mIsRoaming; + private boolean mIsConnectedToProvisioningNetwork; + /** * Indicates whether network connectivity is possible: */ @@ -155,6 +150,7 @@ public class NetworkInfo implements Parcelable { mState = State.UNKNOWN; mIsAvailable = false; // until we're told otherwise, assume unavailable mIsRoaming = false; + mIsConnectedToProvisioningNetwork = false; } /** {@hide} */ @@ -171,6 +167,7 @@ public class NetworkInfo implements Parcelable { mIsFailover = source.mIsFailover; mIsRoaming = source.mIsRoaming; mIsAvailable = source.mIsAvailable; + mIsConnectedToProvisioningNetwork = source.mIsConnectedToProvisioningNetwork; } } @@ -329,6 +326,22 @@ public class NetworkInfo implements Parcelable { } } + /** {@hide} */ + @VisibleForTesting + public boolean isConnectedToProvisioningNetwork() { + synchronized (this) { + return mIsConnectedToProvisioningNetwork; + } + } + + /** {@hide} */ + @VisibleForTesting + public void setIsConnectedToProvisioningNetwork(boolean val) { + synchronized (this) { + mIsConnectedToProvisioningNetwork = val; + } + } + /** * Reports the current coarse-grained state of the network. * @return the coarse-grained state @@ -412,7 +425,9 @@ public class NetworkInfo implements Parcelable { append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo). append(", roaming: ").append(mIsRoaming). append(", failover: ").append(mIsFailover). - append(", isAvailable: ").append(mIsAvailable); + append(", isAvailable: ").append(mIsAvailable). + append(", isConnectedToProvisioningNetwork: "). + append(mIsConnectedToProvisioningNetwork); return builder.toString(); } } @@ -440,6 +455,7 @@ public class NetworkInfo implements Parcelable { dest.writeInt(mIsFailover ? 1 : 0); dest.writeInt(mIsAvailable ? 1 : 0); dest.writeInt(mIsRoaming ? 1 : 0); + dest.writeInt(mIsConnectedToProvisioningNetwork ? 1 : 0); dest.writeString(mReason); dest.writeString(mExtraInfo); } @@ -462,6 +478,7 @@ public class NetworkInfo implements Parcelable { netInfo.mIsFailover = in.readInt() != 0; netInfo.mIsAvailable = in.readInt() != 0; netInfo.mIsRoaming = in.readInt() != 0; + netInfo.mIsConnectedToProvisioningNetwork = in.readInt() != 0; netInfo.mReason = in.readString(); netInfo.mExtraInfo = in.readString(); return netInfo; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index ee23b13d3f..a022fb1d87 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -890,8 +890,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Find the first Provisioning Network NetworkInfo provNi = null; for (NetworkInfo ni : getAllNetworkInfo()) { - if (ni.getDetailedState() - == NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + if (ni.isConnectedToProvisioningNetwork()) { provNi = ni; break; } @@ -2805,7 +2804,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo.State state = info.getState(); if (VDBG || (state == NetworkInfo.State.CONNECTED) || - (state == NetworkInfo.State.DISCONNECTED)) { + (state == NetworkInfo.State.DISCONNECTED) || + (state == NetworkInfo.State.SUSPENDED)) { log("ConnectivityChange for " + info.getTypeName() + ": " + state + "/" + info.getDetailedState()); @@ -2820,7 +2820,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (ConnectivityManager.isNetworkTypeMobile(info.getType()) && (0 != Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0)) - && (state == NetworkInfo.State.CONNECTED)) { + && ((state == NetworkInfo.State.CONNECTED) + || info.isConnectedToProvisioningNetwork())) { checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS); } @@ -2833,8 +2834,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else if (info.getDetailedState() == DetailedState.CAPTIVE_PORTAL_CHECK) { handleCaptivePortalTrackerCheck(info); - } else if (info.getDetailedState() == - DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + } else if (info.isConnectedToProvisioningNetwork()) { /** * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING * for now its an in between network, its a network that @@ -4197,8 +4197,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // If provisioning network handle as a special case, // otherwise launch browser with the intent directly. NetworkInfo ni = getProvisioningNetworkInfo(); - if ((ni != null) && ni.getDetailedState() == - NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + if ((ni != null) && ni.isConnectedToProvisioningNetwork()) { if (DBG) log("handleMobileProvisioningAction: on provisioning network"); MobileDataStateTracker mdst = (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE]; From 9685cd1d1759b418f8adf6c89c1d7f848b1334cc Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Fri, 6 Sep 2013 09:53:08 -0700 Subject: [PATCH 50/71] Tighten test for warm sim and add more debug. - Require a non-204 response multiple times before declaring a redirected error and hence a warm sim. - If there is no connection or dns don't declare its a warm-sim. - Add printing of the http headers to try to get more information if we still get a false positive result. Bug: 9972012 Change-Id: Ic115685cdbbe39c2b4de88b128eaf8d2ea96b45c --- .../android/server/ConnectivityService.java | 73 +++++++++++-------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 7f9dc26fe3..759dce79cf 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3911,39 +3911,41 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** * No connection was possible to the network. + * This is NOT a warm sim. */ - public static final int CMP_RESULT_CODE_NO_CONNECTION = 0; + private static final int CMP_RESULT_CODE_NO_CONNECTION = 0; /** * A connection was made to the internet, all is well. + * This is NOT a warm sim. */ - public static final int CMP_RESULT_CODE_CONNECTABLE = 1; - - /** - * A connection was made but there was a redirection, we appear to be in walled garden. - * This is an indication of a warm sim on a mobile network. - */ - public static final int CMP_RESULT_CODE_REDIRECTED = 2; + private static final int CMP_RESULT_CODE_CONNECTABLE = 1; /** * A connection was made but no dns server was available to resolve a name to address. - * This is an indication of a warm sim on a mobile network. + * This is NOT a warm sim since provisioning network is supported. */ - public static final int CMP_RESULT_CODE_NO_DNS = 3; + private static final int CMP_RESULT_CODE_NO_DNS = 2; /** * A connection was made but could not open a TCP connection. - * This is an indication of a warm sim on a mobile network. + * This is NOT a warm sim since provisioning network is supported. */ - public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4; + private static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 3; + + /** + * A connection was made but there was a redirection, we appear to be in walled garden. + * This is an indication of a warm sim on a mobile network such as T-Mobile. + */ + private static final int CMP_RESULT_CODE_REDIRECTED = 4; /** * The mobile network is a provisioning network. - * This is an indication of a warm sim on a mobile network. + * This is an indication of a warm sim on a mobile network such as AT&T. */ - public static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5; + private static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5; - AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false); + private AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false); @Override public int checkMobileProvisioning(int suggestedTimeOutMs) { @@ -4018,7 +4020,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo(); switch(result) { case CMP_RESULT_CODE_CONNECTABLE: - case CMP_RESULT_CODE_NO_CONNECTION: { + case CMP_RESULT_CODE_NO_CONNECTION: + case CMP_RESULT_CODE_NO_DNS: + case CMP_RESULT_CODE_NO_TCP_CONNECTION: { if (DBG) log("CheckMp.onComplete: ignore, connected or no connection"); break; } @@ -4037,8 +4041,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } break; } - case CMP_RESULT_CODE_NO_DNS: - case CMP_RESULT_CODE_NO_TCP_CONNECTION: { + case CMP_RESULT_CODE_PROVISIONING_NETWORK: { String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url) == false) { if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), url=" + url); @@ -4204,8 +4207,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { MobileDataStateTracker mdst = (MobileDataStateTracker) mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; if (mdst.isProvisioningNetwork()) { - if (DBG) log("isMobileOk: isProvisioningNetwork is true, no TCP conn"); - result = CMP_RESULT_CODE_NO_TCP_CONNECTION; + if (DBG) log("isMobileOk: isProvisioningNetwork is true"); + result = CMP_RESULT_CODE_PROVISIONING_NETWORK; return result; } else { if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue"); @@ -4285,25 +4288,37 @@ public class ConnectivityService extends IConnectivityManager.Stub { urlConn.setAllowUserInteraction(false); urlConn.setRequestProperty("Connection", "close"); int responseCode = urlConn.getResponseCode(); - if (responseCode == 204) { - result = CMP_RESULT_CODE_CONNECTABLE; - } else { - result = CMP_RESULT_CODE_REDIRECTED; - } - log("isMobileOk: connected responseCode=" + responseCode); + + // For debug display the headers + Map> headers = urlConn.getHeaderFields(); + log("isMobileOk: headers=" + headers); + + // Close the connection urlConn.disconnect(); urlConn = null; - return result; + + if (responseCode == 204) { + // Return + log("isMobileOk: expected responseCode=" + responseCode); + result = CMP_RESULT_CODE_CONNECTABLE; + return result; + } else { + // Retry to be sure this was redirected, we've gotten + // occasions where a server returned 200 even though + // the device didn't have a "warm" sim. + log("isMobileOk: not expected responseCode=" + responseCode); + result = CMP_RESULT_CODE_REDIRECTED; + } } catch (Exception e) { log("isMobileOk: HttpURLConnection Exception e=" + e); + result = CMP_RESULT_CODE_NO_TCP_CONNECTION; if (urlConn != null) { urlConn.disconnect(); urlConn = null; } } } - result = CMP_RESULT_CODE_NO_TCP_CONNECTION; - log("isMobileOk: loops|timed out"); + log("isMobileOk: loops|timed out result=" + result); return result; } catch (Exception e) { log("isMobileOk: Exception e=" + e); From 4aa73924fd6e3770bc463648e7860d7387fda96d Mon Sep 17 00:00:00 2001 From: "sy.yun" Date: Mon, 2 Sep 2013 05:24:09 +0900 Subject: [PATCH 51/71] Setting MTU size for specific network. Able to config network specific MTU size. Normally, the default size of MTU is 1500. US - ATT 1410, TMUS 1440, SPRINT 1422 KR - SKT 1440, KT 1450, LGU+ 1428 JP - KDDI 1420, SoftBank 1340 CA - RGS 1430, FIDO 1430, MTS 1430, BELL 1358, SaskTel 1358 AU - TEL 1400 Bug: 10195070 Change-Id: Ie18650b37a3d44af944f2dae4aa97c04fb12cd5e --- core/java/android/net/LinkProperties.java | 35 ++++++++++++++++--- .../src/android/net/LinkPropertiesTest.java | 24 +++++++++++++ .../android/server/ConnectivityService.java | 22 +++++++++++- 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 43d6b71598..284e1a7f28 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -66,6 +66,7 @@ public class LinkProperties implements Parcelable { private String mDomains; private Collection mRoutes = new ArrayList(); private ProxyProperties mHttpProxy; + private int mMtu; // Stores the properties of links that are "stacked" above this link. // Indexed by interface name to allow modification and to prevent duplicates being added. @@ -104,6 +105,7 @@ public class LinkProperties implements Parcelable { for (LinkProperties l: source.mStackedLinks.values()) { addStackedLink(l); } + setMtu(source.getMtu()); } } @@ -223,6 +225,14 @@ public class LinkProperties implements Parcelable { mDomains = domains; } + public void setMtu(int mtu) { + mMtu = mtu; + } + + public int getMtu() { + return mMtu; + } + private RouteInfo routeWithInterface(RouteInfo route) { return new RouteInfo( route.getDestination(), @@ -322,6 +332,7 @@ public class LinkProperties implements Parcelable { mRoutes.clear(); mHttpProxy = null; mStackedLinks.clear(); + mMtu = 0; } /** @@ -346,6 +357,8 @@ public class LinkProperties implements Parcelable { String domainName = "Domains: " + mDomains; + String mtu = "MTU: " + mMtu; + String routes = " Routes: ["; for (RouteInfo route : mRoutes) routes += route.toString() + ","; routes += "] "; @@ -359,7 +372,8 @@ public class LinkProperties implements Parcelable { } stacked += "] "; } - return "{" + ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked + "}"; + return "{" + ifaceName + linkAddresses + routes + dns + domainName + mtu + + proxy + stacked + "}"; } /** @@ -474,6 +488,16 @@ public class LinkProperties implements Parcelable { return true; } + /** + * Compares this {@code LinkProperties} MTU against the target + * + * @@param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + */ + public boolean isIdenticalMtu(LinkProperties target) { + return getMtu() == target.getMtu(); + } + @Override /** * Compares this {@code LinkProperties} instance against the target @@ -505,7 +529,8 @@ public class LinkProperties implements Parcelable { isIdenticalDnses(target) && isIdenticalRoutes(target) && isIdenticalHttpProxy(target) && - isIdenticalStackedLinks(target); + isIdenticalStackedLinks(target) && + isIdenticalMtu(target); } /** @@ -607,7 +632,8 @@ public class LinkProperties implements Parcelable { + ((null == mDomains) ? 0 : mDomains.hashCode()) + mRoutes.size() * 41 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()) - + mStackedLinks.hashCode() * 47); + + mStackedLinks.hashCode() * 47) + + mMtu * 51; } /** @@ -625,7 +651,7 @@ public class LinkProperties implements Parcelable { dest.writeByteArray(d.getAddress()); } dest.writeString(mDomains); - + dest.writeInt(mMtu); dest.writeInt(mRoutes.size()); for(RouteInfo route : mRoutes) { dest.writeParcelable(route, flags); @@ -664,6 +690,7 @@ public class LinkProperties implements Parcelable { } catch (UnknownHostException e) { } } netProp.setDomains(in.readString()); + netProp.setMtu(in.readInt()); addressCount = in.readInt(); for (int i=0; i 10000) { + loge("Unexpected mtu value: " + nt); + return; + } + + try { + if (VDBG) log("Setting MTU size: " + iface + ", " + mtu); + mNetd.setMtu(iface, mtu); + } catch (Exception e) { + Slog.e(TAG, "exception in setMtu()" + e); + } + } /** * Reads the network specific TCP buffer sizes from SystemProperties @@ -4774,4 +4795,3 @@ public class ConnectivityService extends IConnectivityManager.Stub { mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent); } } - From 39dd04c648ee81333a53133255dc62228db94ee9 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 6 Sep 2013 16:49:37 -0700 Subject: [PATCH 52/71] Fix the build. Change-Id: Ia5d29de9db7ea8fd467b3bde551a8cfb95877b41 --- core/tests/coretests/src/android/net/LinkPropertiesTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index 63dd86f997..e63f6b08f6 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -163,8 +163,8 @@ public class LinkPropertiesTest extends TestCase { target.addLinkAddress(LINKADDRV6); target.addDns(DNS1); target.addDns(DNS2); - target.addRoute(GATEWAY1); - target.addRoute(GATEWAY2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); // change mtu target.setMtu(1440); assertFalse(source.equals(target)); From cb5620b2c4c99f75da6fbcea3c753f8d85a64381 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Fri, 6 Sep 2013 22:53:16 -0700 Subject: [PATCH 53/71] Fix docs build. Change-Id: I6fd0d711b2cc7726fdaa9119ee467ed6fab82de1 --- core/java/android/net/LinkProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 284e1a7f28..b4d07a1ec2 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -491,7 +491,7 @@ public class LinkProperties implements Parcelable { /** * Compares this {@code LinkProperties} MTU against the target * - * @@param target LinkProperties to compare. + * @param target LinkProperties to compare. * @return {@code true} if both are identical, {@code false} otherwise. */ public boolean isIdenticalMtu(LinkProperties target) { From b77f15d90b2f99f65cd6b31b18584954eb834e5c Mon Sep 17 00:00:00 2001 From: Yuhao Zheng Date: Mon, 9 Sep 2013 17:00:04 -0700 Subject: [PATCH 54/71] Add a hidden API to toggle airplane mode. Added a hidden API under ConnectivityManager to toggle airplane mode. This may be a temp solution for b/10653570. bug:10653570 Change-Id: I0b2b42230073289eb8dc6891317d62b84e26c133 --- core/java/android/net/ConnectivityManager.java | 16 ++++++++++++++++ core/java/android/net/IConnectivityManager.aidl | 2 ++ .../com/android/server/ConnectivityService.java | 15 +++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 4cf38b6b39..c78a973cee 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1476,4 +1476,20 @@ public class ConnectivityManager { } catch (RemoteException e) { } } + + /** + * Set the value for enabling/disabling airplane mode + * + * @param enable whether to enable airplane mode or not + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. + * @hide + */ + public void setAirplaneMode(boolean enable) { + try { + mService.setAirplaneMode(enable); + } catch (RemoteException e) { + } + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index a6f10ecbe4..b3fa79fc50 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -156,4 +156,6 @@ interface IConnectivityManager LinkQualityInfo[] getAllLinkQualityInfo(); void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url); + + void setAirplaneMode(boolean enable); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 02a78dea33..4e3faca51a 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4681,6 +4681,21 @@ public class ConnectivityService extends IConnectivityManager.Stub { setProvNotificationVisible(visible, networkType, extraInfo, url); } + @Override + public void setAirplaneMode(boolean enable) { + enforceConnectivityInternalPermission(); + final ContentResolver cr = mContext.getContentResolver(); + Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0); + Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.putExtra("state", enable); + final long ident = Binder.clearCallingIdentity(); + try { + mContext.sendBroadcast(intent); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + private void onUserStart(int userId) { synchronized(mVpns) { Vpn userVpn = mVpns.get(userId); From 168cd72f764254d79cc0b716235408f79bf0302e Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 10 Sep 2013 21:03:27 -0700 Subject: [PATCH 55/71] Request all tethering interfaces, fix corruption. netd now tracks statistics for tethered interfaces across tethering sessions, so switch to asking for all tethering stats. (Currently we're double-counting all tethering data, ever since it started tracking across sessions.) Also catch OOME to handle corrupt stats files, which we then dump to DropBox and then start over. Bug: 5868832, 9796109 Change-Id: I2eb2a1bf01b993dd198597d770fe0e022466c6b9 --- core/java/android/net/IConnectivityManager.aidl | 6 ------ .../java/com/android/server/ConnectivityService.java | 10 +--------- .../com/android/server/NetworkStatsServiceTest.java | 8 +++----- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index a6f10ecbe4..826f90ce42 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -93,12 +93,6 @@ interface IConnectivityManager String[] getTetheredIfaces(); - /** - * Return list of interface pairs that are actively tethered. Even indexes are - * remote interface, and odd indexes are corresponding local interfaces. - */ - String[] getTetheredIfacePairs(); - String[] getTetheringErroredIfaces(); String[] getTetherableUsbRegexs(); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 02a78dea33..eca7af7dce 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -58,8 +58,8 @@ import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.LinkAddress; import android.net.LinkProperties; -import android.net.LinkQualityInfo; import android.net.LinkProperties.CompareResult; +import android.net.LinkQualityInfo; import android.net.MobileDataStateTracker; import android.net.NetworkConfig; import android.net.NetworkInfo; @@ -89,7 +89,6 @@ import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; -import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; @@ -114,7 +113,6 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; -import com.android.net.IProxyService; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.Nat464Xlat; @@ -3209,12 +3207,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { return mTethering.getTetheredIfaces(); } - @Override - public String[] getTetheredIfacePairs() { - enforceTetherAccessPermission(); - return mTethering.getTetheredIfacePairs(); - } - public String[] getTetheringErroredIfaces() { enforceTetherAccessPermission(); return mTethering.getErroredIfaces(); diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index a9909b2ecf..a1af8cb79f 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -40,7 +40,6 @@ import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL; import static org.easymock.EasyMock.anyLong; -import static org.easymock.EasyMock.aryEq; import static org.easymock.EasyMock.capture; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.eq; @@ -74,13 +73,13 @@ import com.android.server.net.NetworkStatsService; import com.android.server.net.NetworkStatsService.NetworkStatsSettings; import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config; +import libcore.io.IoUtils; + import org.easymock.Capture; import org.easymock.EasyMock; import java.io.File; -import libcore.io.IoUtils; - /** * Tests for {@link NetworkStatsService}. */ @@ -919,8 +918,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expect(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL))).andReturn(detail).atLeastOnce(); // also include tethering details, since they are folded into UID - expect(mConnManager.getTetheredIfacePairs()).andReturn(tetherIfacePairs).atLeastOnce(); - expect(mNetManager.getNetworkStatsTethering(aryEq(tetherIfacePairs))) + expect(mNetManager.getNetworkStatsTethering()) .andReturn(tetherStats).atLeastOnce(); } From 239a3b22f1dd5cb253042e899c3bd268691933da Mon Sep 17 00:00:00 2001 From: Yuhao Zheng Date: Wed, 11 Sep 2013 09:36:41 -0700 Subject: [PATCH 56/71] Fix for the toggle airplane mode hidden API Fix to https://googleplex-android-review.git.corp.google.com/#/c/356900/ Previous implementation throws SecurityException when the API is called from apps. bug:10653570 Change-Id: I95ae6f07db74d881f1a8d3d40a6486105a068e90 --- services/java/com/android/server/ConnectivityService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 4e3faca51a..1af7cc89a9 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4684,12 +4684,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public void setAirplaneMode(boolean enable) { enforceConnectivityInternalPermission(); - final ContentResolver cr = mContext.getContentResolver(); - Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0); - Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - intent.putExtra("state", enable); final long ident = Binder.clearCallingIdentity(); try { + final ContentResolver cr = mContext.getContentResolver(); + Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0); + Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.putExtra("state", enable); mContext.sendBroadcast(intent); } finally { Binder.restoreCallingIdentity(ident); From 0e1e5c93a246a62f32dbe6be5db901855d4229e1 Mon Sep 17 00:00:00 2001 From: Yuhao Zheng Date: Wed, 11 Sep 2013 09:36:41 -0700 Subject: [PATCH 57/71] Fix for the toggle airplane mode hidden API Fix to https://googleplex-android-review.git.corp.google.com/#/c/356900/ Previous implementation throws SecurityException when the API is called from apps. bug:10653570 Change-Id: I95ae6f07db74d881f1a8d3d40a6486105a068e90 --- services/java/com/android/server/ConnectivityService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 4e3faca51a..1af7cc89a9 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4684,12 +4684,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public void setAirplaneMode(boolean enable) { enforceConnectivityInternalPermission(); - final ContentResolver cr = mContext.getContentResolver(); - Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0); - Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - intent.putExtra("state", enable); final long ident = Binder.clearCallingIdentity(); try { + final ContentResolver cr = mContext.getContentResolver(); + Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0); + Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.putExtra("state", enable); mContext.sendBroadcast(intent); } finally { Binder.restoreCallingIdentity(ident); From 0a9cc50662217d2204d880c2a4b1df8650af31b5 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Fri, 23 Aug 2013 19:21:25 -0400 Subject: [PATCH 58/71] Guarantee that PAC Local Proxy owns Port This changes the PAC support to not broadcast the Proxy information until the Local Proxy has started up and successfully bound to a port so that the local proxy information can be guaranteed to be owned by the proxy. Bug: 10459877 Change-Id: I175cd3388c758c55e341115e4a8241884b90d633 --- core/java/android/net/ProxyProperties.java | 10 +++++++++- .../java/com/android/server/ConnectivityService.java | 3 +-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java index 76aea9f58e..648a4b37eb 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyProperties.java @@ -38,7 +38,7 @@ public class ProxyProperties implements Parcelable { private String mPacFileUrl; public static final String LOCAL_EXCL_LIST = ""; - public static final int LOCAL_PORT = 8182; + public static final int LOCAL_PORT = -1; public static final String LOCAL_HOST = "localhost"; public ProxyProperties(String host, int port, String exclList) { @@ -54,6 +54,14 @@ public class ProxyProperties implements Parcelable { mPacFileUrl = pacFileUrl; } + // Only used in PacManager after Local Proxy is bound. + public ProxyProperties(String pacFileUrl, int localProxyPort) { + mHost = LOCAL_HOST; + mPort = localProxyPort; + setExclusionList(LOCAL_EXCL_LIST); + mPacFileUrl = pacFileUrl; + } + private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) { mHost = host; mPort = port; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 4e3faca51a..47f18e7335 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -114,7 +114,6 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; -import com.android.net.IProxyService; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.Nat464Xlat; @@ -3471,7 +3470,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void sendProxyBroadcast(ProxyProperties proxy) { if (proxy == null) proxy = new ProxyProperties("", 0, ""); - mPacManager.setCurrentProxyScriptUrl(proxy); + if (mPacManager.setCurrentProxyScriptUrl(proxy)) return; if (DBG) log("sending Proxy Broadcast for " + proxy); Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | From e14346f8f42f03477bd168a2d4bd33dc6c665983 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Fri, 13 Sep 2013 12:40:11 -0700 Subject: [PATCH 59/71] checkMobileProvisioning should not block. In checkMobileProvisioning the call to mdst.isProvisioningNetwork() is a blocking call and during monkey testing without SIM this is causing ANR's. Move the initial test for provisioning into isMobileOk so checkMobileProvisioning doesn't block. If mobile is not supported return CMP_RESULT_NO_CONNECTION. Cleaned up some debug. Bug: 10674404 Change-Id: I10a0e922cd6ea9790f66e2083f37e68cb0a8861f --- .../android/server/ConnectivityService.java | 63 +++++++------------ 1 file changed, 24 insertions(+), 39 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3f8d7ebcca..cecb35b843 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3987,40 +3987,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Start off with notification off setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); - // See if we've alreadying determined if we've got a provsioning connection - // if so we don't need to do anything active - MobileDataStateTracker mdstDefault = (MobileDataStateTracker) - mNetTrackers[ConnectivityManager.TYPE_MOBILE]; - boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork(); - - MobileDataStateTracker mdstHipri = (MobileDataStateTracker) - mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; - boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork(); - - if (isDefaultProvisioning || isHipriProvisioning) { - if (mIsNotificationVisible) { - if (DBG) { - log("checkMobileProvisioning: provisioning-ignore notification is visible"); - } - } else { - NetworkInfo ni = null; - if (isDefaultProvisioning) { - ni = mdstDefault.getNetworkInfo(); - } - if (isHipriProvisioning) { - ni = mdstHipri.getNetworkInfo(); - } - String url = getMobileProvisioningUrl(); - if ((ni != null) && (!TextUtils.isEmpty(url))) { - setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), url); - } else { - if (DBG) log("checkMobileProvisioning: provisioning but no url, ignore"); - } - } - mIsCheckingMobileProvisioning.set(false); - return timeOutMs; - } - CheckMp checkMp = new CheckMp(mContext, this); CheckMp.CallBack cb = new CheckMp.CallBack() { @Override @@ -4154,8 +4120,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { mParams = params; if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { - log("isMobileOk: not mobile capable"); result = CMP_RESULT_CODE_NO_CONNECTION; + log("isMobileOk: X not mobile capable result=" + result); + return result; + } + + // See if we've already determined we've got a provisioning connection, + // if so we don't need to do anything active. + MobileDataStateTracker mdstDefault = (MobileDataStateTracker) + mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork(); + log("isMobileOk: isDefaultProvisioning=" + isDefaultProvisioning); + + MobileDataStateTracker mdstHipri = (MobileDataStateTracker) + mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork(); + log("isMobileOk: isHipriProvisioning=" + isHipriProvisioning); + + if (isDefaultProvisioning || isHipriProvisioning) { + result = CMP_RESULT_CODE_PROVISIONING_NETWORK; + log("isMobileOk: X default || hipri is provisioning result=" + result); return result; } @@ -4217,8 +4201,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { MobileDataStateTracker mdst = (MobileDataStateTracker) mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; if (mdst.isProvisioningNetwork()) { - if (DBG) log("isMobileOk: isProvisioningNetwork is true"); result = CMP_RESULT_CODE_PROVISIONING_NETWORK; + if (DBG) log("isMobileOk: X isProvisioningNetwork result=" + result); return result; } else { if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue"); @@ -4233,8 +4217,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { addresses = InetAddress.getAllByName(orgUri.getHost()); } catch (UnknownHostException e) { - log("isMobileOk: UnknownHostException"); result = CMP_RESULT_CODE_NO_DNS; + log("isMobileOk: X UnknownHostException result=" + result); return result; } log("isMobileOk: addresses=" + inetAddressesToString(addresses)); @@ -4309,8 +4293,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (responseCode == 204) { // Return - log("isMobileOk: expected responseCode=" + responseCode); result = CMP_RESULT_CODE_CONNECTABLE; + log("isMobileOk: X expected responseCode=" + responseCode + + " result=" + result); return result; } else { // Retry to be sure this was redirected, we've gotten @@ -4328,7 +4313,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } - log("isMobileOk: loops|timed out result=" + result); + log("isMobileOk: X loops|timed out result=" + result); return result; } catch (Exception e) { log("isMobileOk: Exception e=" + e); From e6d205263f2cd629ea6d77d07c642c818bfbcfa4 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Fri, 13 Sep 2013 12:40:11 -0700 Subject: [PATCH 60/71] checkMobileProvisioning should not block. In checkMobileProvisioning the call to mdst.isProvisioningNetwork() is a blocking call and during monkey testing without SIM this is causing ANR's. Move the initial test for provisioning into isMobileOk so checkMobileProvisioning doesn't block. If mobile is not supported return CMP_RESULT_NO_CONNECTION. Cleaned up some debug. Bug: 10674404 Change-Id: I10a0e922cd6ea9790f66e2083f37e68cb0a8861f --- .../android/server/ConnectivityService.java | 63 +++++++------------ 1 file changed, 24 insertions(+), 39 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3f8d7ebcca..cecb35b843 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3987,40 +3987,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Start off with notification off setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); - // See if we've alreadying determined if we've got a provsioning connection - // if so we don't need to do anything active - MobileDataStateTracker mdstDefault = (MobileDataStateTracker) - mNetTrackers[ConnectivityManager.TYPE_MOBILE]; - boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork(); - - MobileDataStateTracker mdstHipri = (MobileDataStateTracker) - mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; - boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork(); - - if (isDefaultProvisioning || isHipriProvisioning) { - if (mIsNotificationVisible) { - if (DBG) { - log("checkMobileProvisioning: provisioning-ignore notification is visible"); - } - } else { - NetworkInfo ni = null; - if (isDefaultProvisioning) { - ni = mdstDefault.getNetworkInfo(); - } - if (isHipriProvisioning) { - ni = mdstHipri.getNetworkInfo(); - } - String url = getMobileProvisioningUrl(); - if ((ni != null) && (!TextUtils.isEmpty(url))) { - setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), url); - } else { - if (DBG) log("checkMobileProvisioning: provisioning but no url, ignore"); - } - } - mIsCheckingMobileProvisioning.set(false); - return timeOutMs; - } - CheckMp checkMp = new CheckMp(mContext, this); CheckMp.CallBack cb = new CheckMp.CallBack() { @Override @@ -4154,8 +4120,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { mParams = params; if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { - log("isMobileOk: not mobile capable"); result = CMP_RESULT_CODE_NO_CONNECTION; + log("isMobileOk: X not mobile capable result=" + result); + return result; + } + + // See if we've already determined we've got a provisioning connection, + // if so we don't need to do anything active. + MobileDataStateTracker mdstDefault = (MobileDataStateTracker) + mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork(); + log("isMobileOk: isDefaultProvisioning=" + isDefaultProvisioning); + + MobileDataStateTracker mdstHipri = (MobileDataStateTracker) + mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork(); + log("isMobileOk: isHipriProvisioning=" + isHipriProvisioning); + + if (isDefaultProvisioning || isHipriProvisioning) { + result = CMP_RESULT_CODE_PROVISIONING_NETWORK; + log("isMobileOk: X default || hipri is provisioning result=" + result); return result; } @@ -4217,8 +4201,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { MobileDataStateTracker mdst = (MobileDataStateTracker) mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; if (mdst.isProvisioningNetwork()) { - if (DBG) log("isMobileOk: isProvisioningNetwork is true"); result = CMP_RESULT_CODE_PROVISIONING_NETWORK; + if (DBG) log("isMobileOk: X isProvisioningNetwork result=" + result); return result; } else { if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue"); @@ -4233,8 +4217,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { addresses = InetAddress.getAllByName(orgUri.getHost()); } catch (UnknownHostException e) { - log("isMobileOk: UnknownHostException"); result = CMP_RESULT_CODE_NO_DNS; + log("isMobileOk: X UnknownHostException result=" + result); return result; } log("isMobileOk: addresses=" + inetAddressesToString(addresses)); @@ -4309,8 +4293,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (responseCode == 204) { // Return - log("isMobileOk: expected responseCode=" + responseCode); result = CMP_RESULT_CODE_CONNECTABLE; + log("isMobileOk: X expected responseCode=" + responseCode + + " result=" + result); return result; } else { // Retry to be sure this was redirected, we've gotten @@ -4328,7 +4313,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } - log("isMobileOk: loops|timed out result=" + result); + log("isMobileOk: X loops|timed out result=" + result); return result; } catch (Exception e) { log("isMobileOk: Exception e=" + e); From 11fa47227d02ee75839573206eb29d401eafb1a7 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Sat, 14 Sep 2013 09:04:53 -0700 Subject: [PATCH 61/71] Tighten condition for calling checkMobileProvisioning. Add the condition that the connected network needs to be TYPE_MOBILE. This eliminates checking on connecting to secondary networks like FOTA, MMS, SUPL ... This reduces unnecessary attempts to bring up multiple connections at the same time. Especially in the light of the trouble we're having with HFA on Sprint, where we don't want to connect to any other network until HFA has completed. Bug: 10758001 Change-Id: Id294536b70304a51de4752bc1a4ffac734f10f1a --- services/java/com/android/server/ConnectivityService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 19b762d39c..3f13f3acf5 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2953,8 +2953,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (ConnectivityManager.isNetworkTypeMobile(info.getType()) && (0 != Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0)) - && ((state == NetworkInfo.State.CONNECTED) - || info.isConnectedToProvisioningNetwork())) { + && (((state == NetworkInfo.State.CONNECTED) + && (info.getType() == ConnectivityManager.TYPE_MOBILE)) + || info.isConnectedToProvisioningNetwork())) { + log("ConnectivityChange checkMobileProvisioning for" + + " TYPE_MOBILE or ProvisioningNetwork"); checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS); } From 06c96d07ad5858ce4ebb1d69a31607d8c438029a Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Sat, 14 Sep 2013 09:04:53 -0700 Subject: [PATCH 62/71] Tighten condition for calling checkMobileProvisioning. Add the condition that the connected network needs to be TYPE_MOBILE. This eliminates checking on connecting to secondary networks like FOTA, MMS, SUPL ... This reduces unnecessary attempts to bring up multiple connections at the same time. Especially in the light of the trouble we're having with HFA on Sprint, where we don't want to connect to any other network until HFA has completed. Bug: 10758001 Change-Id: Id294536b70304a51de4752bc1a4ffac734f10f1a --- services/java/com/android/server/ConnectivityService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index cecb35b843..7560d090c3 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2953,8 +2953,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (ConnectivityManager.isNetworkTypeMobile(info.getType()) && (0 != Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0)) - && ((state == NetworkInfo.State.CONNECTED) - || info.isConnectedToProvisioningNetwork())) { + && (((state == NetworkInfo.State.CONNECTED) + && (info.getType() == ConnectivityManager.TYPE_MOBILE)) + || info.isConnectedToProvisioningNetwork())) { + log("ConnectivityChange checkMobileProvisioning for" + + " TYPE_MOBILE or ProvisioningNetwork"); checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS); } From b87ab962952486458fd6297f1c349b6f24ce8040 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 24 Sep 2013 11:05:57 -0700 Subject: [PATCH 63/71] Don't redirect dns to an iface without dns servers bug:10115444 Change-Id: Ide42072bb3aae21f8e99c11c2de263e9a765b911 --- .../android/server/ConnectivityService.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3f13f3acf5..56d50103a5 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2794,7 +2794,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } mNumDnsEntries = last; } catch (Exception e) { - if (DBG) loge("exception setting default dns interface: " + e); + loge("exception setting default dns interface: " + e); } } @@ -3779,31 +3779,33 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - public void addUserForwarding(String interfaze, int uid) { + public void addUserForwarding(String interfaze, int uid, boolean forwardDns) { int uidStart = uid * UserHandle.PER_USER_RANGE; int uidEnd = uidStart + UserHandle.PER_USER_RANGE - 1; - addUidForwarding(interfaze, uidStart, uidEnd); + addUidForwarding(interfaze, uidStart, uidEnd, forwardDns); } - public void clearUserForwarding(String interfaze, int uid) { + public void clearUserForwarding(String interfaze, int uid, boolean forwardDns) { int uidStart = uid * UserHandle.PER_USER_RANGE; int uidEnd = uidStart + UserHandle.PER_USER_RANGE - 1; - clearUidForwarding(interfaze, uidStart, uidEnd); + clearUidForwarding(interfaze, uidStart, uidEnd, forwardDns); } - public void addUidForwarding(String interfaze, int uidStart, int uidEnd) { + public void addUidForwarding(String interfaze, int uidStart, int uidEnd, + boolean forwardDns) { try { mNetd.setUidRangeRoute(interfaze,uidStart, uidEnd); - mNetd.setDnsInterfaceForUidRange(interfaze, uidStart, uidEnd); + if (forwardDns) mNetd.setDnsInterfaceForUidRange(interfaze, uidStart, uidEnd); } catch (RemoteException e) { } } - public void clearUidForwarding(String interfaze, int uidStart, int uidEnd) { + public void clearUidForwarding(String interfaze, int uidStart, int uidEnd, + boolean forwardDns) { try { mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd); - mNetd.clearDnsInterfaceForUidRange(uidStart, uidEnd); + if (forwardDns) mNetd.clearDnsInterfaceForUidRange(uidStart, uidEnd); } catch (RemoteException e) { } From 76f49d3ceeb76b1f7e5d0e73d62f44c8e23561cc Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Thu, 3 Oct 2013 08:34:46 -0700 Subject: [PATCH 64/71] Use networkType to display wifi and mobile notification separately. There are two bugs one is I was clearing the notification in CaptivePortalTracker when entering the ActivateState. (double check according to bug 5021626 we should be calling enter) Second is we could have the need to display both icons but can't because we only allow one. The solution I'm proposing here is to allow two notifications and have then controlled separately. Bug: 10886908 Change-Id: I30e7130bc542535492d175640a4990c592f32806 --- .../com/android/server/ConnectivityService.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3f13f3acf5..f005f5ff9c 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3987,8 +3987,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { return timeOutMs; } - // Start off with notification off - setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); + // Start off with mobile notification off + setProvNotificationVisible(false, ConnectivityManager.TYPE_MOBILE_HIPRI, null, null); CheckMp checkMp = new CheckMp(mContext, this); CheckMp.CallBack cb = new CheckMp.CallBack() { @@ -4013,7 +4013,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } if (TextUtils.isEmpty(url) == false) { if (DBG) log("CheckMp.onComplete: warm (redirected), url=" + url); - setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), + setProvNotificationVisible(true, + ConnectivityManager.TYPE_MOBILE_HIPRI, ni.getExtraInfo(), url); } else { if (DBG) log("CheckMp.onComplete: warm (redirected), no url"); @@ -4024,7 +4025,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url) == false) { if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), url=" + url); - setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), + setProvNotificationVisible(true, + ConnectivityManager.TYPE_MOBILE_HIPRI, ni.getExtraInfo(), url); } else { if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url"); @@ -4426,7 +4428,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleMobileProvisioningAction(String url) { // Notication mark notification as not visible - setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); + setProvNotificationVisible(false, ConnectivityManager.TYPE_MOBILE_HIPRI, null, null); // If provisioning network handle as a special case, // otherwise launch browser with the intent directly. @@ -4512,14 +4514,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { notification.setLatestEventInfo(mContext, title, details, notification.contentIntent); try { - notificationManager.notify(NOTIFICATION_ID, 1, notification); + notificationManager.notify(NOTIFICATION_ID, networkType, notification); } catch (NullPointerException npe) { loge("setNotificaitionVisible: visible notificationManager npe=" + npe); npe.printStackTrace(); } } else { try { - notificationManager.cancel(NOTIFICATION_ID, 1); + notificationManager.cancel(NOTIFICATION_ID, networkType); } catch (NullPointerException npe) { loge("setNotificaitionVisible: cancel notificationManager npe=" + npe); npe.printStackTrace(); From 88a69fc2c0b1334cfd430c2947ff6534b85f3359 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 3 Oct 2013 16:59:05 -0700 Subject: [PATCH 65/71] DO NOT MERGE Un-deprecate getDhcpInfo Replacement api isn't available. bug:10003785 Change-Id: I0c91716d9aae61dc1db4d015a78b729157ea99a9 --- core/java/android/net/DhcpInfo.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java index ab4cd9b9ef..3bede5da50 100644 --- a/core/java/android/net/DhcpInfo.java +++ b/core/java/android/net/DhcpInfo.java @@ -22,7 +22,6 @@ import java.net.InetAddress; /** * A simple object for retrieving the results of a DHCP request. - * @deprecated - use LinkProperties - To be removed 11/2014 */ public class DhcpInfo implements Parcelable { public int ipAddress; From 5b1ce8a83580d683d687367862054295020bd07f Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 4 Oct 2013 09:53:39 -0700 Subject: [PATCH 66/71] Un-deprecate getDhcpInfo Replacement api isn't available. bug:10003785 Change-Id: Ibe981ae90e1c6c2f1b65fa225443ae4cc92c2a3a --- core/java/android/net/DhcpInfo.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java index ab4cd9b9ef..3bede5da50 100644 --- a/core/java/android/net/DhcpInfo.java +++ b/core/java/android/net/DhcpInfo.java @@ -22,7 +22,6 @@ import java.net.InetAddress; /** * A simple object for retrieving the results of a DHCP request. - * @deprecated - use LinkProperties - To be removed 11/2014 */ public class DhcpInfo implements Parcelable { public int ipAddress; From f725b93f4855f5a2bf4a9e7428d03ca91a2e7b22 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 3 Oct 2013 16:59:05 -0700 Subject: [PATCH 67/71] DO NOT MERGE Un-deprecate getDhcpInfo Replacement api isn't available. bug:10003785 Change-Id: I0c91716d9aae61dc1db4d015a78b729157ea99a9 --- core/java/android/net/DhcpInfo.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java index ab4cd9b9ef..3bede5da50 100644 --- a/core/java/android/net/DhcpInfo.java +++ b/core/java/android/net/DhcpInfo.java @@ -22,7 +22,6 @@ import java.net.InetAddress; /** * A simple object for retrieving the results of a DHCP request. - * @deprecated - use LinkProperties - To be removed 11/2014 */ public class DhcpInfo implements Parcelable { public int ipAddress; From 9405beeea0855b2b76834049a3a8eb4a445242ae Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 8 Oct 2013 10:41:25 +0900 Subject: [PATCH 68/71] Fix captive portal detection on IPv6 networks. Currently the captive portal check URL is generated by concatenating scheme, "://", IP address, and port. This breaks for IPv6 because IPv6 addresses in URLs must be enclosed in square brackets (e.g., http://2001:db8::1/generate_204 is invalid; should he http://[2001:db8::1]/generate_204 instead). The resulting MalformedURLException causes isMobileOk to report that there is no captive portal, even if there is one. Fortunately the three-arg URL constructor already knows how to construct URLs with IPv6 addresses. Use that instead of generating the URL ourselves. Bug: 10801896 Change-Id: I02605ef62f493a34f25bb405ef02b111543a76fd --- .../java/com/android/server/ConnectivityService.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 59b559e0de..5695ee510d 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4247,6 +4247,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { addrTried ++) { // Choose the address at random but make sure its type is supported + // TODO: This doesn't work 100% of the time, because we may end up + // trying the same invalid address more than once and ignoring one + // of the valid addresses. InetAddress hostAddr = addresses[rand.nextInt(addresses.length)]; if (((hostAddr instanceof Inet4Address) && linkHasIpv4) || ((hostAddr instanceof Inet6Address) && linkHasIpv6)) { @@ -4271,10 +4274,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } // Rewrite the url to have numeric address to use the specific route. - // I also set the "Connection" to "Close" as by default "Keep-Alive" - // is used which is useless in this case. - URL newUrl = new URL(orgUri.getScheme() + "://" - + hostAddr.getHostAddress() + orgUri.getPath()); + URL newUrl = new URL(orgUri.getScheme(), + hostAddr.getHostAddress(), orgUri.getPath()); log("isMobileOk: newUrl=" + newUrl); HttpURLConnection urlConn = null; @@ -4287,6 +4288,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { urlConn.setReadTimeout(SOCKET_TIMEOUT_MS); urlConn.setUseCaches(false); urlConn.setAllowUserInteraction(false); + // Set the "Connection" to "Close" as by default "Keep-Alive" + // is used which is useless in this case. urlConn.setRequestProperty("Connection", "close"); int responseCode = urlConn.getResponseCode(); From 75d9bcddea5f43fc9ca37199674c2cbb3c659e2c Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 7 Oct 2013 14:32:00 -0700 Subject: [PATCH 69/71] Fix issue #11113111: `dumpsys activity service` is broken Change-Id: Ie02d27b377c562085ef7eb5dea144ce2f382c11d From a69f1b06de333a97a99c317d72357f1f2373c636 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Thu, 10 Oct 2013 14:02:51 -0400 Subject: [PATCH 70/71] getProxy in ConnectivityService returns port w/PAC Changes the PacManager to report message back to ConnectivityService to send a broadcast once the download has completed. This allows the ConnectivityService to store the correct proxy info for getProxy(). This made the problem arise that ProxyProperties was not handling port while it had PAC. Added small fix for equals() and parcelization. The combination of these fixes seems to resolve Bug: 11028616. Bug: 11168706 Change-Id: I92d1343a8e804391ab77596b8167a2ef8d76b378 --- core/java/android/net/ProxyProperties.java | 7 +++++-- .../java/com/android/server/ConnectivityService.java | 11 ++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java index 648a4b37eb..78ac75f22c 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyProperties.java @@ -178,7 +178,7 @@ public class ProxyProperties implements Parcelable { // If PAC URL is present in either then they must be equal. // Other parameters will only be for fall back. if (!TextUtils.isEmpty(mPacFileUrl)) { - return mPacFileUrl.equals(p.getPacFileUrl()); + return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort; } if (!TextUtils.isEmpty(p.getPacFileUrl())) { return false; @@ -219,6 +219,7 @@ public class ProxyProperties implements Parcelable { if (mPacFileUrl != null) { dest.writeByte((byte)1); dest.writeString(mPacFileUrl); + dest.writeInt(mPort); return; } else { dest.writeByte((byte)0); @@ -244,7 +245,9 @@ public class ProxyProperties implements Parcelable { String host = null; int port = 0; if (in.readByte() != 0) { - return new ProxyProperties(in.readString()); + String url = in.readString(); + int localPort = in.readInt(); + return new ProxyProperties(url, localPort); } if (in.readByte() != 0) { host = in.readString(); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 5695ee510d..70418e8d04 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -353,6 +353,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15; + /** + * PAC manager has received new port. + */ + private static final int EVENT_PROXY_HAS_CHANGED = 16; + /** Handler used for internal events. */ private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ @@ -679,7 +684,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { }, new IntentFilter(filter)); - mPacManager = new PacManager(mContext); + mPacManager = new PacManager(mContext, mHandler, EVENT_PROXY_HAS_CHANGED); filter = new IntentFilter(); filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); @@ -3124,6 +3129,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleNetworkSamplingTimeout(); break; } + case EVENT_PROXY_HAS_CHANGED: { + handleApplyDefaultProxy((ProxyProperties)msg.obj); + break; + } } } } From af2f34adfd71401c6cc8c827e0e509263c2a72d9 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 14 Oct 2013 18:03:02 -0700 Subject: [PATCH 71/71] Retry captiveportal check even if only one addr We're getting some false positive results on this check and while it was coded to try 3 times given sufficient independent addrs the default url resolves to a single address so we'd just try once. Rework to try again even with fewer urls to try to reduce the false positives. Also adds a random query param to fool proxies into not caching. bug:9972012 Change-Id: Ib719f40ec612065ca6bcd919549fc1164506d35a --- .../android/server/ConnectivityService.java | 53 ++++++++++++------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 70418e8d04..b5f0697472 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4247,27 +4247,35 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("isMobileOk: linkHasIpv4=" + linkHasIpv4 + " linkHasIpv6=" + linkHasIpv6); - // Loop through at most 3 valid addresses or all of the address or until - // we run out of time - int loops = Math.min(3, addresses.length); - for(int validAddr=0, addrTried=0; - (validAddr < loops) && (addrTried < addresses.length) - && (SystemClock.elapsedRealtime() < endTime); - addrTried ++) { + final ArrayList validAddresses = + new ArrayList(addresses.length); - // Choose the address at random but make sure its type is supported - // TODO: This doesn't work 100% of the time, because we may end up - // trying the same invalid address more than once and ignoring one - // of the valid addresses. - InetAddress hostAddr = addresses[rand.nextInt(addresses.length)]; - if (((hostAddr instanceof Inet4Address) && linkHasIpv4) - || ((hostAddr instanceof Inet6Address) && linkHasIpv6)) { - // Valid address, so use it - validAddr += 1; - } else { - // Invalid address so try next address - continue; + for (InetAddress addr : addresses) { + if (((addr instanceof Inet4Address) && linkHasIpv4) || + ((addr instanceof Inet6Address) && linkHasIpv6)) { + validAddresses.add(addr); } + } + + if (validAddresses.size() == 0) { + return CMP_RESULT_CODE_NO_CONNECTION; + } + + int addrTried = 0; + while (true) { + // Loop through at most 3 valid addresses or until + // we run out of time + if (addrTried++ >= 3) { + log("too many loops tried - giving up"); + break; + } + if (SystemClock.elapsedRealtime() >= endTime) { + log("spend too much time - giving up"); + break; + } + + InetAddress hostAddr = validAddresses.get(rand.nextInt( + validAddresses.size())); // Make a route to host so we check the specific interface. if (mCs.requestRouteToHostAddress(ConnectivityManager.TYPE_MOBILE_HIPRI, @@ -4283,8 +4291,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { } // Rewrite the url to have numeric address to use the specific route. + // Add a pointless random query param to fool proxies into not caching. URL newUrl = new URL(orgUri.getScheme(), - hostAddr.getHostAddress(), orgUri.getPath()); + hostAddr.getHostAddress(), + orgUri.getPath() + "?q=" + rand.nextInt(Integer.MAX_VALUE)); log("isMobileOk: newUrl=" + newUrl); HttpURLConnection urlConn = null; @@ -4321,6 +4331,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { // occasions where a server returned 200 even though // the device didn't have a "warm" sim. log("isMobileOk: not expected responseCode=" + responseCode); + // TODO - it would be nice in the single-address case to do + // another DNS resolve here, but flushing the cache is a bit + // heavy-handed. result = CMP_RESULT_CODE_REDIRECTED; } } catch (Exception e) {