Commit 70d3b4c1 authored by Hazem Ashmawy's avatar Hazem Ashmawy Committed by Commit Bot

Pass crash key-value pairs info from native to CrashFileManager

Pass crash key-value pairs info from native while writing crash reports
as MIME minidumps to CrashFileManager in order to be used later by
WebView to show them in WebView Crash UI.

R=tobiasjs@chromium.org

Bug: 958340
Change-Id: Ib594c0429b3721bb8ee1d5a806fcab094d108842
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1591635
Commit-Queue: Hazem Ashmawy <hazems@chromium.org>
Auto-Submit: Hazem Ashmawy <hazems@chromium.org>
Reviewed-by: default avatarIlya Sherman <isherman@chromium.org>
Reviewed-by: default avatarTobias Sargeant <tobiasjs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#658331}
parent aee8357d
...@@ -20,6 +20,7 @@ import java.util.Arrays; ...@@ -20,6 +20,7 @@ import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Scanner; import java.util.Scanner;
import java.util.UUID; import java.util.UUID;
...@@ -344,6 +345,22 @@ public class CrashFileManager { ...@@ -344,6 +345,22 @@ public class CrashFileManager {
} }
} }
/**
* Imports minidumps from Crashpad's database to the Crash Reports directory, converting them to
* MIME files and returning crash info as key-value pairs.
*
* @return a Map for crash report uuid to this crash info key-value pairs.
*/
public Map<String, Map<String, String>> importMinidumpsCrashKeys() {
File crashpadDir = getCrashpadDirectory();
if (!crashpadDir.exists() || !ensureCrashDirExists()) {
return null;
}
File crashDir = getCrashDirectory();
return CrashReportMimeWriter.rewriteMinidumpsAsMIMEsAndGetCrashKeys(
crashpadDir, crashDir);
}
/** /**
* Returns the most recent minidump without a logcat for a given pid, or null if no such * Returns the most recent minidump without a logcat for a given pid, or null if no such
* minidump exists. This method begins by reading all minidumps from Crashpad's database and * minidump exists. This method begins by reading all minidumps from Crashpad's database and
...@@ -360,8 +377,8 @@ public class CrashFileManager { ...@@ -360,8 +377,8 @@ public class CrashFileManager {
* Returns all minidump files that definitely do not have logcat output, sorted by modification * Returns all minidump files that definitely do not have logcat output, sorted by modification
* time stamp. This method begins by reading all minidumps from Crashpad's database and * time stamp. This method begins by reading all minidumps from Crashpad's database and
* rewriting them as MIME files in the Crash Reports directory. Note: This method does not * rewriting them as MIME files in the Crash Reports directory. Note: This method does not
* provide an "if and only if" test: it may return omit some files that lack logcat output, if * provide an "if and only if" test: it may return some files that lack logcat output, if logcat
* logcat output has been intentionally skipped for those minidumps. However, any files returned * output has been intentionally skipped for those minidumps. However, any files returned
* definitely lack logcat output. * definitely lack logcat output.
*/ */
public File[] getMinidumpsSansLogcat() { public File[] getMinidumpsSansLogcat() {
...@@ -369,6 +386,17 @@ public class CrashFileManager { ...@@ -369,6 +386,17 @@ public class CrashFileManager {
return listCrashFiles(MINIDUMP_SANS_LOGCAT_PATTERN); return listCrashFiles(MINIDUMP_SANS_LOGCAT_PATTERN);
} }
/**
* Returns all minidump files currently in the Crash Reports directory 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 some files that lack logcat output, if logcat outpuy has
* been intentionally skipped for those minidumps. However, any files returned definitely lack
* logcat output.
*/
public File[] getCurrentMinidumpsSansLogcat() {
return listCrashFiles(MINIDUMP_SANS_LOGCAT_PATTERN);
}
/** /**
* Returns all minidump files that could still be uploaded, 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. * Only returns files that we have tried to upload less than {@param maxTries} number of times.
......
...@@ -7,6 +7,8 @@ package org.chromium.components.minidump_uploader; ...@@ -7,6 +7,8 @@ package org.chromium.components.minidump_uploader;
import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.JNINamespace;
import java.io.File; import java.io.File;
import java.util.HashMap;
import java.util.Map;
/** /**
* Rewrites minidumps into MIME messages for uploading. * Rewrites minidumps into MIME messages for uploading.
...@@ -15,6 +17,8 @@ import java.io.File; ...@@ -15,6 +17,8 @@ import java.io.File;
public class CrashReportMimeWriter { public class CrashReportMimeWriter {
private static final String TAG = "CrashReportMimeWriter"; private static final String TAG = "CrashReportMimeWriter";
private static final String MINIDUMP_KEY = "upload_file_minidump";
/* /*
* Rewrites minidumps as MIME multipart messages, extracting embedded Crashpad annotations to * Rewrites minidumps as MIME multipart messages, extracting embedded Crashpad annotations to
* include as form data, and including the original minidump as a file attachment. * include as form data, and including the original minidump as a file attachment.
...@@ -26,5 +30,42 @@ public class CrashReportMimeWriter { ...@@ -26,5 +30,42 @@ public class CrashReportMimeWriter {
nativeRewriteMinidumpsAsMIMEs(srcDir.getAbsolutePath(), destDir.getAbsolutePath()); nativeRewriteMinidumpsAsMIMEs(srcDir.getAbsolutePath(), destDir.getAbsolutePath());
} }
/*
* Rewrites minidumps as MIME multipart messages with the embedded Crashpad annotations included
* as form data and the original minidump as a file attachment. The extracted Crashpad
* annotations for eached minidump file are returned as key-value pairs.
*
* @param srcDir A directory containing a crashpad::CrashReportDatabase.
* @param destDir The directory in which to write the MIME files.
* @return Crashpad annotations as key-value pairs mapped by crash file report UUID.
*/
public static Map<String, Map<String, String>> rewriteMinidumpsAsMIMEsAndGetCrashKeys(
File srcDir, File destDir) {
String[] crashesKeyValueArr = nativeRewriteMinidumpsAsMIMEsAndGetCrashKeys(
srcDir.getAbsolutePath(), destDir.getAbsolutePath());
Map<String, Map<String, String>> crashesInfoMap = new HashMap<>();
Map<String, String> lastCrashInfo = new HashMap<>();
// Keys and values for all crash files are flattened in a String array. Each key is followed
// by its value. If the key is the reserved MINIDUMP_KEY, it marks the end of key-value
// pairs for a crash.
assert (crashesKeyValueArr.length % 2 == 0);
for (int i = 0; i < crashesKeyValueArr.length; i += 2) {
String key = crashesKeyValueArr[i];
String value = crashesKeyValueArr[i + 1];
// MINIDUMP_KEY is a reserved key with crash report uuid as value to be used to group
// key-value pairs for that specific crash.
if (key.equals(MINIDUMP_KEY)) {
crashesInfoMap.put(value, lastCrashInfo);
lastCrashInfo = new HashMap<>();
} else {
lastCrashInfo.put(key, value);
}
}
return crashesInfoMap;
}
private static native void nativeRewriteMinidumpsAsMIMEs(String srcDir, String destDir); private static native void nativeRewriteMinidumpsAsMIMEs(String srcDir, String destDir);
private static native String[] nativeRewriteMinidumpsAsMIMEsAndGetCrashKeys(
String srcDir, String destDir);
} }
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <utility> #include <utility>
#include "base/android/jni_array.h"
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
...@@ -36,31 +37,11 @@ enum class ProcessedMinidumpCounts { ...@@ -36,31 +37,11 @@ enum class ProcessedMinidumpCounts {
}; };
#endif // OS_ANDROID #endif // OS_ANDROID
bool MimeifyReportAndWriteToDirectory( bool MimeifyReportWithKeyValuePairs(
const crashpad::CrashReportDatabase::UploadReport& report, const crashpad::CrashReportDatabase::UploadReport& report,
const base::FilePath& dest_dir) { crashpad::HTTPMultipartBuilder* http_multipart_builder,
crashpad::HTTPMultipartBuilder builder; std::vector<std::string>* crashes_key_value_arr,
pid_t pid; pid_t* pid) {
if (!MimeifyReport(report, &builder, &pid)) {
return false;
}
crashpad::FileWriter writer;
if (!writer.Open(dest_dir.Append(base::StringPrintf(
"%s.dmp%d", report.uuid.ToString().c_str(), pid)),
crashpad::FileWriteMode::kCreateOrFail,
crashpad::FilePermissions::kOwnerOnly)) {
return false;
}
return WriteBodyToFile(builder.GetBodyStream().get(), &writer);
}
} // namespace
bool MimeifyReport(const crashpad::CrashReportDatabase::UploadReport& report,
crashpad::HTTPMultipartBuilder* http_multipart_builder,
pid_t* pid) {
crashpad::FileReader* reader = report.Reader(); crashpad::FileReader* reader = report.Reader();
crashpad::FileOffset start_offset = reader->SeekGet(); crashpad::FileOffset start_offset = reader->SeekGet();
if (start_offset < 0) { if (start_offset < 0) {
...@@ -91,6 +72,10 @@ bool MimeifyReport(const crashpad::CrashReportDatabase::UploadReport& report, ...@@ -91,6 +72,10 @@ bool MimeifyReport(const crashpad::CrashReportDatabase::UploadReport& report,
<< kv.second; << kv.second;
} else { } else {
http_multipart_builder->SetFormData(kv.first, kv.second); http_multipart_builder->SetFormData(kv.first, kv.second);
if (crashes_key_value_arr) {
crashes_key_value_arr->push_back(kv.first);
crashes_key_value_arr->push_back(kv.second);
}
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
if (kv.first == kPtypeKey) { if (kv.first == kPtypeKey) {
const crashpad::ExceptionSnapshot* exception = const crashpad::ExceptionSnapshot* exception =
...@@ -124,6 +109,11 @@ bool MimeifyReport(const crashpad::CrashReportDatabase::UploadReport& report, ...@@ -124,6 +109,11 @@ bool MimeifyReport(const crashpad::CrashReportDatabase::UploadReport& report,
} }
} }
if (crashes_key_value_arr) {
crashes_key_value_arr->push_back(kMinidumpKey);
crashes_key_value_arr->push_back(report.uuid.ToString().c_str());
}
http_multipart_builder->SetFileAttachment(kMinidumpKey, http_multipart_builder->SetFileAttachment(kMinidumpKey,
report.uuid.ToString() + ".dmp", report.uuid.ToString() + ".dmp",
reader, "application/octet-stream"); reader, "application/octet-stream");
...@@ -132,6 +122,37 @@ bool MimeifyReport(const crashpad::CrashReportDatabase::UploadReport& report, ...@@ -132,6 +122,37 @@ bool MimeifyReport(const crashpad::CrashReportDatabase::UploadReport& report,
return true; return true;
} }
bool MimeifyReportAndWriteToDirectory(
const crashpad::CrashReportDatabase::UploadReport& report,
const base::FilePath& dest_dir,
std::vector<std::string>* crashes_key_value_arr) {
crashpad::HTTPMultipartBuilder builder;
pid_t pid;
if (!MimeifyReportWithKeyValuePairs(report, &builder, crashes_key_value_arr,
&pid)) {
return false;
}
crashpad::FileWriter writer;
if (!writer.Open(dest_dir.Append(base::StringPrintf(
"%s.dmp%d", report.uuid.ToString().c_str(), pid)),
crashpad::FileWriteMode::kCreateOrFail,
crashpad::FilePermissions::kOwnerOnly)) {
return false;
}
return WriteBodyToFile(builder.GetBodyStream().get(), &writer);
}
} // namespace
bool MimeifyReport(const crashpad::CrashReportDatabase::UploadReport& report,
crashpad::HTTPMultipartBuilder* http_multipart_builder,
pid_t* pid) {
return MimeifyReportWithKeyValuePairs(report, http_multipart_builder, nullptr,
pid);
}
bool WriteBodyToFile(crashpad::HTTPBodyStream* body, bool WriteBodyToFile(crashpad::HTTPBodyStream* body,
crashpad::FileWriterInterface* writer) { crashpad::FileWriterInterface* writer) {
uint8_t buffer[4096]; uint8_t buffer[4096];
...@@ -143,7 +164,8 @@ bool WriteBodyToFile(crashpad::HTTPBodyStream* body, ...@@ -143,7 +164,8 @@ bool WriteBodyToFile(crashpad::HTTPBodyStream* body,
} }
void RewriteMinidumpsAsMIMEs(const base::FilePath& src_dir, void RewriteMinidumpsAsMIMEs(const base::FilePath& src_dir,
const base::FilePath& dest_dir) { const base::FilePath& dest_dir,
std::vector<std::string>* crashes_key_value_arr) {
std::unique_ptr<crashpad::CrashReportDatabase> db = std::unique_ptr<crashpad::CrashReportDatabase> db =
crashpad::CrashReportDatabase::InitializeWithoutCreating(src_dir); crashpad::CrashReportDatabase::InitializeWithoutCreating(src_dir);
if (!db) { if (!db) {
...@@ -167,7 +189,8 @@ void RewriteMinidumpsAsMIMEs(const base::FilePath& src_dir, ...@@ -167,7 +189,8 @@ void RewriteMinidumpsAsMIMEs(const base::FilePath& src_dir,
continue; continue;
case crashpad::CrashReportDatabase::kNoError: case crashpad::CrashReportDatabase::kNoError:
if (MimeifyReportAndWriteToDirectory(*upload_report.get(), dest_dir)) { if (MimeifyReportAndWriteToDirectory(*upload_report.get(), dest_dir,
crashes_key_value_arr)) {
db->RecordUploadComplete(std::move(upload_report), std::string()); db->RecordUploadComplete(std::move(upload_report), std::string());
} else { } else {
crashpad::Metrics::CrashUploadSkipped( crashpad::Metrics::CrashUploadSkipped(
...@@ -200,7 +223,24 @@ static void JNI_CrashReportMimeWriter_RewriteMinidumpsAsMIMEs( ...@@ -200,7 +223,24 @@ static void JNI_CrashReportMimeWriter_RewriteMinidumpsAsMIMEs(
base::android::ConvertJavaStringToUTF8(env, j_src_dir, &src_dir); base::android::ConvertJavaStringToUTF8(env, j_src_dir, &src_dir);
base::android::ConvertJavaStringToUTF8(env, j_dest_dir, &dest_dir); base::android::ConvertJavaStringToUTF8(env, j_dest_dir, &dest_dir);
RewriteMinidumpsAsMIMEs(base::FilePath(src_dir), base::FilePath(dest_dir)); RewriteMinidumpsAsMIMEs(base::FilePath(src_dir), base::FilePath(dest_dir),
nullptr);
}
static base::android::ScopedJavaLocalRef<jobjectArray>
JNI_CrashReportMimeWriter_RewriteMinidumpsAsMIMEsAndGetCrashKeys(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& j_src_dir,
const base::android::JavaParamRef<jstring>& j_dest_dir) {
std::string src_dir, dest_dir;
base::android::ConvertJavaStringToUTF8(env, j_src_dir, &src_dir);
base::android::ConvertJavaStringToUTF8(env, j_dest_dir, &dest_dir);
std::vector<std::string> key_value_arr;
RewriteMinidumpsAsMIMEs(base::FilePath(src_dir), base::FilePath(dest_dir),
&key_value_arr);
return base::android::ToJavaArrayOfStrings(env, key_value_arr);
} }
} // namespace minidump_uploader } // namespace minidump_uploader
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