IdleCache.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
14b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet/*
24b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * Copyright (C) 2008 The Android Open Source Project
34b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet *
44b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
54b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * you may not use this file except in compliance with the License.
64b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * You may obtain a copy of the License at
74b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet *
84b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
94b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet *
104b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software
114b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
124b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * See the License for the specific language governing permissions and
144b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * limitations under the License.
154b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet */
164b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
174b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet/**
184b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * Hangs onto idle live connections for a little while
194b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet */
204b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
214b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohetpackage android.net.http;
224b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
234b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohetimport org.apache.http.HttpHost;
244b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
254b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohetimport android.os.SystemClock;
264b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
274b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet/**
284b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * {@hide}
294b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet */
304b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohetclass IdleCache {
31f354ad108c794bd4c9d1aa9a4f2a526d9c27e224Xavier Ducrohet
324b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    class Entry {
334b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        HttpHost mHost;
344b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        Connection mConnection;
354b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        long mTimeout;
36f354ad108c794bd4c9d1aa9a4f2a526d9c27e224Xavier Ducrohet    };
374b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
384b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    private final static int IDLE_CACHE_MAX = 8;
394b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
404b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    /* Allow five consecutive empty queue checks before shutdown */
414b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    private final static int EMPTY_CHECK_MAX = 5;
424b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
434b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    /* six second timeout for connections */
444b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    private final static int TIMEOUT = 6 * 1000;
454b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    private final static int CHECK_INTERVAL = 2 * 1000;
464b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    private Entry[] mEntries = new Entry[IDLE_CACHE_MAX];
474b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
484b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    private int mCount = 0;
494b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
504b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    private IdleReaper mThread = null;
514b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
524b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    /* stats */
534b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    private int mCached = 0;
544b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    private int mReused = 0;
554b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
564b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    IdleCache() {
574b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        for (int i = 0; i < IDLE_CACHE_MAX; i++) {
584b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            mEntries[i] = new Entry();
594b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        }
604b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    }
614b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
624b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    /**
634b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     * Caches connection, if there is room.
644b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     * @return true if connection cached
654b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     */
664b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    synchronized boolean cacheConnection(
674b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            HttpHost host, Connection connection) {
684b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
694b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        boolean ret = false;
704b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
714b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        if (HttpLog.LOGV) {
724b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            HttpLog.v("IdleCache size " + mCount + " host "  + host);
734b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        }
744b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
754b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        if (mCount < IDLE_CACHE_MAX) {
764b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            long time = SystemClock.uptimeMillis();
774b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            for (int i = 0; i < IDLE_CACHE_MAX; i++) {
784b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                Entry entry = mEntries[i];
794b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                if (entry.mHost == null) {
804b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    entry.mHost = host;
814b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    entry.mConnection = connection;
824b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    entry.mTimeout = time + TIMEOUT;
834b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    mCount++;
844b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    if (HttpLog.LOGV) mCached++;
854b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    ret = true;
864b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    if (mThread == null) {
874b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                        mThread = new IdleReaper();
884b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                        mThread.start();
894b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    }
904b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    break;
914b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                }
924b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            }
934b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        }
944b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        return ret;
954b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    }
964b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
974b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    synchronized Connection getConnection(HttpHost host) {
984b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        Connection ret = null;
994b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
1004b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        if (mCount > 0) {
1014b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            for (int i = 0; i < IDLE_CACHE_MAX; i++) {
1024b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                Entry entry = mEntries[i];
1034b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                HttpHost eHost = entry.mHost;
1044b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                if (eHost != null && eHost.equals(host)) {
1054b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    ret = entry.mConnection;
1064b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    entry.mHost = null;
1074b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    entry.mConnection = null;
1084b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    mCount--;
1094b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    if (HttpLog.LOGV) mReused++;
1104b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    break;
1114b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                }
1124b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            }
1134b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        }
1144b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        return ret;
1154b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    }
1164b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
1174b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    synchronized void clear() {
1184b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        for (int i = 0; mCount > 0 && i < IDLE_CACHE_MAX; i++) {
1194b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            Entry entry = mEntries[i];
1204b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            if (entry.mHost != null) {
1214b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                entry.mHost = null;
1224b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                entry.mConnection.closeConnection();
1234b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                entry.mConnection = null;
1244b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                mCount--;
1254b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            }
1264b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        }
1274b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    }
1284b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
1294b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    private synchronized void clearIdle() {
1304b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        if (mCount > 0) {
1314b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            long time = SystemClock.uptimeMillis();
1324b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            for (int i = 0; i < IDLE_CACHE_MAX; i++) {
1334b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                Entry entry = mEntries[i];
1344b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                if (entry.mHost != null && time > entry.mTimeout) {
1354b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    entry.mHost = null;
1364b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    entry.mConnection.closeConnection();
1374b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    entry.mConnection = null;
1384b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    mCount--;
1394b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                }
1404b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            }
1414b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        }
1424b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    }
1434b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
1444b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    private class IdleReaper extends Thread {
1454b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
1464b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        public void run() {
1474b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            int check = 0;
1484b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
1494b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            setName("IdleReaper");
1504b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            android.os.Process.setThreadPriority(
1514b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    android.os.Process.THREAD_PRIORITY_BACKGROUND);
1524b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            synchronized (IdleCache.this) {
1534b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                while (check < EMPTY_CHECK_MAX) {
1544b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    try {
1554b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                        IdleCache.this.wait(CHECK_INTERVAL);
1564b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    } catch (InterruptedException ex) {
1574b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    }
1584b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    if (mCount == 0) {
1594b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                        check++;
1604b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    } else {
1614b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                        check = 0;
1624b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                        clearIdle();
1634b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                    }
1644b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                }
1654b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                mThread = null;
1664b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            }
1674b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            if (HttpLog.LOGV) {
1684b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                HttpLog.v("IdleCache IdleReaper shutdown: cached " + mCached +
1694b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                          " reused " + mReused);
1704b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                mCached = 0;
1714b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                mReused = 0;
1724b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            }
1734b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        }
1744b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    }
1754b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet}
1764b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet