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

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

Issue 2722223002: Separate collection logic from the extraction of the report (Closed)
Patch Set: Address Siggi's comments 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
« no previous file with comments | « components/browser_watcher/postmortem_report_extractor.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_extractor.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10 #include <vector>
11
12 #include "base/debug/activity_analyzer.h"
13 #include "base/logging.h"
14 #include "base/strings/string_piece.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "components/browser_watcher/stability_data_names.h"
19 #include "components/variations/active_field_trials.h"
20 #include "third_party/crashpad/crashpad/util/misc/uuid.h"
21
22 namespace browser_watcher {
23
24 using ActivitySnapshot = base::debug::ThreadActivityAnalyzer::Snapshot;
25 using base::debug::ActivityUserData;
26 using base::debug::GlobalActivityAnalyzer;
27 using base::debug::GlobalActivityTracker;
28 using base::debug::ThreadActivityAnalyzer;
29
30 namespace {
31
32 const char kFieldTrialKeyPrefix[] = "FieldTrial.";
33
34 // Collects stability user data from the recorded format to the collected
35 // format.
36 void CollectUserData(
37 const ActivityUserData::Snapshot& recorded_map,
38 google::protobuf::Map<std::string, TypedValue>* collected_map,
39 StabilityReport* report) {
40 DCHECK(collected_map);
41
42 for (const auto& name_and_value : recorded_map) {
43 const std::string& key = name_and_value.first;
44 const ActivityUserData::TypedValue& recorded_value = name_and_value.second;
45 TypedValue collected_value;
46
47 switch (recorded_value.type()) {
48 case ActivityUserData::END_OF_VALUES:
49 NOTREACHED();
50 break;
51 case ActivityUserData::RAW_VALUE: {
52 base::StringPiece raw = recorded_value.Get();
53 collected_value.set_bytes_value(raw.data(), raw.size());
54 break;
55 }
56 case ActivityUserData::RAW_VALUE_REFERENCE: {
57 base::StringPiece recorded_ref = recorded_value.GetReference();
58 TypedValue::Reference* collected_ref =
59 collected_value.mutable_bytes_reference();
60 collected_ref->set_address(
61 reinterpret_cast<uintptr_t>(recorded_ref.data()));
62 collected_ref->set_size(recorded_ref.size());
63 break;
64 }
65 case ActivityUserData::STRING_VALUE: {
66 base::StringPiece value = recorded_value.GetString();
67
68 if (report && base::StartsWith(key, kFieldTrialKeyPrefix,
69 base::CompareCase::SENSITIVE)) {
70 // This entry represents an active Field Trial.
71 std::string trial_name =
72 key.substr(std::strlen(kFieldTrialKeyPrefix));
73 variations::ActiveGroupId group_id =
74 variations::MakeActiveGroupId(trial_name, value.as_string());
75 FieldTrial* field_trial = report->add_field_trials();
76 field_trial->set_name_id(group_id.name);
77 field_trial->set_group_id(group_id.group);
78 continue;
79 }
80
81 collected_value.set_string_value(value.data(), value.size());
82 break;
83 }
84 case ActivityUserData::STRING_VALUE_REFERENCE: {
85 base::StringPiece recorded_ref = recorded_value.GetStringReference();
86 TypedValue::Reference* collected_ref =
87 collected_value.mutable_string_reference();
88 collected_ref->set_address(
89 reinterpret_cast<uintptr_t>(recorded_ref.data()));
90 collected_ref->set_size(recorded_ref.size());
91 break;
92 }
93 case ActivityUserData::CHAR_VALUE: {
94 char char_value = recorded_value.GetChar();
95 collected_value.set_char_value(&char_value, 1);
96 break;
97 }
98 case ActivityUserData::BOOL_VALUE:
99 collected_value.set_bool_value(recorded_value.GetBool());
100 break;
101 case ActivityUserData::SIGNED_VALUE:
102 collected_value.set_signed_value(recorded_value.GetInt());
103 break;
104 case ActivityUserData::UNSIGNED_VALUE:
105 collected_value.set_unsigned_value(recorded_value.GetUint());
106 break;
107 }
108
109 (*collected_map)[key].Swap(&collected_value);
110 }
111 }
112
113 void CollectModuleInformation(
114 const std::vector<GlobalActivityTracker::ModuleInfo>& modules,
115 ProcessState* process_state) {
116 DCHECK(process_state);
117
118 for (const GlobalActivityTracker::ModuleInfo& recorded : modules) {
119 CodeModule* collected = process_state->add_modules();
120 collected->set_base_address(recorded.address);
121 collected->set_size(recorded.size);
122 collected->set_code_file(recorded.file);
123
124 // Compute the code identifier using the required format.
125 std::string code_identifier =
126 base::StringPrintf("%08X%zx", recorded.timestamp, recorded.size);
127 collected->set_code_identifier(code_identifier);
128 collected->set_debug_file(recorded.debug_file);
129
130 // Compute the debug identifier using the required format.
131 const crashpad::UUID* uuid =
132 reinterpret_cast<const crashpad::UUID*>(recorded.identifier);
133 std::string debug_identifier = base::StringPrintf(
134 "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x", uuid->data_1,
135 uuid->data_2, uuid->data_3, uuid->data_4[0], uuid->data_4[1],
136 uuid->data_5[0], uuid->data_5[1], uuid->data_5[2], uuid->data_5[3],
137 uuid->data_5[4], uuid->data_5[5], recorded.age);
138 collected->set_debug_identifier(debug_identifier);
139 collected->set_is_unloaded(!recorded.is_loaded);
140 }
141 }
142
143 void CollectThread(
144 const base::debug::ThreadActivityAnalyzer::Snapshot& snapshot,
145 ThreadState* thread_state) {
146 DCHECK(thread_state);
147
148 thread_state->set_thread_name(snapshot.thread_name);
149 thread_state->set_thread_id(snapshot.thread_id);
150 thread_state->set_activity_count(snapshot.activity_stack_depth);
151
152 for (size_t i = 0; i < snapshot.activity_stack.size(); ++i) {
153 const base::debug::Activity& recorded = snapshot.activity_stack[i];
154 Activity* collected = thread_state->add_activities();
155
156 // Collect activity.
157 switch (recorded.activity_type) {
158 case base::debug::Activity::ACT_TASK_RUN:
159 collected->set_type(Activity::ACT_TASK_RUN);
160 collected->set_origin_address(recorded.origin_address);
161 collected->set_task_sequence_id(recorded.data.task.sequence_id);
162 break;
163 case base::debug::Activity::ACT_LOCK_ACQUIRE:
164 collected->set_type(Activity::ACT_LOCK_ACQUIRE);
165 collected->set_lock_address(recorded.data.lock.lock_address);
166 break;
167 case base::debug::Activity::ACT_EVENT_WAIT:
168 collected->set_type(Activity::ACT_EVENT_WAIT);
169 collected->set_event_address(recorded.data.event.event_address);
170 break;
171 case base::debug::Activity::ACT_THREAD_JOIN:
172 collected->set_type(Activity::ACT_THREAD_JOIN);
173 collected->set_thread_id(recorded.data.thread.thread_id);
174 break;
175 case base::debug::Activity::ACT_PROCESS_WAIT:
176 collected->set_type(Activity::ACT_PROCESS_WAIT);
177 collected->set_process_id(recorded.data.process.process_id);
178 break;
179 default:
180 break;
181 }
182
183 // Collect user data.
184 if (i < snapshot.user_data_stack.size()) {
185 CollectUserData(snapshot.user_data_stack[i],
186 collected->mutable_user_data(), nullptr);
187 }
188 }
189 }
190
191 } // namespace
192
193 CollectionStatus Extract(const base::FilePath& stability_file,
194 StabilityReport* report) {
195 DCHECK(report);
196
197 // Create a global analyzer.
198 std::unique_ptr<GlobalActivityAnalyzer> global_analyzer =
199 GlobalActivityAnalyzer::CreateWithFile(stability_file);
200 if (!global_analyzer)
201 return ANALYZER_CREATION_FAILED;
202
203 // Early exit if there is no data.
204 std::vector<std::string> log_messages = global_analyzer->GetLogMessages();
205 ActivityUserData::Snapshot global_data_snapshot =
206 global_analyzer->GetGlobalUserDataSnapshot();
207 ThreadActivityAnalyzer* thread_analyzer = global_analyzer->GetFirstAnalyzer();
208 if (log_messages.empty() && global_data_snapshot.empty() &&
209 !thread_analyzer) {
210 return DEBUG_FILE_NO_DATA;
211 }
212
213 // Collect log messages.
214 for (const std::string& message : log_messages) {
215 report->add_log_messages(message);
216 }
217
218 // Collect global user data.
219 google::protobuf::Map<std::string, TypedValue>& global_data =
220 *(report->mutable_global_data());
221 CollectUserData(global_data_snapshot, &global_data, report);
222
223 // Collect thread activity data.
224 // Note: a single process is instrumented.
225 ProcessState* process_state = report->add_process_states();
226 for (; thread_analyzer != nullptr;
227 thread_analyzer = global_analyzer->GetNextAnalyzer()) {
228 // Only valid analyzers are expected per contract of GetFirstAnalyzer /
229 // GetNextAnalyzer.
230 DCHECK(thread_analyzer->IsValid());
231
232 if (!process_state->has_process_id()) {
233 process_state->set_process_id(
234 thread_analyzer->activity_snapshot().process_id);
235 }
236 DCHECK_EQ(thread_analyzer->activity_snapshot().process_id,
237 process_state->process_id());
238
239 ThreadState* thread_state = process_state->add_threads();
240 CollectThread(thread_analyzer->activity_snapshot(), thread_state);
241 }
242
243 // Collect module information.
244 CollectModuleInformation(global_analyzer->GetModules(), process_state);
245
246 return SUCCESS;
247 }
248
249 } // namespace browser_watcher
OLDNEW
« no previous file with comments | « components/browser_watcher/postmortem_report_extractor.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698