OSDN Git Service

API CHANGE: Add SSLSessionCache public API to allow unbundled SSL session caching.
authorDan Egnor <egnor@google.com>
Tue, 9 Feb 2010 05:56:38 +0000 (21:56 -0800)
committerDan Egnor <egnor@google.com>
Wed, 10 Feb 2010 22:43:21 +0000 (14:43 -0800)
Generally clean up the associated SSLCertificateSocketFactory API as well,
change AndroidHttpClient to use this new thing, and make the android-common
library build SDK-clean (woo hoo).

Bug: 2362543
Bug: 2357311

api/current.xml
common/Android.mk
common/java/com/android/common/AndroidHttpClient.java
common/java/com/android/common/ArrayListCursor.java
core/java/android/net/SSLCertificateSocketFactory.java
core/java/android/net/SSLSessionCache.java [new file with mode: 0644]
core/java/android/provider/Settings.java

index 4b19006..81ce146 100644 (file)
  type="android.net.SSLCertificateSocketFactory"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
-<parameter name="socketReadTimeoutForSslHandshake" type="int">
+<parameter name="handshakeTimeoutMillis" type="int">
 </parameter>
-<exception name="KeyManagementException" type="java.security.KeyManagementException">
-</exception>
-<exception name="NoSuchAlgorithmException" type="java.security.NoSuchAlgorithmException">
-</exception>
 </constructor>
 <method name="createSocket"
  return="java.net.Socket"
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="socket" type="java.net.Socket">
+<parameter name="k" type="java.net.Socket">
 </parameter>
-<parameter name="s" type="java.lang.String">
+<parameter name="host" type="java.lang.String">
 </parameter>
-<parameter name="i" type="int">
+<parameter name="port" type="int">
 </parameter>
-<parameter name="flag" type="boolean">
+<parameter name="close" type="boolean">
 </parameter>
 <exception name="IOException" type="java.io.IOException">
 </exception>
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="inaddr" type="java.net.InetAddress">
+<parameter name="addr" type="java.net.InetAddress">
 </parameter>
-<parameter name="i" type="int">
+<parameter name="port" type="int">
 </parameter>
-<parameter name="inaddr2" type="java.net.InetAddress">
+<parameter name="localAddr" type="java.net.InetAddress">
 </parameter>
-<parameter name="j" type="int">
+<parameter name="localPort" type="int">
 </parameter>
 <exception name="IOException" type="java.io.IOException">
 </exception>
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="inaddr" type="java.net.InetAddress">
+<parameter name="addr" type="java.net.InetAddress">
 </parameter>
-<parameter name="i" type="int">
+<parameter name="port" type="int">
 </parameter>
 <exception name="IOException" type="java.io.IOException">
 </exception>
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="s" type="java.lang.String">
+<parameter name="host" type="java.lang.String">
 </parameter>
-<parameter name="i" type="int">
+<parameter name="port" type="int">
 </parameter>
-<parameter name="inaddr" type="java.net.InetAddress">
+<parameter name="localAddr" type="java.net.InetAddress">
 </parameter>
-<parameter name="j" type="int">
+<parameter name="localPort" type="int">
 </parameter>
 <exception name="IOException" type="java.io.IOException">
 </exception>
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="s" type="java.lang.String">
+<parameter name="host" type="java.lang.String">
 </parameter>
-<parameter name="i" type="int">
+<parameter name="port" type="int">
 </parameter>
 <exception name="IOException" type="java.io.IOException">
 </exception>
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="socketReadTimeoutForSslHandshake" type="int">
+<parameter name="handshakeTimeoutMillis" type="int">
+</parameter>
+</method>
+<method name="getDefault"
+ return="javax.net.SocketFactory"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="handshakeTimeoutMillis" type="int">
+</parameter>
+<parameter name="cache" type="android.net.SSLSessionCache">
 </parameter>
 </method>
 <method name="getDefaultCipherSuites"
  visibility="public"
 >
 </method>
+<method name="getHttpSocketFactory"
+ return="org.apache.http.conn.ssl.SSLSocketFactory"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="handshakeTimeoutMillis" type="int">
+</parameter>
+<parameter name="cache" type="android.net.SSLSessionCache">
+</parameter>
+</method>
 <method name="getSupportedCipherSuites"
  return="java.lang.String[]"
  abstract="false"
 >
 </method>
 </class>
+<class name="SSLSessionCache"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SSLSessionCache"
+ type="android.net.SSLSessionCache"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dir" type="java.io.File">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</constructor>
+<constructor name="SSLSessionCache"
+ type="android.net.SSLSessionCache"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+</class>
 <class name="TrafficStats"
  extends="java.lang.Object"
  abstract="false"
index 76091eb..5c5b01b 100644 (file)
@@ -19,6 +19,7 @@ LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-common
+LOCAL_SDK_VERSION := current
 LOCAL_SRC_FILES := $(call all-java-files-under, java)
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
index 99faf6e..4c65eb0 100644 (file)
@@ -47,8 +47,6 @@ import org.apache.http.params.HttpProtocolParams;
 import org.apache.http.protocol.BasicHttpProcessor;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.BasicHttpContext;
-import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
-import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -59,11 +57,11 @@ import java.util.zip.GZIPOutputStream;
 import java.net.URI;
 import java.security.KeyManagementException;
 
+import android.content.Context;
 import android.content.ContentResolver;
+import android.net.SSLCertificateSocketFactory;
+import android.net.SSLSessionCache;
 import android.os.Looper;
-import android.os.SystemProperties;
-import android.provider.Settings;
-import android.text.TextUtils;
 import android.util.Log;
 
 /**
@@ -76,11 +74,9 @@ import android.util.Log;
  * To retain cookies, simply add a cookie store to the HttpContext:</p>
  *
  * <pre>context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);</pre>
- * 
- * {@hide}
  */
 public final class AndroidHttpClient implements HttpClient {
-        
+
     // Gzip of data shorter than this probably won't be worthwhile
     public static long DEFAULT_SYNC_MIN_GZIP_BYTES = 256;
 
@@ -101,12 +97,11 @@ public final class AndroidHttpClient implements HttpClient {
     /**
      * Create a new HttpClient with reasonable defaults (which you can update).
      *
-     * @param userAgent to report in your HTTP requests.
-     * @param sessionCache persistent session cache
+     * @param userAgent to report in your HTTP requests
+     * @param context to use for caching SSL sessions (may be null for no caching)
      * @return AndroidHttpClient for you to use for all your requests.
      */
-    public static AndroidHttpClient newInstance(String userAgent,
-            SSLClientSessionCache sessionCache) {
+    public static AndroidHttpClient newInstance(String userAgent, Context context) {
         HttpParams params = new BasicHttpParams();
 
         // Turn off stale checking.  Our connections break all the time anyway,
@@ -122,13 +117,16 @@ public final class AndroidHttpClient implements HttpClient {
         // often wants to re-POST after a redirect, which we must do ourselves.
         HttpClientParams.setRedirecting(params, false);
 
+        // Use a session cache for SSL sockets
+        SSLSessionCache sessionCache = context == null ? null : new SSLSessionCache(context);
+
         // Set the specified user agent and register standard protocols.
         HttpProtocolParams.setUserAgent(params, userAgent);
         SchemeRegistry schemeRegistry = new SchemeRegistry();
         schemeRegistry.register(new Scheme("http",
                 PlainSocketFactory.getSocketFactory(), 80));
         schemeRegistry.register(new Scheme("https",
-                socketFactoryWithCache(sessionCache), 443));
+                SSLCertificateSocketFactory.getHttpSocketFactory(30 * 1000, sessionCache), 443));
 
         ClientConnectionManager manager =
                 new ThreadSafeClientConnManager(params, schemeRegistry);
@@ -139,32 +137,6 @@ public final class AndroidHttpClient implements HttpClient {
     }
 
     /**
-     * Returns a socket factory backed by the given persistent session cache.
-     *
-     * @param sessionCache to retrieve sessions from, null for no cache
-     */
-    private static SSLSocketFactory socketFactoryWithCache(
-            SSLClientSessionCache sessionCache) {
-        if (sessionCache == null) {
-            // Use the default factory which doesn't support persistent
-            // caching.
-            return SSLSocketFactory.getSocketFactory();
-        }
-
-        // Create a new SSL context backed by the cache.
-        // TODO: Keep a weak *identity* hash map of caches to engines. In the
-        // mean time, if we have two engines for the same cache, they'll still
-        // share sessions but will have to do so through the persistent cache.
-        SSLContextImpl sslContext = new SSLContextImpl();
-        try {
-            sslContext.engineInit(null, null, null, sessionCache, null);
-        } catch (KeyManagementException e) {
-            throw new AssertionError(e);
-        }
-        return new SSLSocketFactory(sslContext.engineGetSocketFactory());
-    }
-
-    /**
      * Create a new HttpClient with reasonable defaults (which you can update).
      * @param userAgent to report in your HTTP requests.
      * @return AndroidHttpClient for you to use for all your requests.
@@ -339,9 +311,7 @@ public final class AndroidHttpClient implements HttpClient {
      * Shorter data will not be compressed.
      */
     public static long getMinGzipSize(ContentResolver resolver) {
-        return Settings.Secure.getLong(resolver,
-                                       Settings.Secure.SYNC_MIN_GZIP_BYTES,
-                                       DEFAULT_SYNC_MIN_GZIP_BYTES);
+        return DEFAULT_SYNC_MIN_GZIP_BYTES;  // For now, this is just a constant.
     }
 
     /* cURL logging support. */
@@ -367,15 +337,6 @@ public final class AndroidHttpClient implements HttpClient {
         }
 
         /**
-         * Returns true if auth logging is turned on for this configuration.  Can only be set on
-         * insecure devices.
-         */
-        private boolean isAuthLoggable() {
-            String secure = SystemProperties.get("ro.secure");
-            return "0".equals(secure) && Log.isLoggable(tag + "-auth", level);
-        }
-
-        /**
          * Prints a message using this configuration.
          */
         private void println(String message) {
@@ -421,8 +382,9 @@ public final class AndroidHttpClient implements HttpClient {
             if (configuration != null
                     && configuration.isLoggable()
                     && request instanceof HttpUriRequest) {
-                configuration.println(toCurl((HttpUriRequest) request,
-                        configuration.isAuthLoggable()));
+                // Never print auth token -- we used to check ro.secure=0 to
+                // enable that, but can't do that in unbundled code.
+                configuration.println(toCurl((HttpUriRequest) request, false));
             }
         }
     }
index cc1fe27..9ad5c36 100644 (file)
@@ -115,11 +115,6 @@ public class ArrayListCursor extends AbstractCursor {
     }
 
     @Override
-    public boolean deleteRow() {
-        return false;
-    }
-
-    @Override
     public String[] getColumnNames() {
         return mColumnNames;
     }
index e40f1b8..ed76b15 100644 (file)
@@ -40,224 +40,174 @@ import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
+import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
 import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
 import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
 import org.apache.harmony.xnet.provider.jsse.SSLParameters;
 
 /**
- * SSLSocketFactory that provides optional (on debug devices, only) skipping of ssl certificfate
- * chain validation and custom read timeouts used just when connecting to the server/negotiating
- * an ssl session.
- *
- * You can skip the ssl certificate checking at runtime by setting socket.relaxsslcheck=yes on
- * devices that do not have have ro.secure set.
+ * SSLSocketFactory implementation with several extra features:
+ * <ul>
+ * <li>Timeout specification for SSL handshake operations
+ * <li>Optional SSL session caching with {@link SSLSessionCache}
+ * <li>On development devices, "setprop socket.relaxsslcheck yes" bypasses all
+ * SSL certificate checks, for testing with development servers
+ * </ul>
+ * Note that the handshake timeout does not apply to actual connection.
+ * If you want a connection timeout as well, use {@link #createSocket()} and
+ * {@link Socket#connect(SocketAddress, int)}.
  */
 public class SSLCertificateSocketFactory extends SSLSocketFactory {
+    private static final String TAG = "SSLCertificateSocketFactory";
 
-    private static final String LOG_TAG = "SSLCertificateSocketFactory";
-
-    private static final TrustManager[] TRUST_MANAGER = new TrustManager[] {
+    private static final TrustManager[] INSECURE_TRUST_MANAGER = new TrustManager[] {
         new X509TrustManager() {
-            public X509Certificate[] getAcceptedIssuers() {
-                return null;
-            }
-
-            public void checkClientTrusted(X509Certificate[] certs,
-                    String authType) { }
-
-            public void checkServerTrusted(X509Certificate[] certs,
-                    String authType) { }
+            public X509Certificate[] getAcceptedIssuers() { return null; }
+            public void checkClientTrusted(X509Certificate[] certs, String authType) { }
+            public void checkServerTrusted(X509Certificate[] certs, String authType) { }
         }
     };
 
-    private final SSLSocketFactory mFactory;
+    private SSLSocketFactory mInsecureFactory = null;
+    private SSLSocketFactory mSecureFactory = null;
 
-    private final int mSocketReadTimeoutForSslHandshake;
+    private final int mHandshakeTimeoutMillis;
+    private final SSLClientSessionCache mSessionCache;
 
-    /**
-     * Do not use this constructor (will be deprecated).  Use {@link #getDefault(int)} instead.
-     */
-    public SSLCertificateSocketFactory(int socketReadTimeoutForSslHandshake)
-            throws NoSuchAlgorithmException, KeyManagementException {
-        this(socketReadTimeoutForSslHandshake, null /* cache */);
+    /** @deprecated Use {@link #getDefault(int)} instead. */
+    public SSLCertificateSocketFactory(int handshakeTimeoutMillis) {
+        this(handshakeTimeoutMillis, null /* cache */);
     }
 
-    private SSLCertificateSocketFactory(int socketReadTimeoutForSslHandshake,
-            SSLClientSessionCache cache) throws NoSuchAlgorithmException, KeyManagementException {
-        SSLContextImpl sslContext = new SSLContextImpl();
-        sslContext.engineInit(null /* kms */,
-            TRUST_MANAGER, new java.security.SecureRandom(),
-            cache /* client cache */, null /* server cache */);
-        this.mFactory = sslContext.engineGetSocketFactory();
-        this.mSocketReadTimeoutForSslHandshake = socketReadTimeoutForSslHandshake;
+    private SSLCertificateSocketFactory(int handshakeTimeoutMillis, SSLSessionCache cache) {
+        mHandshakeTimeoutMillis = handshakeTimeoutMillis;
+        mSessionCache = cache == null ? null : cache.mSessionCache;
     }
 
     /**
      * Returns a new instance of a socket factory using the specified socket read
      * timeout while connecting with the server/negotiating an ssl session.
      *
-     * @param socketReadTimeoutForSslHandshake the socket read timeout used for performing
-     *        ssl handshake. The socket read timeout is set back to 0 after the handshake.
-     * @return a new SocketFactory, or null on error
+     * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
+     *         for none.  The socket timeout is reset to 0 after the handshake.
+     * @return a new SocketFactory with the specified parameters
      */
-    public static SocketFactory getDefault(int socketReadTimeoutForSslHandshake) {
-        return getDefault(socketReadTimeoutForSslHandshake, null /* cache */);
+    public static SocketFactory getDefault(int handshakeTimeoutMillis) {
+        return getDefault(handshakeTimeoutMillis, null /* cache */);
     }
 
     /**
-     * Returns a new instance of a socket factory using the specified socket read
-     * timeout while connecting with the server/negotiating an ssl session.
+     * Returns a new instance of a socket factory using the specified socket
+     * read timeout while connecting with the server/negotiating an ssl session
      * Persists ssl sessions using the provided {@link SSLClientSessionCache}.
      *
-     * @param socketReadTimeoutForSslHandshake the socket read timeout used for performing
-     *        ssl handshake. The socket read timeout is set back to 0 after the handshake.
-     * @param cache The {@link SSLClientSessionCache} to use, if any.
-     * @return a new SocketFactory, or null on error
-     *
-     * @hide
-    */
-    public static SocketFactory getDefault(int socketReadTimeoutForSslHandshake,
-            SSLClientSessionCache cache) {
-        try {
-            return new SSLCertificateSocketFactory(socketReadTimeoutForSslHandshake, cache);
-        } catch (NoSuchAlgorithmException e) {
-            Log.e(LOG_TAG, 
-                    "SSLCertifcateSocketFactory.getDefault" +
-                    " NoSuchAlgorithmException " , e);
-            return null;
-        } catch (KeyManagementException e) {
-            Log.e(LOG_TAG, 
-                    "SSLCertifcateSocketFactory.getDefault" +
-                    " KeyManagementException " , e);
-            return null; 
-        }
+     * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
+     *         for none.  The socket timeout is reset to 0 after the handshake.
+     * @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
+     * @return a new SocketFactory with the specified parameters
+     */
+    public static SocketFactory getDefault(int handshakeTimeoutMillis, SSLSessionCache cache) {
+        return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache);
     }
 
-    private boolean hasValidCertificateChain(Certificate[] certs) 
-            throws IOException {
-        boolean trusted = (certs != null && (certs.length > 0));
-
-        if (trusted) {
-            try {
-                // the authtype we pass in doesn't actually matter
-                SSLParameters.getDefaultTrustManager()
-                        .checkServerTrusted((X509Certificate[]) certs, "RSA");
-            } catch (GeneralSecurityException e) { 
-                String exceptionMessage = e != null ? e.getMessage() : "none";
-                if (Config.LOGD) {
-                    Log.d(LOG_TAG,"hasValidCertificateChain(): sec. exception: "
-                         + exceptionMessage);
-                }
-                trusted = false;
-            }
-        }
-
-        return trusted;
+    /**
+     * Returns a socket factory (also named SSLSocketFactory, but in a different
+     * namespace) for use with the Apache HTTP stack.
+     *
+     * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
+     *         for none.  The socket timeout is reset to 0 after the handshake.
+     * @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
+     * @return a new SocketFactory with the specified parameters
+     */
+    public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(
+            int handshakeTimeoutMillis,
+            SSLSessionCache cache) {
+        return new org.apache.http.conn.ssl.SSLSocketFactory(
+                new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache));
     }
 
-    private void validateSocket(SSLSocket sslSock, String destHost) 
-            throws IOException
-    {
-        if (Config.LOGV) {
-            Log.v(LOG_TAG,"validateSocket() to host "+destHost);
+    private SSLSocketFactory makeSocketFactory(TrustManager[] trustManagers) {
+        try {
+            SSLContextImpl sslContext = new SSLContextImpl();
+            sslContext.engineInit(null, trustManagers, null, mSessionCache, null);
+            return sslContext.engineGetSocketFactory();
+        } catch (KeyManagementException e) {
+            Log.wtf(TAG, e);
+            return (SSLSocketFactory) SSLSocketFactory.getDefault();  // Fallback
         }
+    }
 
-        String relaxSslCheck = SystemProperties.get("socket.relaxsslcheck");
-        String secure = SystemProperties.get("ro.secure");
-
+    private synchronized SSLSocketFactory getDelegate() {
         // only allow relaxing the ssl check on non-secure builds where the relaxation is
         // specifically requested.
-        if ("0".equals(secure) && "yes".equals(relaxSslCheck)) {
-            if (Config.LOGD) {
-                Log.d(LOG_TAG,"sys prop socket.relaxsslcheck is set," +
-                        " ignoring invalid certs");
+        if ("0".equals(SystemProperties.get("ro.secure")) &&
+            "yes".equals(SystemProperties.get("socket.relaxsslcheck"))) {
+            if (mInsecureFactory == null) {
+                Log.w(TAG, "*** BYPASSING SSL SECURITY CHECKS (socket.relaxsslcheck=yes) ***");
+                mInsecureFactory = makeSocketFactory(INSECURE_TRUST_MANAGER);
             }
-            return;
-        }
-
-        Certificate[] certs = null;
-        sslSock.setUseClientMode(true);
-        sslSock.startHandshake();
-        certs = sslSock.getSession().getPeerCertificates();
-
-        // check that the root certificate in the chain belongs to
-        // a CA we trust
-        if (certs == null) {
-            Log.e(LOG_TAG, 
-                    "[SSLCertificateSocketFactory] no trusted root CA");
-            throw new IOException("no trusted root CA");
-        }
-
-        if (Config.LOGV) {
-            Log.v(LOG_TAG,"validateSocket # certs = " +certs.length);
-        }
-
-        if (!hasValidCertificateChain(certs)) {
-            if (Config.LOGD) {
-                Log.d(LOG_TAG,"validateSocket(): certificate untrusted!");
+            return mInsecureFactory;
+        } else {
+            if (mSecureFactory == null) {
+                mSecureFactory = makeSocketFactory(null);
             }
-            throw new IOException("Certificate untrusted");
-        }
-
-        X509Certificate lastChainCert = (X509Certificate) certs[0];
-
-        if (!DomainNameValidator.match(lastChainCert, destHost)) {
-            if (Config.LOGD) {
-                Log.d(LOG_TAG,"validateSocket(): domain name check failed");
-            }
-            throw new IOException("Domain Name check failed");
+            return mSecureFactory;
         }
     }
 
-    public Socket createSocket(Socket socket, String s, int i, boolean flag)
-            throws IOException
-    {
-        throw new IOException("Cannot validate certification without a hostname");       
+    @Override
+    public Socket createSocket(Socket k, String host, int port, boolean close) throws IOException {
+        OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close);
+        s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+        return s;
     }
 
-    public Socket createSocket(InetAddress inaddr, int i, InetAddress inaddr2, int j)
-            throws IOException
-    {
-        throw new IOException("Cannot validate certification without a hostname");       
+    @Override
+    public Socket createSocket() throws IOException {
+        OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket();
+        s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+        return s;
     }
 
-    public Socket createSocket(InetAddress inaddr, int i) throws IOException {
-        throw new IOException("Cannot validate certification without a hostname");       
+    @Override
+    public Socket createSocket(InetAddress addr, int port, InetAddress localAddr, int localPort)
+            throws IOException {
+        OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
+                addr, port, localAddr, localPort);
+        s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+        return s;
     }
 
-    public Socket createSocket(String s, int i, InetAddress inaddr, int j) throws IOException {
-        SSLSocket sslSock = (SSLSocket) mFactory.createSocket(s, i, inaddr, j);
-
-        if (mSocketReadTimeoutForSslHandshake >= 0) {
-            sslSock.setSoTimeout(mSocketReadTimeoutForSslHandshake);
-        }
-
-        validateSocket(sslSock,s);
-        sslSock.setSoTimeout(0);
-        
-        return sslSock;
+    @Override
+    public Socket createSocket(InetAddress addr, int port) throws IOException {
+        OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port);
+        s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+        return s;
     }
 
-    public Socket createSocket(String s, int i) throws IOException {
-        SSLSocket sslSock = (SSLSocket) mFactory.createSocket(s, i);
-
-        if (mSocketReadTimeoutForSslHandshake >= 0) {
-            sslSock.setSoTimeout(mSocketReadTimeoutForSslHandshake);
-        }
-        
-        validateSocket(sslSock,s);
-        sslSock.setSoTimeout(0);
+    @Override
+    public Socket createSocket(String host, int port, InetAddress localAddr, int localPort)
+            throws IOException {
+        OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
+                host, port, localAddr, localPort);
+        s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+        return s;
+    }
 
-        return sslSock;
+    @Override
+    public Socket createSocket(String host, int port) throws IOException {
+        OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port);
+        s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+        return s;
     }
 
+    @Override
     public String[] getDefaultCipherSuites() {
-        return mFactory.getSupportedCipherSuites();
+        return getDelegate().getSupportedCipherSuites();
     }
 
+    @Override
     public String[] getSupportedCipherSuites() {
-        return mFactory.getSupportedCipherSuites();
+        return getDelegate().getSupportedCipherSuites();
     }
 }
-
-
diff --git a/core/java/android/net/SSLSessionCache.java b/core/java/android/net/SSLSessionCache.java
new file mode 100644 (file)
index 0000000..4cbeb94
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 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 android.net;
+
+import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * File-based cache of established SSL sessions.  When re-establishing a
+ * connection to the same server, using an SSL session cache can save some time,
+ * power, and bandwidth by skipping directly to an encrypted stream.
+ * This is a persistent cache which can span executions of the application.
+ *
+ * @see SSLCertificateSocketFactory
+ */
+public final class SSLSessionCache {
+    private static final String TAG = "SSLSessionCache";
+    /* package */ final SSLClientSessionCache mSessionCache;
+
+    /**
+     * Create a session cache using the specified directory.
+     * Individual session entries will be files within the directory.
+     * Multiple instances for the same directory share data internally.
+     *
+     * @param dir to store session files in (created if necessary)
+     * @throws IOException if the cache can't be opened
+     */
+    public SSLSessionCache(File dir) throws IOException {
+        mSessionCache = FileClientSessionCache.usingDirectory(dir);
+    }
+
+    /**
+     * Create a session cache at the default location for this app.
+     * Multiple instances share data internally.
+     *
+     * @param context for the application
+     */
+    public SSLSessionCache(Context context) {
+        File dir = context.getDir("sslcache", Context.MODE_PRIVATE);
+        SSLClientSessionCache cache = null;
+        try {
+            cache = FileClientSessionCache.usingDirectory(dir);
+        } catch (IOException e) {
+            Log.w(TAG, "Unable to create SSL session cache in " + dir, e);
+        }
+        mSessionCache = cache;
+    }
+}
index c2cdcc0..076903b 100644 (file)
@@ -2814,22 +2814,6 @@ public final class Settings {
                 "sms_outgoing_check_max_count";
 
         /**
-         * Enable use of ssl session caching.
-         * 'db' - save each session in a (per process) database
-         * 'file' - save each session in a (per process) file
-         * not set or any other value - normal java in-memory caching
-         * @hide
-         */
-        public static final String SSL_SESSION_CACHE = "ssl_session_cache";
-
-        /**
-         * How many bytes long a message has to be, in order to be gzipped.
-         * @hide
-         */
-        public static final String SYNC_MIN_GZIP_BYTES =
-                "sync_min_gzip_bytes";
-
-        /**
          * The number of promoted sources in GlobalSearch.
          * @hide
          */