1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/trace_processor/importers/proto/android_probes_parser.h"
18
19 #include <atomic>
20 #include <cinttypes>
21 #include <cstddef>
22 #include <cstdint>
23 #include <cstdlib>
24 #include <cstring>
25 #include <optional>
26
27 #include "perfetto/base/logging.h"
28 #include "perfetto/ext/base/status_or.h"
29 #include "perfetto/ext/base/string_utils.h"
30 #include "perfetto/ext/base/string_view.h"
31 #include "src/trace_processor/importers/common/args_tracker.h"
32 #include "src/trace_processor/importers/common/clock_tracker.h"
33 #include "src/trace_processor/importers/common/event_tracker.h"
34 #include "src/trace_processor/importers/common/metadata_tracker.h"
35 #include "src/trace_processor/importers/common/process_tracker.h"
36 #include "src/trace_processor/importers/common/slice_tracker.h"
37 #include "src/trace_processor/importers/common/track_compressor.h"
38 #include "src/trace_processor/importers/common/track_tracker.h"
39 #include "src/trace_processor/importers/common/tracks.h"
40 #include "src/trace_processor/importers/common/tracks_common.h"
41 #include "src/trace_processor/importers/proto/android_probes_tracker.h"
42 #include "src/trace_processor/storage/metadata.h"
43 #include "src/trace_processor/storage/stats.h"
44 #include "src/trace_processor/storage/trace_storage.h"
45 #include "src/trace_processor/types/trace_processor_context.h"
46 #include "src/trace_processor/types/variadic.h"
47
48 #include "protos/perfetto/common/android_log_constants.pbzero.h"
49 #include "protos/perfetto/common/builtin_clock.pbzero.h"
50 #include "protos/perfetto/config/trace_config.pbzero.h"
51 #include "protos/perfetto/trace/android/android_game_intervention_list.pbzero.h"
52 #include "protos/perfetto/trace/android/android_log.pbzero.h"
53 #include "protos/perfetto/trace/android/android_system_property.pbzero.h"
54 #include "protos/perfetto/trace/android/bluetooth_trace.pbzero.h"
55 #include "protos/perfetto/trace/android/initial_display_state.pbzero.h"
56 #include "protos/perfetto/trace/power/android_energy_estimation_breakdown.pbzero.h"
57 #include "protos/perfetto/trace/power/android_entity_state_residency.pbzero.h"
58 #include "protos/perfetto/trace/power/battery_counters.pbzero.h"
59 #include "protos/perfetto/trace/power/power_rails.pbzero.h"
60
61 namespace perfetto::trace_processor {
62
AndroidProbesParser(TraceProcessorContext * context)63 AndroidProbesParser::AndroidProbesParser(TraceProcessorContext* context)
64 : context_(context),
65 battery_status_id_(context->storage->InternString("BatteryStatus")),
66 plug_type_id_(context->storage->InternString("PlugType")),
67 rail_packet_timestamp_id_(context->storage->InternString("packet_ts")),
68 energy_consumer_id_(
69 context_->storage->InternString("energy_consumer_id")),
70 consumer_type_id_(context_->storage->InternString("consumer_type")),
71 ordinal_id_(context_->storage->InternString("ordinal")),
72 bt_trace_event_id_(
73 context_->storage->InternString("BluetoothTraceEvent")),
74 bt_packet_type_id_(context_->storage->InternString("TracePacketType")),
75 bt_count_id_(context_->storage->InternString("Count")),
76 bt_length_id_(context_->storage->InternString("Length")),
77 bt_op_code_id_(context_->storage->InternString("Op Code")),
78 bt_event_code_id_(context_->storage->InternString("Event Code")),
79 bt_subevent_code_id_(context_->storage->InternString("Subevent Code")),
80 bt_handle_id_(context_->storage->InternString("Handle")) {}
81
ParseBatteryCounters(int64_t ts,ConstBytes blob)82 void AndroidProbesParser::ParseBatteryCounters(int64_t ts, ConstBytes blob) {
83 protos::pbzero::BatteryCounters::Decoder evt(blob);
84 if (evt.has_charge_counter_uah()) {
85 TrackId track = context_->track_tracker->InternTrack(
86 tracks::kBatteryCounterBlueprint,
87 tracks::Dimensions(evt.name(), "charge_uah"));
88 context_->event_tracker->PushCounter(
89 ts, static_cast<double>(evt.charge_counter_uah()), track);
90 } else if (evt.has_energy_counter_uwh() && evt.has_voltage_uv()) {
91 // Calculate charge counter from energy counter and voltage.
92 TrackId track = context_->track_tracker->InternTrack(
93 tracks::kBatteryCounterBlueprint,
94 tracks::Dimensions(evt.name(), "charge_uah"));
95 auto energy = evt.energy_counter_uwh();
96 auto voltage = evt.voltage_uv();
97 if (voltage > 0) {
98 context_->event_tracker->PushCounter(
99 ts, static_cast<double>(energy * 1000000 / voltage), track);
100 }
101 }
102 if (evt.has_capacity_percent()) {
103 TrackId track = context_->track_tracker->InternTrack(
104 tracks::kBatteryCounterBlueprint,
105 tracks::Dimensions(evt.name(), "capacity_pct"));
106 context_->event_tracker->PushCounter(
107 ts, static_cast<double>(evt.capacity_percent()), track);
108 }
109 if (evt.has_current_ua()) {
110 TrackId track = context_->track_tracker->InternTrack(
111 tracks::kBatteryCounterBlueprint,
112 tracks::Dimensions(evt.name(), "current_ua"));
113 context_->event_tracker->PushCounter(
114 ts, static_cast<double>(evt.current_ua()), track);
115 }
116 if (evt.has_current_avg_ua()) {
117 TrackId track = context_->track_tracker->InternTrack(
118 tracks::kBatteryCounterBlueprint,
119 tracks::Dimensions(evt.name(), "current.avg_ua"));
120 context_->event_tracker->PushCounter(
121 ts, static_cast<double>(evt.current_avg_ua()), track);
122 }
123 if (evt.has_voltage_uv()) {
124 TrackId track = context_->track_tracker->InternTrack(
125 tracks::kBatteryCounterBlueprint,
126 tracks::Dimensions(evt.name(), "voltage_uv"));
127 context_->event_tracker->PushCounter(
128 ts, static_cast<double>(evt.voltage_uv()), track);
129 }
130 if (evt.has_current_ua() && evt.has_voltage_uv()) {
131 // Calculate power from current and voltage.
132 TrackId track = context_->track_tracker->InternTrack(
133 tracks::kBatteryCounterBlueprint,
134 tracks::Dimensions(evt.name(), "power_mw"));
135 auto current = evt.current_ua();
136 auto voltage = evt.voltage_uv();
137 // Current is negative when discharging, but we want the power counter to
138 // always be positive, so take the absolute value.
139 auto power = std::abs(static_cast<double>(current * voltage / 1000000000));
140 context_->event_tracker->PushCounter(ts, power, track);
141 }
142 }
143
ParsePowerRails(int64_t ts,uint64_t trace_packet_ts,ConstBytes blob)144 void AndroidProbesParser::ParsePowerRails(int64_t ts,
145 uint64_t trace_packet_ts,
146 ConstBytes blob) {
147 protos::pbzero::PowerRails::Decoder evt(blob);
148
149 // Descriptors should have been processed at tokenization time.
150 PERFETTO_DCHECK(evt.has_energy_data());
151
152 // Because we have some special code in the tokenization phase, we
153 // will only every get one EnergyData message per packet. Therefore,
154 // we can just read the data directly.
155 auto it = evt.energy_data();
156 protos::pbzero::PowerRails::EnergyData::Decoder desc(*it);
157
158 auto* tracker = AndroidProbesTracker::GetOrCreate(context_);
159 auto opt_track = tracker->GetPowerRailTrack(desc.index());
160 if (opt_track.has_value()) {
161 // The tokenization makes sure that this field is always present and
162 // is equal to the packet's timestamp that was passed to us via the sorter.
163 PERFETTO_DCHECK(desc.has_timestamp_ms());
164 PERFETTO_DCHECK(ts / 1000000 == static_cast<int64_t>(desc.timestamp_ms()));
165 auto maybe_counter_id = context_->event_tracker->PushCounter(
166 ts, static_cast<double>(desc.energy()), *opt_track);
167 if (maybe_counter_id) {
168 context_->args_tracker->AddArgsTo(*maybe_counter_id)
169 .AddArg(rail_packet_timestamp_id_,
170 Variadic::UnsignedInteger(trace_packet_ts));
171 }
172 } else {
173 context_->storage->IncrementStats(stats::power_rail_unknown_index);
174 }
175
176 // DCHECK that we only got one message.
177 PERFETTO_DCHECK(!++it);
178 }
179
ParseEnergyBreakdown(int64_t ts,ConstBytes blob)180 void AndroidProbesParser::ParseEnergyBreakdown(int64_t ts, ConstBytes blob) {
181 protos::pbzero::AndroidEnergyEstimationBreakdown::Decoder event(blob);
182 if (!event.has_energy_consumer_id() || !event.has_energy_uws()) {
183 context_->storage->IncrementStats(stats::energy_breakdown_missing_values);
184 return;
185 }
186
187 auto consumer_id = event.energy_consumer_id();
188 auto* tracker = AndroidProbesTracker::GetOrCreate(context_);
189 auto descriptor = tracker->GetEnergyBreakdownDescriptor(consumer_id);
190 if (!descriptor) {
191 context_->storage->IncrementStats(stats::energy_breakdown_missing_values);
192 return;
193 }
194
195 auto total_energy = static_cast<double>(event.energy_uws());
196 static constexpr auto kEnergyConsumerDimension =
197 tracks::UintDimensionBlueprint("energy_consumer_id");
198 static constexpr auto kGlobalBlueprint = tracks::CounterBlueprint(
199 "android_energy_estimation_breakdown", tracks::UnknownUnitBlueprint(),
200 tracks::DimensionBlueprints(kEnergyConsumerDimension),
201 tracks::DynamicNameBlueprint());
202 TrackId energy_track = context_->track_tracker->InternTrack(
203 kGlobalBlueprint, tracks::Dimensions(consumer_id),
204 tracks::DynamicName(descriptor->name),
205 [&](ArgsTracker::BoundInserter& inserter) {
206 inserter.AddArg(consumer_type_id_, Variadic::String(descriptor->type));
207 inserter.AddArg(ordinal_id_, Variadic::Integer(descriptor->ordinal));
208 });
209 context_->event_tracker->PushCounter(ts, total_energy, energy_track);
210
211 // Consumers providing per-uid energy breakdown
212 for (auto it = event.per_uid_breakdown(); it; ++it) {
213 protos::pbzero::AndroidEnergyEstimationBreakdown_EnergyUidBreakdown::Decoder
214 breakdown(*it);
215
216 if (!breakdown.has_uid() || !breakdown.has_energy_uws()) {
217 context_->storage->IncrementStats(
218 stats::energy_uid_breakdown_missing_values);
219 continue;
220 }
221
222 static constexpr auto kUidBlueprint = tracks::CounterBlueprint(
223 "android_energy_estimation_breakdown_per_uid",
224 tracks::UnknownUnitBlueprint(),
225 tracks::DimensionBlueprints(kEnergyConsumerDimension,
226 tracks::kUidDimensionBlueprint),
227 tracks::DynamicNameBlueprint());
228 TrackId energy_uid_track = context_->track_tracker->InternTrack(
229 kUidBlueprint,
230 tracks::Dimensions(consumer_id, static_cast<uint32_t>(breakdown.uid())),
231 tracks::DynamicName(descriptor->name));
232 context_->event_tracker->PushCounter(
233 ts, static_cast<double>(breakdown.energy_uws()), energy_uid_track);
234 }
235 }
236
ParseEntityStateResidency(int64_t ts,ConstBytes blob)237 void AndroidProbesParser::ParseEntityStateResidency(int64_t ts,
238 ConstBytes blob) {
239 protos::pbzero::EntityStateResidency::Decoder event(blob);
240 if (!event.has_residency()) {
241 context_->storage->IncrementStats(stats::entity_state_residency_invalid);
242 return;
243 }
244 static constexpr auto kBlueprint = tracks::CounterBlueprint(
245 "entity_state", tracks::UnknownUnitBlueprint(),
246 tracks::DimensionBlueprints(
247 tracks::StringDimensionBlueprint("entity_name"),
248 tracks::StringDimensionBlueprint("state_name")),
249 tracks::DynamicNameBlueprint());
250 auto* tracker = AndroidProbesTracker::GetOrCreate(context_);
251 for (auto it = event.residency(); it; ++it) {
252 protos::pbzero::EntityStateResidency::StateResidency::Decoder residency(
253 *it);
254 auto entity_state = tracker->GetEntityStateDescriptor(
255 residency.entity_index(), residency.state_index());
256 if (!entity_state) {
257 context_->storage->IncrementStats(
258 stats::entity_state_residency_lookup_failed);
259 return;
260 }
261 TrackId track = context_->track_tracker->InternTrack(
262 kBlueprint,
263 tracks::Dimensions(
264 context_->storage->GetString(entity_state->entity_name),
265 context_->storage->GetString(entity_state->state_name)),
266 tracks::DynamicName(entity_state->overall_name));
267 context_->event_tracker->PushCounter(
268 ts, double(residency.total_time_in_state_ms()), track);
269 }
270 }
271
ParseAndroidLogPacket(ConstBytes blob)272 void AndroidProbesParser::ParseAndroidLogPacket(ConstBytes blob) {
273 protos::pbzero::AndroidLogPacket::Decoder packet(blob);
274 for (auto it = packet.events(); it; ++it)
275 ParseAndroidLogEvent(*it);
276
277 if (packet.has_stats())
278 ParseAndroidLogStats(packet.stats());
279 }
280
ParseAndroidLogEvent(ConstBytes blob)281 void AndroidProbesParser::ParseAndroidLogEvent(ConstBytes blob) {
282 // TODO(primiano): Add events and non-stringified fields to the "raw" table.
283 protos::pbzero::AndroidLogPacket::LogEvent::Decoder evt(blob);
284 auto ts = static_cast<int64_t>(evt.timestamp());
285 auto pid = static_cast<uint32_t>(evt.pid());
286 auto tid = static_cast<uint32_t>(evt.tid());
287 auto prio = static_cast<uint8_t>(evt.prio());
288 StringId tag_id = context_->storage->InternString(
289 evt.has_tag() ? evt.tag() : base::StringView());
290 StringId msg_id = context_->storage->InternString(
291 evt.has_message() ? evt.message() : base::StringView());
292
293 char arg_msg[4096];
294 char* arg_str = &arg_msg[0];
295 *arg_str = '\0';
296 auto arg_avail = [&arg_msg, &arg_str]() {
297 size_t used = static_cast<size_t>(arg_str - arg_msg);
298 PERFETTO_CHECK(used <= sizeof(arg_msg));
299 return sizeof(arg_msg) - used;
300 };
301 for (auto it = evt.args(); it; ++it) {
302 protos::pbzero::AndroidLogPacket::LogEvent::Arg::Decoder arg(*it);
303 if (!arg.has_name())
304 continue;
305 arg_str += base::SprintfTrunc(arg_str, arg_avail(),
306 " %.*s=", static_cast<int>(arg.name().size),
307 arg.name().data);
308 if (arg.has_string_value()) {
309 arg_str += base::SprintfTrunc(arg_str, arg_avail(), "\"%.*s\"",
310 static_cast<int>(arg.string_value().size),
311 arg.string_value().data);
312 } else if (arg.has_int_value()) {
313 arg_str +=
314 base::SprintfTrunc(arg_str, arg_avail(), "%" PRId64, arg.int_value());
315 } else if (arg.has_float_value()) {
316 arg_str += base::SprintfTrunc(arg_str, arg_avail(), "%f",
317 static_cast<double>(arg.float_value()));
318 }
319 }
320
321 if (prio == 0)
322 prio = protos::pbzero::AndroidLogPriority::PRIO_INFO;
323
324 if (arg_str != &arg_msg[0]) {
325 PERFETTO_DCHECK(msg_id.is_null());
326 // Skip the first space char (" foo=1 bar=2" -> "foo=1 bar=2").
327 msg_id = context_->storage->InternString(&arg_msg[1]);
328 }
329 UniquePid utid = tid ? context_->process_tracker->UpdateThread(tid, pid) : 0;
330 base::StatusOr<int64_t> trace_time = context_->clock_tracker->ToTraceTime(
331 protos::pbzero::BUILTIN_CLOCK_REALTIME, ts);
332 if (!trace_time.ok()) {
333 static std::atomic<uint32_t> dlog_count(0);
334 if (dlog_count++ < 10)
335 PERFETTO_DLOG("%s", trace_time.status().c_message());
336 return;
337 }
338
339 // Log events are NOT required to be sorted by trace_time. The virtual table
340 // will take care of sorting on-demand.
341 context_->storage->mutable_android_log_table()->Insert(
342 {trace_time.value(), utid, prio, tag_id, msg_id});
343 }
344
ParseAndroidLogStats(ConstBytes blob)345 void AndroidProbesParser::ParseAndroidLogStats(ConstBytes blob) {
346 protos::pbzero::AndroidLogPacket::Stats::Decoder evt(blob);
347 if (evt.has_num_failed()) {
348 context_->storage->SetStats(stats::android_log_num_failed,
349 static_cast<int64_t>(evt.num_failed()));
350 }
351
352 if (evt.has_num_skipped()) {
353 context_->storage->SetStats(stats::android_log_num_skipped,
354 static_cast<int64_t>(evt.num_skipped()));
355 }
356
357 if (evt.has_num_total()) {
358 context_->storage->SetStats(stats::android_log_num_total,
359 static_cast<int64_t>(evt.num_total()));
360 }
361 }
362
ParseStatsdMetadata(ConstBytes blob)363 void AndroidProbesParser::ParseStatsdMetadata(ConstBytes blob) {
364 protos::pbzero::TraceConfig::StatsdMetadata::Decoder metadata(blob);
365 if (metadata.has_triggering_subscription_id()) {
366 context_->metadata_tracker->SetMetadata(
367 metadata::statsd_triggering_subscription_id,
368 Variadic::Integer(metadata.triggering_subscription_id()));
369 }
370 }
371
ParseAndroidGameIntervention(ConstBytes blob)372 void AndroidProbesParser::ParseAndroidGameIntervention(ConstBytes blob) {
373 protos::pbzero::AndroidGameInterventionList::Decoder intervention_list(blob);
374 constexpr static int kGameModeStandard = 1;
375 constexpr static int kGameModePerformance = 2;
376 constexpr static int kGameModeBattery = 3;
377
378 context_->storage->SetStats(stats::game_intervention_has_read_errors,
379 intervention_list.read_error());
380 context_->storage->SetStats(stats::game_intervention_has_parse_errors,
381 intervention_list.parse_error());
382
383 for (auto pkg_it = intervention_list.game_packages(); pkg_it; ++pkg_it) {
384 protos::pbzero::AndroidGameInterventionList_GamePackageInfo::Decoder
385 game_pkg(*pkg_it);
386 int64_t uid = static_cast<int64_t>(game_pkg.uid());
387 int32_t cur_mode = static_cast<int32_t>(game_pkg.current_mode());
388
389 bool is_standard_mode = false;
390 std::optional<double> standard_downscale;
391 std::optional<int32_t> standard_angle;
392 std::optional<double> standard_fps;
393
394 bool is_performance_mode = false;
395 std::optional<double> perf_downscale;
396 std::optional<int32_t> perf_angle;
397 std::optional<double> perf_fps;
398
399 bool is_battery_mode = false;
400 std::optional<double> battery_downscale;
401 std::optional<int32_t> battery_angle;
402 std::optional<double> battery_fps;
403
404 for (auto mode_it = game_pkg.game_mode_info(); mode_it; ++mode_it) {
405 protos::pbzero::AndroidGameInterventionList_GameModeInfo::Decoder
406 game_mode(*mode_it);
407
408 uint32_t mode_num = game_mode.mode();
409 if (mode_num == kGameModeStandard) {
410 is_standard_mode = true;
411 standard_downscale =
412 static_cast<double>(game_mode.resolution_downscale());
413 standard_angle = game_mode.use_angle();
414 standard_fps = static_cast<double>(game_mode.fps());
415 } else if (mode_num == kGameModePerformance) {
416 is_performance_mode = true;
417 perf_downscale = static_cast<double>(game_mode.resolution_downscale());
418 perf_angle = game_mode.use_angle();
419 perf_fps = static_cast<double>(game_mode.fps());
420 } else if (mode_num == kGameModeBattery) {
421 is_battery_mode = true;
422 battery_downscale =
423 static_cast<double>(game_mode.resolution_downscale());
424 battery_angle = game_mode.use_angle();
425 battery_fps = static_cast<double>(game_mode.fps());
426 }
427 }
428
429 context_->storage->mutable_android_game_intervenion_list_table()->Insert(
430 {context_->storage->InternString(game_pkg.name()), uid, cur_mode,
431 is_standard_mode, standard_downscale, standard_angle, standard_fps,
432 is_performance_mode, perf_downscale, perf_angle, perf_fps,
433 is_battery_mode, battery_downscale, battery_angle, battery_fps});
434 }
435 }
436
ParseInitialDisplayState(int64_t ts,ConstBytes blob)437 void AndroidProbesParser::ParseInitialDisplayState(int64_t ts,
438 ConstBytes blob) {
439 protos::pbzero::InitialDisplayState::Decoder state(blob);
440 TrackId track = context_->track_tracker->InternTrack(
441 tracks::kAndroidScreenStateBlueprint);
442 context_->event_tracker->PushCounter(ts, state.display_state(), track);
443 }
444
ParseAndroidSystemProperty(int64_t ts,ConstBytes blob)445 void AndroidProbesParser::ParseAndroidSystemProperty(int64_t ts,
446 ConstBytes blob) {
447 protos::pbzero::AndroidSystemProperty::Decoder properties(blob);
448 for (auto it = properties.values(); it; ++it) {
449 protos::pbzero::AndroidSystemProperty::PropertyValue::Decoder kv(*it);
450 base::StringView name(kv.name());
451 if (name == "debug.tracing.device_state") {
452 auto state = kv.value();
453 StringId state_id = context_->storage->InternString(state);
454 TrackId track_id = context_->track_tracker->InternTrack(
455 tracks::kAndroidDeviceStateBlueprint);
456 context_->slice_tracker->Scoped(ts, track_id, kNullStringId, state_id, 0);
457 continue;
458 }
459
460 std::optional<int32_t> state =
461 base::StringToInt32(kv.value().ToStdString());
462 if (!state) {
463 continue;
464 }
465
466 // Boot image profiling sysprops are parsed directly into global metadata.
467 // This greatly simplifies identification of associated traces, which
468 // generally have much different performance characteristics. See also
469 // https://source.android.com/docs/core/runtime/boot-image-profiles.
470 if (name == "debug.tracing.profile_boot_classpath") {
471 context_->metadata_tracker->SetMetadata(
472 metadata::android_profile_boot_classpath, Variadic::Integer(*state));
473 continue;
474 } else if (name == "debug.tracing.profile_system_server") {
475 context_->metadata_tracker->SetMetadata(
476 metadata::android_profile_system_server, Variadic::Integer(*state));
477 continue;
478 }
479
480 if (name == "debug.tracing.screen_state") {
481 TrackId track = context_->track_tracker->InternTrack(
482 tracks::kAndroidScreenStateBlueprint);
483 context_->event_tracker->PushCounter(ts, *state, track);
484 continue;
485 }
486
487 static constexpr auto kBlueprint = tracks::CounterBlueprint(
488 "sysprop_counter", tracks::UnknownUnitBlueprint(),
489 tracks::DimensionBlueprints(
490 tracks::StringDimensionBlueprint("sysprop_name")),
491 tracks::DynamicNameBlueprint());
492
493 if (name.StartsWith("debug.tracing.battery_stats.") ||
494 name == "debug.tracing.mcc" || name == "debug.tracing.mnc" ||
495 name == "debug.tracing.desktop_mode_visible_tasks") {
496 StringId name_id = context_->storage->InternString(
497 name.substr(strlen("debug.tracing.")));
498 TrackId track = context_->track_tracker->InternTrack(
499 kBlueprint, tracks::Dimensions(name), tracks::DynamicName(name_id));
500 context_->event_tracker->PushCounter(ts, *state, track);
501 continue;
502 }
503
504 std::optional<StringId> mapped_name_id;
505 if (name == "debug.tracing.battery_status") {
506 mapped_name_id = battery_status_id_;
507 } else if (name == "debug.tracing.plug_type") {
508 mapped_name_id = plug_type_id_;
509 }
510 if (mapped_name_id) {
511 TrackId track = context_->track_tracker->InternTrack(
512 kBlueprint, tracks::Dimensions(name), *mapped_name_id);
513 context_->event_tracker->PushCounter(ts, *state, track);
514 }
515 }
516 }
517
ParseBtTraceEvent(int64_t ts,ConstBytes blob)518 void AndroidProbesParser::ParseBtTraceEvent(int64_t ts, ConstBytes blob) {
519 protos::pbzero::BluetoothTraceEvent::Decoder evt(blob);
520
521 static constexpr auto kBluetoothTraceEventBlueprint = tracks::SliceBlueprint(
522 "bluetooth_trace_event", tracks::DimensionBlueprints(),
523 tracks::StaticNameBlueprint("BluetoothTraceEvent"));
524
525 TrackId track_id =
526 context_->track_tracker->InternTrack(kBluetoothTraceEventBlueprint);
527
528 context_->slice_tracker->Scoped(
529 ts, track_id, kNullStringId, bt_trace_event_id_, evt.duration(),
530 [&evt, this](ArgsTracker::BoundInserter* inserter) {
531 if (evt.has_packet_type()) {
532 StringId packet_type_str = context_->storage->InternString(
533 protos::pbzero::BluetoothTracePacketType_Name(
534 static_cast<
535 ::perfetto::protos::pbzero::BluetoothTracePacketType>(
536 evt.packet_type())));
537 inserter->AddArg(bt_packet_type_id_,
538 Variadic::String(packet_type_str));
539 }
540 if (evt.has_count()) {
541 inserter->AddArg(bt_count_id_,
542 Variadic::UnsignedInteger(evt.count()));
543 }
544 if (evt.has_length()) {
545 inserter->AddArg(bt_length_id_,
546 Variadic::UnsignedInteger(evt.length()));
547 }
548 if (evt.has_op_code()) {
549 inserter->AddArg(bt_op_code_id_,
550 Variadic::UnsignedInteger(evt.op_code()));
551 }
552 if (evt.has_event_code()) {
553 inserter->AddArg(bt_event_code_id_,
554 Variadic::UnsignedInteger(evt.event_code()));
555 }
556 if (evt.has_subevent_code()) {
557 inserter->AddArg(bt_subevent_code_id_,
558 Variadic::UnsignedInteger(evt.subevent_code()));
559 }
560 if (evt.has_connection_handle()) {
561 inserter->AddArg(bt_handle_id_,
562 Variadic::UnsignedInteger(evt.connection_handle()));
563 }
564 });
565 }
566
567 } // namespace perfetto::trace_processor
568