Commit b75db7f4 authored by Hazem Ashmawy's avatar Hazem Ashmawy Committed by Commit Bot

[AW] Get Unuploaded crash files state for crash UI

- Add methods to CrashFileManager to list files with certain upload
  states: forced uploads, skipped upload or ready for upload but not
  forced.
- These methods match the suffix of file names which is used to record
  minidump file upload state.

- Add UnuploadedFilesStateLoader which get the upload state of
  Unuploaded crash files. It uses the newly added methods in
  CrashFileManager.
- This info should be combined with info collected from other logs
  then used in WebView crash UI.

Bug: 964392
Change-Id: Id31013de2dd45235a4a1147591ef3636389b9e89
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1617766
Commit-Queue: Scott Violet <sky@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarTobias Sargeant <tobiasjs@chromium.org>
Auto-Submit: Hazem Ashmawy <hazems@chromium.org>
Cr-Commit-Position: refs/heads/master@{#683693}
parent 78c8feaa
...@@ -879,6 +879,7 @@ android_library("android_webview_java") { ...@@ -879,6 +879,7 @@ android_library("android_webview_java") {
"java/src/org/chromium/android_webview/permission/AwGeolocationCallback.java", "java/src/org/chromium/android_webview/permission/AwGeolocationCallback.java",
"java/src/org/chromium/android_webview/permission/AwPermissionRequest.java", "java/src/org/chromium/android_webview/permission/AwPermissionRequest.java",
"java/src/org/chromium/android_webview/policy/AwPolicyProvider.java", "java/src/org/chromium/android_webview/policy/AwPolicyProvider.java",
"java/src/org/chromium/android_webview/ui/util/UnuploadedFilesStateLoader.java",
"java/src/org/chromium/android_webview/ui/util/UploadedCrashesInfoLoader.java", "java/src/org/chromium/android_webview/ui/util/UploadedCrashesInfoLoader.java",
"java/src/org/chromium/android_webview/ui/util/WebViewCrashLogParser.java", "java/src/org/chromium/android_webview/ui/util/WebViewCrashLogParser.java",
] ]
......
// Copyright 2019 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.android_webview.ui.util;
import org.chromium.components.minidump_uploader.CrashFileManager;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* Gets crashes info about unuploaded minidump files in crash directory.
* Minidump file name contains information about the upload state of the file, its local id and
* number of trials of upload for that report.
*/
public class UnuploadedFilesStateLoader extends CrashInfoLoader {
private CrashFileManager mCrashFileManager;
/**
* @param crashDir the directory where WebView stores crash reports files.
*/
public UnuploadedFilesStateLoader(CrashFileManager crashFileManager) {
mCrashFileManager = crashFileManager;
}
/**
* Get info about unuploaded crash reports and their state.
* Uses file suffixes to get the upload state of a crash report. For more about crash files
* suffixes see docs for {@link CrashFileManager}.
*
* @return list of crashes info.
*/
@Override
public List<CrashInfo> loadCrashesInfo() {
List<CrashInfo> crashes = new ArrayList<>();
for (File file : mCrashFileManager.getMinidumpsNotForcedReadyForUpload()) {
addCrashInfoIfValid(crashes, file.getName(), UploadState.PENDING);
}
for (File file : mCrashFileManager.getMinidumpsForcedUpload()) {
addCrashInfoIfValid(crashes, file.getName(), UploadState.PENDING_USER_REQUESTED);
}
for (File file : mCrashFileManager.getMinidumpsSkippedUpload()) {
addCrashInfoIfValid(crashes, file.getName(), UploadState.SKIPPED);
}
return crashes;
}
private void addCrashInfoIfValid(
List<CrashInfo> crashesList, String fileName, UploadState state) {
String localId = CrashFileManager.getCrashLocalIdFromFileName(fileName);
if (localId != null) {
CrashInfo crashInfo = new CrashInfo(localId);
crashInfo.uploadState = state;
crashesList.add(crashInfo);
}
}
}
// Copyright 2019 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.android_webview.test.ui.util;
import static org.chromium.android_webview.test.OnlyRunIn.ProcessMode.SINGLE_PROCESS;
import android.support.test.filters.SmallTest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.chromium.android_webview.test.AwJUnit4ClassRunner;
import org.chromium.android_webview.test.OnlyRunIn;
import org.chromium.android_webview.ui.util.CrashInfoLoader.CrashInfo;
import org.chromium.android_webview.ui.util.CrashInfoLoader.UploadState;
import org.chromium.android_webview.ui.util.UnuploadedFilesStateLoader;
import org.chromium.components.minidump_uploader.CrashFileManager;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
* Unit tests for UnuploadedFilesStateLoader.
*/
@RunWith(AwJUnit4ClassRunner.class)
@OnlyRunIn(SINGLE_PROCESS)
public class UnuploadedFilesStateLoaderTest {
private static final String LOCAL_ID = "localId1234";
private static final String TEST_FILE_NAME = "test_file-" + LOCAL_ID;
@Rule
public TemporaryFolder mTestCacheDir = new TemporaryFolder();
private File mTestCrashDir;
private CrashFileManager mCrashFileManager;
private UnuploadedFilesStateLoader mCrashInfoLoader;
@Before
public void setup() {
mCrashFileManager = new CrashFileManager(mTestCacheDir.getRoot());
mCrashInfoLoader = new UnuploadedFilesStateLoader(mCrashFileManager);
mTestCrashDir = mCrashFileManager.getCrashDirectory();
mTestCrashDir.mkdirs();
}
@Test
@SmallTest
public void testParseEmptyDir() throws IOException {
List<CrashInfo> crashInfoList = mCrashInfoLoader.loadCrashesInfo();
Assert.assertEquals(0, crashInfoList.size());
}
@Test
@SmallTest
public void testParseSkippedFiles() throws IOException {
new File(mTestCrashDir, TEST_FILE_NAME + ".skipped.try0").createNewFile();
new File(mTestCrashDir, TEST_FILE_NAME + ".skipped5673.try1").createNewFile();
new File(mTestCrashDir, TEST_FILE_NAME + ".skipped5678.try30").createNewFile();
List<CrashInfo> crashInfoList = mCrashInfoLoader.loadCrashesInfo();
Assert.assertEquals(3, crashInfoList.size());
for (CrashInfo crashInfo : crashInfoList) {
Assert.assertEquals(crashInfo.localId, LOCAL_ID);
Assert.assertEquals(crashInfo.uploadState, UploadState.SKIPPED);
}
}
@Test
@SmallTest
public void testParsePendingFiles() throws IOException {
new File(mTestCrashDir, TEST_FILE_NAME + ".dmp.try0").createNewFile();
new File(mTestCrashDir, TEST_FILE_NAME + ".dmp5678.try1").createNewFile();
new File(mTestCrashDir, TEST_FILE_NAME + ".dmp5678.try30").createNewFile();
List<CrashInfo> crashInfoList = mCrashInfoLoader.loadCrashesInfo();
Assert.assertEquals(3, crashInfoList.size());
for (CrashInfo crashInfo : crashInfoList) {
Assert.assertEquals(crashInfo.localId, LOCAL_ID);
Assert.assertEquals(crashInfo.uploadState, UploadState.PENDING);
}
}
@Test
@SmallTest
public void testParseForcedUploadFiles() throws IOException {
new File(mTestCrashDir, TEST_FILE_NAME + ".forced.try0").createNewFile();
new File(mTestCrashDir, TEST_FILE_NAME + ".forced5678.try1").createNewFile();
new File(mTestCrashDir, TEST_FILE_NAME + ".forced5678.try30").createNewFile();
List<CrashInfo> crashInfoList = mCrashInfoLoader.loadCrashesInfo();
Assert.assertEquals(3, crashInfoList.size());
for (CrashInfo crashInfo : crashInfoList) {
Assert.assertEquals(crashInfo.localId, LOCAL_ID);
Assert.assertEquals(crashInfo.uploadState, UploadState.PENDING_USER_REQUESTED);
}
}
@Test
@SmallTest
public void testParseFilesWithInvalidSuffixes() throws IOException {
new File(mTestCrashDir, TEST_FILE_NAME + ".log").createNewFile();
new File(mTestCrashDir, TEST_FILE_NAME + ".json1232").createNewFile();
new File(mTestCrashDir, TEST_FILE_NAME + ".log.try30").createNewFile();
List<CrashInfo> crashInfoList = mCrashInfoLoader.loadCrashesInfo();
Assert.assertEquals(0, crashInfoList.size());
}
}
...@@ -282,6 +282,7 @@ instrumentation_test_apk("webview_instrumentation_test_apk") { ...@@ -282,6 +282,7 @@ instrumentation_test_apk("webview_instrumentation_test_apk") {
"../javatests/src/org/chromium/android_webview/test/services/MockVariationsSeedServer.java", "../javatests/src/org/chromium/android_webview/test/services/MockVariationsSeedServer.java",
"../javatests/src/org/chromium/android_webview/test/services/VariationsSeedServerTest.java", "../javatests/src/org/chromium/android_webview/test/services/VariationsSeedServerTest.java",
"../javatests/src/org/chromium/android_webview/test/services/VisualStateCallbackTest.java", "../javatests/src/org/chromium/android_webview/test/services/VisualStateCallbackTest.java",
"../javatests/src/org/chromium/android_webview/test/ui/util/UnuploadedFilesStateLoaderTest.java",
"../javatests/src/org/chromium/android_webview/test/ui/util/UploadedCrashesInfoLoaderTest.java", "../javatests/src/org/chromium/android_webview/test/ui/util/UploadedCrashesInfoLoaderTest.java",
"../javatests/src/org/chromium/android_webview/test/ui/util/WebViewCrashLogParserTest.java", "../javatests/src/org/chromium/android_webview/test/ui/util/WebViewCrashLogParserTest.java",
"../javatests/src/org/chromium/android_webview/test/util/AwQuotaManagerBridgeTestUtil.java", "../javatests/src/org/chromium/android_webview/test/util/AwQuotaManagerBridgeTestUtil.java",
......
...@@ -65,16 +65,27 @@ public class CrashFileManager { ...@@ -65,16 +65,27 @@ public class CrashFileManager {
// define the id to be a sequence of non separator characters {`-`, `,` or `.`} // define the id to be a sequence of non separator characters {`-`, `,` or `.`}
private static final Pattern CRASH_LOCAL_ID_PATTERN = Pattern.compile("^[^.]+-([^-,]+?)\\."); private static final Pattern CRASH_LOCAL_ID_PATTERN = Pattern.compile("^[^.]+-([^-,]+?)\\.");
// Unlike the MINIDUMP_READY_FOR_UPLOAD_PATTERN below, this pattern omits a ".tryN" suffix. // Unlike the MINIDUMP_ALL_READY_FOR_UPLOAD_PATTERN below, this pattern omits a ".tryN" suffix.
private static final Pattern MINIDUMP_SANS_LOGCAT_PATTERN = private static final Pattern MINIDUMP_SANS_LOGCAT_PATTERN =
Pattern.compile("\\.dmp([0-9]*)\\z"); Pattern.compile("\\.dmp([0-9]*)\\z");
private static final Pattern MINIDUMP_READY_FOR_UPLOAD_PATTERN = // Minidumps that are ready for uploading including forced uploads.
private static final Pattern MINIDUMP_ALL_READY_FOR_UPLOAD_PATTERN =
Pattern.compile("\\.(dmp|forced)([0-9]*)(\\.try([0-9]+))\\z"); Pattern.compile("\\.(dmp|forced)([0-9]*)(\\.try([0-9]+))\\z");
// Minidumps that are ready for uploading excluding forced uploads.
private static final Pattern MINIDUMP_READY_FOR_UPLOAD_PATTERN =
Pattern.compile("\\.(dmp)([0-9]*)(\\.try([0-9]+))\\z");
private static final Pattern UPLOADED_MINIDUMP_PATTERN = private static final Pattern UPLOADED_MINIDUMP_PATTERN =
Pattern.compile("\\.up([0-9]*)(\\.try([0-9]+))\\z"); Pattern.compile("\\.up([0-9]*)(\\.try([0-9]+))\\z");
private static final Pattern MINIDUMP_FORCED_UPLOAD_PATTERN =
Pattern.compile("\\.forced([0-9]*)(\\.try([0-9]+))\\z");
private static final Pattern MINIDUMP_SKIPPED_UPLOAD_PATTERN =
Pattern.compile("\\.skipped([0-9]*)(\\.try([0-9]+))\\z");
private static final String NOT_YET_UPLOADED_MINIDUMP_SUFFIX = ".dmp"; private static final String NOT_YET_UPLOADED_MINIDUMP_SUFFIX = ".dmp";
private static final String UPLOADED_MINIDUMP_SUFFIX = ".up"; private static final String UPLOADED_MINIDUMP_SUFFIX = ".up";
...@@ -408,7 +419,31 @@ public class CrashFileManager { ...@@ -408,7 +419,31 @@ public class CrashFileManager {
* Only returns files that we have tried to upload less than {@param maxTries} number of times. * Only returns files that we have tried to upload less than {@param maxTries} number of times.
*/ */
public File[] getMinidumpsReadyForUpload(int maxTries) { public File[] getMinidumpsReadyForUpload(int maxTries) {
return getFilesBelowMaxTries(listCrashFiles(MINIDUMP_READY_FOR_UPLOAD_PATTERN), maxTries); return getFilesBelowMaxTries(
listCrashFiles(MINIDUMP_ALL_READY_FOR_UPLOAD_PATTERN), maxTries);
}
/**
* Returns minidump files that could still be uploaded excluding forced uploads,
* sorted by modification time stamp.
*/
public File[] getMinidumpsNotForcedReadyForUpload() {
return listCrashFiles(MINIDUMP_READY_FOR_UPLOAD_PATTERN);
}
/**
* Returns all minidump files that could still be uploaded, sorted by modification time stamp.
*/
public File[] getMinidumpsSkippedUpload() {
return listCrashFiles(MINIDUMP_SKIPPED_UPLOAD_PATTERN);
}
/**
* Returns minidump files that are forced to be uploaded by the user, sorted by modification
* time stamp.
*/
public File[] getMinidumpsForcedUpload() {
return listCrashFiles(MINIDUMP_FORCED_UPLOAD_PATTERN);
} }
/** /**
...@@ -596,7 +631,7 @@ public class CrashFileManager { ...@@ -596,7 +631,7 @@ public class CrashFileManager {
* @param uid The uid of the app to check the minidump limit for. * @param uid The uid of the app to check the minidump limit for.
*/ */
private void enforceMinidumpStorageRestrictions(int uid) { private void enforceMinidumpStorageRestrictions(int uid) {
File[] allMinidumpFiles = listCrashFiles(MINIDUMP_READY_FOR_UPLOAD_PATTERN); File[] allMinidumpFiles = listCrashFiles(MINIDUMP_ALL_READY_FOR_UPLOAD_PATTERN);
List<File> minidumpFilesWithCurrentUid = filterMinidumpFilesOnUid(allMinidumpFiles, uid); List<File> minidumpFilesWithCurrentUid = filterMinidumpFilesOnUid(allMinidumpFiles, uid);
// If we have exceeded our cap per uid, delete the oldest minidump of the same uid // If we have exceeded our cap per uid, delete the oldest minidump of the same uid
......
...@@ -325,6 +325,59 @@ public class CrashFileManagerTest { ...@@ -325,6 +325,59 @@ public class CrashFileManagerTest {
actualFiles); actualFiles);
} }
@Test
@SmallTest
@Feature({"Android-AppBase"})
public void testGetMinidumpsNotForcedReadyForUpload() throws IOException {
File forcedFile = new File(mTestRule.getCrashDir(), "456_def.forced" + TEST_PID + ".try2");
forcedFile.createNewFile();
forcedFile.setLastModified(mModificationTimestamp);
mModificationTimestamp += 1000;
CrashFileManager crashFileManager = new CrashFileManager(mTestRule.getCacheDir());
File[] expectedFiles = new File[] {mMultiDigitMaxTriesFile, mOneBelowMultiDigitMaxTriesFile,
mMaxTriesFile, mOneBelowMaxTriesFile, mDmpFile2, mDmpFile1};
File[] actualFiles = crashFileManager.getMinidumpsNotForcedReadyForUpload();
Assert.assertNotNull(actualFiles);
assertArrayEquals("Failed to get the correct minidump files in directory", expectedFiles,
actualFiles);
}
@Test
@SmallTest
@Feature({"Android-AppBase"})
public void testGetMinidumpsSkippedUpload() throws IOException {
File skippedFile =
new File(mTestRule.getCrashDir(), "456_def.skipped" + TEST_PID + ".try2");
skippedFile.createNewFile();
skippedFile.setLastModified(mModificationTimestamp);
mModificationTimestamp += 1000;
CrashFileManager crashFileManager = new CrashFileManager(mTestRule.getCacheDir());
File[] expectedFiles = new File[] {skippedFile};
File[] actualFiles = crashFileManager.getMinidumpsSkippedUpload();
Assert.assertNotNull(actualFiles);
assertArrayEquals("Failed to get the correct minidump files in directory", expectedFiles,
actualFiles);
}
@Test
@SmallTest
@Feature({"Android-AppBase"})
public void testGetMinidumpsForcedUpload() throws IOException {
File forcedFile = new File(mTestRule.getCrashDir(), "456_def.forced" + TEST_PID + ".try2");
forcedFile.createNewFile();
forcedFile.setLastModified(mModificationTimestamp);
mModificationTimestamp += 1000;
CrashFileManager crashFileManager = new CrashFileManager(mTestRule.getCacheDir());
File[] expectedFiles = new File[] {forcedFile};
File[] actualFiles = crashFileManager.getMinidumpsForcedUpload();
Assert.assertNotNull(actualFiles);
assertArrayEquals("Failed to get the correct minidump files in directory", expectedFiles,
actualFiles);
}
@Test @Test
@SmallTest @SmallTest
@Feature({"Android-AppBase"}) @Feature({"Android-AppBase"})
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment