Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(576)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java

Issue 2858893002: Move final part of initialization tasks to ProcessInitializationHandler (Closed)
Patch Set: Addressed comments Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
index 49d3da01c80fe65ded8e912c072588b4a1ea4cb0..dddd8efabf100115a00bf3734dd948efebc2d17d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -6,6 +6,10 @@ package org.chromium.chrome.browser.init;
import android.app.Activity;
import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+import android.os.SystemClock;
+import android.support.annotation.WorkerThread;
import android.view.View;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
@@ -17,18 +21,26 @@ import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.CommandLine;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
+import org.chromium.base.PowerMonitor;
import org.chromium.base.SysUtils;
import org.chromium.base.ThreadUtils;
+import org.chromium.base.TraceEvent;
+import org.chromium.base.annotations.SuppressFBWarnings;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.R;
+import org.chromium.chrome.browser.AfterStartupTaskUtils;
import org.chromium.chrome.browser.AppHooks;
import org.chromium.chrome.browser.ChromeActivitySessionTracker;
import org.chromium.chrome.browser.ChromeApplication;
import org.chromium.chrome.browser.ChromeBackupAgent;
import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.DefaultBrowserInfo;
import org.chromium.chrome.browser.DeferredStartupHandler;
import org.chromium.chrome.browser.DevToolsServer;
import org.chromium.chrome.browser.banners.AppBannerManager;
+import org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetProvider;
+import org.chromium.chrome.browser.crash.LogcatExtractionRunnable;
+import org.chromium.chrome.browser.crash.MinidumpUploadService;
import org.chromium.chrome.browser.download.DownloadController;
import org.chromium.chrome.browser.download.DownloadManagerService;
import org.chromium.chrome.browser.firstrun.ForcedSigninProcessor;
@@ -37,16 +49,31 @@ import org.chromium.chrome.browser.identity.UuidBasedUniqueIdentificationGenerat
import org.chromium.chrome.browser.invalidation.UniqueIdInvalidationClientNameGenerator;
import org.chromium.chrome.browser.locale.LocaleManager;
import org.chromium.chrome.browser.media.MediaCaptureNotificationService;
+import org.chromium.chrome.browser.metrics.LaunchMetrics;
+import org.chromium.chrome.browser.metrics.UmaUtils;
import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
+import org.chromium.chrome.browser.notifications.ChannelsUpdater;
+import org.chromium.chrome.browser.ntp.NewTabPage;
+import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
+import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmarksShim;
+import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
+import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomizations;
import org.chromium.chrome.browser.photo_picker.PhotoPickerDialog;
import org.chromium.chrome.browser.physicalweb.PhysicalWeb;
+import org.chromium.chrome.browser.precache.PrecacheLauncher;
+import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
import org.chromium.chrome.browser.preferences.PrefServiceBridge;
import org.chromium.chrome.browser.rlz.RevenueStats;
import org.chromium.chrome.browser.searchwidget.SearchWidgetProvider;
import org.chromium.chrome.browser.services.AccountsChangedReceiver;
import org.chromium.chrome.browser.services.GoogleServicesManager;
+import org.chromium.chrome.browser.share.ShareHelper;
import org.chromium.chrome.browser.sync.SyncController;
+import org.chromium.chrome.browser.webapps.ChromeWebApkHost;
+import org.chromium.chrome.browser.webapps.WebApkVersionManager;
+import org.chromium.chrome.browser.webapps.WebappRegistry;
+import org.chromium.components.minidump_uploader.CrashFileManager;
import org.chromium.components.signin.AccountManagerHelper;
import org.chromium.content.browser.ChildProcessLauncher;
import org.chromium.content.common.ContentSwitches;
@@ -56,9 +83,13 @@ import org.chromium.printing.PrintingControllerImpl;
import org.chromium.ui.PhotoPickerListener;
import org.chromium.ui.UiUtils;
+import java.io.File;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
import java.util.List;
import java.util.Locale;
+import java.util.concurrent.TimeUnit;
/**
* Handles the initialization dependences of the browser process. This is meant to handle the
@@ -66,10 +97,16 @@ import java.util.Locale;
* triggered a single time for the lifetime of the browser process.
*/
public class ProcessInitializationHandler {
+ private static final String TAG = "ProcessInitHandler";
private static final String SESSIONS_UUID_PREF_KEY = "chromium.sync.sessions.id";
private static final String DEV_TOOLS_SERVER_SOCKET_PREFIX = "chrome";
+ /** Prevents race conditions when deleting snapshot database. */
+ private static final Object SNAPSHOT_DATABASE_LOCK = new Object();
+ private static final String SNAPSHOT_DATABASE_REMOVED = "snapshot_database_removed";
+ private static final String SNAPSHOT_DATABASE_NAME = "snapshots.db";
+
private static ProcessInitializationHandler sInstance;
private boolean mInitializedPreNative;
@@ -80,6 +117,7 @@ public class ProcessInitializationHandler {
/**
* @return The ProcessInitializationHandler for use during the lifetime of the browser process.
*/
+ @SuppressFBWarnings("LI_LAZY_INIT_STATIC")
public static ProcessInitializationHandler getInstance() {
ThreadUtils.checkUiThread();
if (sInstance == null) {
@@ -199,14 +237,24 @@ public class ProcessInitializationHandler {
}
/**
- * Initializes the deferred startup tasks that should only be triggered once per browser process
- * lifetime.
+ * Handle application level deferred startup tasks that can be lazily done after all
+ * the necessary initialization has been completed. Should only be triggered once per browser
+ * process lifetime. Any calls requiring network access should probably go here.
+ *
+ * Keep these tasks short and break up long tasks into multiple smaller tasks, as they run on
+ * the UI thread and are blocking. Remember to follow RAIL guidelines, as much as possible, and
+ * that most devices are quite slow, so leave enough buffer.
*/
public final void initializeDeferredStartupTasks() {
ThreadUtils.checkUiThread();
if (mInitializedDeferredStartupTasks) return;
- handleDeferredStartupTasksInitialization();
mInitializedDeferredStartupTasks = true;
+
+ RecordHistogram.recordLongTimesHistogram("UMA.Debug.EnableCrashUpload.DeferredStartUptime2",
+ SystemClock.uptimeMillis() - UmaUtils.getForegroundStartTime(),
+ TimeUnit.MILLISECONDS);
+
+ handleDeferredStartupTasksInitialization();
}
/**
@@ -220,6 +268,40 @@ public class ProcessInitializationHandler {
deferredStartupHandler.addDeferredTask(new Runnable() {
@Override
public void run() {
+ // Punt all tasks that may block on disk off onto a background thread.
+ initAsyncDiskTask(application);
+
+ DefaultBrowserInfo.initBrowserFetcher();
+
+ AfterStartupTaskUtils.setStartupComplete();
+
+ PartnerBrowserCustomizations.setOnInitializeAsyncFinished(new Runnable() {
+ @Override
+ public void run() {
+ String homepageUrl = HomepageManager.getHomepageUri(application);
+ LaunchMetrics.recordHomePageLaunchMetrics(
+ HomepageManager.isHomepageEnabled(application),
+ NewTabPage.isNTPUrl(homepageUrl), homepageUrl);
+ }
+ });
+
+ PartnerBookmarksShim.kickOffReading(application);
+
+ PowerMonitor.create();
+
+ ShareHelper.clearSharedImages();
+
+ OfflinePageUtils.clearSharedOfflineFiles(application);
+
+ if (ChannelsUpdater.getInstance().shouldUpdateChannels()) {
+ initChannelsAsync();
+ }
+ }
+ });
+
+ deferredStartupHandler.addDeferredTask(new Runnable() {
+ @Override
+ public void run() {
// Clear any media notifications that existed when Chrome was last killed.
MediaCaptureNotificationService.clearMediaNotifications(application);
@@ -316,6 +398,189 @@ public class ProcessInitializationHandler {
});
}
+ private void initChannelsAsync() {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ ChannelsUpdater.getInstance().updateChannels();
+ return null;
+ }
+ }
+ .executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
+ }
+
+ private void initAsyncDiskTask(final Context context) {
+ new AsyncTask<Void, Void, Void>() {
+ /**
+ * The threshold after which it's no longer appropriate to try to attach logcat output
+ * to a minidump file.
+ * Note: This threshold of 12 hours was chosen fairly imprecisely, based on the
+ * following intuition: On the one hand, Chrome can only access its own logcat output,
+ * so the most recent lines should be relevant when available. On a typical device,
+ * multiple hours of logcat output are available. On the other hand, it's important to
+ * provide an escape hatch in case the logcat extraction code itself crashes, as
+ * described in the doesCrashMinidumpNeedLogcat() documentation. Since this is a fairly
+ * small and relatively frequently-executed piece of code, crashes are expected to be
+ * unlikely; so it's okay for the escape hatch to be hard to use -- it's intended as an
+ * extreme last resort.
+ */
+ private static final long LOGCAT_RELEVANCE_THRESHOLD_IN_HOURS = 12;
+
+ private long mAsyncTaskStartTime;
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ try {
+ TraceEvent.begin("ChromeBrowserInitializer.onDeferredStartup.doInBackground");
+ mAsyncTaskStartTime = SystemClock.uptimeMillis();
+
+ initCrashReporting();
+
+ // Initialize the WebappRegistry if it's not already initialized. Must be in
+ // async task due to shared preferences disk access on N.
+ WebappRegistry.getInstance();
+
+ // Force a widget refresh in order to wake up any possible zombie widgets.
+ // This is needed to ensure the right behavior when the process is suddenly
+ // killed.
+ BookmarkWidgetProvider.refreshAllWidgets(context);
+
+ // Initialize whether or not precaching is enabled.
+ PrecacheLauncher.updatePrecachingEnabled(context);
+
+ if (ChromeWebApkHost.isEnabled()) {
+ WebApkVersionManager.updateWebApksIfNeeded();
+ }
+
+ removeSnapshotDatabase(context);
+
+ // Warm up all web app shared prefs. This must be run after the WebappRegistry
+ // instance is initialized.
+ WebappRegistry.warmUpSharedPrefs();
+
+ return null;
+ } finally {
+ TraceEvent.end("ChromeBrowserInitializer.onDeferredStartup.doInBackground");
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Void params) {
+ // Must be run on the UI thread after the WebappRegistry has been completely warmed.
+ WebappRegistry.getInstance().unregisterOldWebapps(System.currentTimeMillis());
+
+ RecordHistogram.recordLongTimesHistogram(
+ "UMA.Debug.EnableCrashUpload.DeferredStartUpAsyncTaskDuration",
+ SystemClock.uptimeMillis() - mAsyncTaskStartTime, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Initializes the crash reporting system. More specifically, enables the crash
+ * reporting system if it is user-permitted, and initiates uploading of any pending
+ * crash reports. Also updates some UMA metrics and performs cleanup in the local crash
+ * minidump storage directory.
+ */
+ private void initCrashReporting() {
+ RecordHistogram.recordLongTimesHistogram("UMA.Debug.EnableCrashUpload.Uptime3",
+ mAsyncTaskStartTime - UmaUtils.getForegroundStartTime(),
+ TimeUnit.MILLISECONDS);
+
+ // Crash reports can be uploaded as part of a background service even while the main
+ // Chrome activity is not running, and hence regular metrics reporting is not
+ // possible. Instead, metrics are temporarily written to prefs; export those prefs
+ // to UMA metrics here.
+ MinidumpUploadService.storeBreakpadUploadStatsInUma(
+ ChromePreferenceManager.getInstance());
+
+ // Likewise, this is a good time to process and clean up any pending or stale crash
+ // reports left behind by previous runs.
+ CrashFileManager crashFileManager =
+ new CrashFileManager(ContextUtils.getApplicationContext().getCacheDir());
+ crashFileManager.cleanOutAllNonFreshMinidumpFiles();
+
+ // Finally, uploading any pending crash reports.
+ File[] minidumps = crashFileManager.getAllMinidumpFiles(
+ MinidumpUploadService.MAX_TRIES_ALLOWED);
+ int numMinidumpsSansLogcat = 0;
+ for (File minidump : minidumps) {
+ if (CrashFileManager.isMinidumpMIMEFirstTry(minidump.getName())) {
+ ++numMinidumpsSansLogcat;
+ }
+ }
+ // TODO(isherman): These two histograms are intended to be temporary, and can
+ // probably be removed around the M60 timeframe: http://crbug.com/699785
+ RecordHistogram.recordSparseSlowlyHistogram(
+ "Stability.Android.PendingMinidumpsOnStartup", minidumps.length);
+ RecordHistogram.recordSparseSlowlyHistogram(
+ "Stability.Android.PendingMinidumpsOnStartup.SansLogcat",
+ numMinidumpsSansLogcat);
+ if (minidumps.length == 0) return;
+
+ Log.i(TAG, "Attempting to upload %d accumulated crash dumps.", minidumps.length);
+ File mostRecentMinidump = minidumps[0];
+ if (doesCrashMinidumpNeedLogcat(mostRecentMinidump)) {
+ AsyncTask.THREAD_POOL_EXECUTOR.execute(
+ new LogcatExtractionRunnable(mostRecentMinidump));
+
+ // The JobScheduler will schedule uploads for all of the available minidumps
+ // once the logcat is attached. But if the JobScheduler API is not being used,
+ // then the logcat extraction process will only initiate an upload for the first
+ // minidump; it's required to manually initiate uploads for all of the remaining
+ // minidumps.
+ if (!MinidumpUploadService.shouldUseJobSchedulerForUploads()) {
+ List<File> remainingMinidumps =
+ Arrays.asList(minidumps).subList(1, minidumps.length);
+ for (File minidump : remainingMinidumps) {
+ MinidumpUploadService.tryUploadCrashDump(minidump);
+ }
+ }
+ } else if (MinidumpUploadService.shouldUseJobSchedulerForUploads()) {
+ MinidumpUploadService.scheduleUploadJob();
+ } else {
+ MinidumpUploadService.tryUploadAllCrashDumps();
+ }
+ }
+
+ /**
+ * Returns whether or not it's appropriate to try to extract recent logcat output and
+ * include that logcat output alongside the given {@param minidump} in a crash report.
+ * Logcat output should only be extracted if (a) it hasn't already been extracted for
+ * this minidump file, and (b) the minidump is fairly fresh. The freshness check is
+ * important for two reasons: (1) First of all, it helps avoid including irrelevant
+ * logcat output for a crash report. (2) Secondly, it provides an escape hatch that can
+ * help circumvent a possible infinite crash loop, if the code responsible for
+ * extracting and appending the logcat content is itself crashing. That is, the user can
+ * wait 12 hours prior to relaunching Chrome, at which point this potential crash loop
+ * would be circumvented.
+ * @return Whether to try to include logcat output in the crash report corresponding to
+ * the given minidump.
+ */
+ private boolean doesCrashMinidumpNeedLogcat(File minidump) {
+ if (!CrashFileManager.isMinidumpMIMEFirstTry(minidump.getName())) return false;
+
+ long ageInMillis = new Date().getTime() - minidump.lastModified();
+ long ageInHours = TimeUnit.HOURS.convert(ageInMillis, TimeUnit.MILLISECONDS);
+ return ageInHours < LOGCAT_RELEVANCE_THRESHOLD_IN_HOURS;
+ }
+ }
+ .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ /**
+ * Deletes the snapshot database which is no longer used because the feature has been removed
+ * in Chrome M41.
+ */
+ @WorkerThread
+ private void removeSnapshotDatabase(Context context) {
+ synchronized (SNAPSHOT_DATABASE_LOCK) {
+ SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
+ if (!prefs.getBoolean(SNAPSHOT_DATABASE_REMOVED, false)) {
+ context.deleteDatabase(SNAPSHOT_DATABASE_NAME);
+ prefs.edit().putBoolean(SNAPSHOT_DATABASE_REMOVED, true).apply();
+ }
+ }
+ }
+
private void startModerateBindingManagementIfNeeded(Context context) {
// Moderate binding doesn't apply to low end devices.
if (SysUtils.isLowEndDevice()) return;
« no previous file with comments | « chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698