summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorDinesh K Garg <dineshg@quicinc.com>2010-07-15 09:29:11 -0700
committerSteve Kondik <shade@chemlab.org>2010-08-03 13:55:49 -0400
commit45c6ef39a7da69ddf772f4a489b5cb8f5595fea1 (patch)
treefc93e7b7e83ead2adf1f53754b17cfe68cf072ae /core
parent0468ca9d7f0f01767ab0d3d4557ddac93b6b2c7e (diff)
downloadframeworks_base-45c6ef39a7da69ddf772f4a489b5cb8f5595fea1.zip
frameworks_base-45c6ef39a7da69ddf772f4a489b5cb8f5595fea1.tar.gz
frameworks_base-45c6ef39a7da69ddf772f4a489b5cb8f5595fea1.tar.bz2
Dns prefetch implementation on Froyo
Change-Id: Ic0223dc2f4ce1443402a69dbb5bd864e92d142b9
Diffstat (limited to 'core')
-rw-r--r--core/java/android/provider/Browser.java29
-rw-r--r--core/java/android/webkit/BrowserFrame.java19
-rw-r--r--core/java/android/webkit/DnsResolver.java206
-rw-r--r--core/java/android/webkit/WebView.java8
-rw-r--r--core/java/android/webkit/WebViewCore.java13
5 files changed, 275 insertions, 0 deletions
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 2fba1d7..9c3a725 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006 The Android Open Source Project
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -342,6 +343,34 @@ public class Browser {
}
/**
+ * Returns top num of visited URLs in the history.
+ * Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS}
+ * @param cr The ContentResolver used to access the database.
+ * @hide pending API council approval
+ */
+ public static final String[] getVisitedHistoryByOrder(ContentResolver cr, String order, int num) {
+ try {
+ String[] projection = new String[] {
+ "url"
+ };
+ Cursor c = cr.query(BOOKMARKS_URI, projection, "visits > 0", null,
+ order);
+
+ int count = (c.getCount() > num)? num:c.getCount();
+ String[] str = new String[count];
+ int i = 0;
+ while ((i<count) && c.moveToNext()) {
+ str[i] = c.getString(0);
+ i++;
+ }
+ c.deactivate();
+ return str;
+ } catch (IllegalStateException e) {
+ return new String[0];
+ }
+ }
+
+ /**
* If there are more than MAX_HISTORY_COUNT non-bookmark history
* items in the bookmark/history table, delete TRUNCATE_N_OLDEST
* of them. This is used to keep our history table to a
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 219a469..071f87c 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006 The Android Open Source Project
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -229,6 +230,22 @@ class BrowserFrame extends Handler {
}
}
+ public void startDnsPrefetch() {
+ if (DebugFlags.BROWSER_FRAME) {
+ Log.v(LOGTAG, "Starting DNS prefetch");
+ }
+
+ DnsResolver dnsResolver = DnsResolver.getInstance();
+ if(dnsResolver == null )
+ return;
+
+ HashMap hostsMap = nativeGetEmbeddedHostNames(dnsResolver.getMaxParallelDnsQueryPerPage());
+ if(hostsMap == null)
+ return;
+
+ dnsResolver.resolveDnsForHostMap(hostsMap);
+ }
+
/**
* Load a url from the network or the filesystem into the main frame.
* Following the same behaviour as Safari, javascript: URLs are not passed
@@ -967,6 +984,8 @@ class BrowserFrame extends Handler {
private native void nativeLoadData(String baseUrl, String data,
String mimeType, String encoding, String historyUrl);
+ private native HashMap nativeGetEmbeddedHostNames(int maxDnsHostCount);
+
/**
* Stop loading the current page.
*/
diff --git a/core/java/android/webkit/DnsResolver.java b/core/java/android/webkit/DnsResolver.java
new file mode 100644
index 0000000..80a0808
--- /dev/null
+++ b/core/java/android/webkit/DnsResolver.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package android.webkit;
+
+import android.os.Handler;
+import android.util.Log;
+import android.os.Message;
+import android.os.Process;
+
+import java.lang.Thread;
+import java.lang.InterruptedException;
+import java.net.UnknownHostException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Semaphore;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+final class DnsResolver {
+
+ private static final String LOGTAG = "webcore";
+
+ /* Max Thread pool size is taken from data published by google
+ * that mentions max hosts per webpage = 8 */
+ private final int MAX_DNS_RESOLVER_THREAD_POOL_SIZE = 8;
+
+ /* This number is derived by considering various factors such as OS DNS cache size,
+ * Browser Cache size and realistic need to spent time on DNS prefetch
+ */
+ private final int MAX_PARALLEL_DNS_QUERIES_PER_PAGE = 64;
+
+ private volatile boolean mDnsResolverThreadPoolRunning = false;
+
+ private volatile boolean mShutDownInProgress = false;
+
+ private static DnsResolver sDnsResolver;
+
+ private HashMap mHostNamesToBeResolved;
+
+ private ExecutorService mDnsResolverThreadPool;
+
+ private static int mDnsResolverRefCount = 0;
+
+ /* Lock to synchronize the access to threadpool */
+ private static Object mThreadPoolLock = new Object();
+
+ public static synchronized DnsResolver createDnsResolver() {
+ if (sDnsResolver == null) {
+ sDnsResolver = new DnsResolver();
+ }
+ ++mDnsResolverRefCount;
+ return sDnsResolver;
+ }
+
+ public static DnsResolver getInstance() {
+ return sDnsResolver;
+ }
+
+ private DnsResolver() {
+ createDnsResolverThreadPool();
+ }
+
+ private void createDnsResolverThreadPool() {
+ final Runnable startDnsResolver = new Runnable() {
+ public void run() {
+ /* DNS resolver priority should be same as of HTTP thread pool */
+ Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_DEFAULT +
+ android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE);
+ mDnsResolverThreadPool = Executors.newFixedThreadPool(MAX_DNS_RESOLVER_THREAD_POOL_SIZE);
+ mHostNamesToBeResolved = new HashMap();
+ boolean bResolvedPriorityHostNames = false;
+ int dnsQueryCounter = 0;
+ int numHosts = 0;
+ while(!mShutDownInProgress) {
+ synchronized(mHostNamesToBeResolved) {
+ numHosts = mHostNamesToBeResolved.size();
+ }
+ if(numHosts <= 0) {
+ try {
+ dnsQueryCounter = 0;
+ bResolvedPriorityHostNames = false;
+ mDnsResolverThreadPoolRunning = true;
+ synchronized(mThreadPoolLock) {
+ mThreadPoolLock.wait();
+ }
+ } catch(java.lang.InterruptedException e) {
+ }
+ }
+ else {
+ synchronized(mHostNamesToBeResolved) {
+ Iterator iterator = mHostNamesToBeResolved.entrySet().iterator();
+ while(iterator.hasNext() && mDnsResolverThreadPoolRunning && (dnsQueryCounter < MAX_PARALLEL_DNS_QUERIES_PER_PAGE)) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ final String hostName = (String)entry.getKey();
+ final String priority = (String)entry.getValue();
+ if( (!bResolvedPriorityHostNames && priority.equalsIgnoreCase("1")) ||
+ ( bResolvedPriorityHostNames && priority.equalsIgnoreCase("0"))
+ ) {
+ ++dnsQueryCounter;
+ iterator.remove();
+ Runnable task = new Runnable() {
+ public void run() {
+ try {
+ java.net.InetAddress.getByName(hostName);
+ } catch(java.net.UnknownHostException e) {
+ }
+ }
+ };
+ mDnsResolverThreadPool.execute (task);
+ }
+ }
+ if(!mDnsResolverThreadPoolRunning || (dnsQueryCounter >= MAX_PARALLEL_DNS_QUERIES_PER_PAGE)) {
+ mHostNamesToBeResolved.clear();
+ }
+ bResolvedPriorityHostNames = (bResolvedPriorityHostNames) ? false:true;
+ }
+ }
+ }
+ mDnsResolverThreadPool.shutdown();
+ sDnsResolver = null;
+ }
+ };
+ Thread dnsResolver = new Thread(startDnsResolver);
+ dnsResolver.setName("DNS resolver");
+ dnsResolver.start();
+ }
+
+ public synchronized void destroyDnsResolver() {
+ --mDnsResolverRefCount;
+ if(mDnsResolverRefCount == 0) {
+ mShutDownInProgress = true;
+ mDnsResolverThreadPoolRunning = false;
+ synchronized(mThreadPoolLock) {
+ mThreadPoolLock.notifyAll();
+ }
+ }
+ }
+
+ public void resolveDnsForHost(String hostName, String priority) {
+ if(hostName == null) {
+ return;
+ }
+ synchronized(mHostNamesToBeResolved) {
+ if(mHostNamesToBeResolved.size() > 0 ) {
+ return;
+ }
+ mHostNamesToBeResolved.put(hostName,priority);
+ }
+ resumeDnsResolverThreadPool();
+ }
+
+ public void resolveDnsForHostMap(HashMap hostMap) {
+ if(hostMap == null) {
+ return;
+ }
+ synchronized (mHostNamesToBeResolved) {
+ mHostNamesToBeResolved.putAll(hostMap);
+ }
+ resumeDnsResolverThreadPool();
+ }
+
+ /* pause will flush all pending DNS queries at the DNS resolver */
+ public void pauseDnsResolverThreadPool() {
+ mDnsResolverThreadPoolRunning = false;
+ }
+
+ /* resume will start DNS resolver executing DNS queries */
+ public void resumeDnsResolverThreadPool() {
+ mDnsResolverThreadPoolRunning = true;
+ synchronized(mThreadPoolLock) {
+ mThreadPoolLock.notifyAll();
+ }
+ }
+
+ /* returns the max number of DNS queries that can be made in background for a page */
+ public int getMaxParallelDnsQueryPerPage() {
+ return MAX_PARALLEL_DNS_QUERIES_PER_PAGE;
+ }
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 766a80c..f3ddbb6 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006 The Android Open Source Project
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1298,6 +1299,13 @@ public class WebView extends AbsoluteLayout
}
/**
+ * @hide pending API council approval.
+ */
+ public void startDnsPrefetch() {
+ mWebViewCore.sendMessage(EventHub.START_DNS_PREFETCH);
+ }
+
+ /**
* Inform WebView of the network state. This is used to set
* the javascript property window.navigator.isOnline and
* generates the online/offline event as specified in HTML5, sec. 5.7.7
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 4118119..7a1f7b5 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2007 The Android Open Source Project
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -197,6 +198,8 @@ final class WebViewCore {
// WebCore thread handler.
mEventHub.transferMessages();
+ DnsResolver.createDnsResolver();
+
// Send a message back to WebView to tell it that we have set up the
// WebCore thread.
if (mWebView != null) {
@@ -771,6 +774,7 @@ final class WebViewCore {
"ON_RESUME", // = 144
"FREE_MEMORY", // = 145
"VALID_NODE_BOUNDS", // = 146
+ "START_DNS_PREFETCH", // = 151
};
class EventHub {
@@ -839,6 +843,7 @@ final class WebViewCore {
// Network-based messaging
static final int CLEAR_SSL_PREF_TABLE = 150;
+ static final int START_DNS_PREFETCH = 151;
// Test harness messages
static final int REQUEST_EXT_REPRESENTATION = 160;
@@ -944,6 +949,7 @@ final class WebViewCore {
break;
case LOAD_URL: {
+ DnsResolver.getInstance().pauseDnsResolverThreadPool();
GetUrlData param = (GetUrlData) msg.obj;
loadUrl(param.mUrl, param.mExtraHeaders);
break;
@@ -1000,6 +1006,7 @@ final class WebViewCore {
break;
case RELOAD:
+ DnsResolver.getInstance().pauseDnsResolverThreadPool();
mBrowserFrame.reload(false);
break;
@@ -1043,6 +1050,7 @@ final class WebViewCore {
if (!mBrowserFrame.committed() && msg.arg1 == -1 &&
(mBrowserFrame.loadType() ==
BrowserFrame.FRAME_LOADTYPE_STANDARD)) {
+ DnsResolver.getInstance().pauseDnsResolverThreadPool();
mBrowserFrame.reload(true);
} else {
mBrowserFrame.goBackOrForward(msg.arg1);
@@ -1357,6 +1365,10 @@ final class WebViewCore {
BrowserFrame.sJavaBridge.removePackageName(
(String) msg.obj);
break;
+
+ case START_DNS_PREFETCH:
+ mBrowserFrame.startDnsPrefetch();
+ break;
}
}
};
@@ -1544,6 +1556,7 @@ final class WebViewCore {
}
mEventHub.blockMessages();
}
+ DnsResolver.getInstance().destroyDnsResolver();
}
//-------------------------------------------------------------------------