am eede7e89: Merge "Minor cleanups to NetdCallbackReceiver.onEvent."

* commit 'eede7e89c94b3bb56c26aec137c53d592d3bc7c3':
  Minor cleanups to NetdCallbackReceiver.onEvent.
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java
index 44cfa94..010e527 100644
--- a/core/java/android/net/ProxyProperties.java
+++ b/core/java/android/net/ProxyProperties.java
@@ -140,6 +140,7 @@
     }
 
     public boolean isValid() {
+        if (!TextUtils.isEmpty(mPacFileUrl)) return true;
         try {
             Proxy.validate(mHost == null ? "" : mHost, mPort == 0 ? "" : Integer.toString(mPort),
                     mExclusionList == null ? "" : mExclusionList);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index a9b4f19..d42ae3a 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -77,6 +77,7 @@
 import android.net.wimax.WimaxManagerConstants;
 import android.os.AsyncTask;
 import android.os.Binder;
+import android.os.Build;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -141,6 +142,7 @@
 import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.URL;
+import java.net.URLConnection;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -154,6 +156,10 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSession;
+
 /**
  * @hide
  */
@@ -3454,7 +3460,7 @@
         synchronized (mProxyLock) {
             if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
             if (mDefaultProxy == proxy) return; // catches repeated nulls
-            if (!proxy.isValid()) {
+            if (proxy != null &&  !proxy.isValid()) {
                 if (DBG) log("Invalid proxy properties, ignoring: " + proxy.toString());
                 return;
             }
@@ -4083,8 +4089,28 @@
     static class CheckMp extends
             AsyncTask<CheckMp.Params, Void, Integer> {
         private static final String CHECKMP_TAG = "CheckMp";
+
+        // adb shell setprop persist.checkmp.testfailures 1 to enable testing failures
+        private static boolean mTestingFailures;
+
+        // Choosing 4 loops as half of them will use HTTPS and the other half HTTP
+        private static final int MAX_LOOPS = 4;
+
+        // Number of milli-seconds to complete all of the retires
         public static final int MAX_TIMEOUT_MS =  60000;
+
+        // The socket should retry only 5 seconds, the default is longer
         private static final int SOCKET_TIMEOUT_MS = 5000;
+
+        // Sleep time for network errors
+        private static final int NET_ERROR_SLEEP_SEC = 3;
+
+        // Sleep time for network route establishment
+        private static final int NET_ROUTE_ESTABLISHMENT_SLEEP_SEC = 3;
+
+        // Short sleep time for polling :(
+        private static final int POLLING_SLEEP_SEC = 1;
+
         private Context mContext;
         private ConnectivityService mCs;
         private TelephonyManager mTm;
@@ -4110,6 +4136,31 @@
             }
         }
 
+        // As explained to me by Brian Carlstrom and Kenny Root, Certificates can be
+        // issued by name or ip address, for Google its by name so when we construct
+        // this HostnameVerifier we'll pass the original Uri and use it to verify
+        // the host. If the host name in the original uril fails we'll test the
+        // hostname parameter just incase things change.
+        static class CheckMpHostnameVerifier implements HostnameVerifier {
+            Uri mOrgUri;
+
+            CheckMpHostnameVerifier(Uri orgUri) {
+                mOrgUri = orgUri;
+            }
+
+            @Override
+            public boolean verify(String hostname, SSLSession session) {
+                HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
+                String orgUriHost = mOrgUri.getHost();
+                boolean retVal = hv.verify(orgUriHost, session) || hv.verify(hostname, session);
+                if (DBG) {
+                    log("isMobileOk: hostnameVerify retVal=" + retVal + " hostname=" + hostname
+                        + " orgUriHost=" + orgUriHost);
+                }
+                return retVal;
+            }
+        }
+
         /**
          * The call back object passed in Params. onComplete will be called
          * on the main thread.
@@ -4120,6 +4171,13 @@
         }
 
         public CheckMp(Context context, ConnectivityService cs) {
+            if (Build.IS_DEBUGGABLE) {
+                mTestingFailures =
+                        SystemProperties.getInt("persist.checkmp.testfailures", 0) == 1;
+            } else {
+                mTestingFailures = false;
+            }
+
             mContext = context;
             mCs = cs;
 
@@ -4191,7 +4249,7 @@
                             mCs.setEnableFailFastMobileData(DctConstants.ENABLED);
                             break;
                         }
-                        sleep(1);
+                        sleep(POLLING_SLEEP_SEC);
                     }
                 }
 
@@ -4209,7 +4267,7 @@
                     }
                     if (VDBG) log("isMobileOk: hipri not started yet");
                     result = CMP_RESULT_CODE_NO_CONNECTION;
-                    sleep(1);
+                    sleep(POLLING_SLEEP_SEC);
                 }
 
                 // Continue trying to connect until time has run out
@@ -4225,7 +4283,7 @@
                                 log("isMobileOk: not connected ni=" +
                                     mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI));
                             }
-                            sleep(1);
+                            sleep(POLLING_SLEEP_SEC);
                             result = CMP_RESULT_CODE_NO_CONNECTION;
                             continue;
                         }
@@ -4243,7 +4301,7 @@
 
                         // 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
+                        // the addresses and will try every address but that will bypass the
                         // route to host we setup and the connection could succeed as the default
                         // interface might be connected to the internet via wifi or other interface.
                         InetAddress[] addresses;
@@ -4280,14 +4338,14 @@
 
                         int addrTried = 0;
                         while (true) {
-                            // Loop through at most 3 valid addresses or until
+                            // Loop through at most MAX_LOOPS valid addresses or until
                             // we run out of time
-                            if (addrTried++ >= 3) {
-                                log("too many loops tried - giving up");
+                            if (addrTried++ >= MAX_LOOPS) {
+                                log("isMobileOk: too many loops tried - giving up");
                                 break;
                             }
                             if (SystemClock.elapsedRealtime() >= endTime) {
-                                log("spend too much time - giving up");
+                                log("isMobileOk: spend too much time - giving up");
                                 break;
                             }
 
@@ -4300,25 +4358,37 @@
                                 // Wait a short time to be sure the route is established ??
                                 log("isMobileOk:"
                                         + " wait to establish route to hostAddr=" + hostAddr);
-                                sleep(3);
+                                sleep(NET_ROUTE_ESTABLISHMENT_SLEEP_SEC);
                             } else {
                                 log("isMobileOk:"
                                         + " could not establish route to hostAddr=" + hostAddr);
+                                // Wait a short time before the next attempt
+                                sleep(NET_ERROR_SLEEP_SEC);
                                 continue;
                             }
 
-                            // 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() + "?q=" + rand.nextInt(Integer.MAX_VALUE));
+                            // Rewrite the url to have numeric address to use the specific route
+                            // using http for half the attempts and https for the other half.
+                            // Doing https first and http second as on a redirected walled garden
+                            // such as t-mobile uses we get a SocketTimeoutException: "SSL
+                            // handshake timed out" which we declare as
+                            // CMP_RESULT_CODE_NO_TCP_CONNECTION. We could change this, but by
+                            // having http second we will be using logic used for some time.
+                            URL newUrl;
+                            String scheme = (addrTried <= (MAX_LOOPS/2)) ? "https" : "http";
+                            newUrl = new URL(scheme, hostAddr.getHostAddress(),
+                                        orgUri.getPath());
                             log("isMobileOk: newUrl=" + newUrl);
 
                             HttpURLConnection urlConn = null;
                             try {
-                                // Open the connection set the request header and get the response
-                                urlConn = (HttpURLConnection) newUrl.openConnection(
+                                // Open the connection set the request headers and get the response
+                                urlConn = (HttpURLConnection)newUrl.openConnection(
                                         java.net.Proxy.NO_PROXY);
+                                if (scheme.equals("https")) {
+                                    ((HttpsURLConnection)urlConn).setHostnameVerifier(
+                                            new CheckMpHostnameVerifier(orgUri));
+                                }
                                 urlConn.setInstanceFollowRedirects(false);
                                 urlConn.setConnectTimeout(SOCKET_TIMEOUT_MS);
                                 urlConn.setReadTimeout(SOCKET_TIMEOUT_MS);
@@ -4337,10 +4407,17 @@
                                 urlConn.disconnect();
                                 urlConn = null;
 
+                                if (mTestingFailures) {
+                                    // Pretend no connection, this tests using http and https
+                                    result = CMP_RESULT_CODE_NO_CONNECTION;
+                                    log("isMobileOk: TESTING_FAILURES, pretend no connction");
+                                    continue;
+                                }
+
                                 if (responseCode == 204) {
                                     // Return
                                     result = CMP_RESULT_CODE_CONNECTABLE;
-                                    log("isMobileOk: X expected responseCode=" + responseCode
+                                    log("isMobileOk: X got expected responseCode=" + responseCode
                                             + " result=" + result);
                                     return result;
                                 } else {
@@ -4354,12 +4431,14 @@
                                     result = CMP_RESULT_CODE_REDIRECTED;
                                 }
                             } catch (Exception e) {
-                                log("isMobileOk: HttpURLConnection Exception e=" + e);
+                                log("isMobileOk: HttpURLConnection Exception" + e);
                                 result = CMP_RESULT_CODE_NO_TCP_CONNECTION;
                                 if (urlConn != null) {
                                     urlConn.disconnect();
                                     urlConn = null;
                                 }
+                                sleep(NET_ERROR_SLEEP_SEC);
+                                continue;
                             }
                         }
                         log("isMobileOk: X loops|timed out result=" + result);
@@ -4387,7 +4466,7 @@
                             log("isMobileOk: connected ni=" +
                                 mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI));
                         }
-                        sleep(1);
+                        sleep(POLLING_SLEEP_SEC);
                         continue;
                     }
                 }
@@ -4452,7 +4531,7 @@
             }
         }
 
-        private void log(String s) {
+        private static void log(String s) {
             Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s);
         }
     }
@@ -4484,8 +4563,9 @@
             mdst.enableMobileProvisioning(url);
         } else {
             if (DBG) log("handleMobileProvisioningAction: on default network");
-            Intent newIntent =
-                    new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+            Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
+                    Intent.CATEGORY_APP_BROWSER);
+            newIntent.setData(Uri.parse(url));
             newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
                     Intent.FLAG_ACTIVITY_NEW_TASK);
             try {