• 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 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