Index: chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java |
index 3f2b7a7f81f29d873404fa0a96f9b706fd882b68..72d8813637b4e181b19047e8ef6e9fc5e5bebbf8 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java |
@@ -27,6 +27,7 @@ import android.view.WindowManager; |
import org.chromium.base.FieldTrialList; |
import org.chromium.base.Log; |
+import org.chromium.base.SysUtils; |
import org.chromium.base.ThreadUtils; |
import org.chromium.base.VisibleForTesting; |
import org.chromium.base.annotations.SuppressFBWarnings; |
@@ -128,37 +129,55 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
return mClientManager.newSession(callback, Binder.getCallingUid(), onDisconnect); |
} |
+ /** Warmup activities that should only happen once. */ |
+ @SuppressFBWarnings("DM_EXIT") |
+ private static void initializeBrowser(final ChromeApplication app) { |
+ ThreadUtils.assertOnUiThread(); |
+ try { |
+ app.startBrowserProcessesAndLoadLibrariesSync(true); |
+ } catch (ProcessInitException e) { |
+ Log.e(TAG, "ProcessInitException while starting the browser process."); |
+ // Cannot do anything without the native library, and cannot show a |
+ // dialog to the user. |
+ System.exit(-1); |
+ } |
+ final Context context = app.getApplicationContext(); |
+ new AsyncTask<Void, Void, Void>() { |
+ @Override |
+ protected Void doInBackground(Void... params) { |
+ ChildProcessLauncher.warmUp(context); |
+ return null; |
+ } |
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
+ ChromeBrowserInitializer.initNetworkChangeNotifier(context); |
+ WarmupManager.getInstance().initializeViewHierarchy( |
+ context, R.layout.custom_tabs_control_container); |
+ } |
+ |
@Override |
public boolean warmup(long flags) { |
+ return warmup(true); |
+ } |
+ |
+ /** |
+ * Starts as much as possible in anticipation of a future navigation. |
+ * |
+ * @param mayCreatesparewebcontents true if warmup() can create a spare renderer. |
+ * @return true for success. |
+ */ |
+ private boolean warmup(final boolean mayCreateSpareWebContents) { |
// Here and in mayLaunchUrl(), don't do expensive work for background applications. |
if (!isCallerForegroundOrSelf()) return false; |
mClientManager.recordUidHasCalledWarmup(Binder.getCallingUid()); |
- if (!mWarmupHasBeenCalled.compareAndSet(false, true)) return true; |
+ final boolean initialized = !mWarmupHasBeenCalled.compareAndSet(false, true); |
// The call is non-blocking and this must execute on the UI thread, post a task. |
ThreadUtils.postOnUiThread(new Runnable() { |
@Override |
- @SuppressFBWarnings("DM_EXIT") |
public void run() { |
- ChromeApplication app = (ChromeApplication) mApplication; |
- try { |
- app.startBrowserProcessesAndLoadLibrariesSync(true); |
- } catch (ProcessInitException e) { |
- Log.e(TAG, "ProcessInitException while starting the browser process."); |
- // Cannot do anything without the native library, and cannot show a |
- // dialog to the user. |
- System.exit(-1); |
+ if (!initialized) initializeBrowser((ChromeApplication) mApplication); |
+ if (mayCreateSpareWebContents && mPrerender == null && !SysUtils.isLowEndDevice()) { |
+ createSpareWebContents(); |
} |
- final Context context = app.getApplicationContext(); |
- new AsyncTask<Void, Void, Void>() { |
- @Override |
- protected Void doInBackground(Void... params) { |
- ChildProcessLauncher.warmUp(context); |
- return null; |
- } |
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
- ChromeBrowserInitializer.initNetworkChangeNotifier(context); |
- WarmupManager.getInstance().initializeViewHierarchy(app.getApplicationContext(), |
- R.layout.custom_tabs_control_container); |
} |
}); |
return true; |
@@ -190,7 +209,11 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
String scheme = url.normalizeScheme().getScheme(); |
if (scheme != null && !scheme.equals("http") && !scheme.equals("https")) return false; |
// Things below need the browser process to be initialized. |
- if (!warmup(0)) return false; // Also does the foreground check. |
+ |
+ // Forbids warmup() from creating a spare renderer, as prerendering wouldn't reuse |
+ // it. Checking whether prerendering is enabled requires the native library to be loaded, |
+ // which is not necessarily the case yet. |
+ if (!warmup(false)) return false; // Also does the foreground check. |
final IBinder session = callback.asBinder(); |
final String urlString = url.toString(); |
@@ -243,6 +266,12 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
return result; |
} |
+ private void destroySpareWebContents() { |
+ ThreadUtils.assertOnUiThread(); |
+ WebContents webContents = takeSpareWebContents(); |
+ if (webContents != null) webContents.destroy(); |
+ } |
+ |
@Override |
public boolean updateVisuals(final ICustomTabsCallback callback, Bundle bundle) { |
final Bundle actionButtonBundle = IntentUtils.safeGetBundle(bundle, |
@@ -481,6 +510,10 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
cancelPrerender(null); |
if (TextUtils.isEmpty(url)) return; |
if (!mClientManager.isPrerenderingAllowed(uid)) return; |
+ |
+ // A prerender will be requested. Time to destroy the spare WebContents. |
+ destroySpareWebContents(); |
+ |
Intent extrasIntent = new Intent(); |
if (extras != null) extrasIntent.putExtras(extras); |
if (IntentHandler.getExtraHeadersFromIntent(extrasIntent) != null) return; |