Home | History | Annotate | Download | only in webkit
      1 /*
      2  * Copyright (C) 2010 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 package android.webkit;
     18 
     19 import java.io.IOException;
     20 import java.util.HashMap;
     21 import java.util.Map;
     22 
     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;
     28 
     29 /**
     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.
     33  */
     34 final class WebViewWorker extends Handler {
     35 
     36     private static final String THREAD_NAME = "WebViewWorkerThread";
     37 
     38     private static WebViewWorker sWorkerHandler;
     39 
     40     private static Map<LoadListener, CacheManager.CacheResult> mCacheResultMap
     41             = new HashMap<LoadListener, CacheManager.CacheResult>();
     42 
     43     /**
     44      * Package level class to be used while creating a cache entry.
     45      */
     46     static class CacheCreateData {
     47         LoadListener mListener;
     48         String mUrl;
     49         String mMimeType;
     50         int mStatusCode;
     51         long mPostId;
     52         Headers mHeaders;
     53     }
     54 
     55     /**
     56      * Package level class to be used while saving a cache entry.
     57      */
     58     static class CacheSaveData {
     59         LoadListener mListener;
     60         String mUrl;
     61         long mPostId;
     62     }
     63 
     64     /**
     65      * Package level class to be used while updating a cache entry's encoding.
     66      */
     67     static class CacheEncoding {
     68         LoadListener mListener;
     69         String mEncoding;
     70     }
     71 
     72     /**
     73      * Package level class to be used while appending data to a cache entry.
     74      */
     75     static class CacheData {
     76         LoadListener mListener;
     77         ByteArrayBuilder.Chunk mChunk;
     78     }
     79 
     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);
     85             thread.start();
     86             sWorkerHandler = new WebViewWorker(thread.getLooper());
     87         }
     88         return sWorkerHandler;
     89     }
     90 
     91     private WebViewWorker(Looper looper) {
     92         super(looper);
     93     }
     94 
     95     // trigger transaction once a minute
     96     private static final int CACHE_TRANSACTION_TICKER_INTERVAL = 60 * 1000;
     97 
     98     private static boolean mCacheTickersBlocked = true;
     99 
    100     // message ids
    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;
    113 
    114     @Override
    115     public void handleMessage(Message msg) {
    116         switch(msg.what) {
    117             case MSG_ADD_STREAMLOADER: {
    118                 StreamLoader loader = (StreamLoader) msg.obj;
    119                 loader.load();
    120                 break;
    121             }
    122             case MSG_ADD_HTTPLOADER: {
    123                 FrameLoader loader = (FrameLoader) msg.obj;
    124                 loader.handleHTTPLoad();
    125                 break;
    126             }
    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);
    133                 if (cache != null) {
    134                     mCacheResultMap.put(data.mListener, cache);
    135                 } else {
    136                     mCacheResultMap.remove(data.mListener);
    137                 }
    138                 break;
    139             }
    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);
    145                 if (cache != null) {
    146                     cache.encoding = data.mEncoding;
    147                 }
    148                 break;
    149             }
    150             case MSG_APPEND_CACHE: {
    151                 assert !JniUtil.useChromiumHttpStack();
    152                 CacheData data = (CacheData) msg.obj;
    153                 CacheManager.CacheResult cache = mCacheResultMap
    154                         .get(data.mListener);
    155                 if (cache != null) {
    156                     cache.contentLength += data.mChunk.mLength;
    157                     if (cache.contentLength > CacheManager.CACHE_MAX_SIZE) {
    158                         CacheManager.cleanupCacheFile(cache);
    159                         mCacheResultMap.remove(data.mListener);
    160                     } else {
    161                         try {
    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);
    167                         }
    168                     }
    169                 }
    170                 data.mChunk.release();
    171                 break;
    172             }
    173             case MSG_SAVE_CACHE: {
    174                 assert !JniUtil.useChromiumHttpStack();
    175                 CacheSaveData data = (CacheSaveData) msg.obj;
    176                 CacheManager.CacheResult cache = mCacheResultMap
    177                         .get(data.mListener);
    178                 if (cache != null) {
    179                     CacheManager.saveCacheFile(data.mUrl, data.mPostId, cache);
    180                     mCacheResultMap.remove(data.mListener);
    181                 }
    182                 break;
    183             }
    184             case MSG_REMOVE_CACHE: {
    185                 assert !JniUtil.useChromiumHttpStack();
    186                 LoadListener listener = (LoadListener) msg.obj;
    187                 CacheManager.CacheResult cache = mCacheResultMap.get(listener);
    188                 if (cache != null) {
    189                     CacheManager.cleanupCacheFile(cache);
    190                     mCacheResultMap.remove(listener);
    191                 }
    192                 break;
    193             }
    194             case MSG_TRIM_CACHE: {
    195                 assert !JniUtil.useChromiumHttpStack();
    196                 CacheManager.trimCacheIfNeeded();
    197                 break;
    198             }
    199             case MSG_CLEAR_CACHE: {
    200                 assert !JniUtil.useChromiumHttpStack();
    201                 CacheManager.clearCache();
    202                 break;
    203             }
    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);
    211                 }
    212                 break;
    213             }
    214             case MSG_PAUSE_CACHE_TRANSACTION: {
    215                 assert !JniUtil.useChromiumHttpStack();
    216                 if (CacheManager.disableTransaction()) {
    217                     mCacheTickersBlocked = true;
    218                     removeMessages(MSG_CACHE_TRANSACTION_TICKER);
    219                 }
    220                 break;
    221             }
    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);
    228                 }
    229                 break;
    230             }
    231         }
    232     }
    233 }
    234