summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorGrace Kloba <klobag@google.com>2010-02-03 10:24:06 -0800
committerGrace Kloba <klobag@google.com>2010-02-04 08:59:10 -0800
commitac75f56600691d318d40301204baaf840c9586f2 (patch)
treeef2e3648d49ed787c732f85bb226e68dd1f9c221 /core
parentbca1c65fe491d070470ca248e804166a33e998a7 (diff)
downloadframeworks_base-ac75f56600691d318d40301204baaf840c9586f2.zip
frameworks_base-ac75f56600691d318d40301204baaf840c9586f2.tar.gz
frameworks_base-ac75f56600691d318d40301204baaf840c9586f2.tar.bz2
Enable StreamLoader to be loaded in a separate thread.
Move ContentLoader and FileLoader to this new way as they involves IO. Will work on CacheLoader later. Change StreamLoader to contain a Handler instead of derive from a Handler so that the Handler can be created in the thread where load() is called. Rename StreamLoader's old "LoadListener mHandler" to mLoadListener. Remove unused import and unreachable exception. Fix http://b/issue?id=2158613 This improved page_cycler performance in moz/intl by 10-30% as we are not blocked by IO any more.
Diffstat (limited to 'core')
-rw-r--r--core/java/android/webkit/CacheLoader.java2
-rw-r--r--core/java/android/webkit/ContentLoader.java28
-rw-r--r--core/java/android/webkit/DataLoader.java16
-rw-r--r--core/java/android/webkit/FileLoader.java34
-rw-r--r--core/java/android/webkit/FrameLoader.java23
-rw-r--r--core/java/android/webkit/StreamLoader.java109
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();
+ }
+ }
+ }
}