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