Index: chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitTaskRunner.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitTaskRunner.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitTaskRunner.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4ad3136de67419162bb3d4829bf50359e985df02 |
--- /dev/null |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitTaskRunner.java |
@@ -0,0 +1,134 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.chrome.browser.init; |
+ |
+import android.os.AsyncTask; |
+ |
+import org.chromium.base.ContextUtils; |
+import org.chromium.base.ThreadUtils; |
+import org.chromium.base.VisibleForTesting; |
+import org.chromium.base.library_loader.LibraryLoader; |
+import org.chromium.base.library_loader.LibraryProcessType; |
+import org.chromium.base.library_loader.ProcessInitException; |
+import org.chromium.chrome.browser.ChromeVersionInfo; |
+import org.chromium.components.variations.firstrun.VariationsSeedFetcher; |
+import org.chromium.content.browser.ChildProcessLauncher; |
+ |
+import java.util.concurrent.Executor; |
+ |
+/** |
+ * Runs asynchronous startup task that need to be run before the native side is |
+ * started. Currently it runs two tasks: |
+ * - Native library loading |
+ * - Fetching the variations seed on first run |
+ */ |
+public abstract class AsyncInitTaskRunner { |
+ private boolean mFetchingVariations; |
+ private boolean mLibraryLoaded; |
+ |
+ private LoadTask mLoadTask; |
+ private FetchSeedTask mFetchSeedTask; |
+ |
+ @VisibleForTesting |
+ boolean shouldFetchVariationsSeedDuringFirstRun() { |
+ return ChromeVersionInfo.isOfficialBuild(); |
+ } |
+ |
+ private class LoadTask extends AsyncTask<Boolean, Void, Boolean> { |
+ @Override |
+ protected Boolean doInBackground(Boolean... allocateChildConnection) { |
+ try { |
+ LibraryLoader libraryLoader = LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER); |
+ libraryLoader.ensureInitialized(); |
+ // The prefetch is done after the library load for two reasons: |
+ // - It is easier to know the library location after it has |
+ // been loaded. |
+ // - Testing has shown that this gives the best compromise, |
+ // by avoiding performance regression on any tested |
+ // device, and providing performance improvement on |
+ // some. Doing it earlier delays UI inflation and more |
+ // generally startup on some devices, most likely by |
+ // competing for IO. |
+ // For experimental results, see http://crbug.com/460438. |
+ libraryLoader.asyncPrefetchLibrariesToMemory(); |
+ } catch (ProcessInitException e) { |
+ return false; |
+ } |
+ if (allocateChildConnection[0]) { |
+ ChildProcessLauncher.warmUp(ContextUtils.getApplicationContext()); |
+ } |
+ return true; |
+ } |
+ |
+ @Override |
+ protected void onPostExecute(Boolean result) { |
+ mLibraryLoaded = result; |
+ tasksPossiblyComplete(mLibraryLoaded); |
+ } |
+ } |
+ |
+ private class FetchSeedTask extends AsyncTask<Void, Void, Void> { |
+ @Override |
+ protected Void doInBackground(Void... params) { |
+ VariationsSeedFetcher.get().fetchSeed(); |
+ return null; |
+ } |
+ |
+ @Override |
+ protected void onPostExecute(Void result) { |
+ mFetchingVariations = false; |
+ tasksPossiblyComplete(true); |
+ } |
+ } |
+ |
+ /** |
+ * Starts the background tasks. |
+ * @param allocateChildConnection Whether a spare child connection should be allocated. Set to |
+ * false if you know that no new renderer is needed. |
+ * @param fetchVariationSeed Whether to initialize the variations seed, if it hasn't been |
+ * initialized in a previous run. |
+ */ |
+ public void startBackgroundTasks(boolean allocateChildConnection, boolean fetchVariationSeed) { |
+ ThreadUtils.assertOnUiThread(); |
+ assert mLoadTask == null; |
+ if (fetchVariationSeed && shouldFetchVariationsSeedDuringFirstRun()) { |
+ mFetchingVariations = true; |
+ mFetchSeedTask = new FetchSeedTask(); |
+ mFetchSeedTask.executeOnExecutor(getExecutor()); |
+ } |
+ |
+ mLoadTask = new LoadTask(); |
+ mLoadTask.executeOnExecutor(getExecutor(), allocateChildConnection); |
+ } |
+ |
+ private void tasksPossiblyComplete(boolean result) { |
+ ThreadUtils.assertOnUiThread(); |
+ |
+ if (!result) { |
+ mLoadTask.cancel(true); |
+ if (mFetchSeedTask != null) mFetchSeedTask.cancel(true); |
+ onFailure(); |
+ } |
+ |
+ if (mLibraryLoaded && !mFetchingVariations) { |
+ onSuccess(); |
+ } |
+ } |
+ |
+ @VisibleForTesting |
+ protected Executor getExecutor() { |
+ return AsyncTask.THREAD_POOL_EXECUTOR; |
+ } |
+ |
+ /** |
+ * Handle successful completion of the Async initialization tasks. |
+ */ |
+ protected abstract void onSuccess(); |
+ |
+ /** |
+ * Handle failed completion of the Async initialization tasks. |
+ */ |
+ protected abstract void onFailure(); |
+} |