1 /*
2 * Copyright (C) 2018 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/traced/probes/android_log/android_log_data_source.h"
18
19 #include "perfetto/base/logging.h"
20 #include "perfetto/base/task_runner.h"
21 #include "perfetto/base/time.h"
22 #include "perfetto/ext/base/file_utils.h"
23 #include "perfetto/ext/base/optional.h"
24 #include "perfetto/ext/base/scoped_file.h"
25 #include "perfetto/ext/base/string_splitter.h"
26 #include "perfetto/ext/base/string_view.h"
27 #include "perfetto/ext/base/unix_socket.h"
28 #include "perfetto/ext/tracing/core/trace_packet.h"
29 #include "perfetto/ext/tracing/core/trace_writer.h"
30 #include "perfetto/tracing/core/data_source_config.h"
31
32 #include "protos/perfetto/common/android_log_constants.pbzero.h"
33 #include "protos/perfetto/config/android/android_log_config.pbzero.h"
34 #include "protos/perfetto/trace/android/android_log.pbzero.h"
35 #include "protos/perfetto/trace/trace_packet.pbzero.h"
36
37 namespace perfetto {
38
39 namespace {
40
41 using protos::pbzero::AndroidLogConfig;
42 using protos::pbzero::AndroidLogId;
43
44 constexpr size_t kBufSize = 4096;
45 const char kLogTagsPath[] = "/system/etc/event-log-tags";
46 const char kLogdrSocket[] = "/dev/socket/logdr";
47
48 // From AOSP's liblog/include/log/log_read.h .
49 // Android Log is supposed to be an ABI as it's exposed also by logcat -b (and
50 // in practice never changed in backwards-incompatible ways in the past).
51 // Note: the casing doesn't match the style guide and instead matches the
52 // original name in liblog for the sake of code-searcheability.
53 struct logger_entry_v4 {
54 uint16_t len; // length of the payload.
55 uint16_t hdr_size; // sizeof(struct logger_entry_v4).
56 int32_t pid; // generating process's pid.
57 uint32_t tid; // generating process's tid.
58 uint32_t sec; // seconds since Epoch.
59 uint32_t nsec; // nanoseconds.
60 uint32_t lid; // log id of the payload, bottom 4 bits currently.
61 uint32_t uid; // generating process's uid.
62 };
63
64 // Event types definition in the binary encoded format, from
65 // liblog/include/log/log.h .
66 // Note that these values don't match the textual definitions of
67 // system/core/android_logevent.logtags (which are not used by perfetto).
68 // The latter are off by one (INT = 1, LONG=2 and so on).
69 enum AndroidEventLogType {
70 EVENT_TYPE_INT = 0,
71 EVENT_TYPE_LONG = 1,
72 EVENT_TYPE_STRING = 2,
73 EVENT_TYPE_LIST = 3,
74 EVENT_TYPE_FLOAT = 4,
75 };
76
77 template <typename T>
ReadAndAdvance(const char ** ptr,const char * end,T * out)78 inline bool ReadAndAdvance(const char** ptr, const char* end, T* out) {
79 if (*ptr > end - sizeof(T))
80 return false;
81 memcpy(reinterpret_cast<void*>(out), *ptr, sizeof(T));
82 *ptr += sizeof(T);
83 return true;
84 }
85
86 } // namespace
87
88 // static
89 const ProbesDataSource::Descriptor AndroidLogDataSource::descriptor = {
90 /*name*/ "android.log",
91 /*flags*/ Descriptor::kFlagsNone,
92 };
93
AndroidLogDataSource(DataSourceConfig ds_config,base::TaskRunner * task_runner,TracingSessionID session_id,std::unique_ptr<TraceWriter> writer)94 AndroidLogDataSource::AndroidLogDataSource(DataSourceConfig ds_config,
95 base::TaskRunner* task_runner,
96 TracingSessionID session_id,
97 std::unique_ptr<TraceWriter> writer)
98 : ProbesDataSource(session_id, &descriptor),
99 task_runner_(task_runner),
100 writer_(std::move(writer)),
101 weak_factory_(this) {
102 AndroidLogConfig::Decoder cfg(ds_config.android_log_config_raw());
103
104 std::vector<uint32_t> log_ids;
105 for (auto id = cfg.log_ids(); id; ++id)
106 log_ids.push_back(static_cast<uint32_t>(*id));
107
108 if (log_ids.empty()) {
109 // If no log id is specified, add the most popular ones.
110 log_ids.push_back(AndroidLogId::LID_DEFAULT);
111 log_ids.push_back(AndroidLogId::LID_EVENTS);
112 log_ids.push_back(AndroidLogId::LID_SYSTEM);
113 log_ids.push_back(AndroidLogId::LID_CRASH);
114 log_ids.push_back(AndroidLogId::LID_KERNEL);
115 }
116
117 // Build the command string that will be sent to the logdr socket on Start(),
118 // which looks like "stream lids=1,2,3,4" (lids == log buffer id(s)).
119 mode_ = "stream tail=1 lids";
120 for (auto it = log_ids.begin(); it != log_ids.end(); it++) {
121 mode_ += it == log_ids.begin() ? "=" : ",";
122 mode_ += std::to_string(*it);
123 }
124
125 // Build a linear vector out of the tag filters and keep track of the string
126 // boundaries. Once done, derive StringView(s) out of the vector. This is
127 // to create a set<StringView> which is backed by contiguous chars that can be
128 // used to lookup StringView(s) from the parsed buffer.
129 // This is to avoid copying strings of tags for the only sake of checking for
130 // their existence in the set.
131 std::vector<std::pair<size_t, size_t>> tag_boundaries;
132 for (auto it = cfg.filter_tags(); it; ++it) {
133 base::StringView tag(*it);
134 const size_t begin = filter_tags_strbuf_.size();
135 filter_tags_strbuf_.insert(filter_tags_strbuf_.end(), tag.begin(),
136 tag.end());
137 const size_t end = filter_tags_strbuf_.size();
138 tag_boundaries.emplace_back(begin, end - begin);
139 }
140 filter_tags_strbuf_.shrink_to_fit();
141 // At this point pointers to |filter_tags_strbuf_| are stable.
142 for (const auto& it : tag_boundaries)
143 filter_tags_.emplace(&filter_tags_strbuf_[it.first], it.second);
144
145 min_prio_ = cfg.min_prio();
146 buf_ = base::PagedMemory::Allocate(kBufSize);
147 }
148
~AndroidLogDataSource()149 AndroidLogDataSource::~AndroidLogDataSource() {
150 if (logdr_sock_) {
151 EnableSocketWatchTask(false);
152 logdr_sock_.Shutdown();
153 }
154 }
155
ConnectLogdrSocket()156 base::UnixSocketRaw AndroidLogDataSource::ConnectLogdrSocket() {
157 auto socket = base::UnixSocketRaw::CreateMayFail(base::SockFamily::kUnix,
158 base::SockType::kSeqPacket);
159 if (!socket || !socket.Connect(kLogdrSocket)) {
160 PERFETTO_PLOG("Failed to connect to %s", kLogdrSocket);
161 return base::UnixSocketRaw();
162 }
163 return socket;
164 }
165
Start()166 void AndroidLogDataSource::Start() {
167 ParseEventLogDefinitions();
168
169 if (!(logdr_sock_ = ConnectLogdrSocket()))
170 return;
171
172 PERFETTO_DLOG("Starting Android log data source: %s", mode_.c_str());
173 if (logdr_sock_.Send(mode_.data(), mode_.size()) <= 0) {
174 PERFETTO_PLOG("send() failed on logdr socket %s", kLogdrSocket);
175 return;
176 }
177 logdr_sock_.SetBlocking(false);
178 EnableSocketWatchTask(true);
179 }
180
EnableSocketWatchTask(bool enable)181 void AndroidLogDataSource::EnableSocketWatchTask(bool enable) {
182 if (fd_watch_task_enabled_ == enable)
183 return;
184
185 if (enable) {
186 auto weak_this = weak_factory_.GetWeakPtr();
187 task_runner_->AddFileDescriptorWatch(logdr_sock_.fd(), [weak_this] {
188 if (weak_this)
189 weak_this->OnSocketDataAvailable();
190 });
191 } else {
192 task_runner_->RemoveFileDescriptorWatch(logdr_sock_.fd());
193 }
194
195 fd_watch_task_enabled_ = enable;
196 }
197
OnSocketDataAvailable()198 void AndroidLogDataSource::OnSocketDataAvailable() {
199 PERFETTO_DCHECK(fd_watch_task_enabled_);
200 auto now_ms = base::GetWallTimeMs().count();
201
202 // Disable the FD watch until the delayed read happens, otherwise we get a
203 // storm of OnSocketDataAvailable() until the delayed ReadLogSocket() happens.
204 EnableSocketWatchTask(false);
205
206 // Delay the read by (at most) 100 ms so we get a chance to batch reads and
207 // don't cause too many context switches in cases of logging storms. The
208 // modulo is to increase the chance that the wakeup is packed together with
209 // some other wakeup task of traced_probes.
210 const uint32_t kBatchMs = 100;
211 uint32_t delay_ms = kBatchMs - static_cast<uint32_t>(now_ms % kBatchMs);
212 auto weak_this = weak_factory_.GetWeakPtr();
213 task_runner_->PostDelayedTask(
214 [weak_this] {
215 if (weak_this) {
216 weak_this->ReadLogSocket();
217 weak_this->EnableSocketWatchTask(true);
218 }
219 },
220 delay_ms);
221 }
222
ReadLogSocket()223 void AndroidLogDataSource::ReadLogSocket() {
224 TraceWriter::TracePacketHandle packet;
225 protos::pbzero::AndroidLogPacket* log_packet = nullptr;
226 size_t num_events = 0;
227 bool stop = false;
228 ssize_t rsize;
229 while (!stop && (rsize = logdr_sock_.Receive(buf_.Get(), kBufSize)) > 0) {
230 num_events++;
231 stats_.num_total++;
232 // Don't hold the message loop for too long. If there are so many events
233 // in the queue, stop at some point and parse the remaining ones in another
234 // task (posted after this while loop).
235 if (num_events > 500) {
236 stop = true;
237 auto weak_this = weak_factory_.GetWeakPtr();
238 task_runner_->PostTask([weak_this] {
239 if (weak_this)
240 weak_this->ReadLogSocket();
241 });
242 }
243 char* buf = reinterpret_cast<char*>(buf_.Get());
244 PERFETTO_DCHECK(reinterpret_cast<uintptr_t>(buf) % 16 == 0);
245 size_t payload_size = reinterpret_cast<logger_entry_v4*>(buf)->len;
246 size_t hdr_size = reinterpret_cast<logger_entry_v4*>(buf)->hdr_size;
247 if (payload_size + hdr_size > static_cast<size_t>(rsize)) {
248 PERFETTO_DLOG(
249 "Invalid Android log frame (hdr: %zu, payload: %zu, rsize: %zd)",
250 hdr_size, payload_size, rsize);
251 stats_.num_failed++;
252 continue;
253 }
254 char* const end = buf + hdr_size + payload_size;
255
256 // In older versions of Android the logger_entry struct can contain less
257 // fields. Copy that in a temporary struct, so that unset fields are
258 // always zero-initialized.
259 logger_entry_v4 entry{};
260 memcpy(&entry, buf, std::min(hdr_size, sizeof(entry)));
261 buf += hdr_size;
262
263 if (!packet) {
264 // Lazily add the packet on the first event. This is to avoid creating
265 // empty packets if there are no events in a task.
266 packet = writer_->NewTracePacket();
267 packet->set_timestamp(
268 static_cast<uint64_t>(base::GetBootTimeNs().count()));
269 log_packet = packet->set_android_log();
270 }
271
272 protos::pbzero::AndroidLogPacket::LogEvent* evt = nullptr;
273
274 if (entry.lid == AndroidLogId::LID_EVENTS) {
275 // Entries in the EVENTS buffer are special, they are binary encoded.
276 // See https://developer.android.com/reference/android/util/EventLog.
277 if (!ParseBinaryEvent(buf, end, log_packet, &evt)) {
278 PERFETTO_DLOG("Failed to parse Android log binary event");
279 stats_.num_failed++;
280 continue;
281 }
282 } else {
283 if (!ParseTextEvent(buf, end, log_packet, &evt)) {
284 PERFETTO_DLOG("Failed to parse Android log text event");
285 stats_.num_failed++;
286 continue;
287 }
288 }
289 if (!evt) {
290 // Parsing succeeded but the event was skipped due to filters.
291 stats_.num_skipped++;
292 continue;
293 }
294
295 // Add the common fields to the event.
296 uint64_t ts = entry.sec * 1000000000ULL + entry.nsec;
297 evt->set_timestamp(ts);
298 evt->set_log_id(static_cast<protos::pbzero::AndroidLogId>(entry.lid));
299 evt->set_pid(entry.pid);
300 evt->set_tid(static_cast<int32_t>(entry.tid));
301 evt->set_uid(static_cast<int32_t>(entry.uid));
302 } // while(logdr_sock_.Receive())
303
304 // Only print the log message if we have seen a bunch of events. This is to
305 // avoid that we keep re-triggering the log socket by writing into the log
306 // buffer ourselves.
307 if (num_events > 3)
308 PERFETTO_DLOG("Seen %zu Android log events", num_events);
309 }
310
ParseTextEvent(const char * start,const char * end,protos::pbzero::AndroidLogPacket * packet,protos::pbzero::AndroidLogPacket::LogEvent ** out_evt)311 bool AndroidLogDataSource::ParseTextEvent(
312 const char* start,
313 const char* end,
314 protos::pbzero::AndroidLogPacket* packet,
315 protos::pbzero::AndroidLogPacket::LogEvent** out_evt) {
316 // Format: [Priority 1 byte] [ tag ] [ NUL ] [ message ]
317 const char* buf = start;
318 int8_t prio;
319 if (!ReadAndAdvance(&buf, end, &prio))
320 return false;
321
322 if (prio > 10) {
323 PERFETTO_DLOG("Skipping log event with suspiciously high priority %d",
324 prio);
325 return false;
326 }
327
328 // Skip if the user specified a min-priority filter in the config.
329 if (prio < min_prio_)
330 return true;
331
332 // Find the null terminator that separates |tag| from |message|.
333 const char* str_end;
334 for (str_end = buf; str_end < end && *str_end; str_end++) {
335 }
336 if (str_end >= end - 2)
337 return false;
338
339 auto tag = base::StringView(buf, static_cast<size_t>(str_end - buf));
340 if (!filter_tags_.empty() && filter_tags_.count(tag) == 0)
341 return true;
342
343 auto* evt = packet->add_events();
344 *out_evt = evt;
345 evt->set_prio(static_cast<protos::pbzero::AndroidLogPriority>(prio));
346 evt->set_tag(tag.data(), tag.size());
347
348 buf = str_end + 1; // Move |buf| to the start of the message.
349 size_t msg_len = static_cast<size_t>(end - buf);
350
351 // Protobuf strings don't need the null terminator. If the string is
352 // null terminated, omit the terminator.
353 if (msg_len > 0 && *(end - 1) == '\0')
354 msg_len--;
355
356 evt->set_message(buf, msg_len);
357 return true;
358 }
359
ParseBinaryEvent(const char * start,const char * end,protos::pbzero::AndroidLogPacket * packet,protos::pbzero::AndroidLogPacket::LogEvent ** out_evt)360 bool AndroidLogDataSource::ParseBinaryEvent(
361 const char* start,
362 const char* end,
363 protos::pbzero::AndroidLogPacket* packet,
364 protos::pbzero::AndroidLogPacket::LogEvent** out_evt) {
365 const char* buf = start;
366 int32_t eid;
367 if (!ReadAndAdvance(&buf, end, &eid))
368 return false;
369
370 // TODO test events with 0 arguments. DNS.
371
372 const EventFormat* fmt = GetEventFormat(eid);
373 if (!fmt) {
374 // We got an event which doesn't have a corresponding entry in
375 // /system/etc/event-log-tags. In most cases this is a bug in the App that
376 // produced the event, which forgot to update the log tags dictionary.
377 return false;
378 }
379
380 if (!filter_tags_.empty() &&
381 filter_tags_.count(base::StringView(fmt->name)) == 0) {
382 return true;
383 }
384
385 auto* evt = packet->add_events();
386 *out_evt = evt;
387 evt->set_tag(fmt->name.c_str());
388 size_t field_num = 0;
389 while (buf < end) {
390 char type = *(buf++);
391 if (field_num >= fmt->fields.size())
392 return true;
393 const char* field_name = fmt->fields[field_num].c_str();
394 switch (type) {
395 case EVENT_TYPE_INT: {
396 int32_t value;
397 if (!ReadAndAdvance(&buf, end, &value))
398 return false;
399 auto* arg = evt->add_args();
400 arg->set_name(field_name);
401 arg->set_int_value(value);
402 field_num++;
403 break;
404 }
405 case EVENT_TYPE_LONG: {
406 int64_t value;
407 if (!ReadAndAdvance(&buf, end, &value))
408 return false;
409 auto* arg = evt->add_args();
410 arg->set_name(field_name);
411 arg->set_int_value(value);
412 field_num++;
413 break;
414 }
415 case EVENT_TYPE_FLOAT: {
416 float value;
417 if (!ReadAndAdvance(&buf, end, &value))
418 return false;
419 auto* arg = evt->add_args();
420 arg->set_name(field_name);
421 arg->set_float_value(value);
422 field_num++;
423 break;
424 }
425 case EVENT_TYPE_STRING: {
426 uint32_t len;
427 if (!ReadAndAdvance(&buf, end, &len) || buf + len > end)
428 return false;
429 auto* arg = evt->add_args();
430 arg->set_name(field_name);
431 arg->set_string_value(buf, len);
432 buf += len;
433 field_num++;
434 break;
435 }
436 case EVENT_TYPE_LIST: {
437 buf++; // EVENT_TYPE_LIST has one byte payload containing the list len.
438 if (field_num > 0) {
439 // Lists are supported only as a top-level node. We stop parsing when
440 // encountering a list as an inner field. The very few of them are not
441 // interesting enough to warrant the extra complexity.
442 return true;
443 }
444 break;
445 }
446 default:
447 PERFETTO_DLOG(
448 "Skipping unknown Android log binary event of type %d for %s at pos"
449 " %zd after parsing %zu fields",
450 static_cast<int>(type), fmt->name.c_str(), buf - start, field_num);
451 return true;
452 } // switch(type)
453 } // while(buf < end)
454 return true;
455 }
456
Flush(FlushRequestID,std::function<void ()> callback)457 void AndroidLogDataSource::Flush(FlushRequestID,
458 std::function<void()> callback) {
459 // Grab most recent entries.
460 if (logdr_sock_)
461 ReadLogSocket();
462
463 // Emit stats.
464 {
465 auto packet = writer_->NewTracePacket();
466 packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
467 auto* stats = packet->set_android_log()->set_stats();
468 stats->set_num_total(stats_.num_total);
469 stats->set_num_skipped(stats_.num_skipped);
470 stats->set_num_failed(stats_.num_failed);
471 }
472
473 writer_->Flush(callback);
474 }
475
ParseEventLogDefinitions()476 void AndroidLogDataSource::ParseEventLogDefinitions() {
477 std::string event_log_tags = ReadEventLogDefinitions();
478 for (base::StringSplitter ss(std::move(event_log_tags), '\n'); ss.Next();) {
479 if (!ParseEventLogDefinitionLine(ss.cur_token(), ss.cur_token_size() + 1)) {
480 PERFETTO_DLOG("Could not parse event log format: %s", ss.cur_token());
481 }
482 }
483 }
484
ParseEventLogDefinitionLine(char * line,size_t len)485 bool AndroidLogDataSource::ParseEventLogDefinitionLine(char* line, size_t len) {
486 base::StringSplitter tok(line, len, ' ');
487 if (!tok.Next())
488 return false;
489 auto id = static_cast<uint32_t>(std::strtoul(tok.cur_token(), nullptr, 10));
490 if (!tok.Next())
491 return false;
492 std::string name(tok.cur_token(), tok.cur_token_size());
493 auto it = event_formats_.emplace(id, EventFormat{std::move(name), {}}).first;
494 char* format = tok.cur_token() + tok.cur_token_size() + 1;
495 if (format >= line + len || !*format || *format == '\n') {
496 return true;
497 }
498 size_t format_len = len - static_cast<size_t>(format - line);
499
500 // Parse the arg formats, e.g.:
501 // (status|1|5),(health|1|5),(present|1|5),(plugged|1|5),(technology|3).
502 // We don't really care neither about the field type nor its unit (the two
503 // numbers after the |). The binary format re-states the type and we don't
504 // currently propagate the unit at all.
505 bool parsed_all_tokens = true;
506 for (base::StringSplitter field(format, format_len, ','); field.Next();) {
507 if (field.cur_token_size() <= 2) {
508 parsed_all_tokens = false;
509 continue;
510 }
511 char* start = field.cur_token() + 1;
512 base::StringSplitter parts(start, field.cur_token_size() - 1, '|');
513 if (!parts.Next()) {
514 parsed_all_tokens = false;
515 continue;
516 }
517 std::string field_name(parts.cur_token(), parts.cur_token_size());
518 it->second.fields.emplace_back(std::move(field_name));
519 }
520 return parsed_all_tokens;
521 }
522
ReadEventLogDefinitions()523 std::string AndroidLogDataSource::ReadEventLogDefinitions() {
524 std::string contents;
525 if (!base::ReadFile(kLogTagsPath, &contents)) {
526 PERFETTO_PLOG("Failed to read %s", kLogTagsPath);
527 return "";
528 }
529 return contents;
530 }
531
GetEventFormat(int id) const532 const AndroidLogDataSource::EventFormat* AndroidLogDataSource::GetEventFormat(
533 int id) const {
534 auto it = event_formats_.find(id);
535 return it == event_formats_.end() ? nullptr : &it->second;
536 }
537
538 } // namespace perfetto
539