Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e38d58bf authored by Dan Egnor's avatar Dan Egnor
Browse files

Remove Google-specific (or only-used-by-Google-code) classes.

Fix a small typo in Context javadoc.
parent 2c3058a8
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -1314,7 +1314,7 @@ public abstract class Context {

    /**
     * Use with {@link #getSystemService} to retrieve a
     * {@blink android.appwidget.AppWidgetManager} for accessing AppWidgets.
     * {@link android.appwidget.AppWidgetManager} for accessing AppWidgets.
     *
     * @hide
     * @see #getSystemService
@@ -1323,7 +1323,7 @@ public abstract class Context {

    /**
     * Use with {@link #getSystemService} to retrieve an
     * {@blink android.backup.IBackupManager IBackupManager} for communicating
     * {@link android.backup.IBackupManager IBackupManager} for communicating
     * with the backup mechanism.
     * @hide
     * 
@@ -1333,7 +1333,7 @@ public abstract class Context {

    /**
     * Use with {@link #getSystemService} to retrieve a
     * {@blink android.os.DropBox DropBox} instance for recording
     * {@link android.os.DropBox DropBox} instance for recording
     * diagnostic logs.
     * @see #getSystemService
     */
+0 −289
Original line number Diff line number Diff line
// Copyright 2009 The Android Open Source Project

package com.android.internal.net;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

import org.apache.commons.codec.binary.Base64;
import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;

import java.util.HashMap;
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 DbSSLSessionCache implements SSLClientSessionCache {
    private static final String TAG = "DbSSLSessionCache";

    /** 
     * 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 = 2;
    
    /** 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;
    
    public static final int MAX_CACHE_SIZE = 256;
    
    private final Map<String, byte[]> mExternalCache =
        new HashMap<String, byte[]>();
        
        
    private DatabaseHelper mDatabaseHelper;

    private boolean mNeedsCacheLoad = true;
    
    public static final String[] PROJECTION = new String[] {
      SSL_CACHE_ID, 
      SSL_CACHE_HOSTPORT,
      SSL_CACHE_SESSION,
      SSL_CACHE_TIME_SEC
    };

    private static final Map<String,DbSSLSessionCache> sInstances =
            new HashMap<String,DbSSLSessionCache>();

    /**
     * Returns a singleton instance of the DbSSLSessionCache that should be used for this
     * context's package.
     *
     * @param context The context that should be used for getting/creating the singleton instance.
     * @return The singleton instance for the context's package.
     */
    public static synchronized DbSSLSessionCache getInstanceForPackage(Context context) {
        String packageName = context.getPackageName();
        if (sInstances.containsKey(packageName)) {
            return sInstances.get(packageName);
        }
        DbSSLSessionCache cache = new DbSSLSessionCache(context);
        sInstances.put(packageName, cache);
        return cache;
    }
    
    /**
     * Create a SslSessionCache instance, using the specified context to 
     * initialize the database.
     * 
     * This constructor will use the default database - created for the application
     * context.
     * 
     * @param activityContext
     */
    private DbSSLSessionCache(Context activityContext) {
        Context appContext = activityContext.getApplicationContext();
        mDatabaseHelper = new DatabaseHelper(appContext);
    }
    
    /**
     * Create a SslSessionCache that uses a specific database.
     * 
     * 
     * @param database
     */
    public DbSSLSessionCache(DatabaseHelper database) {
        this.mDatabaseHelper = database;
    }
    
    public void putSessionData(SSLSession session, byte[] der) {
        if (mDatabaseHelper == null) {
            return;
        }
        synchronized (this.getClass()) {
            SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
            if (mExternalCache.size() == MAX_CACHE_SIZE) {
                // remove oldest.
                // TODO: check if the new one is in cached already ( i.e. update ).
                Cursor byTime = mDatabaseHelper.getReadableDatabase().query(SSL_CACHE_TABLE, 
                        PROJECTION, null, null, null, null, SSL_CACHE_TIME_SEC);
                if (byTime.moveToFirst()) {
                    // TODO: can I do byTime.deleteRow() ? 
                    String hostPort = byTime.getString(SSL_CACHE_HOSTPORT_COL);
                    db.delete(SSL_CACHE_TABLE, 
                            SSL_CACHE_HOSTPORT + "= ?" , new String[] { hostPort });
                    mExternalCache.remove(hostPort);
                } else {
                    Log.w(TAG, "No rows found");
                    // something is wrong, clear it
                    clear();
                }
            }
            // 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);

            mExternalCache.put(key, der);

            try {
                db.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);
        }
    }

    /** 
     * Reset the database and internal state. 
     * Used for testing or to free space.
     */
    public void clear() {
        synchronized(this) {
            try {
                mExternalCache.clear();
                mNeedsCacheLoad = true;
                mDatabaseHelper.getWritableDatabase().delete(SSL_CACHE_TABLE, 
                        null, null);
            } catch (SQLException ex) {
                Log.d(TAG, "Error removing SSL cached entries ", ex);
                // ignore - nothing we can do about it
            }
        } 
    }

    public byte[] getSessionData(byte[] id) {
        // We support client side only - the cache will do nothing for 
        // server-side sessions. 
        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" +
            ");");
            
            // No index - we load on startup, index would slow down inserts.
            // If we want to scale this to lots of rows - we could use 
            // index, but then we'll hit DB a bit too often ( including 
            // negative hits )
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL("DROP TABLE IF EXISTS " + SSL_CACHE_TABLE );
            onCreate(db);
        }

    }
    
}
+0 −84
Original line number Diff line number Diff line
/*
 * 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 com.google.android.net;

import android.net.TrafficStats;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.util.EventLog;
import org.apache.http.HttpEntity;
import org.apache.http.entity.HttpEntityWrapper;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;


public class NetworkStatsEntity extends HttpEntityWrapper {

    private static final int HTTP_STATS_EVENT = 52001;

    private class NetworkStatsInputStream extends FilterInputStream {

        public NetworkStatsInputStream(InputStream wrapped) {
            super(wrapped);
        }

        @Override
        public void close() throws IOException {
            try {
                super.close();
            } finally {
                long processingTime = SystemClock.elapsedRealtime() - mProcessingStartTime;
                long tx = TrafficStats.getUidTxBytes(mUid);
                long rx = TrafficStats.getUidRxBytes(mUid);

                EventLog.writeEvent(HTTP_STATS_EVENT, mUa, mResponseLatency, processingTime,
                        tx - mStartTx, rx - mStartRx);
            }
        }
    }

    private final String mUa;
    private final int mUid;
    private final long mStartTx;
    private final long mStartRx;
    private final long mResponseLatency;
    private final long mProcessingStartTime;

    public NetworkStatsEntity(HttpEntity orig, String ua,
            int uid, long startTx, long startRx, long responseLatency,
            long processingStartTime) {
        super(orig);
        this.mUa = ua;
        this.mUid = uid;
        this.mStartTx = startTx;
        this.mStartRx = startRx;
        this.mResponseLatency = responseLatency;
        this.mProcessingStartTime = processingStartTime;
    }

    public static boolean shouldLogNetworkStats() {
      return "1".equals(SystemProperties.get("googlehttpclient.logstats"));
    }

    @Override
    public InputStream getContent() throws IOException {
        InputStream orig = super.getContent();
        return new NetworkStatsInputStream(orig);
    }
}
+0 −62
Original line number Diff line number Diff line
package com.google.android.net;

import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache;
import android.content.Context;
import android.provider.Settings;
import android.util.Log;

import java.io.File;
import java.io.IOException;

import com.android.internal.net.DbSSLSessionCache;

/**
 * Factory that returns the appropriate implementation of a {@link SSLClientSessionCache} based
 * on gservices.
 *
 * @hide
 */
// TODO: return a proxied implementation that is updated as the gservices value changes.
public final class SSLClientSessionCacheFactory {

    private static final String TAG = "SSLClientSessionCacheFactory";

    public static final String DB = "db";
    public static final String FILE = "file";

    // utility class
    private SSLClientSessionCacheFactory() {}

    /**
     * Returns a new {@link SSLClientSessionCache} based on the persistent cache that's specified,
     * if any, in gservices.  If no cache is specified, returns null.
     * @param context The application context used for the per-process persistent cache.
     * @return A new {@link SSLClientSessionCache}, or null if no persistent cache is configured.
     */
    public static SSLClientSessionCache getCache(Context context) {
        String type = Settings.Gservices.getString(context.getContentResolver(),
                Settings.Gservices.SSL_SESSION_CACHE);

        if (type != null) {
            if (DB.equals(type)) {
                return DbSSLSessionCache.getInstanceForPackage(context);
            } else if (FILE.equals(type)) {
                File dir = context.getFilesDir();
                File cacheDir = new File(dir, "sslcache");
                if (!cacheDir.exists()) {
                    cacheDir.mkdir();
                }
                try {
                    return FileClientSessionCache.usingDirectory(cacheDir);
                } catch (IOException ioe) {
                    Log.w(TAG, "Unable to create FileClientSessionCache in " + cacheDir.getName(), ioe);
                    return null;
                }
            } else {
                Log.w(TAG, "Ignoring unrecognized type: '" + type + "'");       
            }
        }
        return null;
    }
}
+0 −236

File deleted.

Preview size limit exceeded, changes collapsed.

Loading