diff options
author | Grace Kloba <klobag@google.com> | 2010-02-04 09:47:57 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-02-04 09:47:57 -0800 |
commit | 5c33c6252ca2a58b524ee5a86a53114d591619e2 (patch) | |
tree | 7f686b308e1669783e46081fe5605980197401ed /core | |
parent | d0e18ffb82b59d38aeaf0e552f48e734202719ab (diff) | |
parent | ac75f56600691d318d40301204baaf840c9586f2 (diff) | |
download | frameworks_base-5c33c6252ca2a58b524ee5a86a53114d591619e2.zip frameworks_base-5c33c6252ca2a58b524ee5a86a53114d591619e2.tar.gz frameworks_base-5c33c6252ca2a58b524ee5a86a53114d591619e2.tar.bz2 |
Merge "Enable StreamLoader to be loaded in a separate thread."
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/webkit/CacheLoader.java | 2 | ||||
-rw-r--r-- | core/java/android/webkit/ContentLoader.java | 28 | ||||
-rw-r--r-- | core/java/android/webkit/DataLoader.java | 16 | ||||
-rw-r--r-- | core/java/android/webkit/FileLoader.java | 34 | ||||
-rw-r--r-- | core/java/android/webkit/FrameLoader.java | 23 | ||||
-rw-r--r-- | core/java/android/webkit/StreamLoader.java | 109 |
6 files changed, 105 insertions, 107 deletions
diff --git a/core/java/android/webkit/CacheLoader.java b/core/java/android/webkit/CacheLoader.java index de8f888..aeb537c 100644 --- a/core/java/android/webkit/CacheLoader.java +++ b/core/java/android/webkit/CacheLoader.java @@ -43,7 +43,7 @@ class CacheLoader extends StreamLoader { protected boolean setupStreamAndSendStatus() { mDataStream = mCacheResult.inStream; mContentLength = mCacheResult.contentLength; - mHandler.status(1, 1, mCacheResult.httpStatusCode, "OK"); + mLoadListener.status(1, 1, mCacheResult.httpStatusCode, "OK"); return true; } diff --git a/core/java/android/webkit/ContentLoader.java b/core/java/android/webkit/ContentLoader.java index 5eb54b0..d13210a 100644 --- a/core/java/android/webkit/ContentLoader.java +++ b/core/java/android/webkit/ContentLoader.java @@ -16,14 +16,10 @@ package android.webkit; -import android.content.Context; import android.net.http.EventHandler; import android.net.http.Headers; import android.net.Uri; -import java.io.File; -import java.io.FileInputStream; - /** * This class is a concrete implementation of StreamLoader that loads * "content:" URIs @@ -68,7 +64,7 @@ class ContentLoader extends StreamLoader { protected boolean setupStreamAndSendStatus() { Uri uri = Uri.parse(mUrl); if (uri == null) { - mHandler.error( + mLoadListener.error( EventHandler.FILE_NOT_FOUND_ERROR, mContext.getString( com.android.internal.R.string.httpErrorBadUrl) + @@ -78,18 +74,14 @@ class ContentLoader extends StreamLoader { try { mDataStream = mContext.getContentResolver().openInputStream(uri); - mHandler.status(1, 1, 200, "OK"); + mLoadListener.status(1, 1, 200, "OK"); } catch (java.io.FileNotFoundException ex) { - mHandler.error(EventHandler.FILE_NOT_FOUND_ERROR, errString(ex)); - return false; - - } catch (java.io.IOException ex) { - mHandler.error(EventHandler.FILE_ERROR, errString(ex)); + mLoadListener.error(EventHandler.FILE_NOT_FOUND_ERROR, errString(ex)); return false; } catch (RuntimeException ex) { // readExceptionWithFileNotFoundExceptionFromParcel in DatabaseUtils // can throw a serial of RuntimeException. Catch them all here. - mHandler.error(EventHandler.FILE_ERROR, errString(ex)); + mLoadListener.error(EventHandler.FILE_ERROR, errString(ex)); return false; } return true; @@ -103,16 +95,4 @@ class ContentLoader extends StreamLoader { // content can change, we don't want WebKit to cache it headers.setCacheControl("no-store, no-cache"); } - - /** - * Construct a ContentLoader and instruct it to start loading. - * - * @param url "content:" url pointing to content to be loaded - * @param loadListener LoadListener to pass the content to - */ - public static void requestUrl(String url, LoadListener loadListener) { - ContentLoader loader = new ContentLoader(url, loadListener); - loader.load(); - } - } diff --git a/core/java/android/webkit/DataLoader.java b/core/java/android/webkit/DataLoader.java index 2a68a5d..235dc5be 100644 --- a/core/java/android/webkit/DataLoader.java +++ b/core/java/android/webkit/DataLoader.java @@ -62,10 +62,10 @@ class DataLoader extends StreamLoader { @Override protected boolean setupStreamAndSendStatus() { if (mDataStream != null) { - mHandler.status(1, 1, 200, "OK"); + mLoadListener.status(1, 1, 200, "OK"); return true; } else { - mHandler.error(EventHandler.ERROR, + mLoadListener.error(EventHandler.ERROR, mContext.getString(R.string.httpError)); return false; } @@ -74,16 +74,4 @@ class DataLoader extends StreamLoader { @Override protected void buildHeaders(android.net.http.Headers h) { } - - /** - * Construct a DataLoader and instruct it to start loading. - * - * @param url data: URL string optionally containing a mimetype - * @param loadListener LoadListener to pass the content to - */ - public static void requestUrl(String url, LoadListener loadListener) { - DataLoader loader = new DataLoader(url, loadListener); - loader.load(); - } - } diff --git a/core/java/android/webkit/FileLoader.java b/core/java/android/webkit/FileLoader.java index e856cde..e21e9ef 100644 --- a/core/java/android/webkit/FileLoader.java +++ b/core/java/android/webkit/FileLoader.java @@ -18,11 +18,9 @@ package android.webkit; import com.android.internal.R; -import android.content.Context; import android.content.res.AssetManager; import android.net.http.EventHandler; import android.net.http.Headers; -import android.os.Environment; import android.util.Log; import android.util.TypedValue; @@ -111,7 +109,7 @@ class FileLoader extends StreamLoader { // "<package>.R$drawable" if (mPath == null || mPath.length() == 0) { Log.e(LOGTAG, "Need a path to resolve the res file"); - mHandler.error(EventHandler.FILE_ERROR, mContext + mLoadListener.error(EventHandler.FILE_ERROR, mContext .getString(R.string.httpErrorFileNotFound)); return false; @@ -120,7 +118,7 @@ class FileLoader extends StreamLoader { int dot = mPath.indexOf('.', slash); if (slash == -1 || dot == -1) { Log.e(LOGTAG, "Incorrect res path: " + mPath); - mHandler.error(EventHandler.FILE_ERROR, mContext + mLoadListener.error(EventHandler.FILE_ERROR, mContext .getString(R.string.httpErrorFileNotFound)); return false; } @@ -157,13 +155,13 @@ class FileLoader extends StreamLoader { errorMsg = "Caught IllegalAccessException: " + e; } if (errorMsg != null) { - mHandler.error(EventHandler.FILE_ERROR, mContext + mLoadListener.error(EventHandler.FILE_ERROR, mContext .getString(R.string.httpErrorFileNotFound)); return false; } } else { if (!mAllowFileAccess) { - mHandler.error(EventHandler.FILE_ERROR, + mLoadListener.error(EventHandler.FILE_ERROR, mContext.getString(R.string.httpErrorFileNotFound)); return false; } @@ -171,14 +169,14 @@ class FileLoader extends StreamLoader { mDataStream = new FileInputStream(mPath); mContentLength = (new File(mPath)).length(); } - mHandler.status(1, 1, 200, "OK"); + mLoadListener.status(1, 1, 200, "OK"); } catch (java.io.FileNotFoundException ex) { - mHandler.error(EventHandler.FILE_NOT_FOUND_ERROR, errString(ex)); + mLoadListener.error(EventHandler.FILE_NOT_FOUND_ERROR, errString(ex)); return false; } catch (java.io.IOException ex) { - mHandler.error(EventHandler.FILE_ERROR, errString(ex)); + mLoadListener.error(EventHandler.FILE_ERROR, errString(ex)); return false; } return true; @@ -188,22 +186,4 @@ class FileLoader extends StreamLoader { protected void buildHeaders(Headers headers) { // do nothing. } - - - /** - * Construct a FileLoader and instruct it to start loading. - * - * @param url Full file url pointing to content to be loaded - * @param loadListener LoadListener to pass the content to - * @param asset true if url points to an asset. - * @param allowFileAccess true if this FileLoader can load files from the - * file system. - */ - public static void requestUrl(String url, LoadListener loadListener, - int type, boolean allowFileAccess) { - FileLoader loader = new FileLoader(url, loadListener, type, - allowFileAccess); - loader.load(); - } - } diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java index 58eca38..b13c405 100644 --- a/core/java/android/webkit/FrameLoader.java +++ b/core/java/android/webkit/FrameLoader.java @@ -141,24 +141,29 @@ class FrameLoader { return true; } if (URLUtil.isAssetUrl(url)) { - FileLoader.requestUrl(url, loadListener, FileLoader.TYPE_ASSET, - true); + // load asset in a separate thread as it involves IO + new FileLoader(url, loadListener, FileLoader.TYPE_ASSET, true) + .enqueue(); return true; } else if (URLUtil.isResourceUrl(url)) { - FileLoader.requestUrl(url, loadListener, FileLoader.TYPE_RES, - true); + // load resource in a separate thread as it involves IO + new FileLoader(url, loadListener, FileLoader.TYPE_RES, true) + .enqueue(); return true; } else if (URLUtil.isFileUrl(url)) { - FileLoader.requestUrl(url, loadListener, FileLoader.TYPE_FILE, - settings.getAllowFileAccess()); + // load file in a separate thread as it involves IO + new FileLoader(url, loadListener, FileLoader.TYPE_FILE, settings + .getAllowFileAccess()).enqueue(); return true; } else if (URLUtil.isContentUrl(url)) { // Send the raw url to the ContentLoader because it will do a - // permission check and the url has to match.. - ContentLoader.requestUrl(loadListener.url(), loadListener); + // permission check and the url has to match. + // load content in a separate thread as it involves IO + new ContentLoader(loadListener.url(), loadListener).enqueue(); return true; } else if (URLUtil.isDataUrl(url)) { - DataLoader.requestUrl(url, loadListener); + // load data in the current thread to reduce the latency + new DataLoader(url, loadListener).load(); return true; } else if (URLUtil.isAboutUrl(url)) { loadListener.data(mAboutBlank.getBytes(), mAboutBlank.length()); diff --git a/core/java/android/webkit/StreamLoader.java b/core/java/android/webkit/StreamLoader.java index ce26268..4c32997 100644 --- a/core/java/android/webkit/StreamLoader.java +++ b/core/java/android/webkit/StreamLoader.java @@ -20,12 +20,13 @@ import android.content.Context; import android.net.http.EventHandler; import android.net.http.Headers; import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; import android.os.Message; import java.io.IOException; import java.io.InputStream; - /** * This abstract class is used for all content loaders that rely on streaming * content into the rendering engine loading framework. @@ -44,9 +45,7 @@ import java.io.InputStream; * that indicates the content should not be cached. * */ -abstract class StreamLoader extends Handler { - - public static final String NO_STORE = "no-store"; +abstract class StreamLoader implements Handler.Callback { private static final int MSG_STATUS = 100; // Send status to loader private static final int MSG_HEADERS = 101; // Send headers to loader @@ -54,11 +53,19 @@ abstract class StreamLoader extends Handler { private static final int MSG_END = 103; // Send endData to loader protected final Context mContext; - protected final LoadListener mHandler; // loader class + protected final LoadListener mLoadListener; // loader class protected InputStream mDataStream; // stream to read data from protected long mContentLength; // content length of data private byte [] mData; // buffer to pass data to loader with. + // Handler which will be initialized in the thread where load() is called. + private Handler mHandler; + + // Handler which will be used to load StreamLoader in a separate thread + private static StreamQueueHandler sStreamQueueHandler; + + private static final Object sStreamQueueLock = new Object(); + /** * Constructor. Although this class calls the LoadListener, it only calls * the EventHandler Interface methods. LoadListener concrete class is used @@ -67,13 +74,13 @@ abstract class StreamLoader extends Handler { * @param loadlistener The LoadListener to call with the data. */ StreamLoader(LoadListener loadlistener) { - mHandler = loadlistener; + mLoadListener = loadlistener; mContext = loadlistener.getContext(); } /** * This method is called when the derived class should setup mDataStream, - * and call mHandler.status() to indicate that the load can occur. If it + * and call mLoadListener.status() to indicate that the load can occur. If it * fails to setup, it should still call status() with the error code. * * @return true if stream was successfully setup @@ -89,15 +96,40 @@ abstract class StreamLoader extends Handler { */ abstract protected void buildHeaders(Headers headers); + /** + * Calling this method to load this StreamLoader in a separate + * "StreamLoadingThread". + */ + final void enqueue() { + synchronized (sStreamQueueLock) { + if (sStreamQueueHandler == null) { + HandlerThread thread = new HandlerThread( + StreamQueueHandler.THREAD_NAME, + android.os.Process.THREAD_PRIORITY_DEFAULT + + android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE); + thread.start(); + sStreamQueueHandler = new StreamQueueHandler(thread.getLooper()); + } + } + + sStreamQueueHandler.obtainMessage(StreamQueueHandler.MSG_ADD_LOADER, + this).sendToTarget(); + } /** * Calling this method starts the load of the content for this StreamLoader. - * This method simply posts a message to send the status and returns - * immediately. + * This method simply creates a Handler in the current thread and posts a + * message to send the status and returns immediately. */ - public void load() { - if (!mHandler.isSynchronous()) { - sendMessage(obtainMessage(MSG_STATUS)); + final void load() { + synchronized (this) { + if (mHandler == null) { + mHandler = new Handler(this); + } + } + + if (!mLoadListener.isSynchronous()) { + mHandler.sendEmptyMessage(MSG_STATUS); } else { // Load the stream synchronously. if (setupStreamAndSendStatus()) { @@ -105,23 +137,20 @@ abstract class StreamLoader extends Handler { // to pass data to the loader mData = new byte[8192]; sendHeaders(); - while (!sendData() && !mHandler.cancelled()); + while (!sendData() && !mLoadListener.cancelled()); closeStreamAndSendEndData(); - mHandler.loadSynchronousMessages(); + mLoadListener.loadSynchronousMessages(); } } } - /* (non-Javadoc) - * @see android.os.Handler#handleMessage(android.os.Message) - */ - public void handleMessage(Message msg) { - if (DebugFlags.STREAM_LOADER && mHandler.isSynchronous()) { + public boolean handleMessage(Message msg) { + if (mLoadListener.isSynchronous()) { throw new AssertionError(); } - if (mHandler.cancelled()) { + if (mLoadListener.cancelled()) { closeStreamAndSendEndData(); - return; + return true; } switch(msg.what) { case MSG_STATUS: @@ -129,27 +158,27 @@ abstract class StreamLoader extends Handler { // We were able to open the stream, create the array // to pass data to the loader mData = new byte[8192]; - sendMessage(obtainMessage(MSG_HEADERS)); + mHandler.sendEmptyMessage(MSG_HEADERS); } break; case MSG_HEADERS: sendHeaders(); - sendMessage(obtainMessage(MSG_DATA)); + mHandler.sendEmptyMessage(MSG_DATA); break; case MSG_DATA: if (sendData()) { - sendMessage(obtainMessage(MSG_END)); + mHandler.sendEmptyMessage(MSG_END); } else { - sendMessage(obtainMessage(MSG_DATA)); + mHandler.sendEmptyMessage(MSG_DATA); } break; case MSG_END: closeStreamAndSendEndData(); break; default: - super.handleMessage(msg); - break; + return false; } + return true; } /** @@ -161,7 +190,7 @@ abstract class StreamLoader extends Handler { headers.setContentLength(mContentLength); } buildHeaders(headers); - mHandler.headers(headers); + mLoadListener.headers(headers); } /** @@ -176,12 +205,11 @@ abstract class StreamLoader extends Handler { try { int amount = mDataStream.read(mData); if (amount > 0) { - mHandler.data(mData, amount); + mLoadListener.data(mData, amount); return false; } } catch (IOException ex) { - mHandler.error(EventHandler.FILE_ERROR, - ex.getMessage()); + mLoadListener.error(EventHandler.FILE_ERROR, ex.getMessage()); } } return true; @@ -198,7 +226,24 @@ abstract class StreamLoader extends Handler { // ignore. } } - mHandler.endData(); + mLoadListener.endData(); } + private static class StreamQueueHandler extends Handler { + private static final String THREAD_NAME = "StreamLoadingThread"; + + private static final int MSG_ADD_LOADER = 101; + + StreamQueueHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_ADD_LOADER) { + StreamLoader loader = (StreamLoader) msg.obj; + loader.load(); + } + } + } } |