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 /** 28 * {@hide} 29 */ 30 class IdleCache { 31 32 class Entry { 33 HttpHost mHost; 34 Connection mConnection; 35 long mTimeout; 36 }; 37 38 private final static int IDLE_CACHE_MAX = 8; 39 40 /* Allow five consecutive empty queue checks before shutdown */ 41 private final static int EMPTY_CHECK_MAX = 5; 42 43 /* six second timeout for connections */ 44 private final static int TIMEOUT = 6 * 1000; 45 private final static int CHECK_INTERVAL = 2 * 1000; 46 private Entry[] mEntries = new Entry[IDLE_CACHE_MAX]; 47 48 private int mCount = 0; 49 50 private IdleReaper mThread = null; 51 52 /* stats */ 53 private int mCached = 0; 54 private int mReused = 0; 55 56 IdleCache() { 57 for (int i = 0; i < IDLE_CACHE_MAX; i++) { 58 mEntries[i] = new Entry(); 59 } 60 } 61 62 /** 63 * Caches connection, if there is room. 64 * @return true if connection cached 65 */ 66 synchronized boolean cacheConnection( 67 HttpHost host, Connection connection) { 68 69 boolean ret = false; 70 71 if (HttpLog.LOGV) { 72 HttpLog.v("IdleCache size " + mCount + " host " + host); 73 } 74 75 if (mCount < IDLE_CACHE_MAX) { 76 long time = SystemClock.uptimeMillis(); 77 for (int i = 0; i < IDLE_CACHE_MAX; i++) { 78 Entry entry = mEntries[i]; 79 if (entry.mHost == null) { 80 entry.mHost = host; 81 entry.mConnection = connection; 82 entry.mTimeout = time + TIMEOUT; 83 mCount++; 84 if (HttpLog.LOGV) mCached++; 85 ret = true; 86 if (mThread == null) { 87 mThread = new IdleReaper(); 88 mThread.start(); 89 } 90 break; 91 } 92 } 93 } 94 return ret; 95 } 96 97 synchronized Connection getConnection(HttpHost host) { 98 Connection ret = null; 99 100 if (mCount > 0) { 101 for (int i = 0; i < IDLE_CACHE_MAX; i++) { 102 Entry entry = mEntries[i]; 103 HttpHost eHost = entry.mHost; 104 if (eHost != null && eHost.equals(host)) { 105 ret = entry.mConnection; 106 entry.mHost = null; 107 entry.mConnection = null; 108 mCount--; 109 if (HttpLog.LOGV) mReused++; 110 break; 111 } 112 } 113 } 114 return ret; 115 } 116 117 synchronized void clear() { 118 for (int i = 0; mCount > 0 && i < IDLE_CACHE_MAX; i++) { 119 Entry entry = mEntries[i]; 120 if (entry.mHost != null) { 121 entry.mHost = null; 122 entry.mConnection.closeConnection(); 123 entry.mConnection = null; 124 mCount--; 125 } 126 } 127 } 128 129 private synchronized void clearIdle() { 130 if (mCount > 0) { 131 long time = SystemClock.uptimeMillis(); 132 for (int i = 0; i < IDLE_CACHE_MAX; i++) { 133 Entry entry = mEntries[i]; 134 if (entry.mHost != null && time > entry.mTimeout) { 135 entry.mHost = null; 136 entry.mConnection.closeConnection(); 137 entry.mConnection = null; 138 mCount--; 139 } 140 } 141 } 142 } 143 144 private class IdleReaper extends Thread { 145 146 public void run() { 147 int check = 0; 148 149 setName("IdleReaper"); 150 android.os.Process.setThreadPriority( 151 android.os.Process.THREAD_PRIORITY_BACKGROUND); 152 synchronized (IdleCache.this) { 153 while (check < EMPTY_CHECK_MAX) { 154 try { 155 IdleCache.this.wait(CHECK_INTERVAL); 156 } catch (InterruptedException ex) { 157 } 158 if (mCount == 0) { 159 check++; 160 } else { 161 check = 0; 162 clearIdle(); 163 } 164 } 165 mThread = null; 166 } 167 if (HttpLog.LOGV) { 168 HttpLog.v("IdleCache IdleReaper shutdown: cached " + mCached + 169 " reused " + mReused); 170 mCached = 0; 171 mReused = 0; 172 } 173 } 174 } 175 } 176