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

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

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

Powered by Google App Engine
This is Rietveld 408576698