| 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
|
| index beb9c71c40ef026e6e09f5daadc257fbe97e1ac3..922ec5cee4026ec0c205408ea6bf1342e312b018 100644
|
| --- a/chrome/android/java/src/org/chromium/chrome/browser/crash/CrashFileManager.java
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/CrashFileManager.java
|
| @@ -12,6 +12,10 @@ import java.io.FilenameFilter;
|
| import java.io.IOException;
|
| import java.util.Arrays;
|
| import java.util.Comparator;
|
| +import java.util.Date;
|
| +import java.util.HashSet;
|
| +import java.util.Set;
|
| +import java.util.concurrent.TimeUnit;
|
| import java.util.regex.Matcher;
|
| import java.util.regex.Pattern;
|
|
|
| @@ -28,7 +32,7 @@ public class CrashFileManager {
|
|
|
| // This should mirror the C++ CrashUploadList::kReporterLogFilename variable.
|
| @VisibleForTesting
|
| - static final String CRASH_DUMP_LOGFILE = CRASH_DUMP_DIR + "/uploads.log";
|
| + static final String CRASH_DUMP_LOGFILE = "uploads.log";
|
|
|
| private static final Pattern MINIDUMP_FIRST_TRY_PATTERN =
|
| Pattern.compile("\\.dmp([0-9]*)$\\z");
|
| @@ -52,6 +56,17 @@ public class CrashFileManager {
|
|
|
| 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
|
| * Note that the behavior is undecided if the files are created at the same time
|
| @@ -188,6 +203,18 @@ public class CrashFileManager {
|
| return minidumps;
|
| }
|
|
|
| + @VisibleForTesting
|
| + protected File[] getAllFilesSorted() {
|
| + File crashDir = getCrashDirectoryIfExists();
|
| + if (crashDir == null) {
|
| + return new File[] {};
|
| + }
|
| +
|
| + File[] files = crashDir.listFiles();
|
| + Arrays.sort(files, sFileComparator);
|
| + return files;
|
| + }
|
| +
|
| public void cleanOutAllNonFreshMinidumpFiles() {
|
| for (File f : getAllUploadedFiles()) {
|
| deleteFile(f);
|
| @@ -195,20 +222,42 @@ public class CrashFileManager {
|
| for (File f : getAllTempFiles()) {
|
| deleteFile(f);
|
| }
|
| +
|
| + Set<String> recentCrashes = new HashSet<String>();
|
| + for (File f : getAllFilesSorted()) {
|
| + // 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);
|
| + }
|
| + }
|
| }
|
|
|
| @VisibleForTesting
|
| File[] getMatchingFiles(final Pattern pattern) {
|
| - // Get dump dir and get all files with specified suffix.. The path
|
| + // Get dump dir and get all files with specified suffix. The path
|
| // constructed here must match chrome_paths.cc (see case
|
| // chrome::DIR_CRASH_DUMPS).
|
| - File crashDir = getCrashDirectory();
|
| - if (!crashDir.exists()) {
|
| - Log.w(TAG, crashDir.getAbsolutePath() + " does not exist!");
|
| - return new File[] {};
|
| - }
|
| - if (!crashDir.isDirectory()) {
|
| - Log.w(TAG, crashDir.getAbsolutePath() + " is not a directory!");
|
| + File crashDir = getCrashDirectoryIfExists();
|
| + if (crashDir == null) {
|
| return new File[] {};
|
| }
|
| File[] minidumps = crashDir.listFiles(new FilenameFilter() {
|
| @@ -232,6 +281,20 @@ public class CrashFileManager {
|
| return new File(mCacheDir, CRASH_DUMP_DIR);
|
| }
|
|
|
| + @VisibleForTesting
|
| + File getCrashDirectoryIfExists() {
|
| + File crashDirectory = getCrashDirectory();
|
| + if (!crashDirectory.exists()) {
|
| + Log.w(TAG, crashDirectory.getAbsolutePath() + " does not exist!");
|
| + return null;
|
| + }
|
| + if (!crashDirectory.isDirectory()) {
|
| + Log.w(TAG, crashDirectory.getAbsolutePath() + " is not a directory!");
|
| + return null;
|
| + }
|
| + return crashDirectory;
|
| + }
|
| +
|
| public File createNewTempFile(String name) throws IOException {
|
| File f = new File(getCrashDirectory(), name);
|
| if (f.exists()) {
|
| @@ -250,7 +313,7 @@ public class CrashFileManager {
|
| }
|
|
|
| File getCrashUploadLogFile() {
|
| - return new File(mCacheDir, CRASH_DUMP_LOGFILE);
|
| + return new File(getCrashDirectory(), CRASH_DUMP_LOGFILE);
|
| }
|
|
|
| private File[] getAllTempFiles() {
|
|
|