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