diff options
author | Dinesh K Garg <dineshg@quicinc.com> | 2010-07-15 09:29:11 -0700 |
---|---|---|
committer | Steve Kondik <shade@chemlab.org> | 2010-08-03 13:55:49 -0400 |
commit | 45c6ef39a7da69ddf772f4a489b5cb8f5595fea1 (patch) | |
tree | fc93e7b7e83ead2adf1f53754b17cfe68cf072ae /core | |
parent | 0468ca9d7f0f01767ab0d3d4557ddac93b6b2c7e (diff) | |
download | frameworks_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.java | 29 | ||||
-rw-r--r-- | core/java/android/webkit/BrowserFrame.java | 19 | ||||
-rw-r--r-- | core/java/android/webkit/DnsResolver.java | 206 | ||||
-rw-r--r-- | core/java/android/webkit/WebView.java | 8 | ||||
-rw-r--r-- | core/java/android/webkit/WebViewCore.java | 13 |
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(); } //------------------------------------------------------------------------- |