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

Unified Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 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
Index: chrome/android/java_staging/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c0a17a11c3ff7830b2b17d86c8571969801961a
--- /dev/null
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
@@ -0,0 +1,265 @@
+// Copyright 2015 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.crash;
+
+import android.app.IntentService;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
+import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager;
+
+import java.io.File;
+
+/**
+ * Service that is responsible for uploading crash minidumps to the Google crash server.
+ */
+public class MinidumpUploadService extends IntentService {
+
+ private static final String TAG = "MinidumpUploadService";
+
+ // Intent actions
+ private static final String ACTION_FIND_LAST =
+ "com.google.android.apps.chrome.crash.ACTION_FIND_LAST";
+ @VisibleForTesting
+ static final String ACTION_FIND_ALL =
+ "com.google.android.apps.chrome.crash.ACTION_FIND_ALL";
+ @VisibleForTesting
+ static final String ACTION_UPLOAD =
+ "com.google.android.apps.chrome.crash.ACTION_UPLOAD";
+
+ // Intent bundle keys
+ @VisibleForTesting
+ static final String FILE_TO_UPLOAD_KEY = "minidump_file";
+ static final String UPLOAD_LOG_KEY = "upload_log";
+
+ /**
+ * The number of times we will try to upload a crash.
+ */
+ @VisibleForTesting
+ static final int MAX_TRIES_ALLOWED = 3;
+
+ public MinidumpUploadService() {
+ super(TAG);
+ setIntentRedelivery(true);
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ if (isMiniDumpCleanNeeded()) {
+ final CrashFileManager crashFileManager =
+ new CrashFileManager(getApplicationContext().getCacheDir());
+ // Cleaning minidumps in a background not to block the Ui thread.
+ // NOTE: {@link CrashFileManager#cleanAllMiniDumps()} is not thread-safe and can
+ // possibly result in race condition by calling from multiple threads. However, this
+ // should only result in warning messages in logs.
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ crashFileManager.cleanAllMiniDumps();
+ return null;
+ }
+ }.execute();
+ }
+ }
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+ if (intent == null) return;
+ if (ACTION_FIND_LAST.equals(intent.getAction())) {
+ handleFindAndUploadLastCrash(intent);
+ } else if (ACTION_FIND_ALL.equals(intent.getAction())) {
+ handleFindAndUploadAllCrashes();
+ } else if (ACTION_UPLOAD.equals(intent.getAction())) {
+ handleUploadCrash(intent);
+ } else {
+ Log.w(TAG, "Got unknown action from intent: " + intent.getAction());
+ }
+ }
+
+ /**
+ * Creates an intent that when started will find the last created minidump,
+ * and try to upload it.
+ *
+ * @param context the context to use for the intent.
+ * @return an Intent to use to start the service.
+ */
+ public static Intent createFindAndUploadLastCrashIntent(Context context) {
+ Intent intent = new Intent(context, MinidumpUploadService.class);
+ intent.setAction(ACTION_FIND_LAST);
+ return intent;
+ }
+
+ public static void storeBreakpadUploadAttemptsInUma(ChromePreferenceManager pref) {
+ for (int success = pref.getBreakpadUploadSuccessCount(); success > 0; success--) {
+ RecordUserAction.record("MobileBreakpadUploadSuccess");
+ }
+
+ for (int fail = pref.getBreakpadUploadFailCount(); fail > 0; fail--) {
+ RecordUserAction.record("MobileBreakpadUploadFail");
+ }
+
+ pref.setBreakpadUploadSuccessCount(0);
+ pref.setBreakpadUploadFailCount(0);
+ }
+
+ private void handleFindAndUploadLastCrash(Intent intent) {
+ CrashFileManager fileManager = new CrashFileManager(getApplicationContext().getCacheDir());
+ File[] minidumpFiles = fileManager.getAllMinidumpFilesSorted();
+ if (minidumpFiles.length == 0) {
+ // Try again later. Maybe the minidump hasn't finished being written.
+ Log.d(TAG, "Could not find any crash dumps to upload");
+ return;
+ }
+ File minidumpFile = minidumpFiles[0];
+ File logfile = fileManager.getCrashUploadLogFile();
+ Intent uploadIntent = createUploadIntent(getApplicationContext(), minidumpFile, logfile);
+ startService(uploadIntent);
+ }
+
+ /**
+ * Creates an intent that when started will find all minidumps, and try to upload them.
+ *
+ * @param context the context to use for the intent.
+ * @return an Intent to use to start the service.
+ */
+ @VisibleForTesting
+ static Intent createFindAndUploadAllCrashesIntent(Context context) {
+ Intent intent = new Intent(context, MinidumpUploadService.class);
+ intent.setAction(ACTION_FIND_ALL);
+ return intent;
+ }
+
+ private void handleFindAndUploadAllCrashes() {
+ CrashFileManager fileManager = new CrashFileManager(getApplicationContext().getCacheDir());
+ File[] minidumps = fileManager.getAllMinidumpFiles();
+ File logfile = fileManager.getCrashUploadLogFile();
+ Log.i(TAG, "Attempting to upload accumulated crash dumps.");
+ for (File minidump : minidumps) {
+ Intent uploadIntent = createUploadIntent(getApplicationContext(), minidump, logfile);
+ startService(uploadIntent);
+ }
+ }
+
+ /**
+ * Creates an intent that when started will find all minidumps, and try to upload them.
+ *
+ * @param minidumpFile the minidump file to upload.
+ * @return an Intent to use to start the service.
+ */
+ @VisibleForTesting
+ public static Intent createUploadIntent(Context context, File minidumpFile, File logfile) {
+ Intent intent = new Intent(context, MinidumpUploadService.class);
+ intent.setAction(ACTION_UPLOAD);
+ intent.putExtra(FILE_TO_UPLOAD_KEY, minidumpFile.getAbsolutePath());
+ intent.putExtra(UPLOAD_LOG_KEY, logfile.getAbsolutePath());
+ return intent;
+ }
+
+ private void handleUploadCrash(Intent intent) {
+ String minidumpFileName = intent.getStringExtra(FILE_TO_UPLOAD_KEY);
+ if (minidumpFileName == null || minidumpFileName.isEmpty()) {
+ Log.w(TAG, "Cannot upload crash data since minidump is absent.");
+ return;
+ }
+ File minidumpFile = new File(minidumpFileName);
+ if (!minidumpFile.isFile()) {
+ Log.w(TAG, "Cannot upload crash data since specified minidump "
+ + minidumpFileName + "is not present.");
+ return;
+ }
+ int tries = CrashFileManager.readAttemptNumber(minidumpFileName);
+ if (tries == -1 || tries >= MAX_TRIES_ALLOWED) {
+ ChromePreferenceManager.getInstance(this).incrementBreakpadUploadFailCount();
+ Log.d(TAG, "Giving up on trying to upload " + minidumpFileName + " after "
+ + tries + " attempts");
+ return;
+ }
+
+ String logfileName = intent.getStringExtra(UPLOAD_LOG_KEY);
+ File logfile = new File(logfileName);
+
+ // Try to upload minidump
+ MinidumpUploadCallable minidumpUploadCallable =
+ createMinidumpUploadCallable(minidumpFile, logfile);
+ boolean success = minidumpUploadCallable.call();
+
+ if (success) {
+ ChromePreferenceManager.getInstance(this).incrementBreakpadUploadSuccessCount();
+ } else {
+ // Unable to upload minidump. Incrementing try number and restarting.
+
+ // Only create another attempt if we have successfully renamed
+ // the file.
+ String newName = CrashFileManager.tryIncrementAttemptNumber(minidumpFile);
+ tries++;
+ if (newName != null && tries < MAX_TRIES_ALLOWED) {
+ // TODO(nyquist): Do this as an exponential backoff.
+ MinidumpUploadRetry.scheduleRetry(getApplicationContext());
+ } else {
+ Log.w(TAG, "Failed to rename minidump " + minidumpFileName);
+ }
+ }
+ }
+
+ /**
+ * Factory method for creating minidump callables.
+ *
+ * This may be overridden for tests.
+ *
+ * @param minidumpFile the File to upload.
+ * @param logfile the Log file to write to upon successful uploads.
+ * @return a new MinidumpUploadCallable.
+ */
+ @VisibleForTesting
+ MinidumpUploadCallable createMinidumpUploadCallable(File minidumpFile, File logfile) {
+ return new MinidumpUploadCallable(minidumpFile, logfile, getApplicationContext());
+ }
+
+ /**
+ * Attempts to upload all minidump files using the given {@link android.content.Context}.
+ *
+ * Note that this method is asynchronous. All that is guaranteed is that
+ * upload attempts will be enqueued.
+ *
+ * This method is safe to call from the UI thread.
+ *
+ * @param context Context of the application.
+ */
+ public static void tryUploadAllCrashDumps(Context context) {
+ Intent findAndUploadAllCrashesIntent = createFindAndUploadAllCrashesIntent(context);
+ context.startService(findAndUploadAllCrashesIntent);
+ }
+
+ /**
+ * Checks whether it is the first time restrictions for cellular uploads should apply. Is used
+ * to determine whether unsent crash uploads should be deleted which should happen only once.
+ */
+ @VisibleForTesting
+ protected boolean isMiniDumpCleanNeeded() {
+ SharedPreferences sharedPreferences =
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+
+ // If cellular upload logic is enabled and the preference used for that is not initialized
+ // then this is the first time that logic is enabled.
+ boolean cleanNeeded =
+ !sharedPreferences.contains(MinidumpUploadCallable.PREF_LAST_UPLOAD_DAY)
+ && PrivacyPreferencesManager.getInstance(getApplicationContext()).isUploadLimited();
+
+ // Initialize the preference with default value to make sure the above check works only
+ // once.
+ if (cleanNeeded) {
+ sharedPreferences.edit().putInt(MinidumpUploadCallable.PREF_LAST_UPLOAD_DAY, 0).apply();
+ }
+ return cleanNeeded;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698