19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Hangs onto idle live connections for a little while
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.net.http;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.apache.http.HttpHost;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide}
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass IdleCache {
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class Entry {
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        HttpHost mHost;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Connection mConnection;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long mTimeout;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static int IDLE_CACHE_MAX = 8;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Allow five consecutive empty queue checks before shutdown */
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static int EMPTY_CHECK_MAX = 5;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* six second timeout for connections */
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static int TIMEOUT = 6 * 1000;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static int CHECK_INTERVAL = 2 * 1000;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Entry[] mEntries = new Entry[IDLE_CACHE_MAX];
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mCount = 0;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private IdleReaper mThread = null;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* stats */
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mCached = 0;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mReused = 0;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    IdleCache() {
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < IDLE_CACHE_MAX; i++) {
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEntries[i] = new Entry();
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Caches connection, if there is room.
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if connection cached
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    synchronized boolean cacheConnection(
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            HttpHost host, Connection connection) {
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean ret = false;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (HttpLog.LOGV) {
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            HttpLog.v("IdleCache size " + mCount + " host "  + host);
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCount < IDLE_CACHE_MAX) {
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long time = SystemClock.uptimeMillis();
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < IDLE_CACHE_MAX; i++) {
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Entry entry = mEntries[i];
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (entry.mHost == null) {
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    entry.mHost = host;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    entry.mConnection = connection;
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    entry.mTimeout = time + TIMEOUT;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCount++;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (HttpLog.LOGV) mCached++;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret = true;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (mThread == null) {
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mThread = new IdleReaper();
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mThread.start();
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    synchronized Connection getConnection(HttpHost host) {
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Connection ret = null;
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCount > 0) {
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < IDLE_CACHE_MAX; i++) {
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Entry entry = mEntries[i];
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                HttpHost eHost = entry.mHost;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (eHost != null && eHost.equals(host)) {
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret = entry.mConnection;
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    entry.mHost = null;
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    entry.mConnection = null;
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCount--;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (HttpLog.LOGV) mReused++;
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret;
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    synchronized void clear() {
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; mCount > 0 && i < IDLE_CACHE_MAX; i++) {
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Entry entry = mEntries[i];
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (entry.mHost != null) {
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                entry.mHost = null;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                entry.mConnection.closeConnection();
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                entry.mConnection = null;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mCount--;
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private synchronized void clearIdle() {
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCount > 0) {
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long time = SystemClock.uptimeMillis();
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < IDLE_CACHE_MAX; i++) {
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Entry entry = mEntries[i];
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (entry.mHost != null && time > entry.mTimeout) {
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    entry.mHost = null;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    entry.mConnection.closeConnection();
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    entry.mConnection = null;
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCount--;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class IdleReaper extends Thread {
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int check = 0;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setName("IdleReaper");
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            android.os.Process.setThreadPriority(
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    android.os.Process.THREAD_PRIORITY_BACKGROUND);
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (IdleCache.this) {
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                while (check < EMPTY_CHECK_MAX) {
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        IdleCache.this.wait(CHECK_INTERVAL);
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (InterruptedException ex) {
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (mCount == 0) {
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        check++;
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        check = 0;
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        clearIdle();
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mThread = null;
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (HttpLog.LOGV) {
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                HttpLog.v("IdleCache IdleReaper shutdown: cached " + mCached +
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          " reused " + mReused);
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mCached = 0;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mReused = 0;
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
176