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