Merge "Remove SSLPerformanceTest and DatabaseSessionCache."
This commit is contained in:
@@ -1,312 +0,0 @@
|
||||
// Copyright 2009 The Android Open Source Project
|
||||
|
||||
package android.core;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.database.SQLException;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.util.Log;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
/**
|
||||
* Hook into harmony SSL cache to persist the SSL sessions.
|
||||
*
|
||||
* Current implementation is suitable for saving a small number of hosts -
|
||||
* like google services. It can be extended with expiration and more features
|
||||
* to support more hosts.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public class DatabaseSessionCache implements SSLClientSessionCache {
|
||||
private static final String TAG = "SslSessionCache";
|
||||
static DatabaseHelper sDefaultDatabaseHelper;
|
||||
|
||||
private DatabaseHelper mDatabaseHelper;
|
||||
|
||||
/**
|
||||
* Table where sessions are stored.
|
||||
*/
|
||||
public static final String SSL_CACHE_TABLE = "ssl_sessions";
|
||||
|
||||
private static final String SSL_CACHE_ID = "_id";
|
||||
|
||||
/**
|
||||
* Key is host:port - port is not optional.
|
||||
*/
|
||||
private static final String SSL_CACHE_HOSTPORT = "hostport";
|
||||
|
||||
/**
|
||||
* Base64-encoded DER value of the session.
|
||||
*/
|
||||
private static final String SSL_CACHE_SESSION = "session";
|
||||
|
||||
/**
|
||||
* Time when the record was added - should be close to the time
|
||||
* of the initial session negotiation.
|
||||
*/
|
||||
private static final String SSL_CACHE_TIME_SEC = "time_sec";
|
||||
|
||||
public static final String DATABASE_NAME = "ssl_sessions.db";
|
||||
|
||||
public static final int DATABASE_VERSION = 1;
|
||||
|
||||
/** public for testing
|
||||
*/
|
||||
public static final int SSL_CACHE_ID_COL = 0;
|
||||
public static final int SSL_CACHE_HOSTPORT_COL = 1;
|
||||
public static final int SSL_CACHE_SESSION_COL = 2;
|
||||
public static final int SSL_CACHE_TIME_SEC_COL = 3;
|
||||
|
||||
private static final String SAVE_ON_ADD = "save_on_add";
|
||||
|
||||
static boolean sHookInitializationDone = false;
|
||||
|
||||
public static final int MAX_CACHE_SIZE = 256;
|
||||
|
||||
private static final Map<String, byte[]> mExternalCache =
|
||||
new LinkedHashMap<String, byte[]>(MAX_CACHE_SIZE, 0.75f, true) {
|
||||
@Override
|
||||
public boolean removeEldestEntry(
|
||||
Map.Entry<String, byte[]> eldest) {
|
||||
boolean shouldDelete = this.size() > MAX_CACHE_SIZE;
|
||||
|
||||
// TODO: delete from DB
|
||||
return shouldDelete;
|
||||
}
|
||||
};
|
||||
static boolean mNeedsCacheLoad = true;
|
||||
|
||||
public static final String[] PROJECTION = new String[] {
|
||||
SSL_CACHE_ID,
|
||||
SSL_CACHE_HOSTPORT,
|
||||
SSL_CACHE_SESSION,
|
||||
SSL_CACHE_TIME_SEC
|
||||
};
|
||||
|
||||
/**
|
||||
* This class needs to be installed as a hook, if the security property
|
||||
* is set. Getting the right classloader may be fun since we don't use
|
||||
* Provider to get its classloader, but in android this is in same
|
||||
* loader with AndroidHttpClient.
|
||||
*
|
||||
* This constructor will use the default database. You must
|
||||
* call init() before to specify the context used for the database and
|
||||
* check settings.
|
||||
*/
|
||||
public DatabaseSessionCache() {
|
||||
Log.v(TAG, "Instance created.");
|
||||
// May be null if caching is disabled - no sessions will be persisted.
|
||||
this.mDatabaseHelper = sDefaultDatabaseHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SslSessionCache instance, using the specified context to
|
||||
* initialize the database.
|
||||
*
|
||||
* This constructor will use the default database - created the first
|
||||
* time.
|
||||
*
|
||||
* @param activityContext
|
||||
*/
|
||||
public DatabaseSessionCache(Context activityContext) {
|
||||
// Static init - only one initialization will happen.
|
||||
// Each SslSessionCache is using the same DB.
|
||||
init(activityContext);
|
||||
// May be null if caching is disabled - no sessions will be persisted.
|
||||
this.mDatabaseHelper = sDefaultDatabaseHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SslSessionCache that uses a specific database.
|
||||
*
|
||||
* @param database
|
||||
*/
|
||||
public DatabaseSessionCache(DatabaseHelper database) {
|
||||
this.mDatabaseHelper = database;
|
||||
}
|
||||
|
||||
// public static boolean enabled(Context androidContext) {
|
||||
// String sslCache = Settings.Secure.getString(androidContext.getContentResolver(),
|
||||
// Settings.Secure.SSL_SESSION_CACHE);
|
||||
//
|
||||
// if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
// Log.d(TAG, "enabled " + sslCache + " " + androidContext.getPackageName());
|
||||
// }
|
||||
//
|
||||
// return SAVE_ON_ADD.equals(sslCache);
|
||||
// }
|
||||
|
||||
/**
|
||||
* You must call this method to enable SSL session caching for an app.
|
||||
*/
|
||||
public synchronized static void init(Context activityContext) {
|
||||
// It is possible that multiple provider will try to install this hook.
|
||||
// We want a single db per VM.
|
||||
if (sHookInitializationDone) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// // More values can be added in future to provide different
|
||||
// // behaviours, like 'batch save'.
|
||||
// if (enabled(activityContext)) {
|
||||
Context appContext = activityContext.getApplicationContext();
|
||||
sDefaultDatabaseHelper = new DatabaseHelper(appContext);
|
||||
|
||||
// Set default SSLSocketFactory
|
||||
// The property is defined in the javadocs for javax.net.SSLSocketFactory
|
||||
// (no constant defined there)
|
||||
// This should cover all code using SSLSocketFactory.getDefault(),
|
||||
// including native http client and apache httpclient.
|
||||
// MCS is using its own custom factory - will need special code.
|
||||
// Security.setProperty("ssl.SocketFactory.provider",
|
||||
// SslSocketFactoryWithCache.class.getName());
|
||||
// }
|
||||
|
||||
// Won't try again.
|
||||
sHookInitializationDone = true;
|
||||
}
|
||||
|
||||
public void putSessionData(SSLSession session, byte[] der) {
|
||||
if (mDatabaseHelper == null) {
|
||||
return;
|
||||
}
|
||||
if (mExternalCache.size() > MAX_CACHE_SIZE) {
|
||||
// remove oldest.
|
||||
Cursor byTime = mDatabaseHelper.getWritableDatabase().query(SSL_CACHE_TABLE,
|
||||
PROJECTION, null, null, null, null, SSL_CACHE_TIME_SEC);
|
||||
byTime.moveToFirst();
|
||||
// TODO: can I do byTime.deleteRow() ?
|
||||
String hostPort = byTime.getString(SSL_CACHE_HOSTPORT_COL);
|
||||
|
||||
mDatabaseHelper.getWritableDatabase().delete(SSL_CACHE_TABLE,
|
||||
SSL_CACHE_HOSTPORT + "= ?" , new String[] { hostPort });
|
||||
}
|
||||
// Serialize native session to standard DER encoding
|
||||
long t0 = System.currentTimeMillis();
|
||||
|
||||
String b64 = new String(Base64.encodeBase64(der));
|
||||
String key = session.getPeerHost() + ":" + session.getPeerPort();
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(SSL_CACHE_HOSTPORT, key);
|
||||
values.put(SSL_CACHE_SESSION, b64);
|
||||
values.put(SSL_CACHE_TIME_SEC, System.currentTimeMillis() / 1000);
|
||||
|
||||
synchronized (this.getClass()) {
|
||||
mExternalCache.put(key, der);
|
||||
|
||||
try {
|
||||
mDatabaseHelper.getWritableDatabase().insert(SSL_CACHE_TABLE, null /*nullColumnHack */ , values);
|
||||
} catch(SQLException ex) {
|
||||
// Ignore - nothing we can do to recover, and caller shouldn't
|
||||
// be affected.
|
||||
Log.w(TAG, "Ignoring SQL exception when caching session", ex);
|
||||
}
|
||||
}
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
long t1 = System.currentTimeMillis();
|
||||
Log.d(TAG, "New SSL session " + session.getPeerHost() +
|
||||
" DER len: " + der.length + " " + (t1 - t0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public byte[] getSessionData(String host, int port) {
|
||||
// Current (simple) implementation does a single lookup to DB, then saves
|
||||
// all entries to the cache.
|
||||
|
||||
// This works for google services - i.e. small number of certs.
|
||||
// If we extend this to all processes - we should hold a separate cache
|
||||
// or do lookups to DB each time.
|
||||
if (mDatabaseHelper == null) {
|
||||
return null;
|
||||
}
|
||||
synchronized(this.getClass()) {
|
||||
if (mNeedsCacheLoad) {
|
||||
// Don't try to load again, if something is wrong on the first
|
||||
// request it'll likely be wrong each time.
|
||||
mNeedsCacheLoad = false;
|
||||
long t0 = System.currentTimeMillis();
|
||||
|
||||
Cursor cur = null;
|
||||
try {
|
||||
cur = mDatabaseHelper.getReadableDatabase().query(SSL_CACHE_TABLE, PROJECTION, null,
|
||||
null, null, null, null);
|
||||
if (cur.moveToFirst()) {
|
||||
do {
|
||||
String hostPort = cur.getString(SSL_CACHE_HOSTPORT_COL);
|
||||
String value = cur.getString(SSL_CACHE_SESSION_COL);
|
||||
|
||||
if (hostPort == null || value == null) {
|
||||
continue;
|
||||
}
|
||||
// TODO: blob support ?
|
||||
byte[] der = Base64.decodeBase64(value.getBytes());
|
||||
mExternalCache.put(hostPort, der);
|
||||
} while (cur.moveToNext());
|
||||
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
Log.d(TAG, "Error loading SSL cached entries ", ex);
|
||||
} finally {
|
||||
if (cur != null) {
|
||||
cur.close();
|
||||
}
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
long t1 = System.currentTimeMillis();
|
||||
Log.d(TAG, "LOADED CACHED SSL " + (t1 - t0) + " ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String key = host + ":" + port;
|
||||
|
||||
return mExternalCache.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getSessionData(byte[] id) {
|
||||
// We support client side only - the cache will do nothing on client.
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Visible for testing.
|
||||
*/
|
||||
public static class DatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
public DatabaseHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null /* factory */, DATABASE_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
db.execSQL("CREATE TABLE " + SSL_CACHE_TABLE + " (" +
|
||||
SSL_CACHE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
|
||||
SSL_CACHE_HOSTPORT + " TEXT UNIQUE ON CONFLICT REPLACE," +
|
||||
SSL_CACHE_SESSION + " TEXT," +
|
||||
SSL_CACHE_TIME_SEC + " INTEGER" +
|
||||
");");
|
||||
db.execSQL("CREATE INDEX ssl_sessions_idx1 ON ssl_sessions (" +
|
||||
SSL_CACHE_HOSTPORT + ");");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
db.execSQL("DROP TABLE IF EXISTS " + SSL_CACHE_TABLE );
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,432 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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.core;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
import android.os.Debug;
|
||||
import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache;
|
||||
import org.apache.harmony.xnet.provider.jsse.OpenSSLContextImpl;
|
||||
import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
|
||||
import org.apache.http.conn.scheme.SchemeRegistry;
|
||||
import org.apache.http.conn.scheme.Scheme;
|
||||
import org.apache.http.conn.ClientConnectionManager;
|
||||
import org.apache.http.conn.ssl.SSLSocketFactory;
|
||||
import org.apache.http.impl.conn.SingleClientConnManager;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.ResponseHandler;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.HttpResponse;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSessionContext;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.Principal;
|
||||
import java.security.KeyManagementException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class SSLPerformanceTest extends AndroidTestCase {
|
||||
|
||||
static final byte[] SESSION_DATA = new byte[6000];
|
||||
static {
|
||||
for (int i = 0; i < SESSION_DATA.length; i++) {
|
||||
SESSION_DATA[i] = (byte) i;
|
||||
}
|
||||
}
|
||||
|
||||
static final File dataDir = new File("/data/data/android.core/");
|
||||
static final File filesDir = new File(dataDir, "files");
|
||||
static final File dbDir = new File(dataDir, "databases");
|
||||
|
||||
static final String CACHE_DIR
|
||||
= SSLPerformanceTest.class.getName() + "/cache";
|
||||
|
||||
static final int ITERATIONS = 10;
|
||||
|
||||
public void testCreateNewEmptyDatabase() {
|
||||
deleteDatabase();
|
||||
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
|
||||
cache.getSessionData("crazybob.org", 443);
|
||||
|
||||
stopwatch.stop();
|
||||
}
|
||||
|
||||
public void testCreateNewEmptyDirectory() throws IOException {
|
||||
deleteDirectory();
|
||||
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
|
||||
getCacheDirectory());
|
||||
cache.getSessionData("crazybob.org", 443);
|
||||
|
||||
stopwatch.stop();
|
||||
}
|
||||
|
||||
public void testOpenDatabaseWith10Sessions() {
|
||||
deleteDatabase();
|
||||
|
||||
DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
|
||||
putSessionsIn(cache);
|
||||
closeDatabase();
|
||||
|
||||
System.err.println("Size of ssl_sessions.db w/ 10 sessions: "
|
||||
+ new File(dbDir, "ssl_sessions.db").length());
|
||||
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
cache = new DatabaseSessionCache(getContext());
|
||||
cache.getSessionData("crazybob.org", 443);
|
||||
|
||||
stopwatch.stop();
|
||||
}
|
||||
|
||||
public void testOpenDirectoryWith10Sessions() throws IOException {
|
||||
deleteDirectory();
|
||||
|
||||
SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
|
||||
getCacheDirectory());
|
||||
putSessionsIn(cache);
|
||||
closeDirectoryCache();
|
||||
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
cache = FileClientSessionCache.usingDirectory(
|
||||
getCacheDirectory());
|
||||
cache.getSessionData("crazybob.org", 443);
|
||||
|
||||
stopwatch.stop();
|
||||
}
|
||||
|
||||
public void testGetSessionFromDatabase() {
|
||||
deleteDatabase();
|
||||
|
||||
DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
|
||||
cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
|
||||
closeDatabase();
|
||||
|
||||
cache = new DatabaseSessionCache(getContext());
|
||||
cache.getSessionData("crazybob.org", 443);
|
||||
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
byte[] sessionData = cache.getSessionData("foo", 443);
|
||||
|
||||
stopwatch.stop();
|
||||
|
||||
assertTrue(Arrays.equals(SESSION_DATA, sessionData));
|
||||
}
|
||||
|
||||
public void testGetSessionFromDirectory() throws IOException {
|
||||
deleteDirectory();
|
||||
|
||||
SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
|
||||
getCacheDirectory());
|
||||
cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
|
||||
closeDirectoryCache();
|
||||
|
||||
cache = FileClientSessionCache.usingDirectory(
|
||||
getCacheDirectory());
|
||||
cache.getSessionData("crazybob.org", 443);
|
||||
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
byte[] sessionData = cache.getSessionData("foo", 443);
|
||||
|
||||
stopwatch.stop();
|
||||
|
||||
assertTrue(Arrays.equals(SESSION_DATA, sessionData));
|
||||
}
|
||||
|
||||
public void testPutSessionIntoDatabase() {
|
||||
deleteDatabase();
|
||||
|
||||
DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
|
||||
cache.getSessionData("crazybob.org", 443);
|
||||
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
|
||||
|
||||
stopwatch.stop();
|
||||
}
|
||||
|
||||
public void testPutSessionIntoDirectory() throws IOException {
|
||||
deleteDirectory();
|
||||
|
||||
SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
|
||||
getCacheDirectory());
|
||||
cache.getSessionData("crazybob.org", 443);
|
||||
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
|
||||
|
||||
stopwatch.stop();
|
||||
}
|
||||
|
||||
public void testEngineInit() throws IOException, KeyManagementException {
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
new OpenSSLContextImpl().engineInit(null, null, null);
|
||||
|
||||
stopwatch.stop();
|
||||
}
|
||||
|
||||
public void testWebRequestWithoutCache() throws IOException,
|
||||
KeyManagementException {
|
||||
OpenSSLContextImpl sslContext = new OpenSSLContextImpl();
|
||||
sslContext.engineInit(null, null, null);
|
||||
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
getVerisignDotCom(sslContext);
|
||||
|
||||
stopwatch.stop();
|
||||
}
|
||||
|
||||
public void testWebRequestWithFileCache() throws IOException,
|
||||
KeyManagementException {
|
||||
deleteDirectory();
|
||||
|
||||
OpenSSLContextImpl sslContext = new OpenSSLContextImpl();
|
||||
sslContext.engineInit(null, null, null);
|
||||
sslContext.engineGetClientSessionContext().setPersistentCache(
|
||||
FileClientSessionCache.usingDirectory(getCacheDirectory()));
|
||||
|
||||
// Make sure www.google.com is in the cache.
|
||||
getVerisignDotCom(sslContext);
|
||||
|
||||
// Re-initialize so we hit the file cache.
|
||||
sslContext.engineInit(null, null, null);
|
||||
sslContext.engineGetClientSessionContext().setPersistentCache(
|
||||
FileClientSessionCache.usingDirectory(getCacheDirectory()));
|
||||
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
getVerisignDotCom(sslContext);
|
||||
|
||||
stopwatch.stop();
|
||||
}
|
||||
|
||||
public void testWebRequestWithInMemoryCache() throws IOException,
|
||||
KeyManagementException {
|
||||
deleteDirectory();
|
||||
|
||||
OpenSSLContextImpl sslContext = new OpenSSLContextImpl();
|
||||
sslContext.engineInit(null, null, null);
|
||||
|
||||
// Make sure www.google.com is in the cache.
|
||||
getVerisignDotCom(sslContext);
|
||||
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
getVerisignDotCom(sslContext);
|
||||
|
||||
stopwatch.stop();
|
||||
}
|
||||
|
||||
private void getVerisignDotCom(OpenSSLContextImpl sslContext)
|
||||
throws IOException {
|
||||
SchemeRegistry schemeRegistry = new SchemeRegistry();
|
||||
schemeRegistry.register(new Scheme("https",
|
||||
new SSLSocketFactory(sslContext.engineGetSocketFactory()),
|
||||
443));
|
||||
|
||||
ClientConnectionManager manager =
|
||||
new SingleClientConnManager(null, schemeRegistry);
|
||||
|
||||
new DefaultHttpClient(manager, null).execute(
|
||||
new HttpGet("https://www.verisign.com"),
|
||||
new ResponseHandler<Object>() {
|
||||
public Object handleResponse(HttpResponse response)
|
||||
throws ClientProtocolException, IOException {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void putSessionsIn(SSLClientSessionCache cache) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
cache.putSessionData(new FakeSession("host" + i), SESSION_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteDatabase() {
|
||||
closeDatabase();
|
||||
if (!new File(dbDir, "ssl_sessions.db").delete()) {
|
||||
System.err.println("Failed to delete database.");
|
||||
}
|
||||
}
|
||||
|
||||
private void closeDatabase() {
|
||||
if (DatabaseSessionCache.sDefaultDatabaseHelper != null) {
|
||||
DatabaseSessionCache.sDefaultDatabaseHelper.close();
|
||||
}
|
||||
DatabaseSessionCache.sDefaultDatabaseHelper = null;
|
||||
DatabaseSessionCache.sHookInitializationDone = false;
|
||||
DatabaseSessionCache.mNeedsCacheLoad = true;
|
||||
}
|
||||
|
||||
private void deleteDirectory() {
|
||||
closeDirectoryCache();
|
||||
|
||||
File dir = getCacheDirectory();
|
||||
if (!dir.exists()) {
|
||||
return;
|
||||
}
|
||||
for (File file : dir.listFiles()) {
|
||||
file.delete();
|
||||
}
|
||||
if (!dir.delete()) {
|
||||
System.err.println("Failed to delete directory.");
|
||||
}
|
||||
}
|
||||
|
||||
private void closeDirectoryCache() {
|
||||
try {
|
||||
Method reset = FileClientSessionCache.class
|
||||
.getDeclaredMethod("reset");
|
||||
reset.setAccessible(true);
|
||||
reset.invoke(null);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private File getCacheDirectory() {
|
||||
return new File(getContext().getFilesDir(), CACHE_DIR);
|
||||
}
|
||||
|
||||
class Stopwatch {
|
||||
{
|
||||
Debug.startAllocCounting();
|
||||
}
|
||||
long start = System.nanoTime();
|
||||
|
||||
void stop() {
|
||||
long elapsed = (System.nanoTime() - start) / 1000;
|
||||
Debug.stopAllocCounting();
|
||||
System.err.println(getName() + ": " + elapsed + "us, "
|
||||
+ Debug.getThreadAllocCount() + " allocations, "
|
||||
+ Debug.getThreadAllocSize() + " bytes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FakeSession implements SSLSession {
|
||||
final String host;
|
||||
|
||||
FakeSession(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public int getApplicationBufferSize() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String getCipherSuite() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public long getCreationTime() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public byte[] getId() {
|
||||
return host.getBytes();
|
||||
}
|
||||
|
||||
public long getLastAccessedTime() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Certificate[] getLocalCertificates() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Principal getLocalPrincipal() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public int getPacketBufferSize() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public javax.security.cert.X509Certificate[] getPeerCertificateChain() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Certificate[] getPeerCertificates() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String getPeerHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public int getPeerPort() {
|
||||
return 443;
|
||||
}
|
||||
|
||||
public Principal getPeerPrincipal() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public SSLSessionContext getSessionContext() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Object getValue(String name) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String[] getValueNames() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void putValue(String name, Object value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void removeValue(String name) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user