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