1a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath/* 2a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Copyright (C) 2008 The Android Open Source Project 3a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * 4a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Licensed under the Apache License, Version 2.0 (the "License"); 5a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * you may not use this file except in compliance with the License. 6a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * You may obtain a copy of the License at 7a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * 8a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * http://www.apache.org/licenses/LICENSE-2.0 9a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * 10a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Unless required by applicable law or agreed to in writing, software 11a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * distributed under the License is distributed on an "AS IS" BASIS, 12a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * See the License for the specific language governing permissions and 14a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * limitations under the License. 15a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 16a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 17a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath/** 18a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Hangs onto idle live connections for a little while 19a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 20a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 21a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathpackage android.net.http; 22a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 23a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.HttpHost; 24a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 25a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport android.os.SystemClock; 26a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 27a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathclass IdleCache { 28a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 29a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath class Entry { 30a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath HttpHost mHost; 31a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Connection mConnection; 32a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath long mTimeout; 33a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath }; 34a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 35a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private final static int IDLE_CACHE_MAX = 8; 36a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 37a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /* Allow five consecutive empty queue checks before shutdown */ 38a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private final static int EMPTY_CHECK_MAX = 5; 39a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 40a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /* six second timeout for connections */ 41a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private final static int TIMEOUT = 6 * 1000; 42a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private final static int CHECK_INTERVAL = 2 * 1000; 43a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private Entry[] mEntries = new Entry[IDLE_CACHE_MAX]; 44a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 45a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private int mCount = 0; 46a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 47a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private IdleReaper mThread = null; 48a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 49a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /* stats */ 50a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private int mCached = 0; 51a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private int mReused = 0; 52a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 53a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath IdleCache() { 54a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath for (int i = 0; i < IDLE_CACHE_MAX; i++) { 55a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mEntries[i] = new Entry(); 56a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 57a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 58a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 59a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 60a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Caches connection, if there is room. 61a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @return true if connection cached 62a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 63a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath synchronized boolean cacheConnection( 64a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath HttpHost host, Connection connection) { 65a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 66a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath boolean ret = false; 67a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 68a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (HttpLog.LOGV) { 69a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath HttpLog.v("IdleCache size " + mCount + " host " + host); 70a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 71a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 72a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (mCount < IDLE_CACHE_MAX) { 73a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath long time = SystemClock.uptimeMillis(); 74a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath for (int i = 0; i < IDLE_CACHE_MAX; i++) { 75a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Entry entry = mEntries[i]; 76a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (entry.mHost == null) { 77a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entry.mHost = host; 78a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entry.mConnection = connection; 79a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entry.mTimeout = time + TIMEOUT; 80a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mCount++; 81a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (HttpLog.LOGV) mCached++; 82a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath ret = true; 83a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (mThread == null) { 84a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mThread = new IdleReaper(); 85a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mThread.start(); 86a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 87a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath break; 88a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 89a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 90a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 91a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return ret; 92a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 93a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 94a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath synchronized Connection getConnection(HttpHost host) { 95a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Connection ret = null; 96a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 97a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (mCount > 0) { 98a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath for (int i = 0; i < IDLE_CACHE_MAX; i++) { 99a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Entry entry = mEntries[i]; 100a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath HttpHost eHost = entry.mHost; 101a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (eHost != null && eHost.equals(host)) { 102a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath ret = entry.mConnection; 103a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entry.mHost = null; 104a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entry.mConnection = null; 105a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mCount--; 106a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (HttpLog.LOGV) mReused++; 107a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath break; 108a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 109a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 110a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 111a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return ret; 112a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 113a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 114a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath synchronized void clear() { 115a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath for (int i = 0; mCount > 0 && i < IDLE_CACHE_MAX; i++) { 116a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Entry entry = mEntries[i]; 117a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (entry.mHost != null) { 118a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entry.mHost = null; 119a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entry.mConnection.closeConnection(); 120a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entry.mConnection = null; 121a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mCount--; 122a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 123a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 124a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 125a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 126a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private synchronized void clearIdle() { 127a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (mCount > 0) { 128a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath long time = SystemClock.uptimeMillis(); 129a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath for (int i = 0; i < IDLE_CACHE_MAX; i++) { 130a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Entry entry = mEntries[i]; 131a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (entry.mHost != null && time > entry.mTimeout) { 132a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entry.mHost = null; 133a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entry.mConnection.closeConnection(); 134a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entry.mConnection = null; 135a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mCount--; 136a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 137a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 138a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 139a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 140a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 141a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private class IdleReaper extends Thread { 142a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 143a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void run() { 144a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath int check = 0; 145a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 146a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath setName("IdleReaper"); 147a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath android.os.Process.setThreadPriority( 148a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath android.os.Process.THREAD_PRIORITY_BACKGROUND); 149a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath synchronized (IdleCache.this) { 150a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath while (check < EMPTY_CHECK_MAX) { 151a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath try { 152a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath IdleCache.this.wait(CHECK_INTERVAL); 153a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } catch (InterruptedException ex) { 154a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 155a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (mCount == 0) { 156a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath check++; 157a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 158a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath check = 0; 159a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath clearIdle(); 160a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 161a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 162a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mThread = null; 163a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 164a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (HttpLog.LOGV) { 165a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath HttpLog.v("IdleCache IdleReaper shutdown: cached " + mCached + 166a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath " reused " + mReused); 167a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mCached = 0; 168a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath mReused = 0; 169a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 170a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 171a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 172a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath} 173