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

Side by Side Diff: components/browser_watcher/postmortem_minidump_writer_win.cc

Issue 2685053003: Switch stability reports to use the crashed version's details (Closed)
Patch Set: Missing BUILD dependencies Created 3 years, 10 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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 // Note: aside from using windows headers to obtain the definitions of minidump 5 // Note: aside from using windows headers to obtain the definitions of minidump
6 // structures, nothing here is windows specific. This seems like the best 6 // structures, nothing here is windows specific. This seems like the best
7 // approach given this code is for temporary experimentation on Windows. 7 // approach given this code is for temporary experimentation on Windows.
8 // Longer term, Crashpad will take over the minidump writing in this case as 8 // Longer term, Crashpad will take over the minidump writing in this case as
9 // well. 9 // well.
10 10
11 #include "components/browser_watcher/postmortem_minidump_writer.h" 11 #include "components/browser_watcher/postmortem_minidump_writer.h"
12 12
13 #include <windows.h> // NOLINT 13 #include <windows.h> // NOLINT
14 #include <dbghelp.h> 14 #include <dbghelp.h>
15 15
16 #include <map> 16 #include <map>
17 #include <type_traits> 17 #include <type_traits>
18 #include <vector> 18 #include <vector>
19 19
20 #include "base/files/file_util.h" 20 #include "base/files/file_util.h"
21 #include "base/macros.h" 21 #include "base/macros.h"
22 #include "base/metrics/histogram_macros.h"
22 #include "base/numerics/safe_math.h" 23 #include "base/numerics/safe_math.h"
23 #include "base/strings/string_piece.h" 24 #include "base/strings/string_piece.h"
25 #include "components/browser_watcher/stability_data_names.h"
24 #include "third_party/crashpad/crashpad/minidump/minidump_extensions.h" 26 #include "third_party/crashpad/crashpad/minidump/minidump_extensions.h"
25 27
26 namespace browser_watcher { 28 namespace browser_watcher {
27 29
28 namespace { 30 namespace {
29 31
30 // The stream type assigned to the minidump stream that holds the serialized 32 // The stream type assigned to the minidump stream that holds the serialized
31 // stability report. 33 // stability report.
32 // Note: the value was obtained by adding 1 to the stream type used for holding 34 // Note: the value was obtained by adding 1 to the stream type used for holding
33 // the SyzyAsan proto. 35 // the SyzyAsan proto.
34 // TODO(manzagop): centralize the stream type definitions to avoid issues. 36 // TODO(manzagop): centralize the stream type definitions to avoid issues.
35 const uint32_t kStabilityReportStreamType = 0x4B6B0002; 37 const uint32_t kStabilityReportStreamType = 0x4B6B0002;
36 38
39 struct ProductDetails {
40 std::string product;
41 std::string channel;
42 std::string platform;
43 std::string version;
44 };
45
46 bool GetStringFromTypedValueMap(
47 const google::protobuf::Map<std::string, TypedValue>& map,
48 const std::string& key,
49 std::string* out) {
50 DCHECK(out);
51
52 auto it = map.find(key);
53 if (it == map.end())
54 return false;
55
56 const TypedValue& value = it->second;
57 if (value.value_case() != TypedValue::kStringValue)
58 return false;
59
60 *out = value.string_value();
61 return true;
62 }
63
64 bool GetProductDetails(
65 const google::protobuf::Map<std::string, TypedValue>& global_data,
66 ProductDetails* product_details) {
67 DCHECK(product_details);
68
69 if (!GetStringFromTypedValueMap(global_data, kStabilityProduct,
70 &(product_details->product)))
71 return false;
bcwhite 2017/02/13 13:16:59 Is it possible to fetch only partial data? Would
manzagop (departed) 2017/02/13 17:07:45 Missing fields are unlikely (all 4 are recorded as
72 if (!GetStringFromTypedValueMap(global_data, kStabilityChannel,
73 &(product_details->channel)))
74 return false;
75 if (!GetStringFromTypedValueMap(global_data, kStabilityPlatform,
76 &(product_details->platform)))
77 return false;
78 return GetStringFromTypedValueMap(global_data, kStabilityVersion,
79 &(product_details->version));
80 }
81
37 int64_t GetFileOffset(base::File* file) { 82 int64_t GetFileOffset(base::File* file) {
38 DCHECK(file); 83 DCHECK(file);
39 return file->Seek(base::File::FROM_CURRENT, 0LL); 84 return file->Seek(base::File::FROM_CURRENT, 0LL);
40 } 85 }
41 86
42 // Returns true if the file is empty, and false if the file is not empty or if 87 // Returns true if the file is empty, and false if the file is not empty or if
43 // there is an error. 88 // there is an error.
44 bool IsFileEmpty(base::File* file) { 89 bool IsFileEmpty(base::File* file) {
45 DCHECK(file); 90 DCHECK(file);
46 int64_t end = file->Seek(base::File::FROM_END, 0LL); 91 int64_t end = file->Seek(base::File::FROM_END, 0LL);
(...skipping 10 matching lines...) Expand all
57 public: 102 public:
58 PostmortemMinidumpWriter(); 103 PostmortemMinidumpWriter();
59 ~PostmortemMinidumpWriter(); 104 ~PostmortemMinidumpWriter();
60 105
61 // Write to |minidump_file| a minimal minidump that wraps |report|. Returns 106 // Write to |minidump_file| a minimal minidump that wraps |report|. Returns
62 // true on success, false otherwise. 107 // true on success, false otherwise.
63 // Note: the caller owns |minidump_file| and is responsible for keeping it 108 // Note: the caller owns |minidump_file| and is responsible for keeping it
64 // valid for this object's lifetime. |minidump_file| is expected to be empty 109 // valid for this object's lifetime. |minidump_file| is expected to be empty
65 // and a binary stream. 110 // and a binary stream.
66 bool WriteDump(base::PlatformFile minidump_file, 111 bool WriteDump(base::PlatformFile minidump_file,
67 const StabilityReport& report, 112 const crashpad::UUID& client_id,
68 const MinidumpInfo& minidump_info); 113 const crashpad::UUID& report_id,
114 StabilityReport* report);
69 115
70 private: 116 private:
71 // An offset within a minidump file. Note: using this type to avoid including 117 // An offset within a minidump file. Note: using this type to avoid including
72 // windows.h and relying on the RVA type. 118 // windows.h and relying on the RVA type.
73 using FilePosition = uint32_t; 119 using FilePosition = uint32_t;
74 120
75 // The minidump header is always located at the head. 121 // The minidump header is always located at the head.
76 static const FilePosition kHeaderPos = 0U; 122 static const FilePosition kHeaderPos = 0U;
77 123
78 bool WriteDumpImpl(const StabilityReport& report, 124 bool WriteDumpImpl(const StabilityReport& report,
79 const MinidumpInfo& minidump_info); 125 const crashpad::UUID& client_id,
126 const crashpad::UUID& report_id,
127 const ProductDetails& product_details);
80 128
81 bool AppendCrashpadInfo(const crashpad::UUID& client_id, 129 bool AppendCrashpadInfo(const crashpad::UUID& client_id,
82 const crashpad::UUID& report_id, 130 const crashpad::UUID& report_id,
83 const std::map<std::string, std::string>& crash_keys); 131 const std::map<std::string, std::string>& crash_keys);
84 132
85 bool AppendCrashpadDictionaryEntry( 133 bool AppendCrashpadDictionaryEntry(
86 const std::string& key, 134 const std::string& key,
87 const std::string& value, 135 const std::string& value,
88 std::vector<crashpad::MinidumpSimpleStringDictionaryEntry>* entries); 136 std::vector<crashpad::MinidumpSimpleStringDictionaryEntry>* entries);
89 137
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 178
131 PostmortemMinidumpWriter::PostmortemMinidumpWriter() 179 PostmortemMinidumpWriter::PostmortemMinidumpWriter()
132 : next_available_byte_(0U), minidump_file_(nullptr) {} 180 : next_available_byte_(0U), minidump_file_(nullptr) {}
133 181
134 PostmortemMinidumpWriter::~PostmortemMinidumpWriter() { 182 PostmortemMinidumpWriter::~PostmortemMinidumpWriter() {
135 DCHECK_EQ(nullptr, minidump_file_); 183 DCHECK_EQ(nullptr, minidump_file_);
136 } 184 }
137 185
138 bool PostmortemMinidumpWriter::WriteDump( 186 bool PostmortemMinidumpWriter::WriteDump(
139 base::PlatformFile minidump_platform_file, 187 base::PlatformFile minidump_platform_file,
140 const StabilityReport& report, 188 const crashpad::UUID& client_id,
141 const MinidumpInfo& minidump_info) { 189 const crashpad::UUID& report_id,
190 StabilityReport* report) {
142 DCHECK_NE(base::kInvalidPlatformFile, minidump_platform_file); 191 DCHECK_NE(base::kInvalidPlatformFile, minidump_platform_file);
192 DCHECK(report);
143 193
144 DCHECK_EQ(0U, next_available_byte_); 194 DCHECK_EQ(0U, next_available_byte_);
145 DCHECK(directory_.empty()); 195 DCHECK(directory_.empty());
146 DCHECK_EQ(nullptr, minidump_file_); 196 DCHECK_EQ(nullptr, minidump_file_);
147 197
198 // Ensure the report contains the crasher's product details.
199 ProductDetails product_details = {};
200 if (!GetProductDetails(report->global_data(), &product_details)) {
201 // The report is missing the basic information to determine the affected
202 // version. Ignore the report.
203 UMA_HISTOGRAM_COUNTS_100("ActivityTracker.Collect.MissingProductDetails",
204 1);
205 return false;
206 }
207
208 // No need to keep the version details inside the report.
209 report->mutable_global_data()->erase(kStabilityProduct);
210 report->mutable_global_data()->erase(kStabilityChannel);
211 report->mutable_global_data()->erase(kStabilityPlatform);
212 report->mutable_global_data()->erase(kStabilityVersion);
213
148 // We do not own |minidump_platform_file|, but we want to rely on base::File's 214 // We do not own |minidump_platform_file|, but we want to rely on base::File's
149 // API, and so we need to duplicate it. 215 // API, and so we need to duplicate it.
150 HANDLE duplicated_handle; 216 HANDLE duplicated_handle;
151 BOOL duplicate_success = ::DuplicateHandle( 217 BOOL duplicate_success = ::DuplicateHandle(
152 ::GetCurrentProcess(), minidump_platform_file, ::GetCurrentProcess(), 218 ::GetCurrentProcess(), minidump_platform_file, ::GetCurrentProcess(),
153 &duplicated_handle, 0, FALSE, DUPLICATE_SAME_ACCESS); 219 &duplicated_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
154 if (!duplicate_success) 220 if (!duplicate_success)
155 return false; 221 return false;
156 base::File minidump_file(duplicated_handle); 222 base::File minidump_file(duplicated_handle);
157 DCHECK(minidump_file.IsValid()); 223 DCHECK(minidump_file.IsValid());
158 minidump_file_ = &minidump_file; 224 minidump_file_ = &minidump_file;
159 DCHECK_EQ(0LL, GetFileOffset(minidump_file_)); 225 DCHECK_EQ(0LL, GetFileOffset(minidump_file_));
160 DCHECK(IsFileEmpty(minidump_file_)); 226 DCHECK(IsFileEmpty(minidump_file_));
161 227
162 // Write the minidump, then reset members. 228 // Write the minidump, then reset members.
163 bool success = WriteDumpImpl(report, minidump_info); 229 bool success = WriteDumpImpl(*report, client_id, report_id, product_details);
164 next_available_byte_ = 0U; 230 next_available_byte_ = 0U;
165 directory_.clear(); 231 directory_.clear();
166 minidump_file_ = nullptr; 232 minidump_file_ = nullptr;
167 233
168 return success; 234 return success;
169 } 235 }
170 236
171 bool PostmortemMinidumpWriter::WriteDumpImpl( 237 bool PostmortemMinidumpWriter::WriteDumpImpl(
172 const StabilityReport& report, 238 const StabilityReport& report,
173 const MinidumpInfo& minidump_info) { 239 const crashpad::UUID& client_id,
240 const crashpad::UUID& report_id,
241 const ProductDetails& product_details) {
174 // Allocate space for the header and seek the cursor. 242 // Allocate space for the header and seek the cursor.
175 FilePosition pos = 0U; 243 FilePosition pos = 0U;
176 if (!Allocate(sizeof(MINIDUMP_HEADER), &pos)) 244 if (!Allocate(sizeof(MINIDUMP_HEADER), &pos))
177 return false; 245 return false;
178 if (!SeekCursor(sizeof(MINIDUMP_HEADER))) 246 if (!SeekCursor(sizeof(MINIDUMP_HEADER)))
179 return false; 247 return false;
180 DCHECK_EQ(kHeaderPos, pos); 248 DCHECK_EQ(kHeaderPos, pos);
181 249
182 // Write the proto to the file. 250 // Write the proto to the file.
183 std::string serialized_report; 251 std::string serialized_report;
184 if (!report.SerializeToString(&serialized_report)) 252 if (!report.SerializeToString(&serialized_report))
185 return false; 253 return false;
186 FilePosition report_pos = 0U; 254 FilePosition report_pos = 0U;
187 if (!AppendBytes(serialized_report, &report_pos)) 255 if (!AppendBytes(serialized_report, &report_pos))
188 return false; 256 return false;
189 257
190 // The directory entry for the stability report's stream. 258 // The directory entry for the stability report's stream.
191 RegisterDirectoryEntry(kStabilityReportStreamType, report_pos, 259 RegisterDirectoryEntry(kStabilityReportStreamType, report_pos,
192 serialized_report.length()); 260 serialized_report.length());
193 261
194 // Write mandatory crash keys. These will be read by crashpad and used as 262 // Write mandatory crash keys. These will be read by crashpad and used as
195 // http request parameters for the upload. Keys and values should match 263 // http request parameters for the upload. Keys and values should match
196 // server side configuration. 264 // server side configuration.
197 // TODO(manzagop): use product and version from the stability report. The 265 // TODO(manzagop): use product and version from the stability report. The
198 // current executable's values are an (imperfect) proxy. 266 // current executable's values are an (imperfect) proxy.
199 std::map<std::string, std::string> crash_keys = { 267 std::map<std::string, std::string> crash_keys = {
200 {"prod", minidump_info.product_name + "_Postmortem"}, 268 {"prod", product_details.product + "_Postmortem"},
201 {"ver", minidump_info.version_number}, 269 {"ver", product_details.version},
202 {"channel", minidump_info.channel_name}, 270 {"channel", product_details.channel},
203 {"plat", minidump_info.platform}}; 271 {"plat", product_details.platform}};
204 if (!AppendCrashpadInfo(minidump_info.client_id, minidump_info.report_id, 272 if (!AppendCrashpadInfo(client_id, report_id, crash_keys))
205 crash_keys))
206 return false; 273 return false;
207 274
208 // Write the directory. 275 // Write the directory.
209 FilePosition directory_pos = 0U; 276 FilePosition directory_pos = 0U;
210 if (!AppendVec(directory_, &directory_pos)) 277 if (!AppendVec(directory_, &directory_pos))
211 return false; 278 return false;
212 279
213 // Write the header. 280 // Write the header.
214 MINIDUMP_HEADER header; 281 MINIDUMP_HEADER header;
215 header.Signature = MINIDUMP_SIGNATURE; 282 header.Signature = MINIDUMP_SIGNATURE;
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 uint32_t size) { 465 uint32_t size) {
399 MINIDUMP_DIRECTORY entry = {0}; 466 MINIDUMP_DIRECTORY entry = {0};
400 entry.StreamType = stream_type; 467 entry.StreamType = stream_type;
401 entry.Location.Rva = pos; 468 entry.Location.Rva = pos;
402 entry.Location.DataSize = size; 469 entry.Location.DataSize = size;
403 directory_.push_back(entry); 470 directory_.push_back(entry);
404 } 471 }
405 472
406 } // namespace 473 } // namespace
407 474
408 MinidumpInfo::MinidumpInfo() {} 475 bool WritePostmortemDump(base::PlatformFile minidump_file,
476 const crashpad::UUID& client_id,
477 const crashpad::UUID& report_id,
478 StabilityReport* report) {
479 DCHECK(report);
409 480
410 MinidumpInfo::~MinidumpInfo() {}
411
412 bool WritePostmortemDump(base::PlatformFile minidump_file,
413 const StabilityReport& report,
414 const MinidumpInfo& minidump_info) {
415 PostmortemMinidumpWriter writer; 481 PostmortemMinidumpWriter writer;
416 return writer.WriteDump(minidump_file, report, minidump_info); 482 return writer.WriteDump(minidump_file, client_id, report_id, report);
417 } 483 }
418 484
419 } // namespace browser_watcher 485 } // namespace browser_watcher
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698