Index: chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java |
index 148b8a6097a18854e69ec18e84ee524609ea4d42..48314e0f91a0a366292da6e5adec70099123ee07 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java |
@@ -4,9 +4,14 @@ |
package org.chromium.chrome.browser.crash; |
+import android.annotation.SuppressLint; |
import android.app.IntentService; |
+import android.app.job.JobInfo; |
+import android.content.ComponentName; |
import android.content.Context; |
import android.content.Intent; |
+import android.os.Build; |
+import android.os.PersistableBundle; |
import android.support.annotation.StringDef; |
import org.chromium.base.Log; |
@@ -14,10 +19,13 @@ import org.chromium.base.StreamUtil; |
import org.chromium.base.VisibleForTesting; |
import org.chromium.base.annotations.CalledByNative; |
import org.chromium.base.metrics.RecordHistogram; |
+import org.chromium.chrome.browser.ChromeFeatureList; |
import org.chromium.chrome.browser.preferences.ChromePreferenceManager; |
import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager; |
+import org.chromium.components.background_task_scheduler.TaskIds; |
import org.chromium.components.minidump_uploader.CrashFileManager; |
import org.chromium.components.minidump_uploader.MinidumpUploadCallable; |
+import org.chromium.components.minidump_uploader.MinidumpUploadJobService; |
import org.chromium.components.minidump_uploader.util.CrashReportingPermissionManager; |
import java.io.BufferedReader; |
@@ -68,6 +76,45 @@ public class MinidumpUploadService extends IntentService { |
} |
/** |
+ * @return Whether to use the JobSchduler API to upload crash reports, rather than directly |
+ * creating a service for uploading. |
+ */ |
+ public static boolean shouldUseJobSchedulerForUploads() { |
+ // The JobScheduler API is only available as of Android L. |
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return false; |
+ |
+ return ChromeFeatureList.isEnabled( |
+ ChromeFeatureList.UPLOAD_CRASH_REPORTS_USING_JOB_SCHEDULER); |
+ } |
+ |
+ /** |
+ * Schedules uploading of all pending minidumps, using the JobScheduler API. |
+ */ |
+ @SuppressLint("NewApi") |
+ public static void scheduleUploadJob(Context context) { |
+ assert shouldUseJobSchedulerForUploads(); |
+ |
+ CrashReportingPermissionManager permissionManager = PrivacyPreferencesManager.getInstance(); |
+ PersistableBundle permissions = new PersistableBundle(); |
+ // Note: putBoolean is only available in API level 22, so massage the data into ints |
+ // instead. |
+ permissions.putInt(ChromeMinidumpUploaderDelegate.IS_CLIENT_IN_METRICS_SAMPLE, |
+ permissionManager.isClientInMetricsSample() ? 1 : 0); |
+ permissions.putInt(ChromeMinidumpUploaderDelegate.IS_CRASH_UPLOAD_DISABLED_BY_COMMAND_LINE, |
+ permissionManager.isCrashUploadDisabledByCommandLine() ? 1 : 0); |
+ permissions.putInt(ChromeMinidumpUploaderDelegate.IS_UPLOAD_ENABLED_FOR_TESTS, |
+ permissionManager.isUploadEnabledForTests() ? 1 : 0); |
+ |
+ JobInfo.Builder builder = |
+ new JobInfo |
+ .Builder(TaskIds.CHROME_MINIDUMP_UPLOADING_JOB_ID, |
+ new ComponentName(context, ChromeMinidumpUploadJobService.class)) |
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) |
+ .setExtras(permissions); |
+ MinidumpUploadJobService.scheduleUpload(context, builder); |
+ } |
+ |
+ /** |
* Stores the successes and failures from uploading crash to UMA, |
*/ |
public static void storeBreakpadUploadStatsInUma(ChromePreferenceManager pref) { |
@@ -106,10 +153,6 @@ public class MinidumpUploadService extends IntentService { |
return; |
} |
int tries = CrashFileManager.readAttemptNumber(minidumpFileName); |
- // -1 means no attempt number was read. |
- if (tries == -1) { |
- tries = 0; |
- } |
// Since we do not rename a file after reaching max number of tries, |
// files that have maxed out tries will NOT reach this. |
@@ -132,21 +175,23 @@ public class MinidumpUploadService extends IntentService { |
if (uploadStatus == MinidumpUploadCallable.UPLOAD_SUCCESS) { |
// Only update UMA stats if an intended and successful upload. |
- incrementCrashSuccessUploadCount(getNewNameAfterSuccessfulUpload(minidumpFileName)); |
+ incrementCrashSuccessUploadCount(minidumpFileName); |
} else if (uploadStatus == MinidumpUploadCallable.UPLOAD_FAILURE) { |
// Unable to upload minidump. Incrementing try number and restarting. |
+ ++tries; |
+ if (tries == MAX_TRIES_ALLOWED) { |
+ // Only record failure to UMA after we have maxed out the allotted tries. |
+ incrementCrashFailureUploadCount(minidumpFileName); |
+ } |
- // Only create another attempt if we have successfully renamed |
- // the file. |
+ // Only create another attempt if we have successfully renamed the file. |
String newName = CrashFileManager.tryIncrementAttemptNumber(minidumpFile); |
if (newName != null) { |
- if (++tries < MAX_TRIES_ALLOWED) { |
+ if (tries < MAX_TRIES_ALLOWED) { |
// TODO(nyquist): Do this as an exponential backoff. |
MinidumpUploadRetry.scheduleRetry( |
getApplicationContext(), getCrashReportingPermissionManager()); |
} else { |
- // Only record failure to UMA after we have maxed out the allotted tries. |
- incrementCrashFailureUploadCount(newName); |
Log.d(TAG, "Giving up on trying to upload " + minidumpFileName + "after " |
+ tries + " number of tries."); |
} |
@@ -208,18 +253,30 @@ public class MinidumpUploadService extends IntentService { |
} |
/** |
- * Increment the count of success/failure by 1 and distinguish between different types of |
- * crashes by looking into the file. |
- * @param fileName is the name of a minidump file that contains the type of crash. |
+ * Increments the count of successful uploads by 1. Distinguishes between different types of |
+ * crashes by looking into the file contents. Because this code can execute in a context when |
+ * the main Chrome activity is no longer running, the counts are stored in shared preferences; |
+ * they are later read and recorded as metrics by the main Chrome activity. |
+ * NOTE: This method should be called *after* renaming the file, since renaming occurs as a |
+ * side-effect of a successful upload. |
+ * @param originalFilename The name of the successfully uploaded minidump, *prior* to uploading. |
*/ |
- private void incrementCrashSuccessUploadCount(String fileName) { |
+ public static void incrementCrashSuccessUploadCount(String originalFilename) { |
ChromePreferenceManager.getInstance().incrementCrashSuccessUploadCount( |
- getCrashType(fileName)); |
+ getCrashType(getNewNameAfterSuccessfulUpload(originalFilename))); |
} |
- private void incrementCrashFailureUploadCount(String fileName) { |
+ /** |
+ * Increments the count of failed uploads by 1. Distinguishes between different types of crashes |
+ * by looking into the file contents. Because this code can execute in a context when the main |
+ * Chrome activity is no longer running, the counts are stored in shared preferences; they are |
+ * later read and recorded as metrics by the main Chrome activity. |
+ * NOTE: This method should be called *prior* to renaming the file. |
+ * @param originalFilename The name of the successfully uploaded minidump, *prior* to uploading. |
+ */ |
+ public static void incrementCrashFailureUploadCount(String originalFilename) { |
ChromePreferenceManager.getInstance().incrementCrashFailureUploadCount( |
- getCrashType(fileName)); |
+ getCrashType(originalFilename)); |
} |
/** |
@@ -249,6 +306,7 @@ public class MinidumpUploadService extends IntentService { |
*/ |
public static void tryUploadCrashDump(Context context, File minidumpFile) |
throws SecurityException { |
+ assert !shouldUseJobSchedulerForUploads(); |
CrashFileManager fileManager = new CrashFileManager(context.getCacheDir()); |
Intent intent = new Intent(context, MinidumpUploadService.class); |
intent.setAction(ACTION_UPLOAD); |
@@ -268,11 +326,12 @@ public class MinidumpUploadService extends IntentService { |
* @param context Context of the application. |
*/ |
public static void tryUploadAllCrashDumps(Context context) { |
+ assert !shouldUseJobSchedulerForUploads(); |
CrashFileManager fileManager = new CrashFileManager(context.getCacheDir()); |
File[] minidumps = fileManager.getAllMinidumpFiles(MAX_TRIES_ALLOWED); |
Log.i(TAG, "Attempting to upload accumulated crash dumps."); |
for (File minidump : minidumps) { |
- MinidumpUploadService.tryUploadCrashDump(context, minidump); |
+ tryUploadCrashDump(context, minidump); |
} |
} |
@@ -305,6 +364,11 @@ public class MinidumpUploadService extends IntentService { |
Log.w(TAG, "Could not rename the file " + minidumpFile.getName() + " for re-upload"); |
return; |
} |
- MinidumpUploadService.tryUploadCrashDump(context, renamedMinidumpFile); |
+ |
+ if (shouldUseJobSchedulerForUploads()) { |
+ scheduleUploadJob(context); |
+ } else { |
+ tryUploadCrashDump(context, renamedMinidumpFile); |
+ } |
} |
} |