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