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

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

Issue 2280313002: [Android] Delete old crash reports (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Suppress irrelevant build warnings Created 4 years, 3 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 unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.crash; 5 package org.chromium.chrome.browser.crash;
6 6
7 import org.chromium.base.Log; 7 import org.chromium.base.Log;
8 import org.chromium.base.VisibleForTesting; 8 import org.chromium.base.VisibleForTesting;
9 9
10 import java.io.File; 10 import java.io.File;
11 import java.io.FilenameFilter; 11 import java.io.FilenameFilter;
12 import java.io.IOException; 12 import java.io.IOException;
13 import java.util.Arrays; 13 import java.util.Arrays;
14 import java.util.Comparator; 14 import java.util.Comparator;
15 import java.util.Date;
16 import java.util.HashSet;
17 import java.util.Set;
18 import java.util.concurrent.TimeUnit;
15 import java.util.regex.Matcher; 19 import java.util.regex.Matcher;
16 import java.util.regex.Pattern; 20 import java.util.regex.Pattern;
17 21
18 /** 22 /**
19 * Responsible for the Crash Report directory. It routinely scans the directory 23 * Responsible for the Crash Report directory. It routinely scans the directory
20 * for new Minidump files and takes appropriate actions by either uploading new 24 * for new Minidump files and takes appropriate actions by either uploading new
21 * crash dumps or deleting old ones. 25 * crash dumps or deleting old ones.
22 */ 26 */
23 public class CrashFileManager { 27 public class CrashFileManager {
24 private static final String TAG = "CrashFileManager"; 28 private static final String TAG = "CrashFileManager";
25 29
26 @VisibleForTesting 30 @VisibleForTesting
27 static final String CRASH_DUMP_DIR = "Crash Reports"; 31 static final String CRASH_DUMP_DIR = "Crash Reports";
28 32
29 // This should mirror the C++ CrashUploadList::kReporterLogFilename variable . 33 // This should mirror the C++ CrashUploadList::kReporterLogFilename variable .
30 @VisibleForTesting 34 @VisibleForTesting
31 static final String CRASH_DUMP_LOGFILE = CRASH_DUMP_DIR + "/uploads.log"; 35 static final String CRASH_DUMP_LOGFILE = "uploads.log";
32 36
33 private static final Pattern MINIDUMP_FIRST_TRY_PATTERN = 37 private static final Pattern MINIDUMP_FIRST_TRY_PATTERN =
34 Pattern.compile("\\.dmp([0-9]*)$\\z"); 38 Pattern.compile("\\.dmp([0-9]*)$\\z");
35 39
36 private static final Pattern MINIDUMP_MIME_FIRST_TRY_PATTERN = 40 private static final Pattern MINIDUMP_MIME_FIRST_TRY_PATTERN =
37 Pattern.compile("\\.dmp([0-9]+)$\\z"); 41 Pattern.compile("\\.dmp([0-9]+)$\\z");
38 42
39 private static final Pattern MINIDUMP_PATTERN = 43 private static final Pattern MINIDUMP_PATTERN =
40 Pattern.compile("\\.dmp([0-9]*)(\\.try[0-9])?\\z"); 44 Pattern.compile("\\.dmp([0-9]*)(\\.try[0-9])?\\z");
41 45
42 private static final Pattern UPLOADED_MINIDUMP_PATTERN = Pattern.compile("\\ .up([0-9]*)\\z"); 46 private static final Pattern UPLOADED_MINIDUMP_PATTERN = Pattern.compile("\\ .up([0-9]*)\\z");
43 47
44 private static final String UPLOADED_MINIDUMP_SUFFIX = ".up"; 48 private static final String UPLOADED_MINIDUMP_SUFFIX = ".up";
45 49
46 private static final String UPLOAD_ATTEMPT_DELIMITER = ".try"; 50 private static final String UPLOAD_ATTEMPT_DELIMITER = ".try";
47 51
48 @VisibleForTesting 52 @VisibleForTesting
49 protected static final String TMP_SUFFIX = ".tmp"; 53 protected static final String TMP_SUFFIX = ".tmp";
50 54
51 private static final Pattern TMP_PATTERN = Pattern.compile("\\.tmp\\z"); 55 private static final Pattern TMP_PATTERN = Pattern.compile("\\.tmp\\z");
52 56
57 // The maximum number of non-uploaded crashes that may be kept in the crash reports directory.
58 // Chosen to attempt to balance between keeping a generous number of crashes , and not using up
59 // too much filesystem storage space for obsolete crash reports.
60 @VisibleForTesting
61 protected static final int MAX_CRASH_REPORTS_TO_KEEP = 10;
62
63 // The maximum age, in days, considered acceptable for a crash report. Repor ts older than this
64 // age will be removed. The constant is chosen to be quite conservative, whi le still allowing
65 // users to eventually reclaim filesystem storage space from obsolete crash reports.
66 private static final int MAX_CRASH_REPORT_AGE_IN_DAYS = 30;
67
53 /** 68 /**
54 * Comparator used for sorting files by modification 69 * Comparator used for sorting files by modification
55 * Note that the behavior is undecided if the files are created at the same time 70 * Note that the behavior is undecided if the files are created at the same time
56 * @return Comparator for prioritizing the more recently modified file 71 * @return Comparator for prioritizing the more recently modified file
57 */ 72 */
58 @VisibleForTesting 73 @VisibleForTesting
59 protected static final Comparator<File> sFileComparator = new Comparator<Fi le>() { 74 protected static final Comparator<File> sFileComparator = new Comparator<Fi le>() {
60 @Override 75 @Override
61 public int compare(File lhs, File rhs) { 76 public int compare(File lhs, File rhs) {
62 if (lhs == rhs) { 77 if (lhs == rhs) {
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 public File[] getAllMinidumpFiles() { 162 public File[] getAllMinidumpFiles() {
148 return getMatchingFiles(MINIDUMP_PATTERN); 163 return getMatchingFiles(MINIDUMP_PATTERN);
149 } 164 }
150 165
151 public File[] getAllMinidumpFilesSorted() { 166 public File[] getAllMinidumpFilesSorted() {
152 File[] minidumps = getAllMinidumpFiles(); 167 File[] minidumps = getAllMinidumpFiles();
153 Arrays.sort(minidumps, sFileComparator); 168 Arrays.sort(minidumps, sFileComparator);
154 return minidumps; 169 return minidumps;
155 } 170 }
156 171
172 @VisibleForTesting
173 protected File[] getAllFilesSorted() {
gayane -on leave until 09-2017 2016/08/29 18:56:47 Should we make getAllFilesSorted function to retur
Ilya Sherman 2016/08/29 22:33:01 The intention is for getAllFilesSorted() to return
gayane -on leave until 09-2017 2016/08/30 15:37:12 I would imagine smth like getAllAvailableMinidumpS
174 File crashDir = getCrashDirectoryIfExists();
175 if (crashDir == null) {
176 return new File[] {};
177 }
178
179 File[] files = crashDir.listFiles();
180 Arrays.sort(files, sFileComparator);
181 return files;
182 }
183
157 public void cleanOutAllNonFreshMinidumpFiles() { 184 public void cleanOutAllNonFreshMinidumpFiles() {
158 for (File f : getAllUploadedFiles()) { 185 for (File f : getAllUploadedFiles()) {
159 deleteFile(f); 186 deleteFile(f);
160 } 187 }
161 for (File f : getAllTempFiles()) { 188 for (File f : getAllTempFiles()) {
162 deleteFile(f); 189 deleteFile(f);
163 } 190 }
191
192 Set<String> recentCrashes = new HashSet<String>();
193 for (File f : getAllFilesSorted()) {
194 // The uploads.log file should always be preserved, as it stores the metadata that
195 // powers the chrome://crashes UI.
196 if (f.getName().equals(CRASH_DUMP_LOGFILE)) {
197 continue;
198 }
199
200 // Delete the oldest crash reports that exceed the cap on the number of allowed reports.
201 // Each crash typically has two files associated with it: a .dmp fil e and a .logcat
202 // file. These have the same filename other than the file extension.
203 String fileNameSansExtension = f.getName().split("\\.")[0];
gayane -on leave until 09-2017 2016/08/29 18:56:47 According to the filenameWithIncrementedAttemptNum
Ilya Sherman 2016/08/29 22:33:01 Yeah, I'm not sure why tests allow ".try1.dmp" as
gayane -on leave until 09-2017 2016/08/30 15:37:12 no, particular input, just misunderstood the split
204 if (recentCrashes.size() < MAX_CRASH_REPORTS_TO_KEEP) {
205 recentCrashes.add(fileNameSansExtension);
206 } else if (!recentCrashes.contains(fileNameSansExtension)) {
207 deleteFile(f);
208 continue;
209 }
210
211 // Delete any crash reports that are especially old.
212 long ageInMillis = new Date().getTime() - f.lastModified();
213 long ageInDays = TimeUnit.DAYS.convert(ageInMillis, TimeUnit.MILLISE CONDS);
214 if (ageInDays > MAX_CRASH_REPORT_AGE_IN_DAYS) {
gayane -on leave until 09-2017 2016/08/29 18:56:47 Shouldn't this be before we decide to add the repo
Ilya Sherman 2016/08/29 22:33:01 The behavior should be equivalent, but I agree it
215 deleteFile(f);
216 }
217 }
164 } 218 }
165 219
166 @VisibleForTesting 220 @VisibleForTesting
167 File[] getMatchingFiles(final Pattern pattern) { 221 File[] getMatchingFiles(final Pattern pattern) {
168 // Get dump dir and get all files with specified suffix.. The path 222 // Get dump dir and get all files with specified suffix. The path
169 // constructed here must match chrome_paths.cc (see case 223 // constructed here must match chrome_paths.cc (see case
170 // chrome::DIR_CRASH_DUMPS). 224 // chrome::DIR_CRASH_DUMPS).
171 File crashDir = getCrashDirectory(); 225 File crashDir = getCrashDirectoryIfExists();
172 if (!crashDir.exists()) { 226 if (crashDir == null) {
173 Log.w(TAG, crashDir.getAbsolutePath() + " does not exist!");
174 return new File[] {};
175 }
176 if (!crashDir.isDirectory()) {
177 Log.w(TAG, crashDir.getAbsolutePath() + " is not a directory!");
178 return new File[] {}; 227 return new File[] {};
179 } 228 }
180 File[] minidumps = crashDir.listFiles(new FilenameFilter() { 229 File[] minidumps = crashDir.listFiles(new FilenameFilter() {
181 @Override 230 @Override
182 public boolean accept(File dir, String filename) { 231 public boolean accept(File dir, String filename) {
183 Matcher match = pattern.matcher(filename); 232 Matcher match = pattern.matcher(filename);
184 int tries = readAttemptNumber(filename); 233 int tries = readAttemptNumber(filename);
185 return match.find() && tries < MinidumpUploadService.MAX_TRIES_A LLOWED; 234 return match.find() && tries < MinidumpUploadService.MAX_TRIES_A LLOWED;
186 } 235 }
187 }); 236 });
188 return minidumps; 237 return minidumps;
189 } 238 }
190 239
191 @VisibleForTesting 240 @VisibleForTesting
192 File[] getAllUploadedFiles() { 241 File[] getAllUploadedFiles() {
193 return getMatchingFiles(UPLOADED_MINIDUMP_PATTERN); 242 return getMatchingFiles(UPLOADED_MINIDUMP_PATTERN);
194 } 243 }
195 244
196 @VisibleForTesting 245 @VisibleForTesting
197 File getCrashDirectory() { 246 File getCrashDirectory() {
198 return new File(mCacheDir, CRASH_DUMP_DIR); 247 return new File(mCacheDir, CRASH_DUMP_DIR);
199 } 248 }
200 249
250 @VisibleForTesting
251 File getCrashDirectoryIfExists() {
252 File crashDirectory = getCrashDirectory();
253 if (!crashDirectory.exists()) {
254 Log.w(TAG, crashDirectory.getAbsolutePath() + " does not exist!");
255 return null;
256 }
257 if (!crashDirectory.isDirectory()) {
258 Log.w(TAG, crashDirectory.getAbsolutePath() + " is not a directory!" );
259 return null;
260 }
261 return crashDirectory;
262 }
263
201 public File createNewTempFile(String name) throws IOException { 264 public File createNewTempFile(String name) throws IOException {
202 File f = new File(getCrashDirectory(), name); 265 File f = new File(getCrashDirectory(), name);
203 if (f.exists()) { 266 if (f.exists()) {
204 if (f.delete()) { 267 if (f.delete()) {
205 f = new File(getCrashDirectory(), name); 268 f = new File(getCrashDirectory(), name);
206 } else { 269 } else {
207 Log.w(TAG, "Unable to delete previous logfile" 270 Log.w(TAG, "Unable to delete previous logfile"
208 + f.getAbsolutePath()); 271 + f.getAbsolutePath());
209 } 272 }
210 } 273 }
211 return f; 274 return f;
212 } 275 }
213 276
214 File getCrashFile(String filename) { 277 File getCrashFile(String filename) {
215 return new File(getCrashDirectory(), filename); 278 return new File(getCrashDirectory(), filename);
216 } 279 }
217 280
218 File getCrashUploadLogFile() { 281 File getCrashUploadLogFile() {
219 return new File(mCacheDir, CRASH_DUMP_LOGFILE); 282 return new File(getCrashDirectory(), CRASH_DUMP_LOGFILE);
220 } 283 }
221 284
222 private File[] getAllTempFiles() { 285 private File[] getAllTempFiles() {
223 return getMatchingFiles(TMP_PATTERN); 286 return getMatchingFiles(TMP_PATTERN);
224 } 287 }
225 } 288 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698