2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android.webkit;
19 import java.io.IOException;
20 import java.util.HashMap;
23 import android.net.http.Headers;
24 import android.os.Handler;
25 import android.os.HandlerThread;
26 import android.os.Looper;
27 import android.os.Message;
30 * WebViewWorker executes in a separate thread other than UI and WebViewCore. To
31 * avoid blocking UI or WebKit's execution, the caller can send a message to
32 * WebViewWorker.getHandler() and it will be handled in the WebViewWorkerThread.
34 final class WebViewWorker extends Handler {
36 private static final String THREAD_NAME = "WebViewWorkerThread";
38 private static WebViewWorker sWorkerHandler;
40 private static Map<LoadListener, CacheManager.CacheResult> mCacheResultMap
41 = new HashMap<LoadListener, CacheManager.CacheResult>();
44 * Package level class to be used while creating a cache entry.
46 static class CacheCreateData {
47 LoadListener mListener;
56 * Package level class to be used while saving a cache entry.
58 static class CacheSaveData {
59 LoadListener mListener;
65 * Package level class to be used while updating a cache entry's encoding.
67 static class CacheEncoding {
68 LoadListener mListener;
73 * Package level class to be used while appending data to a cache entry.
75 static class CacheData {
76 LoadListener mListener;
77 ByteArrayBuilder.Chunk mChunk;
80 static synchronized WebViewWorker getHandler() {
81 if (sWorkerHandler == null) {
82 HandlerThread thread = new HandlerThread(THREAD_NAME,
83 android.os.Process.THREAD_PRIORITY_DEFAULT
84 + android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE);
86 sWorkerHandler = new WebViewWorker(thread.getLooper());
88 return sWorkerHandler;
91 private WebViewWorker(Looper looper) {
95 // trigger transaction once a minute
96 private static final int CACHE_TRANSACTION_TICKER_INTERVAL = 60 * 1000;
98 private static boolean mCacheTickersBlocked = true;
101 static final int MSG_ADD_STREAMLOADER = 101;
102 static final int MSG_ADD_HTTPLOADER = 102;
103 static final int MSG_CREATE_CACHE = 103;
104 static final int MSG_UPDATE_CACHE_ENCODING = 104;
105 static final int MSG_APPEND_CACHE = 105;
106 static final int MSG_SAVE_CACHE = 106;
107 static final int MSG_REMOVE_CACHE = 107;
108 static final int MSG_TRIM_CACHE = 108;
109 static final int MSG_CLEAR_CACHE = 109;
110 static final int MSG_CACHE_TRANSACTION_TICKER = 110;
111 static final int MSG_PAUSE_CACHE_TRANSACTION = 111;
112 static final int MSG_RESUME_CACHE_TRANSACTION = 112;
115 public void handleMessage(Message msg) {
117 case MSG_ADD_STREAMLOADER: {
118 StreamLoader loader = (StreamLoader) msg.obj;
122 case MSG_ADD_HTTPLOADER: {
123 FrameLoader loader = (FrameLoader) msg.obj;
124 loader.handleHTTPLoad();
127 case MSG_CREATE_CACHE: {
128 assert !JniUtil.useChromiumHttpStack();
129 CacheCreateData data = (CacheCreateData) msg.obj;
130 CacheManager.CacheResult cache = CacheManager.createCacheFile(
131 data.mUrl, data.mStatusCode, data.mHeaders,
132 data.mMimeType, data.mPostId, false);
134 mCacheResultMap.put(data.mListener, cache);
136 mCacheResultMap.remove(data.mListener);
140 case MSG_UPDATE_CACHE_ENCODING: {
141 assert !JniUtil.useChromiumHttpStack();
142 CacheEncoding data = (CacheEncoding) msg.obj;
143 CacheManager.CacheResult cache = mCacheResultMap
144 .get(data.mListener);
146 cache.encoding = data.mEncoding;
150 case MSG_APPEND_CACHE: {
151 assert !JniUtil.useChromiumHttpStack();
152 CacheData data = (CacheData) msg.obj;
153 CacheManager.CacheResult cache = mCacheResultMap
154 .get(data.mListener);
156 cache.contentLength += data.mChunk.mLength;
157 if (cache.contentLength > CacheManager.CACHE_MAX_SIZE) {
158 CacheManager.cleanupCacheFile(cache);
159 mCacheResultMap.remove(data.mListener);
162 cache.outStream.write(data.mChunk.mArray, 0,
163 data.mChunk.mLength);
164 } catch (IOException e) {
165 CacheManager.cleanupCacheFile(cache);
166 mCacheResultMap.remove(data.mListener);
170 data.mChunk.release();
173 case MSG_SAVE_CACHE: {
174 assert !JniUtil.useChromiumHttpStack();
175 CacheSaveData data = (CacheSaveData) msg.obj;
176 CacheManager.CacheResult cache = mCacheResultMap
177 .get(data.mListener);
179 CacheManager.saveCacheFile(data.mUrl, data.mPostId, cache);
180 mCacheResultMap.remove(data.mListener);
184 case MSG_REMOVE_CACHE: {
185 assert !JniUtil.useChromiumHttpStack();
186 LoadListener listener = (LoadListener) msg.obj;
187 CacheManager.CacheResult cache = mCacheResultMap.get(listener);
189 CacheManager.cleanupCacheFile(cache);
190 mCacheResultMap.remove(listener);
194 case MSG_TRIM_CACHE: {
195 assert !JniUtil.useChromiumHttpStack();
196 CacheManager.trimCacheIfNeeded();
199 case MSG_CLEAR_CACHE: {
200 assert !JniUtil.useChromiumHttpStack();
201 CacheManager.clearCache();
204 case MSG_CACHE_TRANSACTION_TICKER: {
205 assert !JniUtil.useChromiumHttpStack();
206 if (!mCacheTickersBlocked) {
207 CacheManager.endTransaction();
208 CacheManager.startTransaction();
209 sendEmptyMessageDelayed(MSG_CACHE_TRANSACTION_TICKER,
210 CACHE_TRANSACTION_TICKER_INTERVAL);
214 case MSG_PAUSE_CACHE_TRANSACTION: {
215 assert !JniUtil.useChromiumHttpStack();
216 if (CacheManager.disableTransaction()) {
217 mCacheTickersBlocked = true;
218 removeMessages(MSG_CACHE_TRANSACTION_TICKER);
222 case MSG_RESUME_CACHE_TRANSACTION: {
223 assert !JniUtil.useChromiumHttpStack();
224 if (CacheManager.enableTransaction()) {
225 mCacheTickersBlocked = false;
226 sendEmptyMessageDelayed(MSG_CACHE_TRANSACTION_TICKER,
227 CACHE_TRANSACTION_TICKER_INTERVAL);