• 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 <optional>
20 
21 #include "perfetto/ext/base/string_utils.h"
22 #include "perfetto/ext/traced/sys_stats_counters.h"
23 #include "src/trace_processor/importers/common/args_tracker.h"
24 #include "src/trace_processor/importers/common/async_track_set_tracker.h"
25 #include "src/trace_processor/importers/common/clock_tracker.h"
26 #include "src/trace_processor/importers/common/event_tracker.h"
27 #include "src/trace_processor/importers/common/metadata_tracker.h"
28 #include "src/trace_processor/importers/common/process_tracker.h"
29 #include "src/trace_processor/importers/syscalls/syscall_tracker.h"
30 #include "src/trace_processor/types/tcp_state.h"
31 #include "src/trace_processor/types/trace_processor_context.h"
32 
33 #include "protos/perfetto/common/android_energy_consumer_descriptor.pbzero.h"
34 #include "protos/perfetto/common/android_log_constants.pbzero.h"
35 #include "protos/perfetto/common/builtin_clock.pbzero.h"
36 #include "protos/perfetto/config/trace_config.pbzero.h"
37 #include "protos/perfetto/trace/android/android_game_intervention_list.pbzero.h"
38 #include "protos/perfetto/trace/android/android_log.pbzero.h"
39 #include "protos/perfetto/trace/android/android_system_property.pbzero.h"
40 #include "protos/perfetto/trace/android/initial_display_state.pbzero.h"
41 #include "protos/perfetto/trace/power/android_energy_estimation_breakdown.pbzero.h"
42 #include "protos/perfetto/trace/power/android_entity_state_residency.pbzero.h"
43 #include "protos/perfetto/trace/power/battery_counters.pbzero.h"
44 #include "protos/perfetto/trace/power/power_rails.pbzero.h"
45 #include "protos/perfetto/trace/ps/process_stats.pbzero.h"
46 #include "protos/perfetto/trace/ps/process_tree.pbzero.h"
47 #include "protos/perfetto/trace/sys_stats/sys_stats.pbzero.h"
48 #include "protos/perfetto/trace/system_info.pbzero.h"
49 
50 #include "src/trace_processor/importers/proto/android_probes_tracker.h"
51 
52 namespace perfetto {
53 namespace trace_processor {
54 
AndroidProbesParser(TraceProcessorContext * context)55 AndroidProbesParser::AndroidProbesParser(TraceProcessorContext* context)
56     : context_(context),
57       batt_charge_id_(context->storage->InternString("batt.charge_uah")),
58       batt_capacity_id_(context->storage->InternString("batt.capacity_pct")),
59       batt_current_id_(context->storage->InternString("batt.current_ua")),
60       batt_current_avg_id_(
61           context->storage->InternString("batt.current.avg_ua")),
62       batt_voltage_id_(context->storage->InternString("batt.voltage_uv")),
63       screen_state_id_(context->storage->InternString("ScreenState")),
64       device_state_id_(context->storage->InternString("DeviceStateChanged")),
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 
ParseBatteryCounters(int64_t ts,ConstBytes blob)69 void AndroidProbesParser::ParseBatteryCounters(int64_t ts, ConstBytes blob) {
70   protos::pbzero::BatteryCounters::Decoder evt(blob.data, blob.size);
71   StringId batt_charge_id = batt_charge_id_;
72   StringId batt_capacity_id = batt_capacity_id_;
73   StringId batt_current_id = batt_current_id_;
74   StringId batt_current_avg_id = batt_current_avg_id_;
75   StringId batt_voltage_id = batt_voltage_id_;
76   if (evt.has_name()) {
77     std::string batt_name = evt.name().ToStdString();
78     batt_charge_id = context_->storage->InternString(base::StringView(
79         std::string("batt.").append(batt_name).append(".charge_uah")));
80     batt_capacity_id = context_->storage->InternString(base::StringView(
81         std::string("batt.").append(batt_name).append(".capacity_pct")));
82     batt_current_id = context_->storage->InternString(base::StringView(
83         std::string("batt.").append(batt_name).append(".current_ua")));
84     batt_current_avg_id = context_->storage->InternString(base::StringView(
85         std::string("batt.").append(batt_name).append(".current.avg_ua")));
86     batt_voltage_id = context_->storage->InternString(base::StringView(
87         std::string("batt.").append(batt_name).append(".voltage_uv")));
88   }
89   if (evt.has_charge_counter_uah()) {
90     TrackId track = context_->track_tracker->InternGlobalCounterTrack(
91         TrackTracker::Group::kPower, batt_charge_id);
92     context_->event_tracker->PushCounter(
93         ts, static_cast<double>(evt.charge_counter_uah()), track);
94   } else if (evt.has_energy_counter_uwh() && evt.has_voltage_uv()) {
95     // Calculate charge counter from energy counter and voltage.
96     TrackId track = context_->track_tracker->InternGlobalCounterTrack(
97         TrackTracker::Group::kPower, batt_charge_id);
98     auto energy = evt.energy_counter_uwh();
99     auto voltage = evt.voltage_uv();
100     if (voltage > 0) {
101       context_->event_tracker->PushCounter(
102           ts, static_cast<double>(energy * 1000000 / voltage), track);
103     }
104   }
105 
106   if (evt.has_capacity_percent()) {
107     TrackId track = context_->track_tracker->InternGlobalCounterTrack(
108         TrackTracker::Group::kPower, batt_capacity_id);
109     context_->event_tracker->PushCounter(
110         ts, static_cast<double>(evt.capacity_percent()), track);
111   }
112   if (evt.has_current_ua()) {
113     TrackId track = context_->track_tracker->InternGlobalCounterTrack(
114         TrackTracker::Group::kPower, batt_current_id);
115     context_->event_tracker->PushCounter(
116         ts, static_cast<double>(evt.current_ua()), track);
117   }
118   if (evt.has_current_avg_ua()) {
119     TrackId track = context_->track_tracker->InternGlobalCounterTrack(
120         TrackTracker::Group::kPower, batt_current_avg_id);
121     context_->event_tracker->PushCounter(
122         ts, static_cast<double>(evt.current_avg_ua()), track);
123   }
124   if (evt.has_voltage_uv()) {
125     TrackId track = context_->track_tracker->InternGlobalCounterTrack(
126         TrackTracker::Group::kPower, batt_voltage_id);
127     context_->event_tracker->PushCounter(
128         ts, static_cast<double>(evt.voltage_uv()), track);
129   }
130 }
131 
ParsePowerRails(int64_t ts,uint64_t trace_packet_ts,ConstBytes blob)132 void AndroidProbesParser::ParsePowerRails(int64_t ts,
133                                           uint64_t trace_packet_ts,
134                                           ConstBytes blob) {
135   protos::pbzero::PowerRails::Decoder evt(blob.data, blob.size);
136 
137   // Descriptors should have been processed at tokenization time.
138   PERFETTO_DCHECK(evt.has_energy_data());
139 
140   // Because we have some special code in the tokenization phase, we
141   // will only every get one EnergyData message per packet. Therefore,
142   // we can just read the data directly.
143   auto it = evt.energy_data();
144   protos::pbzero::PowerRails::EnergyData::Decoder desc(*it);
145 
146   auto* tracker = AndroidProbesTracker::GetOrCreate(context_);
147   auto opt_track = tracker->GetPowerRailTrack(desc.index());
148   if (opt_track.has_value()) {
149     // The tokenization makes sure that this field is always present and
150     // is equal to the packet's timestamp that was passed to us via the sorter.
151     PERFETTO_DCHECK(desc.has_timestamp_ms());
152     PERFETTO_DCHECK(ts / 1000000 == static_cast<int64_t>(desc.timestamp_ms()));
153     auto maybe_counter_id = context_->event_tracker->PushCounter(
154         ts, static_cast<double>(desc.energy()), *opt_track);
155     if (maybe_counter_id) {
156       context_->args_tracker->AddArgsTo(*maybe_counter_id)
157           .AddArg(rail_packet_timestamp_id_,
158                   Variadic::UnsignedInteger(trace_packet_ts));
159     }
160   } else {
161     context_->storage->IncrementStats(stats::power_rail_unknown_index);
162   }
163 
164   // DCHECK that we only got one message.
165   PERFETTO_DCHECK(!++it);
166 }
167 
ParseEnergyBreakdown(int64_t ts,ConstBytes blob)168 void AndroidProbesParser::ParseEnergyBreakdown(int64_t ts, ConstBytes blob) {
169   protos::pbzero::AndroidEnergyEstimationBreakdown::Decoder event(blob.data,
170                                                                   blob.size);
171 
172   if (!event.has_energy_consumer_id() || !event.has_energy_uws()) {
173     context_->storage->IncrementStats(stats::energy_breakdown_missing_values);
174     return;
175   }
176 
177   auto consumer_id = event.energy_consumer_id();
178   auto* tracker = AndroidProbesTracker::GetOrCreate(context_);
179   auto energy_consumer_specs =
180       tracker->GetEnergyBreakdownDescriptor(consumer_id);
181 
182   if (!energy_consumer_specs) {
183     context_->storage->IncrementStats(stats::energy_breakdown_missing_values);
184     return;
185   }
186 
187   auto total_energy = static_cast<double>(event.energy_uws());
188   auto consumer_name = energy_consumer_specs->name;
189   auto consumer_type = energy_consumer_specs->type;
190   auto ordinal = energy_consumer_specs->ordinal;
191 
192   TrackId energy_track = context_->track_tracker->InternEnergyCounterTrack(
193       consumer_name, consumer_id, consumer_type, ordinal);
194   context_->event_tracker->PushCounter(ts, total_energy, energy_track);
195 
196   // Consumers providing per-uid energy breakdown
197   for (auto it = event.per_uid_breakdown(); it; ++it) {
198     protos::pbzero::AndroidEnergyEstimationBreakdown_EnergyUidBreakdown::Decoder
199         breakdown(*it);
200 
201     if (!breakdown.has_uid() || !breakdown.has_energy_uws()) {
202       context_->storage->IncrementStats(
203           stats::energy_uid_breakdown_missing_values);
204       continue;
205     }
206 
207     TrackId energy_uid_track =
208         context_->track_tracker->InternEnergyPerUidCounterTrack(
209             consumer_name, consumer_id, breakdown.uid());
210     context_->event_tracker->PushCounter(
211         ts, static_cast<double>(breakdown.energy_uws()), energy_uid_track);
212   }
213 }
214 
ParseEntityStateResidency(int64_t ts,ConstBytes blob)215 void AndroidProbesParser::ParseEntityStateResidency(int64_t ts,
216                                                     ConstBytes blob) {
217   protos::pbzero::EntityStateResidency::Decoder event(blob.data, blob.size);
218 
219   if (!event.has_residency()) {
220     context_->storage->IncrementStats(stats::entity_state_residency_invalid);
221     return;
222   }
223 
224   auto* tracker = AndroidProbesTracker::GetOrCreate(context_);
225 
226   for (auto it = event.residency(); it; ++it) {
227     protos::pbzero::EntityStateResidency::StateResidency::Decoder residency(
228         *it);
229 
230     auto entity_state = tracker->GetEntityStateDescriptor(
231         residency.entity_index(), residency.state_index());
232     if (!entity_state) {
233       context_->storage->IncrementStats(
234           stats::entity_state_residency_lookup_failed);
235       return;
236     }
237 
238     TrackId track = context_->track_tracker->InternGlobalCounterTrack(
239         TrackTracker::Group::kPower, entity_state->overall_name);
240     context_->event_tracker->PushCounter(
241         ts, double(residency.total_time_in_state_ms()), track);
242   }
243 }
244 
ParseAndroidLogPacket(ConstBytes blob)245 void AndroidProbesParser::ParseAndroidLogPacket(ConstBytes blob) {
246   protos::pbzero::AndroidLogPacket::Decoder packet(blob.data, blob.size);
247   for (auto it = packet.events(); it; ++it)
248     ParseAndroidLogEvent(*it);
249 
250   if (packet.has_stats())
251     ParseAndroidLogStats(packet.stats());
252 }
253 
ParseAndroidLogEvent(ConstBytes blob)254 void AndroidProbesParser::ParseAndroidLogEvent(ConstBytes blob) {
255   // TODO(primiano): Add events and non-stringified fields to the "raw" table.
256   protos::pbzero::AndroidLogPacket::LogEvent::Decoder evt(blob.data, blob.size);
257   int64_t ts = static_cast<int64_t>(evt.timestamp());
258   uint32_t pid = static_cast<uint32_t>(evt.pid());
259   uint32_t tid = static_cast<uint32_t>(evt.tid());
260   uint8_t prio = static_cast<uint8_t>(evt.prio());
261   StringId tag_id = context_->storage->InternString(
262       evt.has_tag() ? evt.tag() : base::StringView());
263   StringId msg_id = context_->storage->InternString(
264       evt.has_message() ? evt.message() : base::StringView());
265 
266   char arg_msg[4096];
267   char* arg_str = &arg_msg[0];
268   *arg_str = '\0';
269   auto arg_avail = [&arg_msg, &arg_str]() {
270     size_t used = static_cast<size_t>(arg_str - arg_msg);
271     PERFETTO_CHECK(used <= sizeof(arg_msg));
272     return sizeof(arg_msg) - used;
273   };
274   for (auto it = evt.args(); it; ++it) {
275     protos::pbzero::AndroidLogPacket::LogEvent::Arg::Decoder arg(*it);
276     if (!arg.has_name())
277       continue;
278     arg_str += base::SprintfTrunc(arg_str, arg_avail(),
279                                   " %.*s=", static_cast<int>(arg.name().size),
280                                   arg.name().data);
281     if (arg.has_string_value()) {
282       arg_str += base::SprintfTrunc(arg_str, arg_avail(), "\"%.*s\"",
283                                     static_cast<int>(arg.string_value().size),
284                                     arg.string_value().data);
285     } else if (arg.has_int_value()) {
286       arg_str +=
287           base::SprintfTrunc(arg_str, arg_avail(), "%" PRId64, arg.int_value());
288     } else if (arg.has_float_value()) {
289       arg_str += base::SprintfTrunc(arg_str, arg_avail(), "%f",
290                                     static_cast<double>(arg.float_value()));
291     }
292   }
293 
294   if (prio == 0)
295     prio = protos::pbzero::AndroidLogPriority::PRIO_INFO;
296 
297   if (arg_str != &arg_msg[0]) {
298     PERFETTO_DCHECK(msg_id.is_null());
299     // Skip the first space char (" foo=1 bar=2" -> "foo=1 bar=2").
300     msg_id = context_->storage->InternString(&arg_msg[1]);
301   }
302   UniquePid utid = tid ? context_->process_tracker->UpdateThread(tid, pid) : 0;
303   base::StatusOr<int64_t> trace_time = context_->clock_tracker->ToTraceTime(
304       protos::pbzero::BUILTIN_CLOCK_REALTIME, ts);
305   if (!trace_time.ok()) {
306     static std::atomic<uint32_t> dlog_count(0);
307     if (dlog_count++ < 10)
308       PERFETTO_DLOG("%s", trace_time.status().c_message());
309     return;
310   }
311 
312   // Log events are NOT required to be sorted by trace_time. The virtual table
313   // will take care of sorting on-demand.
314   context_->storage->mutable_android_log_table()->Insert(
315       {trace_time.value(), utid, prio, tag_id, msg_id});
316 }
317 
ParseAndroidLogStats(ConstBytes blob)318 void AndroidProbesParser::ParseAndroidLogStats(ConstBytes blob) {
319   protos::pbzero::AndroidLogPacket::Stats::Decoder evt(blob.data, blob.size);
320   if (evt.has_num_failed()) {
321     context_->storage->SetStats(stats::android_log_num_failed,
322                                 static_cast<int64_t>(evt.num_failed()));
323   }
324 
325   if (evt.has_num_skipped()) {
326     context_->storage->SetStats(stats::android_log_num_skipped,
327                                 static_cast<int64_t>(evt.num_skipped()));
328   }
329 
330   if (evt.has_num_total()) {
331     context_->storage->SetStats(stats::android_log_num_total,
332                                 static_cast<int64_t>(evt.num_total()));
333   }
334 }
335 
ParseStatsdMetadata(ConstBytes blob)336 void AndroidProbesParser::ParseStatsdMetadata(ConstBytes blob) {
337   protos::pbzero::TraceConfig::StatsdMetadata::Decoder metadata(blob.data,
338                                                                 blob.size);
339   if (metadata.has_triggering_subscription_id()) {
340     context_->metadata_tracker->SetMetadata(
341         metadata::statsd_triggering_subscription_id,
342         Variadic::Integer(metadata.triggering_subscription_id()));
343   }
344 }
345 
ParseAndroidGameIntervention(ConstBytes blob)346 void AndroidProbesParser::ParseAndroidGameIntervention(ConstBytes blob) {
347   protos::pbzero::AndroidGameInterventionList::Decoder intervention_list(
348       blob.data, blob.size);
349   constexpr static int kGameModeStandard = 1;
350   constexpr static int kGameModePerformance = 2;
351   constexpr static int kGameModeBattery = 3;
352 
353   context_->storage->SetStats(stats::game_intervention_has_read_errors,
354                               intervention_list.read_error());
355   context_->storage->SetStats(stats::game_intervention_has_parse_errors,
356                               intervention_list.parse_error());
357 
358   for (auto pkg_it = intervention_list.game_packages(); pkg_it; ++pkg_it) {
359     protos::pbzero::AndroidGameInterventionList_GamePackageInfo::Decoder
360         game_pkg(*pkg_it);
361     int64_t uid = static_cast<int64_t>(game_pkg.uid());
362     int32_t cur_mode = static_cast<int32_t>(game_pkg.current_mode());
363 
364     bool is_standard_mode = false;
365     std::optional<double> standard_downscale;
366     std::optional<int32_t> standard_angle;
367     std::optional<double> standard_fps;
368 
369     bool is_performance_mode = false;
370     std::optional<double> perf_downscale;
371     std::optional<int32_t> perf_angle;
372     std::optional<double> perf_fps;
373 
374     bool is_battery_mode = false;
375     std::optional<double> battery_downscale;
376     std::optional<int32_t> battery_angle;
377     std::optional<double> battery_fps;
378 
379     for (auto mode_it = game_pkg.game_mode_info(); mode_it; ++mode_it) {
380       protos::pbzero::AndroidGameInterventionList_GameModeInfo::Decoder
381           game_mode(*mode_it);
382 
383       uint32_t mode_num = game_mode.mode();
384       if (mode_num == kGameModeStandard) {
385         is_standard_mode = true;
386         standard_downscale =
387             static_cast<double>(game_mode.resolution_downscale());
388         standard_angle = game_mode.use_angle();
389         standard_fps = static_cast<double>(game_mode.fps());
390       } else if (mode_num == kGameModePerformance) {
391         is_performance_mode = true;
392         perf_downscale = static_cast<double>(game_mode.resolution_downscale());
393         perf_angle = game_mode.use_angle();
394         perf_fps = static_cast<double>(game_mode.fps());
395       } else if (mode_num == kGameModeBattery) {
396         is_battery_mode = true;
397         battery_downscale =
398             static_cast<double>(game_mode.resolution_downscale());
399         battery_angle = game_mode.use_angle();
400         battery_fps = static_cast<double>(game_mode.fps());
401       }
402     }
403 
404     context_->storage->mutable_android_game_intervenion_list_table()->Insert(
405         {context_->storage->InternString(game_pkg.name()), uid, cur_mode,
406          is_standard_mode, standard_downscale, standard_angle, standard_fps,
407          is_performance_mode, perf_downscale, perf_angle, perf_fps,
408          is_battery_mode, battery_downscale, battery_angle, battery_fps});
409   }
410 }
411 
ParseInitialDisplayState(int64_t ts,ConstBytes blob)412 void AndroidProbesParser::ParseInitialDisplayState(int64_t ts,
413                                                    ConstBytes blob) {
414   protos::pbzero::InitialDisplayState::Decoder state(blob.data, blob.size);
415 
416   TrackId track = context_->track_tracker->InternGlobalCounterTrack(
417       TrackTracker::Group::kDeviceState, screen_state_id_);
418   context_->event_tracker->PushCounter(ts, state.display_state(), track);
419 }
420 
ParseAndroidSystemProperty(int64_t ts,ConstBytes blob)421 void AndroidProbesParser::ParseAndroidSystemProperty(int64_t ts,
422                                                      ConstBytes blob) {
423   protos::pbzero::AndroidSystemProperty::Decoder properties(blob.data,
424                                                             blob.size);
425   for (auto it = properties.values(); it; ++it) {
426     protos::pbzero::AndroidSystemProperty::PropertyValue::Decoder kv(*it);
427     base::StringView name(kv.name());
428     std::optional<StringId> mapped_name_id;
429 
430     if (name == "debug.tracing.device_state") {
431       auto state = kv.value();
432 
433       StringId state_id = context_->storage->InternString(state);
434       auto track_set_id =
435           context_->async_track_set_tracker->InternGlobalTrackSet(
436               device_state_id_);
437       TrackId track_id =
438           context_->async_track_set_tracker->Scoped(track_set_id, ts, 0);
439       context_->slice_tracker->Scoped(ts, track_id, kNullStringId, state_id, 0);
440     } else if (name.StartsWith("debug.tracing.battery_stats.") ||
441                name == "debug.tracing.mcc" || name == "debug.tracing.mnc") {
442       StringId name_id = context_->storage->InternString(
443           name.substr(strlen("debug.tracing.")));
444       std::optional<int32_t> state =
445           base::StringToInt32(kv.value().ToStdString());
446       if (state) {
447         TrackId track = context_->track_tracker->InternGlobalCounterTrack(
448             TrackTracker::Group::kNetwork, name_id);
449         context_->event_tracker->PushCounter(ts, *state, track);
450       }
451     } else if (name == "debug.tracing.screen_state") {
452       mapped_name_id = screen_state_id_;
453     } else if (name == "debug.tracing.battery_status") {
454       mapped_name_id = battery_status_id_;
455     } else if (name == "debug.tracing.plug_type") {
456       mapped_name_id = plug_type_id_;
457     }
458     if (mapped_name_id) {
459       std::optional<int32_t> state =
460           base::StringToInt32(kv.value().ToStdString());
461       if (state) {
462         TrackId track = context_->track_tracker->InternGlobalCounterTrack(
463             TrackTracker::Group::kDeviceState, *mapped_name_id);
464         context_->event_tracker->PushCounter(ts, *state, track);
465       }
466     }
467   }
468 }
469 
470 }  // namespace trace_processor
471 }  // namespace perfetto
472