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 7c01cd6ce0b51df1c45c44dce4a7a4ee04404980..40e18510582f79dd50d26609d0f1ae6e4075a7b3 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 |
@@ -86,7 +86,6 @@ import org.chromium.ui.base.SelectFileDialog; |
import java.io.File; |
import java.util.ArrayList; |
-import java.util.Arrays; |
import java.util.Date; |
import java.util.List; |
import java.util.Locale; |
@@ -503,34 +502,78 @@ public class ProcessInitializationHandler { |
new CrashFileManager(ContextUtils.getApplicationContext().getCacheDir()); |
crashFileManager.cleanOutAllNonFreshMinidumpFiles(); |
- // Finally, uploading any pending crash reports. |
- File[] minidumps = crashFileManager.getAllMinidumpFiles( |
+ // Next, identify any minidumps that lack logcat output, and are too old to add |
+ // logcat output to. Mark these as ready for upload. If there is a fresh minidump |
+ // that still needs logcat output to be attached, stash it for now. |
+ File minidumpMissingLogcat = processMinidumpsSansLogcat(crashFileManager); |
+ |
+ // Now, upload all pending crash reports that are not still in need of logcat data. |
+ File[] minidumps = crashFileManager.getMinidumpsReadyForUpload( |
MinidumpUploadService.MAX_TRIES_ALLOWED); |
- if (minidumps.length == 0) return; |
+ if (minidumps.length > 0) { |
+ Log.i(TAG, "Attempting to upload %d accumulated crash dumps.", |
+ minidumps.length); |
+ if (MinidumpUploadService.shouldUseJobSchedulerForUploads()) { |
+ MinidumpUploadService.scheduleUploadJob(); |
+ } else { |
+ MinidumpUploadService.tryUploadAllCrashDumps(); |
+ } |
+ } |
- Log.i(TAG, "Attempting to upload %d accumulated crash dumps.", minidumps.length); |
- File mostRecentMinidump = minidumps[0]; |
- if (doesCrashMinidumpNeedLogcat(mostRecentMinidump)) { |
+ // Finally, if there is a minidump that still needs logcat output to be attached, do |
+ // so now. Note: It's important to do this strictly after calling |
+ // |crashFileManager.getMinidumpsReadyForUpload()|. Otherwise, there is a race |
+ // between appending the logcat and getting the results from that call, as the |
+ // minidump will be renamed to be a valid file for upload upon logcat extraction |
+ // success. |
+ if (minidumpMissingLogcat != null) { |
+ // Note: When using the JobScheduler API to schedule uploads, this call might |
+ // result in a duplicate request to schedule minidump uploads -- if the call |
+ // succeeds, and there were also other pending minidumps found above. This is |
+ // fine; the job scheduler is robust to such duplicate calls. |
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); |
- } |
+ new LogcatExtractionRunnable(minidumpMissingLogcat)); |
+ } |
+ } |
+ |
+ /** |
+ * Process all pending minidump files that lack logcat output. As a simplifying |
+ * assumption, assume that logcat output would only be relevant to the most recent |
+ * pending minidump, if there are multiple. As of Chrome version 58, about 50% of |
+ * startups that had *any* pending minidumps had at least one pending minidump without |
+ * any logcat output. About 5% had multiple minidumps without any logcat output. |
+ * |
+ * TODO(isherman): This is the simplest approach to resolving the complexity of |
+ * correctly attributing logcat output to the correct crash. However, it would be better |
+ * to attach logcat output to each minidump file that lacks it, if the relevant output |
+ * is still available. We can look at timestamps to correlate logcat lines with the |
+ * minidumps they correspond to. |
+ * |
+ * @return A single fresh minidump that should have logcat attached to it, or null if no |
+ * such minidump exists. |
+ */ |
+ private File processMinidumpsSansLogcat(CrashFileManager crashFileManager) { |
+ File[] minidumpsSansLogcat = crashFileManager.getMinidumpsSansLogcat(); |
+ |
+ // If there are multiple minidumps present that are missing logcat output, only |
+ // append it to the most recent one. Upload the rest as-is. |
+ if (minidumpsSansLogcat.length > 1) { |
+ for (int i = 1; i < minidumpsSansLogcat.length; ++i) { |
+ CrashFileManager.trySetReadyForUpload(minidumpsSansLogcat[i]); |
+ } |
+ } |
+ |
+ // Try to identify a single fresh minidump that should have logcat output appended |
+ // to it. |
+ if (minidumpsSansLogcat.length > 0) { |
+ File mostRecentMinidumpSansLogcat = minidumpsSansLogcat[0]; |
+ if (doesCrashMinidumpNeedLogcat(mostRecentMinidumpSansLogcat)) { |
+ return mostRecentMinidumpSansLogcat; |
+ } else { |
+ CrashFileManager.trySetReadyForUpload(mostRecentMinidumpSansLogcat); |
} |
- } else if (MinidumpUploadService.shouldUseJobSchedulerForUploads()) { |
- MinidumpUploadService.scheduleUploadJob(); |
- } else { |
- MinidumpUploadService.tryUploadAllCrashDumps(); |
} |
+ return null; |
} |
/** |
@@ -548,7 +591,7 @@ public class ProcessInitializationHandler { |
* the given minidump. |
*/ |
private boolean doesCrashMinidumpNeedLogcat(File minidump) { |
- if (!CrashFileManager.isMinidumpMIMEFirstTry(minidump.getName())) return false; |
+ if (!CrashFileManager.isMinidumpSansLogcat(minidump.getName())) return false; |
long ageInMillis = new Date().getTime() - minidump.lastModified(); |
long ageInHours = TimeUnit.HOURS.convert(ageInMillis, TimeUnit.MILLISECONDS); |