• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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