Home | History | Annotate | Download | only in liblog
      1 /*
      2  * Copyright (C) 2007-2016 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 <assert.h>
     18 #include <ctype.h>
     19 #include <errno.h>
     20 #include <fcntl.h>
     21 #include <inttypes.h>
     22 #include <limits.h>
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <string.h>
     26 #include <sys/mman.h>
     27 
     28 #include <experimental/string_view>
     29 #include <functional>
     30 #include <string>
     31 #include <unordered_map>
     32 
     33 #include <log/event_tag_map.h>
     34 #include <log/log_properties.h>
     35 #include <private/android_logger.h>
     36 #include <utils/FastStrcmp.h>
     37 #include <utils/RWLock.h>
     38 
     39 #include "log_portability.h"
     40 #include "logd_reader.h"
     41 
     42 #define OUT_TAG "EventTagMap"
     43 
     44 class MapString {
     45  private:
     46   const std::string* alloc;                  // HAS-AN
     47   const std::experimental::string_view str;  // HAS-A
     48 
     49  public:
     50   operator const std::experimental::string_view() const {
     51     return str;
     52   }
     53 
     54   const char* data() const {
     55     return str.data();
     56   }
     57   size_t length() const {
     58     return str.length();
     59   }
     60 
     61   bool operator==(const MapString& rval) const {
     62     if (length() != rval.length()) return false;
     63     if (length() == 0) return true;
     64     return fastcmp<strncmp>(data(), rval.data(), length()) == 0;
     65   }
     66   bool operator!=(const MapString& rval) const {
     67     return !(*this == rval);
     68   }
     69 
     70   MapString(const char* str, size_t len) : alloc(NULL), str(str, len) {
     71   }
     72   explicit MapString(const std::string& str)
     73       : alloc(new std::string(str)), str(alloc->data(), alloc->length()) {
     74   }
     75   MapString(MapString&& rval)
     76       : alloc(rval.alloc), str(rval.data(), rval.length()) {
     77     rval.alloc = NULL;
     78   }
     79   explicit MapString(const MapString& rval)
     80       : alloc(rval.alloc ? new std::string(*rval.alloc) : NULL),
     81         str(alloc ? alloc->data() : rval.data(), rval.length()) {
     82   }
     83 
     84   ~MapString() {
     85     if (alloc) delete alloc;
     86   }
     87 };
     88 
     89 // Hash for MapString
     90 template <>
     91 struct std::hash<MapString>
     92     : public std::unary_function<const MapString&, size_t> {
     93   size_t operator()(const MapString& __t) const noexcept {
     94     if (!__t.length()) return 0;
     95     return std::hash<std::experimental::string_view>()(
     96         std::experimental::string_view(__t));
     97   }
     98 };
     99 
    100 typedef std::pair<MapString, MapString> TagFmt;
    101 
    102 template <>
    103 struct std::hash<TagFmt> : public std::unary_function<const TagFmt&, size_t> {
    104   size_t operator()(const TagFmt& __t) const noexcept {
    105     // Tag is typically unique.  Will cost us an extra 100ns for the
    106     // unordered_map lookup if we instead did a hash that combined
    107     // both of tag and fmt members, e.g.:
    108     //
    109     // return std::hash<MapString>()(__t.first) ^
    110     //        std::hash<MapString>()(__t.second);
    111     return std::hash<MapString>()(__t.first);
    112   }
    113 };
    114 
    115 // Map
    116 struct EventTagMap {
    117 #define NUM_MAPS 2
    118   // memory-mapped source file; we get strings from here
    119   void* mapAddr[NUM_MAPS];
    120   size_t mapLen[NUM_MAPS];
    121 
    122  private:
    123   std::unordered_map<uint32_t, TagFmt> Idx2TagFmt;
    124   std::unordered_map<TagFmt, uint32_t> TagFmt2Idx;
    125   std::unordered_map<MapString, uint32_t> Tag2Idx;
    126   // protect unordered sets
    127   android::RWLock rwlock;
    128 
    129  public:
    130   EventTagMap() {
    131     memset(mapAddr, 0, sizeof(mapAddr));
    132     memset(mapLen, 0, sizeof(mapLen));
    133   }
    134 
    135   ~EventTagMap() {
    136     Idx2TagFmt.clear();
    137     TagFmt2Idx.clear();
    138     Tag2Idx.clear();
    139     for (size_t which = 0; which < NUM_MAPS; ++which) {
    140       if (mapAddr[which]) {
    141         munmap(mapAddr[which], mapLen[which]);
    142         mapAddr[which] = 0;
    143       }
    144     }
    145   }
    146 
    147   bool emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose = false);
    148   const TagFmt* find(uint32_t tag) const;
    149   int find(TagFmt&& tagfmt) const;
    150   int find(MapString&& tag) const;
    151 };
    152 
    153 bool EventTagMap::emplaceUnique(uint32_t tag, const TagFmt& tagfmt,
    154                                 bool verbose) {
    155   bool ret = true;
    156   static const char errorFormat[] =
    157       OUT_TAG ": duplicate tag entries %" PRIu32 ":%.*s:%.*s and %" PRIu32
    158               ":%.*s:%.*s)\n";
    159   android::RWLock::AutoWLock writeLock(rwlock);
    160   {
    161     std::unordered_map<uint32_t, TagFmt>::const_iterator it;
    162     it = Idx2TagFmt.find(tag);
    163     if (it != Idx2TagFmt.end()) {
    164       if (verbose) {
    165         fprintf(stderr, errorFormat, it->first, (int)it->second.first.length(),
    166                 it->second.first.data(), (int)it->second.second.length(),
    167                 it->second.second.data(), tag, (int)tagfmt.first.length(),
    168                 tagfmt.first.data(), (int)tagfmt.second.length(),
    169                 tagfmt.second.data());
    170       }
    171       ret = false;
    172     } else {
    173       Idx2TagFmt.emplace(std::make_pair(tag, tagfmt));
    174     }
    175   }
    176 
    177   {
    178     std::unordered_map<TagFmt, uint32_t>::const_iterator it;
    179     it = TagFmt2Idx.find(tagfmt);
    180     if (it != TagFmt2Idx.end()) {
    181       if (verbose) {
    182         fprintf(stderr, errorFormat, it->second, (int)it->first.first.length(),
    183                 it->first.first.data(), (int)it->first.second.length(),
    184                 it->first.second.data(), tag, (int)tagfmt.first.length(),
    185                 tagfmt.first.data(), (int)tagfmt.second.length(),
    186                 tagfmt.second.data());
    187       }
    188       ret = false;
    189     } else {
    190       TagFmt2Idx.emplace(std::make_pair(tagfmt, tag));
    191     }
    192   }
    193 
    194   {
    195     std::unordered_map<MapString, uint32_t>::const_iterator it;
    196     it = Tag2Idx.find(tagfmt.first);
    197     if (!tagfmt.second.length() && (it != Tag2Idx.end())) {
    198       Tag2Idx.erase(it);
    199       it = Tag2Idx.end();
    200     }
    201     if (it == Tag2Idx.end()) {
    202       Tag2Idx.emplace(std::make_pair(tagfmt.first, tag));
    203     }
    204   }
    205 
    206   return ret;
    207 }
    208 
    209 const TagFmt* EventTagMap::find(uint32_t tag) const {
    210   std::unordered_map<uint32_t, TagFmt>::const_iterator it;
    211   android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
    212   it = Idx2TagFmt.find(tag);
    213   if (it == Idx2TagFmt.end()) return NULL;
    214   return &(it->second);
    215 }
    216 
    217 int EventTagMap::find(TagFmt&& tagfmt) const {
    218   std::unordered_map<TagFmt, uint32_t>::const_iterator it;
    219   android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
    220   it = TagFmt2Idx.find(std::move(tagfmt));
    221   if (it == TagFmt2Idx.end()) return -1;
    222   return it->second;
    223 }
    224 
    225 int EventTagMap::find(MapString&& tag) const {
    226   std::unordered_map<MapString, uint32_t>::const_iterator it;
    227   android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
    228   it = Tag2Idx.find(std::move(tag));
    229   if (it == Tag2Idx.end()) return -1;
    230   return it->second;
    231 }
    232 
    233 // Scan one tag line.
    234 //
    235 // "*pData" should be pointing to the first digit in the tag number.  On
    236 // successful return, it will be pointing to the last character in the
    237 // tag line (i.e. the character before the start of the next line).
    238 //
    239 // lineNum = 0 removes verbose comments and requires us to cache the
    240 // content rather than make direct raw references since the content
    241 // will disappear after the call. A non-zero lineNum means we own the
    242 // data and it will outlive the call.
    243 //
    244 // Returns 0 on success, nonzero on failure.
    245 static int scanTagLine(EventTagMap* map, char** pData, int lineNum) {
    246   char* cp;
    247   unsigned long val = strtoul(*pData, &cp, 10);
    248   if (cp == *pData) {
    249     if (lineNum) {
    250       fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", lineNum);
    251     }
    252     errno = EINVAL;
    253     return -1;
    254   }
    255 
    256   uint32_t tagIndex = val;
    257   if (tagIndex != val) {
    258     if (lineNum) {
    259       fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", lineNum);
    260     }
    261     errno = ERANGE;
    262     return -1;
    263   }
    264 
    265   while ((*++cp != '\n') && isspace(*cp)) {
    266   }
    267 
    268   if (*cp == '\n') {
    269     if (lineNum) {
    270       fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", lineNum);
    271     }
    272     errno = EINVAL;
    273     return -1;
    274   }
    275 
    276   const char* tag = cp;
    277   // Determine whether "c" is a valid tag char.
    278   while (isalnum(*++cp) || (*cp == '_')) {
    279   }
    280   size_t tagLen = cp - tag;
    281 
    282   if (!isspace(*cp)) {
    283     if (lineNum) {
    284       fprintf(stderr, OUT_TAG ": invalid tag chars on line %d\n", lineNum);
    285     }
    286     errno = EINVAL;
    287     return -1;
    288   }
    289 
    290   while (isspace(*cp) && (*cp != '\n')) ++cp;
    291   const char* fmt = NULL;
    292   size_t fmtLen = 0;
    293   if (*cp != '#') {
    294     fmt = cp;
    295     while ((*cp != '\n') && (*cp != '#')) ++cp;
    296     while ((cp > fmt) && isspace(*(cp - 1))) --cp;
    297     fmtLen = cp - fmt;
    298   }
    299 
    300   // KISS Only report identicals if they are global
    301   // Ideally we want to check if there are identicals
    302   // recorded for the same uid, but recording that
    303   // unused detail in our database is too burdensome.
    304   bool verbose = true;
    305   while ((*cp != '#') && (*cp != '\n')) ++cp;
    306   if (*cp == '#') {
    307     do {
    308       ++cp;
    309     } while (isspace(*cp) && (*cp != '\n'));
    310     verbose = !!fastcmp<strncmp>(cp, "uid=", strlen("uid="));
    311   }
    312 
    313   while (*cp != '\n') ++cp;
    314 #ifdef DEBUG
    315   fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - *pData), *pData);
    316 #endif
    317   *pData = cp;
    318 
    319   if (lineNum) {
    320     if (map->emplaceUnique(tagIndex,
    321                            TagFmt(std::make_pair(MapString(tag, tagLen),
    322                                                  MapString(fmt, fmtLen))),
    323                            verbose)) {
    324       return 0;
    325     }
    326   } else {
    327     // cache
    328     if (map->emplaceUnique(
    329             tagIndex,
    330             TagFmt(std::make_pair(MapString(std::string(tag, tagLen)),
    331                                   MapString(std::string(fmt, fmtLen)))))) {
    332       return 0;
    333     }
    334   }
    335   errno = EMLINK;
    336   return -1;
    337 }
    338 
    339 static const char* eventTagFiles[NUM_MAPS] = {
    340   EVENT_TAG_MAP_FILE, "/dev/event-log-tags",
    341 };
    342 
    343 // Parse the tags out of the file.
    344 static int parseMapLines(EventTagMap* map, size_t which) {
    345   char* cp = static_cast<char*>(map->mapAddr[which]);
    346   size_t len = map->mapLen[which];
    347   char* endp = cp + len;
    348 
    349   // insist on EOL at EOF; simplifies parsing and null-termination
    350   if (!len || (*(endp - 1) != '\n')) {
    351 #ifdef DEBUG
    352     fprintf(stderr, OUT_TAG ": map file %zu[%zu] missing EOL on last line\n",
    353             which, len);
    354 #endif
    355     if (which) {  // do not propagate errors for other files
    356       return 0;
    357     }
    358     errno = EINVAL;
    359     return -1;
    360   }
    361 
    362   bool lineStart = true;
    363   int lineNum = 1;
    364   while (cp < endp) {
    365     if (*cp == '\n') {
    366       lineStart = true;
    367       lineNum++;
    368     } else if (lineStart) {
    369       if (*cp == '#') {
    370         // comment; just scan to end
    371         lineStart = false;
    372       } else if (isdigit(*cp)) {
    373         // looks like a tag; scan it out
    374         if (scanTagLine(map, &cp, lineNum) != 0) {
    375           if (!which || (errno != EMLINK)) {
    376             return -1;
    377           }
    378         }
    379         lineNum++;  // we eat the '\n'
    380                     // leave lineStart==true
    381       } else if (isspace(*cp)) {
    382         // looks like leading whitespace; keep scanning
    383       } else {
    384         fprintf(stderr,
    385                 OUT_TAG
    386                 ": unexpected chars (0x%02x) in tag number on line %d\n",
    387                 *cp, lineNum);
    388         errno = EINVAL;
    389         return -1;
    390       }
    391     } else {
    392       // this is a blank or comment line
    393     }
    394     cp++;
    395   }
    396 
    397   return 0;
    398 }
    399 
    400 // Open the map file and allocate a structure to manage it.
    401 //
    402 // We create a private mapping because we want to terminate the log tag
    403 // strings with '\0'.
    404 LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName) {
    405   EventTagMap* newTagMap;
    406   off_t end[NUM_MAPS];
    407   int save_errno, fd[NUM_MAPS];
    408   size_t which;
    409 
    410   memset(fd, -1, sizeof(fd));
    411   memset(end, 0, sizeof(end));
    412 
    413   for (which = 0; which < NUM_MAPS; ++which) {
    414     const char* tagfile = fileName ? fileName : eventTagFiles[which];
    415 
    416     fd[which] = open(tagfile, O_RDONLY | O_CLOEXEC);
    417     if (fd[which] < 0) {
    418       if (!which) {
    419         save_errno = errno;
    420         fprintf(stderr, OUT_TAG ": unable to open map '%s': %s\n", tagfile,
    421                 strerror(save_errno));
    422         goto fail_errno;
    423       }
    424       continue;
    425     }
    426     end[which] = lseek(fd[which], 0L, SEEK_END);
    427     save_errno = errno;
    428     (void)lseek(fd[which], 0L, SEEK_SET);
    429     if (!which && (end[0] < 0)) {
    430       fprintf(stderr, OUT_TAG ": unable to seek map '%s' %s\n", tagfile,
    431               strerror(save_errno));
    432       goto fail_close;
    433     }
    434     if (fileName) break;  // Only allow one as specified
    435   }
    436 
    437   newTagMap = new EventTagMap;
    438   if (newTagMap == NULL) {
    439     save_errno = errno;
    440     goto fail_close;
    441   }
    442 
    443   for (which = 0; which < NUM_MAPS; ++which) {
    444     if (fd[which] >= 0) {
    445       newTagMap->mapAddr[which] =
    446           mmap(NULL, end[which], which ? PROT_READ : PROT_READ | PROT_WRITE,
    447                which ? MAP_SHARED : MAP_PRIVATE, fd[which], 0);
    448       save_errno = errno;
    449       close(fd[which]);
    450       fd[which] = -1;
    451       if ((newTagMap->mapAddr[which] != MAP_FAILED) &&
    452           (newTagMap->mapAddr[which] != NULL)) {
    453         newTagMap->mapLen[which] = end[which];
    454       } else if (!which) {
    455         const char* tagfile = fileName ? fileName : eventTagFiles[which];
    456 
    457         fprintf(stderr, OUT_TAG ": mmap(%s) failed: %s\n", tagfile,
    458                 strerror(save_errno));
    459         goto fail_unmap;
    460       }
    461     }
    462   }
    463 
    464   for (which = 0; which < NUM_MAPS; ++which) {
    465     if (parseMapLines(newTagMap, which) != 0) {
    466       delete newTagMap;
    467       return NULL;
    468     }
    469   }
    470 
    471   return newTagMap;
    472 
    473 fail_unmap:
    474   save_errno = EINVAL;
    475   delete newTagMap;
    476 fail_close:
    477   for (which = 0; which < NUM_MAPS; ++which) close(fd[which]);
    478 fail_errno:
    479   errno = save_errno;
    480   return NULL;
    481 }
    482 
    483 // Close the map.
    484 LIBLOG_ABI_PUBLIC void android_closeEventTagMap(EventTagMap* map) {
    485   if (map) delete map;
    486 }
    487 
    488 // Cache miss, go to logd to acquire a public reference.
    489 // Because we lack access to a SHARED PUBLIC /dev/event-log-tags file map?
    490 static const TagFmt* __getEventTag(EventTagMap* map, unsigned int tag) {
    491   // call event tag service to arrange for a new tag
    492   char* buf = NULL;
    493   // Can not use android::base::StringPrintf, asprintf + free instead.
    494   static const char command_template[] = "getEventTag id=%u";
    495   int ret = asprintf(&buf, command_template, tag);
    496   if (ret > 0) {
    497     // Add some buffer margin for an estimate of the full return content.
    498     char* cp;
    499     size_t size =
    500         ret - strlen(command_template) +
    501         strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
    502     if (size > (size_t)ret) {
    503       cp = static_cast<char*>(realloc(buf, size));
    504       if (cp) {
    505         buf = cp;
    506       } else {
    507         size = ret;
    508       }
    509     } else {
    510       size = ret;
    511     }
    512     // Ask event log tag service for an existing entry
    513     if (__send_log_msg(buf, size) >= 0) {
    514       buf[size - 1] = '\0';
    515       unsigned long val = strtoul(buf, &cp, 10);        // return size
    516       if ((buf != cp) && (val > 0) && (*cp == '\n')) {  // truncation OK
    517         ++cp;
    518         if (!scanTagLine(map, &cp, 0)) {
    519           free(buf);
    520           return map->find(tag);
    521         }
    522       }
    523     }
    524     free(buf);
    525   }
    526   return NULL;
    527 }
    528 
    529 // Look up an entry in the map.
    530 LIBLOG_ABI_PUBLIC const char* android_lookupEventTag_len(const EventTagMap* map,
    531                                                          size_t* len,
    532                                                          unsigned int tag) {
    533   if (len) *len = 0;
    534   const TagFmt* str = map->find(tag);
    535   if (!str) {
    536     str = __getEventTag(const_cast<EventTagMap*>(map), tag);
    537   }
    538   if (!str) return NULL;
    539   if (len) *len = str->first.length();
    540   return str->first.data();
    541 }
    542 
    543 // Look up an entry in the map.
    544 LIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
    545     const EventTagMap* map, size_t* len, unsigned int tag) {
    546   if (len) *len = 0;
    547   const TagFmt* str = map->find(tag);
    548   if (!str) {
    549     str = __getEventTag(const_cast<EventTagMap*>(map), tag);
    550   }
    551   if (!str) return NULL;
    552   if (len) *len = str->second.length();
    553   return str->second.data();
    554 }
    555 
    556 // This function is deprecated and replaced with android_lookupEventTag_len
    557 // since it will cause the map to change from Shared and backed by a file,
    558 // to Private Dirty and backed up by swap, albeit highly compressible. By
    559 // deprecating this function everywhere, we save 100s of MB of memory space.
    560 LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
    561                                                      unsigned int tag) {
    562   size_t len;
    563   const char* tagStr = android_lookupEventTag_len(map, &len, tag);
    564 
    565   if (!tagStr) return tagStr;
    566   char* cp = const_cast<char*>(tagStr);
    567   cp += len;
    568   if (*cp) *cp = '\0';  // Trigger copy on write :-( and why deprecated.
    569   return tagStr;
    570 }
    571 
    572 // Look up tagname, generate one if necessary, and return a tag
    573 LIBLOG_ABI_PUBLIC int android_lookupEventTagNum(EventTagMap* map,
    574                                                 const char* tagname,
    575                                                 const char* format, int prio) {
    576   size_t len = strlen(tagname);
    577   if (!len) {
    578     errno = EINVAL;
    579     return -1;
    580   }
    581 
    582   if ((prio != ANDROID_LOG_UNKNOWN) && (prio < ANDROID_LOG_SILENT) &&
    583       !__android_log_is_loggable_len(prio, tagname, len,
    584                                      __android_log_is_debuggable()
    585                                          ? ANDROID_LOG_VERBOSE
    586                                          : ANDROID_LOG_DEBUG)) {
    587     errno = EPERM;
    588     return -1;
    589   }
    590 
    591   if (!format) format = "";
    592   ssize_t fmtLen = strlen(format);
    593   int ret = map->find(TagFmt(
    594       std::make_pair(MapString(tagname, len), MapString(format, fmtLen))));
    595   if (ret != -1) return ret;
    596 
    597   // call event tag service to arrange for a new tag
    598   char* buf = NULL;
    599   // Can not use android::base::StringPrintf, asprintf + free instead.
    600   static const char command_template[] = "getEventTag name=%s format=\"%s\"";
    601   ret = asprintf(&buf, command_template, tagname, format);
    602   if (ret > 0) {
    603     // Add some buffer margin for an estimate of the full return content.
    604     char* cp;
    605     size_t size =
    606         ret - strlen(command_template) +
    607         strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
    608     if (size > (size_t)ret) {
    609       cp = static_cast<char*>(realloc(buf, size));
    610       if (cp) {
    611         buf = cp;
    612       } else {
    613         size = ret;
    614       }
    615     } else {
    616       size = ret;
    617     }
    618     // Ask event log tag service for an allocation
    619     if (__send_log_msg(buf, size) >= 0) {
    620       buf[size - 1] = '\0';
    621       unsigned long val = strtoul(buf, &cp, 10);        // return size
    622       if ((buf != cp) && (val > 0) && (*cp == '\n')) {  // truncation OK
    623         val = strtoul(cp + 1, &cp, 10);                 // allocated tag number
    624         if ((val > 0) && (val < UINT32_MAX) && (*cp == '\t')) {
    625           free(buf);
    626           ret = val;
    627           // cache
    628           map->emplaceUnique(ret, TagFmt(std::make_pair(
    629                                       MapString(std::string(tagname, len)),
    630                                       MapString(std::string(format, fmtLen)))));
    631           return ret;
    632         }
    633       }
    634     }
    635     free(buf);
    636   }
    637 
    638   // Hail Mary
    639   ret = map->find(MapString(tagname, len));
    640   if (ret == -1) errno = ESRCH;
    641   return ret;
    642 }
    643