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

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

Issue 2339193003: A collector for postmortem reports (Closed)
Patch Set: 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "components/browser_watcher/postmortem_report_collector.h"
6
7 #include <utility>
8
9 #include "base/debug/activity_analyzer.h"
10 #include "base/files/file_enumerator.h"
11 #include "base/files/file_util.h"
12 #include "base/logging.h"
13 #include "base/path_service.h"
14 #include "components/browser_watcher/postmortem_minidump_writer.h"
15 #include "components/version_info/version_info.h"
16 #include "third_party/crashpad/crashpad/client/settings.h"
17 #include "third_party/crashpad/crashpad/util/misc/uuid.h"
18
19 using base::FilePath;
20
21 namespace browser_watcher {
22
23 using base::debug::GlobalActivityAnalyzer;
24 using base::debug::ThreadActivityAnalyzer;
25 using crashpad::CrashReportDatabase;
26
27 PostmortemReportCollector::PostmortemReportCollector() {}
28
29 // TODO(manzagop): throttling and graceful handling of too much data.
30 int PostmortemReportCollector::CollectAndSubmitForUpload(
31 const base::FilePath& debug_info_dir,
32 const base::FilePath::StringType& debug_file_pattern,
33 const std::set<base::FilePath>& excluded_debug_files,
34 crashpad::CrashReportDatabase* report_database) {
35 DCHECK_NE(true, debug_info_dir.empty());
36 DCHECK_NE(true, debug_file_pattern.empty());
37 DCHECK_NE(nullptr, report_database);
38
39 // Collect the list of files to harvest.
40 std::vector<FilePath> debug_files = GetDebugStateFilePaths(
41 debug_info_dir, debug_file_pattern, excluded_debug_files);
42
43 // Determine the crashpad client id.
44 crashpad::UUID client_id;
45 crashpad::Settings* settings = report_database->GetSettings();
46 if (settings) {
47 // If GetSettings() or GetClientID() fails client_id will be left at its
48 // default value, all zeroes, which is appropriate.
49 settings->GetClientID(&client_id);
50 }
51
52 // The number of postmortem reports recovered irrespective of whether they
53 // were successfully wrapped in a minidump and registered with the reporter.
54 int postmortem_cnt = 0;
55
56 // Note: the code below involves two notions of report:
57 // - crashpad reports
58 // - chrome internal state reports, which are reported wrapped inside a
59 // crashpad report
60 for (const FilePath& file : debug_files) {
61 // Collect the data from the debug file to a proto.
62 std::unique_ptr<StabilityReport> report_proto = Collect(file);
63
64 // If the file cannot be deleted, do not report its contents. This will
65 // cause some under reporting:
66 // - for the contents of a file that cannot be deleted,
67 // - when the report fails to be reported after deletion (e.g. due to
68 // crashpad error or to a crash).
69 // However, under reporting is preferable to the over reporting that would
70 // happen with a file that cannot be deleted.
71 // TODO(manzagop): metrics for the number of non-deletable files and to
72 // track whether reports are lost.
73 if (!base::DeleteFile(file, false)) {
74 LOG(ERROR) << "Failed to delete " << file.value();
75 continue;
76 }
77
78 // The file was empty, or there was an error collecting the data. Detailed
79 // logging happens within the Collect function.
80 if (!report_proto)
81 continue;
82
83 ++postmortem_cnt;
84
85 // Prepare a crashpad report.
86 CrashReportDatabase::NewReport* new_report;
Sigurður Ásgeirsson 2016/09/14 18:04:31 nullme?
manzagop (departed) 2016/09/15 15:07:38 Done.
87 CrashReportDatabase::OperationStatus database_status =
88 report_database->PrepareNewCrashReport(&new_report);
89 if (database_status != CrashReportDatabase::kNoError) {
90 LOG(ERROR) << "PrepareNewCrashReport failed";
91 continue;
92 }
93 CrashReportDatabase::CallErrorWritingCrashReport
94 call_error_writing_crash_report(report_database, new_report);
95
96 // Write the report to a minidump.
97 if (!WriteReportToMinidump(*report_proto, client_id, new_report->uuid,
98 reinterpret_cast<FILE*>(new_report->handle))) {
99 continue;
100 }
101
Sigurður Ásgeirsson 2016/09/14 18:04:31 maybe you want to defer the file delete and bail t
manzagop (departed) 2016/09/15 15:07:38 Done, but I also added a deletion at l.80 for the
102 // Finalize the report wrt the report database.
103 call_error_writing_crash_report.Disarm();
104 crashpad::UUID unused_report_id;
105 database_status = report_database->FinishedWritingCrashReport(
106 new_report, &unused_report_id);
107 if (database_status != CrashReportDatabase::kNoError) {
108 LOG(ERROR) << "FinishedWritingCrashReport failed";
109 continue;
110 }
111 }
112
113 return postmortem_cnt;
114 }
115
116 std::vector<FilePath> PostmortemReportCollector::GetDebugStateFilePaths(
117 const base::FilePath& debug_info_dir,
118 const base::FilePath::StringType& debug_file_pattern,
119 const std::set<FilePath>& excluded_debug_files) {
120 DCHECK_NE(true, debug_info_dir.empty());
121 DCHECK_NE(true, debug_file_pattern.empty());
122
123 std::vector<FilePath> paths;
124 base::FileEnumerator enumerator(debug_info_dir, false /* recursive */,
125 base::FileEnumerator::FILES,
126 debug_file_pattern);
127 FilePath path;
128 for (path = enumerator.Next(); !path.empty(); path = enumerator.Next()) {
129 if (excluded_debug_files.find(path) == excluded_debug_files.end())
130 paths.push_back(path);
131 }
132 return paths;
133 }
134
135 std::unique_ptr<StabilityReport> PostmortemReportCollector::Collect(
136 const base::FilePath& debug_state_file) {
137 // Create a global analyzer.
138 std::unique_ptr<GlobalActivityAnalyzer> global_analyzer =
139 GlobalActivityAnalyzer::CreateWithFile(debug_state_file);
140 if (!global_analyzer)
141 return nullptr;
142
143 // Early exit if there is no data.
144 ThreadActivityAnalyzer* thread_analyzer = global_analyzer->GetFirstAnalyzer();
145 if (!thread_analyzer) {
146 // No data. This case happens in the case of a clean exit.
147 return nullptr;
148 }
149
150 // Iterate through the thread analyzers, fleshing out the report.
151 std::unique_ptr<StabilityReport> report(new StabilityReport());
152 ProcessState* process_state = report->add_process_states();
153
154 while (thread_analyzer) {
155 // Only valid analyzers are expected.
156 DCHECK(thread_analyzer->IsValid());
Sigurður Ásgeirsson 2016/09/14 18:04:30 why is this - do they only become invalid on a rac
manzagop (departed) 2016/09/15 15:07:38 An analyzer is valid or invalid from construction
157
158 ThreadState* thread_state = process_state->add_threads();
159 thread_state->set_thread_name(thread_analyzer->GetThreadName());
160
161 // TODO(manzagop): flesh this out.
162
163 thread_analyzer = global_analyzer->GetNextAnalyzer();
164 }
165
166 return report;
167 }
168
169 bool PostmortemReportCollector::WriteReportToMinidump(
170 const StabilityReport& report,
171 const crashpad::UUID& client_id,
172 const crashpad::UUID& report_id,
173 base::PlatformFile minidump_file) {
174 MinidumpInfo mindump_info;
175 mindump_info.client_id = client_id;
176 mindump_info.report_id = report_id;
177 mindump_info.product_name = version_info::GetProductName();
178 mindump_info.version_number = version_info::GetVersionNumber();
179
180 return WritePostmortemDump(minidump_file, report, mindump_info);
181 }
182
183 } // namespace browser_watcher
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698