• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
IdleCache()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      */
cacheConnection( HttpHost host, Connection connection)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 
getConnection(HttpHost host)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 
clear()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 
clearIdle()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 
run()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