• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 <ctype.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <inttypes.h>
21 #include <pthread.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/mman.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/uio.h>
28 #include <unistd.h>
29 
30 #include <string>
31 
32 #include <android-base/file.h>
33 #include <android-base/logging.h>
34 #include <android-base/macros.h>
35 #include <android-base/scopeguard.h>
36 #include <android-base/stringprintf.h>
37 #include <android-base/threads.h>
38 #include <log/log_event_list.h>
39 #include <log/log_properties.h>
40 #include <log/log_read.h>
41 #include <private/android_filesystem_config.h>
42 
43 #include "LogStatistics.h"
44 #include "LogTags.h"
45 #include "LogUtils.h"
46 
47 using android::base::make_scope_guard;
48 
49 static LogTags* logtags;
50 
51 const char LogTags::system_event_log_tags[] = "/system/etc/event-log-tags";
52 const char LogTags::dynamic_event_log_tags[] = "/dev/event-log-tags";
53 // Only for debug
54 const char LogTags::debug_event_log_tags[] = "/data/misc/logd/event-log-tags";
55 
56 // Sniff for first uid=%d in utf8z comment string
sniffUid(const char * comment,const char * endp)57 static uid_t sniffUid(const char* comment, const char* endp) {
58     if (!comment) return AID_ROOT;
59 
60     if (*comment == '#') ++comment;
61     while ((comment < endp) && (*comment != '\n') && isspace(*comment))
62         ++comment;
63     static const char uid_str[] = "uid=";
64     if (((comment + strlen(uid_str)) >= endp) ||
65         fastcmp<strncmp>(comment, uid_str, strlen(uid_str)) ||
66         !isdigit(comment[strlen(uid_str)]))
67         return AID_ROOT;
68     char* cp;
69     unsigned long Uid = strtoul(comment + 4, &cp, 10);
70     if ((cp > endp) || (Uid >= INT_MAX)) return AID_ROOT;
71 
72     return Uid;
73 }
74 
75 // Checks for file corruption, and report false if there was no need
76 // to rebuild the referenced file.  Failure to rebuild is only logged,
77 // does not cause a return value of false.
RebuildFileEventLogTags(const char * filename,bool warn)78 bool LogTags::RebuildFileEventLogTags(const char* filename, bool warn) {
79     int fd;
80 
81     {
82         android::RWLock::AutoRLock readLock(rwlock);
83 
84         if (tag2total.begin() == tag2total.end()) {
85             return false;
86         }
87 
88         file2watermark_const_iterator iwater = file2watermark.find(filename);
89         if (iwater == file2watermark.end()) {
90             return false;
91         }
92 
93         struct stat sb;
94         if (!stat(filename, &sb) && ((size_t)sb.st_size >= iwater->second)) {
95             return false;
96         }
97 
98         // dump what we already know back into the file?
99         fd = TEMP_FAILURE_RETRY(open(
100             filename, O_WRONLY | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
101         if (fd >= 0) {
102             time_t now = time(nullptr);
103             struct tm tm;
104             localtime_r(&now, &tm);
105             char timebuf[20];
106             strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", &tm);
107             android::base::WriteStringToFd(
108                 android::base::StringPrintf(
109                     "# Rebuilt %.20s, content owned by logd\n", timebuf),
110                 fd);
111             for (const auto& it : tag2total) {
112                 android::base::WriteStringToFd(
113                     formatEntry_locked(it.first, AID_ROOT), fd);
114             }
115             close(fd);
116         }
117     }
118 
119     if (warn) {
120         if (fd < 0) {
121             LOG(ERROR) << filename << " failed to rebuild";
122         } else {
123             LOG(ERROR) << filename << " missing, damaged or truncated; rebuilt";
124         }
125     }
126 
127     if (fd >= 0) {
128         android::RWLock::AutoWLock writeLock(rwlock);
129 
130         struct stat sb;
131         if (!stat(filename, &sb)) file2watermark[filename] = sb.st_size;
132     }
133 
134     return true;
135 }
136 
AddEventLogTags(uint32_t tag,uid_t uid,const std::string & Name,const std::string & Format,const char * source,bool warn)137 void LogTags::AddEventLogTags(uint32_t tag, uid_t uid, const std::string& Name,
138                               const std::string& Format, const char* source,
139                               bool warn) {
140     std::string Key = Name;
141     if (Format.length()) Key += "+" + Format;
142 
143     bool update = !source || !!strcmp(source, system_event_log_tags);
144     bool newOne;
145 
146     {
147         android::RWLock::AutoWLock writeLock(rwlock);
148 
149         tag2total_const_iterator itot = tag2total.find(tag);
150 
151         // unlikely except for dupes, or updates to uid list (more later)
152         if (itot != tag2total.end()) update = false;
153 
154         newOne = tag2name.find(tag) == tag2name.end();
155         key2tag[Key] = tag;
156 
157         if (Format.length()) {
158             if (key2tag.find(Name) == key2tag.end()) {
159                 key2tag[Name] = tag;
160             }
161             tag2format[tag] = Format;
162         }
163         tag2name[tag] = Name;
164 
165         tag2uid_const_iterator ut = tag2uid.find(tag);
166         if (ut != tag2uid.end()) {
167             if (uid == AID_ROOT) {
168                 tag2uid.erase(ut);
169                 update = true;
170             } else if (ut->second.find(uid) == ut->second.end()) {
171                 const_cast<uid_list&>(ut->second).emplace(uid);
172                 update = true;
173             }
174         } else if (newOne && (uid != AID_ROOT)) {
175             tag2uid[tag].emplace(uid);
176             update = true;
177         }
178 
179         // updatePersist -> trigger output on modified
180         // content, reset tag2total if available
181         if (update && (itot != tag2total.end())) tag2total[tag] = 0;
182     }
183 
184     if (update) {
185         WritePersistEventLogTags(tag, uid, source);
186     } else if (warn && !newOne && source) {
187         // For the files, we want to report dupes.
188         LOG(DEBUG) << "Multiple tag " << tag << " " << Name << " " << Format << " " << source;
189     }
190 }
191 
192 // Read the event log tags file, and build up our internal database
ReadFileEventLogTags(const char * filename,bool warn)193 void LogTags::ReadFileEventLogTags(const char* filename, bool warn) {
194     bool etc = !strcmp(filename, system_event_log_tags);
195 
196     if (!etc) {
197         RebuildFileEventLogTags(filename, warn);
198     }
199     std::string content;
200     if (android::base::ReadFileToString(filename, &content)) {
201         char* cp = (char*)content.c_str();
202         char* endp = cp + content.length();
203 
204         {
205             android::RWLock::AutoRLock writeLock(rwlock);
206 
207             file2watermark[filename] = content.length();
208         }
209 
210         char* lineStart = cp;
211         while (cp < endp) {
212             if (*cp == '\n') {
213                 lineStart = cp;
214             } else if (lineStart) {
215                 if (*cp == '#') {
216                     /* comment; just scan to end */
217                     lineStart = nullptr;
218                 } else if (isdigit(*cp)) {
219                     unsigned long Tag = strtoul(cp, &cp, 10);
220                     if (warn && (Tag > emptyTag)) {
221                         LOG(WARNING) << "tag too large " << Tag;
222                     }
223                     while ((cp < endp) && (*cp != '\n') && isspace(*cp)) ++cp;
224                     if (cp >= endp) break;
225                     if (*cp == '\n') continue;
226                     const char* name = cp;
227                     /* Determine whether it is a valid tag name [a-zA-Z0-9_] */
228                     bool hasAlpha = false;
229                     while ((cp < endp) && (isalnum(*cp) || (*cp == '_'))) {
230                         if (!isdigit(*cp)) hasAlpha = true;
231                         ++cp;
232                     }
233                     std::string Name(name, cp - name);
234 #ifdef ALLOW_NOISY_LOGGING_OF_PROBLEM_WITH_LOTS_OF_TECHNICAL_DEBT
235                     static const size_t maximum_official_tag_name_size = 24;
236                     if (warn && (Name.length() > maximum_official_tag_name_size)) {
237                         LOG(WARNING) << "tag name too long " << Name;
238                     }
239 #endif
240                     if (hasAlpha &&
241                         ((cp >= endp) || (*cp == '#') || isspace(*cp))) {
242                         if (Tag > emptyTag) {
243                             if (*cp != '\n') lineStart = nullptr;
244                             continue;
245                         }
246                         while ((cp < endp) && (*cp != '\n') && isspace(*cp))
247                             ++cp;
248                         const char* format = cp;
249                         uid_t uid = AID_ROOT;
250                         while ((cp < endp) && (*cp != '\n')) {
251                             if (*cp == '#') {
252                                 uid = sniffUid(cp, endp);
253                                 lineStart = nullptr;
254                                 break;
255                             }
256                             ++cp;
257                         }
258                         while ((cp > format) && isspace(cp[-1])) {
259                             --cp;
260                             lineStart = nullptr;
261                         }
262                         std::string Format(format, cp - format);
263 
264                         AddEventLogTags((uint32_t)Tag, uid, Name, Format,
265                                         filename, warn);
266                     } else {
267                         if (warn) {
268                             LOG(ERROR) << android::base::StringPrintf("tag name invalid %.*s",
269                                                                       (int)(cp - name + 1), name);
270                         }
271                         lineStart = nullptr;
272                     }
273                 } else if (!isspace(*cp)) {
274                     break;
275                 }
276             }
277             cp++;
278         }
279     } else if (warn) {
280 #ifdef __ANDROID__
281         LOG(ERROR) << "Cannot read " << filename;
282 #endif
283     }
284 }
285 
286 // Extract a 4-byte value from a byte stream.
get4LE(const char * msg)287 static inline uint32_t get4LE(const char* msg) {
288     const uint8_t* src = reinterpret_cast<const uint8_t*>(msg);
289     return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
290 }
291 
292 // Additional persistent sources for invented log tags.  Read the
293 // special pmsg event for log tags, and build up our internal
294 // database with any found.
ReadPersistEventLogTags()295 void LogTags::ReadPersistEventLogTags() {
296     struct logger_list* logger_list =
297             android_logger_list_alloc(ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK, 0, (pid_t)0);
298     if (!logger_list) return;
299 
300     struct logger* e = android_logger_open(logger_list, LOG_ID_EVENTS);
301     struct logger* s = android_logger_open(logger_list, LOG_ID_SECURITY);
302     if (!e && !s) {
303         android_logger_list_free(logger_list);
304         return;
305     }
306 
307     for (;;) {
308         struct log_msg log_msg;
309         int ret = android_logger_list_read(logger_list, &log_msg);
310         if (ret <= 0) break;
311 
312         const char* msg = log_msg.msg();
313         if (!msg) continue;
314         if (log_msg.entry.len <= sizeof(uint32_t)) continue;
315         uint32_t Tag = get4LE(msg);
316         if (Tag != TAG_DEF_LOG_TAG) continue;
317         uid_t uid = log_msg.entry.uid;
318 
319         std::string Name;
320         std::string Format;
321         android_log_list_element elem;
322         {
323             auto ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
324                                                  log_msg.entry.len - sizeof(uint32_t));
325             auto guard = make_scope_guard([&ctx]() { android_log_destroy(&ctx); });
326             elem = android_log_read_next(ctx);
327             if (elem.type != EVENT_TYPE_LIST) {
328                 continue;
329             }
330             elem = android_log_read_next(ctx);
331             if (elem.type != EVENT_TYPE_INT) {
332                 continue;
333             }
334             Tag = elem.data.int32;
335             elem = android_log_read_next(ctx);
336             if (elem.type != EVENT_TYPE_STRING) {
337                 continue;
338             }
339             Name = std::string(elem.data.string, elem.len);
340             elem = android_log_read_next(ctx);
341             if (elem.type != EVENT_TYPE_STRING) {
342                 continue;
343             }
344             Format = std::string(elem.data.string, elem.len);
345             elem = android_log_read_next(ctx);
346         }
347         if ((elem.type != EVENT_TYPE_LIST_STOP) || !elem.complete) continue;
348 
349         AddEventLogTags(Tag, uid, Name, Format);
350     }
351     android_logger_list_free(logger_list);
352 }
353 
LogTags()354 LogTags::LogTags() {
355     ReadFileEventLogTags(system_event_log_tags);
356     // Following will likely fail on boot, but is required if logd restarts
357     ReadFileEventLogTags(dynamic_event_log_tags, false);
358     if (__android_log_is_debuggable()) {
359         ReadFileEventLogTags(debug_event_log_tags, false);
360     }
361     ReadPersistEventLogTags();
362 
363     logtags = this;
364 }
365 
366 // Converts an event tag into a name
tagToName(uint32_t tag) const367 const char* LogTags::tagToName(uint32_t tag) const {
368     tag2name_const_iterator it;
369 
370     android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
371 
372     it = tag2name.find(tag);
373     if ((it == tag2name.end()) || (it->second.length() == 0)) return nullptr;
374 
375     return it->second.c_str();
376 }
377 
378 // Prototype in LogUtils.h allowing external access to our database.
379 //
380 // This must be a pure reader to our database, as everything else is
381 // guaranteed single-threaded except this access point which is
382 // asynchonous and can be multithreaded and thus rentrant.  The
383 // object's rwlock is only used to guarantee atomic access to the
384 // unordered_map to prevent corruption, with a requirement to be a
385 // low chance of contention for this call.  If we end up changing
386 // this algorithm resulting in write, then we should use a different
387 // lock than the object's rwlock to protect groups of associated
388 // actions.
tagToName(uint32_t tag)389 const char* android::tagToName(uint32_t tag) {
390     LogTags* me = logtags;
391 
392     if (!me) return nullptr;
393     me->WritePmsgEventLogTags(tag);
394     return me->tagToName(tag);
395 }
396 
397 // converts an event tag into a format
tagToFormat(uint32_t tag) const398 const char* LogTags::tagToFormat(uint32_t tag) const {
399     tag2format_const_iterator iform;
400 
401     android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
402 
403     iform = tag2format.find(tag);
404     if (iform == tag2format.end()) return nullptr;
405 
406     return iform->second.c_str();
407 }
408 
409 // converts a name into an event tag
nameToTag(const char * name) const410 uint32_t LogTags::nameToTag(const char* name) const {
411     uint32_t ret = emptyTag;
412 
413     // Bug: Only works for a single entry, we can have multiple entries,
414     // one for each format, so we find first entry recorded, or entry with
415     // no format associated with it.
416 
417     android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
418 
419     key2tag_const_iterator ik = key2tag.find(std::string(name));
420     if (ik != key2tag.end()) ret = ik->second;
421 
422     return ret;
423 }
424 
425 // Caller must perform locks, can be under reader (for pre-check) or
426 // writer lock.  We use this call to invent a new deterministically
427 // random tag, unique is cleared if no conflicts.  If format is NULL,
428 // we are in readonly mode.
nameToTag_locked(const std::string & name,const char * format,bool & unique)429 uint32_t LogTags::nameToTag_locked(const std::string& name, const char* format,
430                                    bool& unique) {
431     key2tag_const_iterator ik;
432 
433     bool write = format != nullptr;
434     unique = write;
435 
436     if (!write) {
437         // Bug: Only works for a single entry, we can have multiple entries,
438         // one for each format, so we find first entry recorded, or entry with
439         // no format associated with it.
440         ik = key2tag.find(name);
441         if (ik == key2tag.end()) return emptyTag;
442         return ik->second;
443     }
444 
445     std::string Key(name);
446     if (*format) Key += std::string("+") + format;
447 
448     ik = key2tag.find(Key);
449     if (ik != key2tag.end()) {
450         unique = false;
451         return ik->second;
452     }
453 
454     size_t Hash = key2tag.hash_function()(Key);
455     uint32_t Tag = Hash;
456     // This sets an upper limit on the conflics we are allowed to deal with.
457     for (unsigned i = 0; i < 256;) {
458         tag2name_const_iterator it = tag2name.find(Tag);
459         if (it == tag2name.end()) return Tag;
460         std::string localKey(it->second);
461         tag2format_const_iterator iform = tag2format.find(Tag);
462         if ((iform == tag2format.end()) && iform->second.length()) {
463             localKey += "+" + iform->second;
464         }
465         unique = !!it->second.compare(localKey);
466         if (!unique) return Tag;  // unlikely except in a race
467 
468         ++i;
469         // Algorithm to convert hash to next tag
470         if (i < 32) {
471             Tag = (Hash >> i);
472             // size_t is 32 bits, or upper word zero, rotate
473             if ((sizeof(Hash) <= 4) || ((Hash & (uint64_t(-1LL) << 32)) == 0)) {
474                 Tag |= Hash << (32 - i);
475             }
476         } else {
477             Tag = Hash + i - 31;
478         }
479     }
480     return emptyTag;
481 }
482 
openFile(const char * name,int mode,bool warning)483 static int openFile(const char* name, int mode, bool warning) {
484     int fd = TEMP_FAILURE_RETRY(open(name, mode));
485     if (fd < 0 && warning) {
486         PLOG(ERROR) << "Failed to open " << name;
487     }
488     return fd;
489 }
490 
WritePmsgEventLogTags(uint32_t tag,uid_t uid)491 void LogTags::WritePmsgEventLogTags(uint32_t tag, uid_t uid) {
492     android::RWLock::AutoRLock readLock(rwlock);
493 
494     tag2total_const_iterator itot = tag2total.find(tag);
495     if (itot == tag2total.end()) return;  // source is a static entry
496 
497     size_t lastTotal = itot->second;
498 
499     // Every 16K (half the smallest configurable pmsg buffer size) record
500     static const size_t rate_to_pmsg = 16 * 1024;
501     if (lastTotal && (LogStatistics::sizesTotal() - lastTotal) < rate_to_pmsg) {
502         return;
503     }
504 
505     static int pmsg_fd = -1;
506     if (pmsg_fd < 0) {
507         pmsg_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
508         // unlikely, but deal with partners with borken pmsg
509         if (pmsg_fd < 0) return;
510     }
511 
512     std::string Name = tag2name[tag];
513     tag2format_const_iterator iform = tag2format.find(tag);
514     std::string Format = (iform != tag2format.end()) ? iform->second : "";
515 
516     auto ctx = create_android_logger(TAG_DEF_LOG_TAG);
517     auto guard = make_scope_guard([&ctx]() { android_log_destroy(&ctx); });
518     if (android_log_write_int32(ctx, static_cast<int32_t>(tag) < 0) ||
519         android_log_write_string8_len(ctx, Name.c_str(), Name.size()) < 0 ||
520         android_log_write_string8_len(ctx, Format.c_str(), Format.size()) < 0) {
521         return;
522     }
523 
524     const char* cp = nullptr;
525     ssize_t len = android_log_write_list_buffer(ctx, &cp);
526 
527     if (len <= 0 || cp == nullptr) {
528         return;
529     }
530 
531     std::string buffer(cp, len);
532 
533     /*
534      *  struct {
535      *      // what we provide to pstore
536      *      android_pmsg_log_header_t pmsgHeader;
537      *      // what we provide to file
538      *      android_log_header_t header;
539      *      // caller provides
540      *      union {
541      *          struct {
542      *              char     prio;
543      *              char     payload[];
544      *          } string;
545      *          struct {
546      *              uint32_t tag
547      *              char     payload[];
548      *          } binary;
549      *      };
550      *  };
551      */
552 
553     struct timespec ts;
554     clock_gettime(CLOCK_REALTIME, &ts);
555 
556     android_log_header_t header = {
557             .id = LOG_ID_EVENTS,
558             .tid = static_cast<uint16_t>(android::base::GetThreadId()),
559             .realtime.tv_sec = static_cast<uint32_t>(ts.tv_sec),
560             .realtime.tv_nsec = static_cast<uint32_t>(ts.tv_nsec),
561     };
562 
563     uint32_t outTag = TAG_DEF_LOG_TAG;
564     outTag = get4LE((const char*)&outTag);
565 
566     android_pmsg_log_header_t pmsgHeader = {
567         .magic = LOGGER_MAGIC,
568         .len = (uint16_t)(sizeof(pmsgHeader) + sizeof(header) + sizeof(outTag) +
569                           buffer.length()),
570         .uid = (uint16_t)AID_ROOT,
571         .pid = (uint16_t)getpid(),
572     };
573 
574     struct iovec Vec[] = { { (unsigned char*)&pmsgHeader, sizeof(pmsgHeader) },
575                            { (unsigned char*)&header, sizeof(header) },
576                            { (unsigned char*)&outTag, sizeof(outTag) },
577                            { (unsigned char*)const_cast<char*>(buffer.data()),
578                              buffer.length() } };
579 
580     tag2uid_const_iterator ut = tag2uid.find(tag);
581     if (ut == tag2uid.end()) {
582         TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
583     } else if (uid != AID_ROOT) {
584         pmsgHeader.uid = (uint16_t)uid;
585         TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
586     } else {
587         for (auto& it : ut->second) {
588             pmsgHeader.uid = (uint16_t)it;
589             TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
590         }
591     }
592 }
593 
WriteDynamicEventLogTags(uint32_t tag,uid_t uid)594 void LogTags::WriteDynamicEventLogTags(uint32_t tag, uid_t uid) {
595     static const int mode =
596         O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
597 
598     int fd = openFile(dynamic_event_log_tags, mode, true);
599     if (fd < 0) return;
600 
601     android::RWLock::AutoWLock writeLock(rwlock);
602 
603     std::string ret = formatEntry_locked(tag, uid, false);
604     android::base::WriteStringToFd(ret, fd);
605     close(fd);
606 
607     size_t size = 0;
608     file2watermark_const_iterator iwater;
609 
610     iwater = file2watermark.find(dynamic_event_log_tags);
611     if (iwater != file2watermark.end()) size = iwater->second;
612 
613     file2watermark[dynamic_event_log_tags] = size + ret.length();
614 }
615 
WriteDebugEventLogTags(uint32_t tag,uid_t uid)616 void LogTags::WriteDebugEventLogTags(uint32_t tag, uid_t uid) {
617     static const int mode =
618         O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
619 
620     static bool one = true;
621     int fd = openFile(debug_event_log_tags, mode, one);
622     one = fd >= 0;
623     if (!one) return;
624 
625     android::RWLock::AutoWLock writeLock(rwlock);
626 
627     std::string ret = formatEntry_locked(tag, uid, false);
628     android::base::WriteStringToFd(ret, fd);
629     close(fd);
630 
631     size_t size = 0;
632     file2watermark_const_iterator iwater;
633 
634     iwater = file2watermark.find(debug_event_log_tags);
635     if (iwater != file2watermark.end()) size = iwater->second;
636 
637     file2watermark[debug_event_log_tags] = size + ret.length();
638 }
639 
640 // How we maintain some runtime or reboot stickiness
WritePersistEventLogTags(uint32_t tag,uid_t uid,const char * source)641 void LogTags::WritePersistEventLogTags(uint32_t tag, uid_t uid,
642                                        const char* source) {
643     // very unlikely
644     bool etc = source && !strcmp(source, system_event_log_tags);
645     if (etc) return;
646 
647     bool dynamic = source && !strcmp(source, dynamic_event_log_tags);
648     bool debug = (!dynamic && source && !strcmp(source, debug_event_log_tags)) ||
649                  !__android_log_is_debuggable();
650 
651     WritePmsgEventLogTags(tag, uid);
652 
653     size_t lastTotal = 0;
654     {
655         android::RWLock::AutoRLock readLock(rwlock);
656 
657         tag2total_const_iterator itot = tag2total.find(tag);
658         if (itot != tag2total.end()) lastTotal = itot->second;
659     }
660 
661     if (lastTotal == 0) {  // denotes first time for this one
662         if (!dynamic || !RebuildFileEventLogTags(dynamic_event_log_tags)) {
663             WriteDynamicEventLogTags(tag, uid);
664         }
665 
666         if (!debug && !RebuildFileEventLogTags(debug_event_log_tags)) {
667             WriteDebugEventLogTags(tag, uid);
668         }
669     }
670 
671     lastTotal = LogStatistics::sizesTotal();
672     if (!lastTotal) ++lastTotal;
673 
674     // record totals for next watermark.
675     android::RWLock::AutoWLock writeLock(rwlock);
676     tag2total[tag] = lastTotal;
677 }
678 
679 // nameToTag converts a name into an event tag. If format is NULL, then we
680 // are in readonly mode.
nameToTag(uid_t uid,const char * name,const char * format)681 uint32_t LogTags::nameToTag(uid_t uid, const char* name, const char* format) {
682     std::string Name = std::string(name);
683     bool write = format != nullptr;
684     bool updateUid = uid != AID_ROOT;
685     bool updateFormat = format && *format;
686     bool unique;
687     uint32_t Tag;
688 
689     {
690         android::RWLock::AutoRLock readLock(rwlock);
691 
692         Tag = nameToTag_locked(Name, format, unique);
693         if (updateUid && (Tag != emptyTag) && !unique) {
694             tag2uid_const_iterator ut = tag2uid.find(Tag);
695             if ((ut != tag2uid.end()) &&
696                 (ut->second.find(uid) == ut->second.end())) {
697                 unique = write;  // write passthrough to update uid counts
698                 if (!write) Tag = emptyTag;  // deny read access
699             }
700         }
701     }
702 
703     if (Tag == emptyTag) return Tag;
704     WritePmsgEventLogTags(Tag, uid);  // record references periodically
705     if (!unique) return Tag;
706 
707     bool updateWrite = false;
708     bool updateTag;
709 
710     // Special case of AddEventLogTags, checks per-uid counter which makes
711     // no sense there, and is also optimized somewhat to reduce write times.
712     {
713         android::RWLock::AutoWLock writeLock(rwlock);
714 
715         // double check after switch from read lock to write lock for Tag
716         updateTag = tag2name.find(Tag) == tag2name.end();
717         // unlikely, either update, race inviting conflict or multiple uids
718         if (!updateTag) {
719             Tag = nameToTag_locked(Name, format, unique);
720             if (Tag == emptyTag) return Tag;
721             // is it multiple uid's setting this value
722             if (!unique) {
723                 tag2uid_const_iterator ut = tag2uid.find(Tag);
724                 if (updateUid) {
725                     // Add it to the uid list
726                     if ((ut == tag2uid.end()) ||
727                         (ut->second.find(uid) != ut->second.end())) {
728                         return Tag;
729                     }
730                     const_cast<uid_list&>(ut->second).emplace(uid);
731                     updateWrite = true;
732                 } else {
733                     if (ut == tag2uid.end()) return Tag;
734                     // (system) adding a global one, erase the uid list
735                     tag2uid.erase(ut);
736                     updateWrite = true;
737                 }
738             }
739         }
740 
741         // Update section
742         size_t count;
743         if (updateUid) {
744             count = 0;
745             uid2count_const_iterator ci = uid2count.find(uid);
746             if (ci != uid2count.end()) {
747                 count = ci->second;
748                 if (count >= max_per_uid) {
749                     if (!updateWrite) return emptyTag;
750                     // If we are added to the per-Uid perms, leak the Tag
751                     // if it already exists.
752                     updateUid = false;
753                     updateTag = false;
754                     updateFormat = false;
755                 }
756             }
757         }
758 
759         // updateWrite -> trigger output on modified content, reset tag2total
760         //    also sets static to dynamic entries if they are alterred,
761         //    only occurs if they have a uid, and runtime adds another uid.
762         if (updateWrite) tag2total[Tag] = 0;
763 
764         if (updateTag) {
765             // mark as a dynamic entry, but do not upset current total counter
766             tag2total_const_iterator itot = tag2total.find(Tag);
767             if (itot == tag2total.end()) tag2total[Tag] = 0;
768 
769             if (*format) {
770                 key2tag[Name + "+" + format] = Tag;
771                 if (key2tag.find(Name) == key2tag.end()) key2tag[Name] = Tag;
772             } else {
773                 key2tag[Name] = Tag;
774             }
775             tag2name[Tag] = Name;
776         }
777         if (updateFormat) tag2format[Tag] = format;
778 
779         if (updateUid) {
780             tag2uid[Tag].emplace(uid);
781             uid2count[uid] = count + 1;
782         }
783     }
784 
785     if (updateTag || updateFormat || updateWrite) {
786         WritePersistEventLogTags(Tag, uid);
787     }
788 
789     return Tag;
790 }
791 
formatEntry(uint32_t tag,uid_t uid,const char * name,const char * format)792 std::string LogTags::formatEntry(uint32_t tag, uid_t uid, const char* name,
793                                  const char* format) {
794     if (!format || !format[0]) {
795         return android::base::StringPrintf("%" PRIu32 "\t%s\n", tag, name);
796     }
797     size_t len = (strlen(name) + 7) / 8;
798     static const char tabs[] = "\t\t\t";
799     if (len > strlen(tabs)) len = strlen(tabs);
800     std::string Uid;
801     if (uid != AID_ROOT) Uid = android::base::StringPrintf(" # uid=%u", uid);
802     return android::base::StringPrintf("%" PRIu32 "\t%s%s\t%s%s\n", tag, name,
803                                        &tabs[len], format, Uid.c_str());
804 }
805 
formatEntry_locked(uint32_t tag,uid_t uid,bool authenticate)806 std::string LogTags::formatEntry_locked(uint32_t tag, uid_t uid,
807                                         bool authenticate) {
808     const char* name = tag2name[tag].c_str();
809 
810     const char* format = "";
811     tag2format_const_iterator iform = tag2format.find(tag);
812     if (iform != tag2format.end()) format = iform->second.c_str();
813 
814     // Access permission test, do not report dynamic entries
815     // that do not belong to us.
816     tag2uid_const_iterator ut = tag2uid.find(tag);
817     if (ut == tag2uid.end()) {
818         return formatEntry(tag, AID_ROOT, name, format);
819     }
820     if (uid != AID_ROOT) {
821         if (authenticate && (ut->second.find(uid) == ut->second.end())) {
822             return std::string("");
823         }
824         return formatEntry(tag, uid, name, format);
825     }
826 
827     // Show all, one for each registered uid (we are group root)
828     std::string ret;
829     for (auto& it : ut->second) {
830         ret += formatEntry(tag, it, name, format);
831     }
832     return ret;
833 }
834 
formatEntry(uint32_t tag,uid_t uid)835 std::string LogTags::formatEntry(uint32_t tag, uid_t uid) {
836     android::RWLock::AutoRLock readLock(rwlock);
837     return formatEntry_locked(tag, uid);
838 }
839 
formatGetEventTag(uid_t uid,const char * name,const char * format)840 std::string LogTags::formatGetEventTag(uid_t uid, const char* name,
841                                        const char* format) {
842     bool all = name && (name[0] == '*') && !name[1];
843     bool list = !name || all;
844     std::string ret;
845 
846     if (!list) {
847         // switch to read entry only if format == "*"
848         if (format && (format[0] == '*') && !format[1]) format = nullptr;
849 
850         // WAI: for null format, only works for a single entry, we can have
851         // multiple entries, one for each format, so we find first entry
852         // recorded, or entry with no format associated with it.
853         // We may desire to print all that match the name, but we did not
854         // add a mapping table for that and the cost is too high.
855         uint32_t tag = nameToTag(uid, name, format);
856         if (tag == emptyTag) return std::string("-1 ESRCH");
857         if (uid == AID_ROOT) {
858             android::RWLock::AutoRLock readLock(rwlock);
859 
860             // first uid in list so as to manufacture an accurate reference
861             tag2uid_const_iterator ut = tag2uid.find(tag);
862             if ((ut != tag2uid.end()) &&
863                 (ut->second.begin() != ut->second.end())) {
864                 uid = *(ut->second.begin());
865             }
866         }
867         ret = formatEntry(tag, uid, name, format ?: tagToFormat(tag));
868         if (!ret.length()) return std::string("-1 ESRCH");
869         return ret;
870     }
871 
872     android::RWLock::AutoRLock readLock(rwlock);
873     if (all) {
874         // everything under the sun
875         for (const auto& it : tag2name) {
876             ret += formatEntry_locked(it.first, uid);
877         }
878     } else {
879         // set entries are dynamic
880         for (const auto& it : tag2total) {
881             ret += formatEntry_locked(it.first, uid);
882         }
883     }
884     return ret;
885 }
886