• 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 "perfetto/base/logging.h"
20 #include "perfetto/ext/traced/sys_stats_counters.h"
21 #include "src/trace_processor/importers/common/args_tracker.h"
22 #include "src/trace_processor/importers/common/clock_tracker.h"
23 #include "src/trace_processor/importers/common/event_tracker.h"
24 #include "src/trace_processor/importers/common/process_tracker.h"
25 #include "src/trace_processor/importers/proto/metadata_tracker.h"
26 #include "src/trace_processor/importers/syscalls/syscall_tracker.h"
27 #include "src/trace_processor/types/trace_processor_context.h"
28 
29 #include "protos/perfetto/common/android_log_constants.pbzero.h"
30 #include "protos/perfetto/common/builtin_clock.pbzero.h"
31 #include "protos/perfetto/config/trace_config.pbzero.h"
32 #include "protos/perfetto/trace/android/android_log.pbzero.h"
33 #include "protos/perfetto/trace/android/initial_display_state.pbzero.h"
34 #include "protos/perfetto/trace/android/packages_list.pbzero.h"
35 #include "protos/perfetto/trace/power/battery_counters.pbzero.h"
36 #include "protos/perfetto/trace/power/power_rails.pbzero.h"
37 #include "protos/perfetto/trace/ps/process_stats.pbzero.h"
38 #include "protos/perfetto/trace/ps/process_tree.pbzero.h"
39 #include "protos/perfetto/trace/sys_stats/sys_stats.pbzero.h"
40 #include "protos/perfetto/trace/system_info.pbzero.h"
41 
42 #include "src/trace_processor/importers/proto/android_probes_tracker.h"
43 
44 namespace perfetto {
45 namespace trace_processor {
46 
AndroidProbesParser(TraceProcessorContext * context)47 AndroidProbesParser::AndroidProbesParser(TraceProcessorContext* context)
48     : context_(context),
49       batt_charge_id_(context->storage->InternString("batt.charge_uah")),
50       batt_capacity_id_(context->storage->InternString("batt.capacity_pct")),
51       batt_current_id_(context->storage->InternString("batt.current_ua")),
52       batt_current_avg_id_(
53           context->storage->InternString("batt.current.avg_ua")),
54       screen_state_id_(context->storage->InternString("ScreenState")) {}
55 
ParseBatteryCounters(int64_t ts,ConstBytes blob)56 void AndroidProbesParser::ParseBatteryCounters(int64_t ts, ConstBytes blob) {
57   protos::pbzero::BatteryCounters::Decoder evt(blob.data, blob.size);
58   if (evt.has_charge_counter_uah()) {
59     TrackId track =
60         context_->track_tracker->InternGlobalCounterTrack(batt_charge_id_);
61     context_->event_tracker->PushCounter(
62         ts, static_cast<double>(evt.charge_counter_uah()), track);
63   }
64   if (evt.has_capacity_percent()) {
65     TrackId track =
66         context_->track_tracker->InternGlobalCounterTrack(batt_capacity_id_);
67     context_->event_tracker->PushCounter(
68         ts, static_cast<double>(evt.capacity_percent()), track);
69   }
70   if (evt.has_current_ua()) {
71     TrackId track =
72         context_->track_tracker->InternGlobalCounterTrack(batt_current_id_);
73     context_->event_tracker->PushCounter(
74         ts, static_cast<double>(evt.current_ua()), track);
75   }
76   if (evt.has_current_avg_ua()) {
77     TrackId track =
78         context_->track_tracker->InternGlobalCounterTrack(batt_current_avg_id_);
79     context_->event_tracker->PushCounter(
80         ts, static_cast<double>(evt.current_avg_ua()), track);
81   }
82 }
83 
ParsePowerRails(int64_t ts,ConstBytes blob)84 void AndroidProbesParser::ParsePowerRails(int64_t ts, ConstBytes blob) {
85   protos::pbzero::PowerRails::Decoder evt(blob.data, blob.size);
86 
87   // Descriptors should have been processed at tokenization time.
88   PERFETTO_DCHECK(evt.has_energy_data());
89 
90   // Because we have some special code in the tokenization phase, we
91   // will only every get one EnergyData message per packet. Therefore,
92   // we can just read the data directly.
93   auto it = evt.energy_data();
94   protos::pbzero::PowerRails::EnergyData::Decoder desc(*it);
95 
96   auto opt_rail_name =
97       AndroidProbesTracker::GetOrCreate(context_)->GetPowerRailName(
98           desc.index());
99   if (opt_rail_name) {
100     // The tokenization makes sure that this field is always present and
101     // is equal to the packet's timestamp (as the packet was forged in
102     // the tokenizer).
103     PERFETTO_DCHECK(desc.has_timestamp_ms());
104     PERFETTO_DCHECK(ts / 1000000 == static_cast<int64_t>(desc.timestamp_ms()));
105 
106     TrackId track =
107         context_->track_tracker->InternGlobalCounterTrack(*opt_rail_name);
108     context_->event_tracker->PushCounter(ts, static_cast<double>(desc.energy()),
109                                          track);
110   } else {
111     context_->storage->IncrementStats(stats::power_rail_unknown_index);
112   }
113 
114   // DCHECK that we only got one message.
115   PERFETTO_DCHECK(!++it);
116 }
117 
ParseAndroidLogPacket(ConstBytes blob)118 void AndroidProbesParser::ParseAndroidLogPacket(ConstBytes blob) {
119   protos::pbzero::AndroidLogPacket::Decoder packet(blob.data, blob.size);
120   for (auto it = packet.events(); it; ++it)
121     ParseAndroidLogEvent(*it);
122 
123   if (packet.has_stats())
124     ParseAndroidLogStats(packet.stats());
125 }
126 
ParseAndroidLogEvent(ConstBytes blob)127 void AndroidProbesParser::ParseAndroidLogEvent(ConstBytes blob) {
128   // TODO(primiano): Add events and non-stringified fields to the "raw" table.
129   protos::pbzero::AndroidLogPacket::LogEvent::Decoder evt(blob.data, blob.size);
130   int64_t ts = static_cast<int64_t>(evt.timestamp());
131   uint32_t pid = static_cast<uint32_t>(evt.pid());
132   uint32_t tid = static_cast<uint32_t>(evt.tid());
133   uint8_t prio = static_cast<uint8_t>(evt.prio());
134   StringId tag_id = context_->storage->InternString(
135       evt.has_tag() ? evt.tag() : base::StringView());
136   StringId msg_id = context_->storage->InternString(
137       evt.has_message() ? evt.message() : base::StringView());
138 
139   char arg_msg[4096];
140   char* arg_str = &arg_msg[0];
141   *arg_str = '\0';
142   auto arg_avail = [&arg_msg, &arg_str]() {
143     return sizeof(arg_msg) - static_cast<size_t>(arg_str - arg_msg);
144   };
145   for (auto it = evt.args(); it; ++it) {
146     protos::pbzero::AndroidLogPacket::LogEvent::Arg::Decoder arg(*it);
147     if (!arg.has_name())
148       continue;
149     arg_str +=
150         snprintf(arg_str, arg_avail(),
151                  " %.*s=", static_cast<int>(arg.name().size), arg.name().data);
152     if (arg.has_string_value()) {
153       arg_str += snprintf(arg_str, arg_avail(), "\"%.*s\"",
154                           static_cast<int>(arg.string_value().size),
155                           arg.string_value().data);
156     } else if (arg.has_int_value()) {
157       arg_str += snprintf(arg_str, arg_avail(), "%" PRId64, arg.int_value());
158     } else if (arg.has_float_value()) {
159       arg_str += snprintf(arg_str, arg_avail(), "%f",
160                           static_cast<double>(arg.float_value()));
161     }
162   }
163 
164   if (prio == 0)
165     prio = protos::pbzero::AndroidLogPriority::PRIO_INFO;
166 
167   if (arg_str != &arg_msg[0]) {
168     PERFETTO_DCHECK(msg_id.is_null());
169     // Skip the first space char (" foo=1 bar=2" -> "foo=1 bar=2").
170     msg_id = context_->storage->InternString(&arg_msg[1]);
171   }
172   UniquePid utid = tid ? context_->process_tracker->UpdateThread(tid, pid) : 0;
173   base::Optional<int64_t> opt_trace_time = context_->clock_tracker->ToTraceTime(
174       protos::pbzero::BUILTIN_CLOCK_REALTIME, ts);
175   if (!opt_trace_time)
176     return;
177 
178   // Log events are NOT required to be sorted by trace_time. The virtual table
179   // will take care of sorting on-demand.
180   context_->storage->mutable_android_log_table()->Insert(
181       {opt_trace_time.value(), utid, prio, tag_id, msg_id});
182 }
183 
ParseAndroidLogStats(ConstBytes blob)184 void AndroidProbesParser::ParseAndroidLogStats(ConstBytes blob) {
185   protos::pbzero::AndroidLogPacket::Stats::Decoder evt(blob.data, blob.size);
186   if (evt.has_num_failed()) {
187     context_->storage->SetStats(stats::android_log_num_failed,
188                                 static_cast<int64_t>(evt.num_failed()));
189   }
190 
191   if (evt.has_num_skipped()) {
192     context_->storage->SetStats(stats::android_log_num_skipped,
193                                 static_cast<int64_t>(evt.num_skipped()));
194   }
195 
196   if (evt.has_num_total()) {
197     context_->storage->SetStats(stats::android_log_num_total,
198                                 static_cast<int64_t>(evt.num_total()));
199   }
200 }
201 
ParseStatsdMetadata(ConstBytes blob)202 void AndroidProbesParser::ParseStatsdMetadata(ConstBytes blob) {
203   protos::pbzero::TraceConfig::StatsdMetadata::Decoder metadata(blob.data,
204                                                                 blob.size);
205   if (metadata.has_triggering_subscription_id()) {
206     context_->metadata_tracker->SetMetadata(
207         metadata::statsd_triggering_subscription_id,
208         Variadic::Integer(metadata.triggering_subscription_id()));
209   }
210 }
211 
ParseAndroidPackagesList(ConstBytes blob)212 void AndroidProbesParser::ParseAndroidPackagesList(ConstBytes blob) {
213   protos::pbzero::PackagesList::Decoder pkg_list(blob.data, blob.size);
214   context_->storage->SetStats(stats::packages_list_has_read_errors,
215                               pkg_list.read_error());
216   context_->storage->SetStats(stats::packages_list_has_parse_errors,
217                               pkg_list.parse_error());
218 
219   AndroidProbesTracker* tracker = AndroidProbesTracker::GetOrCreate(context_);
220   for (auto it = pkg_list.packages(); it; ++it) {
221     protos::pbzero::PackagesList_PackageInfo::Decoder pkg(*it);
222     std::string pkg_name = pkg.name().ToStdString();
223     if (!tracker->ShouldInsertPackage(pkg_name)) {
224       continue;
225     }
226     context_->storage->mutable_package_list_table()->Insert(
227         {context_->storage->InternString(pkg.name()),
228          static_cast<int64_t>(pkg.uid()), pkg.debuggable(),
229          pkg.profileable_from_shell(),
230          static_cast<int64_t>(pkg.version_code())});
231     tracker->InsertedPackage(std::move(pkg_name));
232   }
233 }
234 
ParseInitialDisplayState(int64_t ts,ConstBytes blob)235 void AndroidProbesParser::ParseInitialDisplayState(int64_t ts,
236                                                    ConstBytes blob) {
237   protos::pbzero::InitialDisplayState::Decoder state(blob.data, blob.size);
238 
239   TrackId track =
240       context_->track_tracker->InternGlobalCounterTrack(screen_state_id_);
241   context_->event_tracker->PushCounter(ts, state.display_state(), track);
242 }
243 
244 }  // namespace trace_processor
245 }  // namespace perfetto
246