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

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

Issue 2464943002: Componentize CrashFileManager and MinidumpUploadCallable. (Closed)
Patch Set: Update copyright year of moved files. Created 4 years, 1 month 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/src/org/chromium/chrome/browser/crash/CrashFileManager.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/CrashFileManager.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/CrashFileManager.java
deleted file mode 100644
index f7c4679b3a2c2179a2c66aa8f9d95d44d717789c..0000000000000000000000000000000000000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/crash/CrashFileManager.java
+++ /dev/null
@@ -1,387 +0,0 @@
-// 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.support.annotation.Nullable;
-
-import org.chromium.base.Log;
-import org.chromium.base.VisibleForTesting;
-
-import java.io.File;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Scanner;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Pattern;
-
-/**
- * Responsible for the Crash Report directory. It routinely scans the directory
- * for new Minidump files and takes appropriate actions by either uploading new
- * crash dumps or deleting old ones.
- */
-public class CrashFileManager {
- private static final String TAG = "CrashFileManager";
-
- @VisibleForTesting
- static final String CRASH_DUMP_DIR = "Crash Reports";
-
- // This should mirror the C++ CrashUploadList::kReporterLogFilename variable.
- @VisibleForTesting
- static final String CRASH_DUMP_LOGFILE = "uploads.log";
-
- private static final Pattern MINIDUMP_FIRST_TRY_PATTERN =
- Pattern.compile("\\.dmp([0-9]*)$\\z");
-
- private static final Pattern MINIDUMP_MIME_FIRST_TRY_PATTERN =
- Pattern.compile("\\.dmp([0-9]+)$\\z");
-
- private static final Pattern MINIDUMP_PATTERN =
- Pattern.compile("\\.dmp([0-9]*)(\\.try([0-9]+))?\\z");
-
- private static final Pattern UPLOADED_MINIDUMP_PATTERN = Pattern.compile("\\.up([0-9]*)\\z");
-
- private static final String NOT_YET_UPLOADED_MINIDUMP_SUFFIX = ".dmp";
-
- private static final String UPLOADED_MINIDUMP_SUFFIX = ".up";
-
- private static final String UPLOAD_SKIPPED_MINIDUMP_SUFFIX = ".skipped";
-
- private static final String UPLOAD_FORCED_MINIDUMP_SUFFIX = ".forced";
-
- private static final String UPLOAD_ATTEMPT_DELIMITER = ".try";
-
- @VisibleForTesting
- protected static final String TMP_SUFFIX = ".tmp";
-
- private static final Pattern TMP_PATTERN = Pattern.compile("\\.tmp\\z");
-
- // The maximum number of non-uploaded crashes that may be kept in the crash reports directory.
- // Chosen to attempt to balance between keeping a generous number of crashes, and not using up
- // too much filesystem storage space for obsolete crash reports.
- @VisibleForTesting
- protected static final int MAX_CRASH_REPORTS_TO_KEEP = 10;
-
- // The maximum age, in days, considered acceptable for a crash report. Reports older than this
- // age will be removed. The constant is chosen to be quite conservative, while still allowing
- // users to eventually reclaim filesystem storage space from obsolete crash reports.
- private static final int MAX_CRASH_REPORT_AGE_IN_DAYS = 30;
-
- /**
- * Comparator used for sorting files by modification date.
- * @return Comparator for prioritizing the more recently modified file
- */
- @VisibleForTesting
- protected static final Comparator<File> sFileComparator = new Comparator<File>() {
- @Override
- public int compare(File lhs, File rhs) {
- if (lhs.lastModified() == rhs.lastModified()) {
- return lhs.compareTo(rhs);
- } else if (lhs.lastModified() < rhs.lastModified()) {
- return 1;
- } else {
- return -1;
- }
- }
- };
-
- @VisibleForTesting
- static boolean deleteFile(File fileToDelete) {
- boolean isSuccess = fileToDelete.delete();
- if (!isSuccess) {
- Log.w(TAG, "Unable to delete " + fileToDelete.getAbsolutePath());
- }
- return isSuccess;
- }
-
- public File[] getMinidumpWithoutLogcat() {
- return listCrashFiles(MINIDUMP_FIRST_TRY_PATTERN);
- }
-
- public static boolean isMinidumpMIMEFirstTry(String path) {
- return MINIDUMP_MIME_FIRST_TRY_PATTERN.matcher(path).find();
- }
-
- public static String tryIncrementAttemptNumber(File mFileToUpload) {
- String newName = filenameWithIncrementedAttemptNumber(mFileToUpload.getPath());
- return mFileToUpload.renameTo(new File(newName)) ? newName : null;
- }
-
- /**
- * @return The file name to rename to after an addition attempt to upload
- */
- @VisibleForTesting
- public static String filenameWithIncrementedAttemptNumber(String filename) {
- int numTried = readAttemptNumber(filename);
- if (numTried > 0) {
- int newCount = numTried + 1;
- return filename.replace(
- UPLOAD_ATTEMPT_DELIMITER + numTried, UPLOAD_ATTEMPT_DELIMITER + newCount);
- } else {
- return filename + UPLOAD_ATTEMPT_DELIMITER + "1";
- }
- }
-
- /**
- * 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.
- *
- * @return The renamed file, or null if renaming failed.
- */
- public static File trySetForcedUpload(File fileToUpload) {
- if (fileToUpload.getName().contains(UPLOADED_MINIDUMP_SUFFIX)) {
- Log.w(TAG, "Refusing to reset upload attempt state for a file that has already been "
- + "successfully uploaded: " + fileToUpload.getName());
- return null;
- }
- File renamedFile = new File(filenameWithForcedUploadState(fileToUpload.getPath()));
- return fileToUpload.renameTo(renamedFile) ? renamedFile : null;
- }
-
- /**
- * @return True iff the provided File was manually forced (by the user) to be uploaded.
- */
- public static boolean isForcedUpload(File fileToUpload) {
- return fileToUpload.getName().contains(UPLOAD_FORCED_MINIDUMP_SUFFIX);
- }
-
- /**
- * @return The filename to rename to so as to manually force an upload (including clearing any
- * previous upload attempt history).
- */
- @VisibleForTesting
- protected static String filenameWithForcedUploadState(String filename) {
- int numTried = readAttemptNumber(filename);
- if (numTried > 0) {
- filename = filename.replace(
- UPLOAD_ATTEMPT_DELIMITER + numTried, UPLOAD_ATTEMPT_DELIMITER + 0);
- }
- filename = filename.replace(UPLOAD_SKIPPED_MINIDUMP_SUFFIX, UPLOAD_FORCED_MINIDUMP_SUFFIX);
- return filename.replace(NOT_YET_UPLOADED_MINIDUMP_SUFFIX, UPLOAD_FORCED_MINIDUMP_SUFFIX);
- }
-
- @VisibleForTesting
- public static int readAttemptNumber(String filename) {
- int tryIndex = filename.lastIndexOf(UPLOAD_ATTEMPT_DELIMITER);
- if (tryIndex >= 0) {
- tryIndex += UPLOAD_ATTEMPT_DELIMITER.length();
- String numTriesString = filename.substring(tryIndex);
- Scanner numTriesScanner = new Scanner(numTriesString).useDelimiter("[^0-9]+");
- try {
- int nextInt = numTriesScanner.nextInt();
- // Only return the number if it occurs just after the UPLOAD_ATTEMPT_DELIMITER.
- return numTriesString.indexOf(Integer.toString(nextInt)) == 0 ? nextInt : 0;
- } catch (NoSuchElementException e) {
- return 0;
- }
- }
- return 0;
- }
-
- /**
- * Marks a crash dump file as successfully uploaded, by renaming the file.
- *
- * Does not immediately delete the file, for testing reasons. However, if renaming fails,
- * attempts to delete the file immediately.
- */
- public static void markUploadSuccess(File crashDumpFile) {
- CrashFileManager.renameCrashDumpFollowingUpload(crashDumpFile, UPLOADED_MINIDUMP_SUFFIX);
- }
-
- /**
- * Marks a crash dump file's upload being skipped. An upload might be skipped due to lack of
- * user consent, or due to this client being excluded from the sample of clients reporting
- * crashes.
- *
- * Renames the file rather than deleting it, so that the user can manually upload the file later
- * (via chrome://crashes). However, if renaming fails, attempts to delete the file immediately.
- */
- public static void markUploadSkipped(File crashDumpFile) {
- CrashFileManager.renameCrashDumpFollowingUpload(
- crashDumpFile, UPLOAD_SKIPPED_MINIDUMP_SUFFIX);
- }
-
- /**
- * Renames a crash dump file. However, if renaming fails, attempts to delete the file
- * immediately.
- */
- private static void renameCrashDumpFollowingUpload(File crashDumpFile, String suffix) {
- // The pre-upload filename might have been either "foo.dmpN.tryM" or "foo.forcedN.tryM".
- String newName = crashDumpFile.getPath()
- .replace(NOT_YET_UPLOADED_MINIDUMP_SUFFIX, suffix)
- .replace(UPLOAD_FORCED_MINIDUMP_SUFFIX, suffix);
- boolean renamed = crashDumpFile.renameTo(new File(newName));
- if (!renamed) {
- Log.w(TAG, "Failed to rename " + crashDumpFile);
- if (!crashDumpFile.delete()) {
- Log.w(TAG, "Failed to delete " + crashDumpFile);
- }
- }
- }
-
- private final File mCacheDir;
-
- public CrashFileManager(File cacheDir) {
- if (cacheDir == null) {
- throw new NullPointerException("Specified context cannot be null.");
- } else if (!cacheDir.isDirectory()) {
- throw new IllegalArgumentException(cacheDir.getAbsolutePath()
- + " is not a directory.");
- }
- mCacheDir = cacheDir;
- }
-
- /**
- * Returns all minidump files that could still be uploaded, sorted by modification time stamp.
- * Forced uploads are not included. Only returns files that we have tried to upload less
- * than {@param maxTries} number of times.
- */
- public File[] getAllMinidumpFiles(int maxTries) {
- return getFilesBelowMaxTries(listCrashFiles(MINIDUMP_PATTERN), maxTries);
- }
-
- public void cleanOutAllNonFreshMinidumpFiles() {
- for (File f : getAllUploadedFiles()) {
- deleteFile(f);
- }
- for (File f : getAllTempFiles()) {
- deleteFile(f);
- }
-
- Set<String> recentCrashes = new HashSet<String>();
- for (File f : listCrashFiles(null)) {
- // The uploads.log file should always be preserved, as it stores the metadata that
- // powers the chrome://crashes UI.
- if (f.getName().equals(CRASH_DUMP_LOGFILE)) {
- continue;
- }
-
- // Delete any crash reports that are especially old.
- long ageInMillis = new Date().getTime() - f.lastModified();
- long ageInDays = TimeUnit.DAYS.convert(ageInMillis, TimeUnit.MILLISECONDS);
- if (ageInDays > MAX_CRASH_REPORT_AGE_IN_DAYS) {
- deleteFile(f);
- continue;
- }
-
- // Delete the oldest crash reports that exceed the cap on the number of allowed reports.
- // Each crash typically has two files associated with it: a .dmp file and a .logcat
- // file. These have the same filename other than the file extension.
- String fileNameSansExtension = f.getName().split("\\.")[0];
- if (recentCrashes.size() < MAX_CRASH_REPORTS_TO_KEEP) {
- recentCrashes.add(fileNameSansExtension);
- } else if (!recentCrashes.contains(fileNameSansExtension)) {
- deleteFile(f);
- }
- }
- }
-
- /**
- * Filters a set of files to keep the ones we have tried to upload only a few times.
- * Given a set of files {@param unfilteredFiles}, returns only the files in that set which we
- * have tried to upload less than {@param maxTries} times.
- */
- @VisibleForTesting
- static File[] getFilesBelowMaxTries(File[] unfilteredFiles, int maxTries) {
- List<File> filesBelowMaxTries = new ArrayList<>(unfilteredFiles.length);
- for (File file : unfilteredFiles) {
- if (readAttemptNumber(file.getName()) < maxTries) {
- filesBelowMaxTries.add(file);
- }
- }
- return filesBelowMaxTries.toArray(new File[filesBelowMaxTries.size()]);
- }
-
- @VisibleForTesting
- File[] listCrashFiles(@Nullable final Pattern pattern) {
- File crashDir = getCrashDirectory();
-
- FilenameFilter filter = null;
- if (pattern != null) {
- filter = new FilenameFilter() {
- @Override
- public boolean accept(File dir, String filename) {
- return pattern.matcher(filename).find();
- }
- };
- }
- File[] minidumps = crashDir.listFiles(filter);
- if (minidumps == null) {
- Log.w(TAG, crashDir.getAbsolutePath() + " does not exist or is not a directory");
- return new File[] {};
- }
- Arrays.sort(minidumps, sFileComparator);
- return minidumps;
- }
-
- @VisibleForTesting
- File[] getAllUploadedFiles() {
- return listCrashFiles(UPLOADED_MINIDUMP_PATTERN);
- }
-
- @VisibleForTesting
- File getCrashDirectory() {
- return new File(mCacheDir, CRASH_DUMP_DIR);
- }
-
- public File createNewTempFile(String name) throws IOException {
- File f = new File(getCrashDirectory(), name);
- if (f.exists()) {
- if (f.delete()) {
- f = new File(getCrashDirectory(), name);
- } else {
- Log.w(TAG, "Unable to delete previous logfile"
- + f.getAbsolutePath());
- }
- }
- return f;
- }
-
- File getCrashFile(String filename) {
- return new File(getCrashDirectory(), filename);
- }
-
- /**
- * Returns the minidump file with the given local ID, or null if no minidump file has the given
- * local ID.
- * NOTE: Crash files that have already been successfully uploaded are not included.
- *
- * @param localId The local ID of the crash report.
- * @return The matching File, or null if no matching file is found.
- */
- File getCrashFileWithLocalId(String localId) {
- for (File f : listCrashFiles(null)) {
- // Only match non-uploaded or previously skipped files. In particular, do not match
- // successfully uploaded files; nor files which are not minidump files, such as logcat
- // files.
- if (!f.getName().contains(NOT_YET_UPLOADED_MINIDUMP_SUFFIX)
- && !f.getName().contains(UPLOAD_SKIPPED_MINIDUMP_SUFFIX)
- && !f.getName().contains(UPLOAD_FORCED_MINIDUMP_SUFFIX)) {
- continue;
- }
-
- String filenameSansExtension = f.getName().split("\\.")[0];
- if (filenameSansExtension.endsWith(localId)) {
- return f;
- }
- }
- return null;
- }
-
- File getCrashUploadLogFile() {
- return new File(getCrashDirectory(), CRASH_DUMP_LOGFILE);
- }
-
- private File[] getAllTempFiles() {
- return listCrashFiles(TMP_PATTERN);
- }
-}

Powered by Google App Engine
This is Rietveld 408576698