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

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

Issue 2715903003: Bound the impact of system instability on chrome instability. (Closed)
Patch Set: Merge fixups Created 3 years, 9 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 #include "components/browser_watcher/postmortem_report_collector.h" 5 #include "components/browser_watcher/postmortem_report_collector.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/files/file_enumerator.h" 9 #include "base/files/file_enumerator.h"
10 #include "base/files/file_util.h" 10 #include "base/files/file_util.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/metrics/histogram_macros.h" 12 #include "base/metrics/histogram_macros.h"
13 #include "base/path_service.h" 13 #include "base/path_service.h"
14 #include "base/strings/string_piece.h" 14 #include "base/strings/string_piece.h"
15 #include "base/strings/string_util.h" 15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h" 16 #include "base/strings/utf_string_conversions.h"
17 #include "components/browser_watcher/postmortem_minidump_writer.h" 17 #include "components/browser_watcher/postmortem_minidump_writer.h"
18 #include "components/browser_watcher/stability_data_names.h" 18 #include "components/browser_watcher/stability_data_names.h"
19 #include "third_party/crashpad/crashpad/client/settings.h" 19 #include "third_party/crashpad/crashpad/client/settings.h"
20 #include "third_party/crashpad/crashpad/util/misc/uuid.h" 20 #include "third_party/crashpad/crashpad/util/misc/uuid.h"
21 21
22 namespace browser_watcher { 22 namespace browser_watcher {
23 23
24 using base::FilePath; 24 using base::FilePath;
25 using crashpad::CrashReportDatabase; 25 using crashpad::CrashReportDatabase;
26 26
27 namespace {
28
29 // DO NOT CHANGE VALUES. This is logged persistently in a histogram.
30 enum SystemSessionAnalysisStatus {
31 SYSTEM_SESSION_ANALYSIS_SUCCESS = 0,
32 SYSTEM_SESSION_ANALYSIS_NO_TIMESTAMP = 1,
33 SYSTEM_SESSION_ANALYSIS_NO_ANALYZER = 2,
34 SYSTEM_SESSION_ANALYSIS_FAILED = 3,
35 SYSTEM_SESSION_ANALYSIS_OUTSIDE_RANGE = 4,
36 SYSTEM_SESSION_ANALYSIS_STATUS_MAX = 5
37 };
38
39 bool GetStartTimestamp(
40 const google::protobuf::Map<std::string, TypedValue>& global_data,
41 base::Time* time) {
42 DCHECK(time);
43
44 const auto& it = global_data.find(kStabilityStartTimestamp);
45 if (it == global_data.end())
46 return false;
47
48 const TypedValue& value = it->second;
49 if (value.value_case() != TypedValue::kSignedValue)
50 return false;
51
52 *time = base::Time::FromInternalValue(value.signed_value());
53 return true;
54 }
55
56 } // namespace
57
27 PostmortemReportCollector::PostmortemReportCollector( 58 PostmortemReportCollector::PostmortemReportCollector(
28 const std::string& product_name, 59 const std::string& product_name,
29 const std::string& version_number, 60 const std::string& version_number,
30 const std::string& channel_name) 61 const std::string& channel_name,
62 SystemSessionAnalyzer* analyzer)
31 : product_name_(product_name), 63 : product_name_(product_name),
32 version_number_(version_number), 64 version_number_(version_number),
33 channel_name_(channel_name) {} 65 channel_name_(channel_name),
66 system_session_analyzer_(analyzer) {}
34 67
35 PostmortemReportCollector::~PostmortemReportCollector() {} 68 PostmortemReportCollector::~PostmortemReportCollector() {}
36 69
37 int PostmortemReportCollector::CollectAndSubmitForUpload( 70 int PostmortemReportCollector::CollectAndSubmitAllPendingReports(
38 const FilePath& debug_info_dir, 71 const base::FilePath& debug_info_dir,
39 const FilePath::StringType& debug_file_pattern, 72 const base::FilePath::StringType& debug_file_pattern,
40 const std::set<FilePath>& excluded_debug_files, 73 const std::set<base::FilePath>& excluded_debug_files,
41 crashpad::CrashReportDatabase* report_database) { 74 crashpad::CrashReportDatabase* report_database) {
42 DCHECK_NE(true, debug_info_dir.empty()); 75 DCHECK_NE(true, debug_info_dir.empty());
43 DCHECK_NE(true, debug_file_pattern.empty()); 76 DCHECK_NE(true, debug_file_pattern.empty());
44 DCHECK_NE(nullptr, report_database); 77 DCHECK_NE(nullptr, report_database);
45 78
46 // Collect the list of files to harvest. 79 // Collect the list of files to harvest.
47 std::vector<FilePath> debug_files = GetDebugStateFilePaths( 80 std::vector<FilePath> debug_files = GetDebugStateFilePaths(
48 debug_info_dir, debug_file_pattern, excluded_debug_files); 81 debug_info_dir, debug_file_pattern, excluded_debug_files);
49 UMA_HISTOGRAM_COUNTS_100("ActivityTracker.Collect.StabilityFileCount", 82 UMA_HISTOGRAM_COUNTS_100("ActivityTracker.Collect.StabilityFileCount",
50 debug_files.size()); 83 debug_files.size());
51 84
52 // Determine the crashpad client id. 85 // Determine the crashpad client id.
53 crashpad::UUID client_id; 86 crashpad::UUID client_id;
54 crashpad::Settings* settings = report_database->GetSettings(); 87 crashpad::Settings* settings = report_database->GetSettings();
55 if (settings) { 88 if (settings) {
56 // If GetSettings() or GetClientID() fails client_id will be left at its 89 // If GetSettings() or GetClientID() fails client_id will be left at its
57 // default value, all zeroes, which is appropriate. 90 // default value, all zeroes, which is appropriate.
58 settings->GetClientID(&client_id); 91 settings->GetClientID(&client_id);
59 } 92 }
60 93
61 // Process each stability file. 94 // Process each stability file.
62 int success_cnt = 0; 95 int success_cnt = 0;
63 for (const FilePath& file : debug_files) { 96 for (const FilePath& file : debug_files) {
64 CollectionStatus status = 97 CollectionStatus status =
65 CollectAndSubmit(client_id, file, report_database); 98 CollectAndSubmitOneReport(client_id, file, report_database);
66 // TODO(manzagop): consider making this a stability metric. 99 // TODO(manzagop): consider making this a stability metric.
67 UMA_HISTOGRAM_ENUMERATION("ActivityTracker.Collect.Status", status, 100 UMA_HISTOGRAM_ENUMERATION("ActivityTracker.Collect.Status", status,
68 COLLECTION_STATUS_MAX); 101 COLLECTION_STATUS_MAX);
69 if (status == SUCCESS) 102 if (status == SUCCESS)
70 ++success_cnt; 103 ++success_cnt;
71 } 104 }
72 105
73 return success_cnt; 106 return success_cnt;
74 } 107 }
75 108
76 std::vector<FilePath> PostmortemReportCollector::GetDebugStateFilePaths( 109 std::vector<FilePath> PostmortemReportCollector::GetDebugStateFilePaths(
77 const FilePath& debug_info_dir, 110 const FilePath& debug_info_dir,
78 const FilePath::StringType& debug_file_pattern, 111 const FilePath::StringType& debug_file_pattern,
79 const std::set<FilePath>& excluded_debug_files) { 112 const std::set<FilePath>& excluded_debug_files) {
80 DCHECK_NE(true, debug_info_dir.empty()); 113 DCHECK_NE(true, debug_info_dir.empty());
81 DCHECK_NE(true, debug_file_pattern.empty()); 114 DCHECK_NE(true, debug_file_pattern.empty());
82 115
83 std::vector<FilePath> paths; 116 std::vector<FilePath> paths;
84 base::FileEnumerator enumerator(debug_info_dir, false /* recursive */, 117 base::FileEnumerator enumerator(debug_info_dir, false /* recursive */,
85 base::FileEnumerator::FILES, 118 base::FileEnumerator::FILES,
86 debug_file_pattern); 119 debug_file_pattern);
87 FilePath path; 120 FilePath path;
88 for (path = enumerator.Next(); !path.empty(); path = enumerator.Next()) { 121 for (path = enumerator.Next(); !path.empty(); path = enumerator.Next()) {
89 if (excluded_debug_files.find(path) == excluded_debug_files.end()) 122 if (excluded_debug_files.find(path) == excluded_debug_files.end())
90 paths.push_back(path); 123 paths.push_back(path);
91 } 124 }
92 return paths; 125 return paths;
93 } 126 }
94 127
95 CollectionStatus PostmortemReportCollector::CollectAndSubmit( 128 CollectionStatus PostmortemReportCollector::CollectAndSubmitOneReport(
96 const crashpad::UUID& client_id, 129 const crashpad::UUID& client_id,
97 const FilePath& file, 130 const FilePath& file,
98 crashpad::CrashReportDatabase* report_database) { 131 crashpad::CrashReportDatabase* report_database) {
99 DCHECK_NE(nullptr, report_database); 132 DCHECK_NE(nullptr, report_database);
100 133
101 // Note: the code below involves two notions of report: chrome internal state 134 // Note: the code below involves two notions of report: chrome internal state
102 // reports and the crashpad reports they get wrapped into. 135 // reports and the crashpad reports they get wrapped into.
103 136
104 // Collect the data from the debug file to a proto. Note: a non-empty report 137 // Collect the data from the debug file to a proto. Note: a non-empty report
105 // is interpreted here as an unclean exit. 138 // is interpreted here as an unclean exit.
106 StabilityReport report_proto; 139 StabilityReport report_proto;
107 CollectionStatus status = Collect(file, &report_proto); 140 CollectionStatus status = CollectOneReport(file, &report_proto);
108 if (status != SUCCESS) { 141 if (status != SUCCESS) {
109 // The file was empty, or there was an error collecting the data. Detailed 142 // The file was empty, or there was an error collecting the data. Detailed
110 // logging happens within the Collect function. 143 // logging happens within the Collect function.
111 if (!base::DeleteFile(file, false)) 144 if (!base::DeleteFile(file, false))
112 DLOG(ERROR) << "Failed to delete " << file.value(); 145 DLOG(ERROR) << "Failed to delete " << file.value();
113 return status; 146 return status;
114 } 147 }
115 148
116 // Prepare a crashpad report. 149 // Prepare a crashpad report.
117 CrashReportDatabase::NewReport* new_report = nullptr; 150 CrashReportDatabase::NewReport* new_report = nullptr;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 database_status = report_database->FinishedWritingCrashReport( 185 database_status = report_database->FinishedWritingCrashReport(
153 new_report, &unused_report_id); 186 new_report, &unused_report_id);
154 if (database_status != CrashReportDatabase::kNoError) { 187 if (database_status != CrashReportDatabase::kNoError) {
155 DLOG(ERROR) << "FinishedWritingCrashReport failed"; 188 DLOG(ERROR) << "FinishedWritingCrashReport failed";
156 return FINISHED_WRITING_CRASH_REPORT_FAILED; 189 return FINISHED_WRITING_CRASH_REPORT_FAILED;
157 } 190 }
158 191
159 return SUCCESS; 192 return SUCCESS;
160 } 193 }
161 194
162 CollectionStatus PostmortemReportCollector::Collect(const base::FilePath& file, 195 CollectionStatus PostmortemReportCollector::CollectOneReport(
163 StabilityReport* report) { 196 const base::FilePath& file,
197 StabilityReport* report) {
164 DCHECK(report); 198 DCHECK(report);
199
165 CollectionStatus status = Extract(file, report); 200 CollectionStatus status = Extract(file, report);
166 if (status != SUCCESS) 201 if (status != SUCCESS)
167 return status; 202 return status;
168 203
169 // Add the reporter's details to the report. 204 SetReporterDetails(report);
205 RecordSystemShutdownState(report);
206
207 return SUCCESS;
208 }
209
210 void PostmortemReportCollector::SetReporterDetails(
211 StabilityReport* report) const {
212 DCHECK(report);
213
170 google::protobuf::Map<std::string, TypedValue>& global_data = 214 google::protobuf::Map<std::string, TypedValue>& global_data =
171 *(report->mutable_global_data()); 215 *(report->mutable_global_data());
216
217 // Reporter version details. These are useful as the reporter may be of a
218 // different version.
172 global_data[kStabilityReporterChannel].set_string_value(channel_name()); 219 global_data[kStabilityReporterChannel].set_string_value(channel_name());
173 #if defined(ARCH_CPU_X86) 220 #if defined(ARCH_CPU_X86)
174 global_data[kStabilityReporterPlatform].set_string_value( 221 global_data[kStabilityReporterPlatform].set_string_value(
175 std::string("Win32")); 222 std::string("Win32"));
176 #elif defined(ARCH_CPU_X86_64) 223 #elif defined(ARCH_CPU_X86_64)
177 global_data[kStabilityReporterPlatform].set_string_value( 224 global_data[kStabilityReporterPlatform].set_string_value(
178 std::string("Win64")); 225 std::string("Win64"));
179 #endif 226 #endif
180 global_data[kStabilityReporterProduct].set_string_value(product_name()); 227 global_data[kStabilityReporterProduct].set_string_value(product_name());
181 global_data[kStabilityReporterVersion].set_string_value(version_number()); 228 global_data[kStabilityReporterVersion].set_string_value(version_number());
229 }
182 230
183 return SUCCESS; 231 void PostmortemReportCollector::RecordSystemShutdownState(
232 StabilityReport* report) const {
233 DCHECK(report);
234
235 // The session state for the stability report, recorded to provided visibility
236 // into whether the system session was clean.
237 SystemState::SessionState session_state = SystemState::UNKNOWN;
238 // The status of the analysis, recorded to provide insight into the success
239 // or failure of the analysis.
240 SystemSessionAnalysisStatus status = SYSTEM_SESSION_ANALYSIS_SUCCESS;
241
242 base::Time time;
243 if (!GetStartTimestamp(report->global_data(), &time)) {
244 status = SYSTEM_SESSION_ANALYSIS_NO_TIMESTAMP;
245 } else if (!system_session_analyzer_) {
246 status = SYSTEM_SESSION_ANALYSIS_NO_ANALYZER;
247 } else {
248 SystemSessionAnalyzer::Status analyzer_status =
249 system_session_analyzer_->IsSessionUnclean(time);
250 switch (analyzer_status) {
251 case SystemSessionAnalyzer::FAILED:
252 status = SYSTEM_SESSION_ANALYSIS_FAILED;
253 break;
254 case SystemSessionAnalyzer::CLEAN:
255 session_state = SystemState::CLEAN;
256 break;
257 case SystemSessionAnalyzer::UNCLEAN:
258 session_state = SystemState::UNCLEAN;
259 break;
260 case SystemSessionAnalyzer::OUTSIDE_RANGE:
261 status = SYSTEM_SESSION_ANALYSIS_OUTSIDE_RANGE;
262 break;
263 }
264 }
265
266 report->mutable_system_state()->set_session_state(session_state);
267 UMA_HISTOGRAM_ENUMERATION(
268 "ActivityTracker.Collect.SystemSessionAnalysisStatus", status,
269 SYSTEM_SESSION_ANALYSIS_STATUS_MAX);
184 } 270 }
185 271
186 bool PostmortemReportCollector::WriteReportToMinidump( 272 bool PostmortemReportCollector::WriteReportToMinidump(
187 StabilityReport* report, 273 StabilityReport* report,
188 const crashpad::UUID& client_id, 274 const crashpad::UUID& client_id,
189 const crashpad::UUID& report_id, 275 const crashpad::UUID& report_id,
190 base::PlatformFile minidump_file) { 276 base::PlatformFile minidump_file) {
191 DCHECK(report); 277 DCHECK(report);
192 278
193 return WritePostmortemDump(minidump_file, client_id, report_id, report); 279 return WritePostmortemDump(minidump_file, client_id, report_id, report);
194 } 280 }
195 281
196 } // namespace browser_watcher 282 } // namespace browser_watcher
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698