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