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

Unified Diff: components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java

Issue 2862353003: [Crash Reporting] Fix a race between uploading and appending logcat data. (Closed)
Patch Set: Rebase 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
Index: components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java
diff --git a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java
index 8214b7b5b449d705f067d3313235b955c31ac420..6451173389494f3e5b7cc1c2b86d4c175fd2b620 100644
--- a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java
+++ b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java
@@ -29,24 +29,24 @@ import java.util.regex.Pattern;
/**
* The CrashFileManager is responsible for managing the "Crash Reports" directory containing
* minidump files and shepherding them through a state machine represented by the file names. Note
- * that some of the steps are optional:
+ * that the second step is optional.
* 1. foo.dmp is a minidump file, written to the directory by Breakpad.
* (2) foo.dmpNNNNN is a minidump file, where NNNNN is the PID (process id) of the crashing
* process. This step is optional -- that is, a minidump could fail to have its PID included in
* the filename.
- * (3) foo.dmpNNNNN.try0 is a minidump file with recent logcat output attached to it. This step is
- * optional -- that is, logcat output might fail to be extracted for the minidump. Notably,
+ * 3. foo.dmp.try0 or foo.dmpNNNNN.try0 is a minidump file with recent logcat output attached to
+ * it; or a file for which logcat output has been intentionally omitted. Notably,
* Webview-generated minidumps do not include logcat output.
* 4. foo.dmpNNNNN.tryM for M > 0 is a minidump file that's been attempted to be uploaded to the
* crash server, but for which M upload attempts have failed.
- * 5. foo.up, foo.upNNNNN, or foo.upNNNNN.tryM are all valid possible names for a successfully
- * uploaded file.
- * 6. foo.skipped, foo.skippedNNNNN, or foo.skippedNNNNN.tryM are all valid possible names for a
- * file whose upload was skipped. An upload may be skipped, for example, if the user has not
- * consented to uploading crash reports. These files are marked as skipped rather than deleted
- * immediately to allow the user to manually initiate an upload.
- * 7. foo.forced, foo.forcedNNNNN, or foo.forcedNNNNN.tryM are all valid possible names for a file
- * that the user has manually requested to upload.
+ * 5. foo.up.tryM and foo.upNNNNN.tryM are both valid possible names for a successfully uploaded
+ * file.
+ * 6. foo.skipped.tryM and foo.skippedNNNNN.tryM are both valid possible names for a file whose
+ * upload was skipped. An upload may be skipped, for example, if the user has not consented to
+ * uploading crash reports. These files are marked as skipped rather than deleted immediately to
+ * allow the user to manually initiate an upload.
+ * 7. foo.forced.tryM and foo.forcedNNNNN.tryM are both valid possible names for a file that the
+ * user has manually requested to upload.
* 8. foo.tmp is a temporary file.
*/
public class CrashFileManager {
@@ -61,12 +61,17 @@ public class CrashFileManager {
@VisibleForTesting
public static final String CRASH_DUMP_LOGFILE = "uploads.log";
- private static final Pattern MINIDUMP_MIME_FIRST_TRY_PATTERN =
- Pattern.compile("\\.dmp([0-9]+)$\\z");
+ // Unlike the MINIDUMP_READY_FOR_UPLOAD_PATTERN below, this pattern omits a ".tryN" suffix.
+ private static final Pattern MINIDUMP_SANS_LOGCAT_PATTERN =
+ Pattern.compile("\\.dmp([0-9]*)\\z");
- private static final Pattern MINIDUMP_PATTERN =
- Pattern.compile("\\.(dmp|forced)([0-9]*)(\\.try([0-9]+))?\\z");
+ private static final Pattern MINIDUMP_READY_FOR_UPLOAD_PATTERN =
+ Pattern.compile("\\.(dmp|forced)([0-9]*)(\\.try([0-9]+))\\z");
+ // TODO(isherman): The ".tryN" suffix is currently optional, so that old uploaded minidump files
+ // will continue to be detected as such. However, new uploads are guaranteed to include this
+ // suffix. Tighten this regex (by removing the final '?') in roughly the M61 timeframe:
+ // http://crbug.com/719120
private static final Pattern UPLOADED_MINIDUMP_PATTERN =
Pattern.compile("\\.up([0-9]*)(\\.try([0-9]+))?\\z");
@@ -80,6 +85,9 @@ public class CrashFileManager {
private static final String UPLOAD_ATTEMPT_DELIMITER = ".try";
+ // The suffix used when a minidump is first ready for upload: ".try0".
+ public static final String READY_FOR_UPLOAD_SUFFIX = UPLOAD_ATTEMPT_DELIMITER + "0";
+
// A delimiter between uid and the rest of a minidump filename. Only used for WebView minidumps.
private static final String UID_DELIMITER = "_";
@@ -140,8 +148,17 @@ public class CrashFileManager {
return isSuccess;
}
- public static boolean isMinidumpMIMEFirstTry(String path) {
- return MINIDUMP_MIME_FIRST_TRY_PATTERN.matcher(path).find();
+ /**
+ * Returns whether a minidump file definitely lacks logcat output. Note: This method does not
+ * provide an "if and only if" test: it may return false for a path that lacks logcat output, if
+ * logcat output has been intentionally skipped for that minidump. However, a return value of
+ * true means that the file definitely lacks logcat output.
+ * @param path The minidump pathname to test.
+ * @return Whether the given path corresponds to a minidump file that definitely lacks logcat
+ * output.
+ */
+ public static boolean isMinidumpSansLogcat(String path) {
+ return MINIDUMP_SANS_LOGCAT_PATTERN.matcher(path).find();
}
public static String tryIncrementAttemptNumber(File mFileToUpload) {
@@ -168,6 +185,20 @@ public class CrashFileManager {
}
/**
+ * Attempts to rename the given file to mark it as ready for upload. This should be done when
+ * logcat extraction fails or is otherwise intentionally skipped. An equivalent operation is
+ * done when extraction succeeds; but since the logcat output needs to be included in the
+ * uploaded data, more than a simple rename is needed.
+ *
+ * @return The renamed file, or null if renaming failed.
+ */
+ public static File trySetReadyForUpload(File fileToUpload) {
+ assert CrashFileManager.isMinidumpSansLogcat(fileToUpload.getName());
+ File renamedFile = new File(fileToUpload.getPath() + READY_FOR_UPLOAD_SUFFIX);
+ return fileToUpload.renameTo(renamedFile) ? renamedFile : null;
+ }
+
+ /**
* Attempts to rename the given file to mark it as a forced upload. This is useful for allowing
* users to manually initiate previously skipped uploads.
*
@@ -309,18 +340,21 @@ public class CrashFileManager {
}
/**
- * Returns all minidump files that could still be uploaded, sorted by modification time stamp.
- * Only returns files that we have tried to upload less than {@param maxTries} number of times.
+ * Returns all minidump files that definitely do not have logcat output, sorted by modification
+ * time stamp. Note: This method does not provide an "if and only if" test: it may return omit
+ * some files that lack logcat output, if logcat output has been intentionally skipped for those
+ * minidumps. However, any files returned definitely lack logcat output.
*/
- public File[] getAllMinidumpFiles(int maxTries) {
- return getFilesBelowMaxTries(getAllMinidumpFilesIncludingFailed(), maxTries);
+ public File[] getMinidumpsSansLogcat() {
+ return listCrashFiles(MINIDUMP_SANS_LOGCAT_PATTERN);
}
/**
- * Returns all minidump files sorted by modification time stamp.
+ * Returns all minidump files that could still be uploaded, sorted by modification time stamp.
+ * Only returns files that we have tried to upload less than {@param maxTries} number of times.
*/
- private File[] getAllMinidumpFilesIncludingFailed() {
- return listCrashFiles(MINIDUMP_PATTERN);
+ public File[] getMinidumpsReadyForUpload(int maxTries) {
+ return getFilesBelowMaxTries(listCrashFiles(MINIDUMP_READY_FOR_UPLOAD_PATTERN), maxTries);
}
/**
@@ -486,7 +520,7 @@ public class CrashFileManager {
* @param uid The uid of the app to check the minidump limit for.
*/
private void enforceMinidumpStorageRestrictions(int uid) {
- File[] allMinidumpFiles = getAllMinidumpFilesIncludingFailed();
+ File[] allMinidumpFiles = listCrashFiles(MINIDUMP_READY_FOR_UPLOAD_PATTERN);
List<File> minidumpFilesWithCurrentUid = filterMinidumpFilesOnUid(allMinidumpFiles, uid);
// If we have exceeded our cap per uid, delete the oldest minidump of the same uid
@@ -598,7 +632,8 @@ public class CrashFileManager {
* some entity. A uid, on the other hand, is a unique identifier for Android packages.
*/
private static String createUniqueMinidumpNameForUid(int uid) {
- return uid + UID_DELIMITER + UUID.randomUUID() + NOT_YET_UPLOADED_MINIDUMP_SUFFIX;
+ return uid + UID_DELIMITER + UUID.randomUUID() + NOT_YET_UPLOADED_MINIDUMP_SUFFIX
+ + READY_FOR_UPLOAD_SUFFIX;
}
/**

Powered by Google App Engine
This is Rietveld 408576698