• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
operator const std::experimental::string_view() const50   operator const std::experimental::string_view() const {
51     return str;
52   }
53 
data() const54   const char* data() const {
55     return str.data();
56   }
length() const57   size_t length() const {
58     return str.length();
59   }
60 
operator ==(const MapString & rval) const61   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   }
operator !=(const MapString & rval) const66   bool operator!=(const MapString& rval) const {
67     return !(*this == rval);
68   }
69 
MapString(const char * str,size_t len)70   MapString(const char* str, size_t len) : alloc(NULL), str(str, len) {
71   }
MapString(const std::string & str)72   explicit MapString(const std::string& str)
73       : alloc(new std::string(str)), str(alloc->data(), alloc->length()) {
74   }
MapString(MapString && rval)75   MapString(MapString&& rval)
76       : alloc(rval.alloc), str(rval.data(), rval.length()) {
77     rval.alloc = NULL;
78   }
MapString(const MapString & rval)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 
~MapString()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> {
operator ()std::hash93   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> {
operator ()std::hash104   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:
EventTagMapEventTagMap130   EventTagMap() {
131     memset(mapAddr, 0, sizeof(mapAddr));
132     memset(mapLen, 0, sizeof(mapLen));
133   }
134 
~EventTagMapEventTagMap135   ~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 
emplaceUnique(uint32_t tag,const TagFmt & tagfmt,bool verbose)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 
find(uint32_t tag) const209 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 
find(TagFmt && tagfmt) const217 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 
find(MapString && tag) const225 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 // The position after the end of a valid section of the tag string,
234 // caller makes sure delimited appropriately.
endOfTag(const char * cp)235 static const char* endOfTag(const char* cp) {
236   while (*cp && (isalnum(*cp) || strchr("_.-@,", *cp))) ++cp;
237   return cp;
238 }
239 
240 // Scan one tag line.
241 //
242 // "pData" should be pointing to the first digit in the tag number.  On
243 // successful return, it will be pointing to the last character in the
244 // tag line (i.e. the character before the start of the next line).
245 //
246 // lineNum = 0 removes verbose comments and requires us to cache the
247 // content rather than make direct raw references since the content
248 // will disappear after the call. A non-zero lineNum means we own the
249 // data and it will outlive the call.
250 //
251 // Returns 0 on success, nonzero on failure.
scanTagLine(EventTagMap * map,const char * & pData,int lineNum)252 static int scanTagLine(EventTagMap* map, const char*& pData, int lineNum) {
253   char* ep;
254   unsigned long val = strtoul(pData, &ep, 10);
255   const char* cp = ep;
256   if (cp == pData) {
257     if (lineNum) {
258       fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", lineNum);
259     }
260     errno = EINVAL;
261     return -1;
262   }
263 
264   uint32_t tagIndex = val;
265   if (tagIndex != val) {
266     if (lineNum) {
267       fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", lineNum);
268     }
269     errno = ERANGE;
270     return -1;
271   }
272 
273   while ((*++cp != '\n') && isspace(*cp)) {
274   }
275 
276   if (*cp == '\n') {
277     if (lineNum) {
278       fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", lineNum);
279     }
280     errno = EINVAL;
281     return -1;
282   }
283 
284   const char* tag = cp;
285   cp = endOfTag(cp);
286   size_t tagLen = cp - tag;
287 
288   if (!isspace(*cp)) {
289     if (lineNum) {
290       fprintf(stderr, OUT_TAG ": invalid tag char %c on line %d\n", *cp,
291               lineNum);
292     }
293     errno = EINVAL;
294     return -1;
295   }
296 
297   while (isspace(*cp) && (*cp != '\n')) ++cp;
298   const char* fmt = NULL;
299   size_t fmtLen = 0;
300   if (*cp && (*cp != '#')) {
301     fmt = cp;
302     while (*cp && (*cp != '\n') && (*cp != '#')) ++cp;
303     while ((cp > fmt) && isspace(*(cp - 1))) --cp;
304     fmtLen = cp - fmt;
305   }
306 
307   // KISS Only report identicals if they are global
308   // Ideally we want to check if there are identicals
309   // recorded for the same uid, but recording that
310   // unused detail in our database is too burdensome.
311   bool verbose = true;
312   while (*cp && (*cp != '#') && (*cp != '\n')) ++cp;
313   if (*cp == '#') {
314     do {
315       ++cp;
316     } while (isspace(*cp) && (*cp != '\n'));
317     verbose = !!fastcmp<strncmp>(cp, "uid=", strlen("uid="));
318   }
319 
320   while (*cp && (*cp != '\n')) ++cp;
321 #ifdef DEBUG
322   fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - pData), pData);
323 #endif
324   pData = cp;
325 
326   if (lineNum) {
327     if (map->emplaceUnique(tagIndex,
328                            TagFmt(std::make_pair(MapString(tag, tagLen),
329                                                  MapString(fmt, fmtLen))),
330                            verbose)) {
331       return 0;
332     }
333   } else {
334     // cache
335     if (map->emplaceUnique(
336             tagIndex,
337             TagFmt(std::make_pair(MapString(std::string(tag, tagLen)),
338                                   MapString(std::string(fmt, fmtLen)))))) {
339       return 0;
340     }
341   }
342   errno = EMLINK;
343   return -1;
344 }
345 
346 static const char* eventTagFiles[NUM_MAPS] = {
347   EVENT_TAG_MAP_FILE, "/dev/event-log-tags",
348 };
349 
350 // Parse the tags out of the file.
parseMapLines(EventTagMap * map,size_t which)351 static int parseMapLines(EventTagMap* map, size_t which) {
352   const char* cp = static_cast<char*>(map->mapAddr[which]);
353   size_t len = map->mapLen[which];
354   const char* endp = cp + len;
355 
356   // insist on EOL at EOF; simplifies parsing and null-termination
357   if (!len || (*(endp - 1) != '\n')) {
358 #ifdef DEBUG
359     fprintf(stderr, OUT_TAG ": map file %zu[%zu] missing EOL on last line\n",
360             which, len);
361 #endif
362     if (which) {  // do not propagate errors for other files
363       return 0;
364     }
365     errno = EINVAL;
366     return -1;
367   }
368 
369   bool lineStart = true;
370   int lineNum = 1;
371   while (cp < endp) {
372     if (*cp == '\n') {
373       lineStart = true;
374       lineNum++;
375     } else if (lineStart) {
376       if (*cp == '#') {
377         // comment; just scan to end
378         lineStart = false;
379       } else if (isdigit(*cp)) {
380         // looks like a tag; scan it out
381         if (scanTagLine(map, cp, lineNum) != 0) {
382           if (!which || (errno != EMLINK)) {
383             return -1;
384           }
385         }
386         lineNum++;  // we eat the '\n'
387                     // leave lineStart==true
388       } else if (isspace(*cp)) {
389         // looks like leading whitespace; keep scanning
390       } else {
391         fprintf(stderr,
392                 OUT_TAG
393                 ": unexpected chars (0x%02x) in tag number on line %d\n",
394                 *cp, lineNum);
395         errno = EINVAL;
396         return -1;
397       }
398     } else {
399       // this is a blank or comment line
400     }
401     cp++;
402   }
403 
404   return 0;
405 }
406 
407 // Open the map file and allocate a structure to manage it.
408 //
409 // We create a private mapping because we want to terminate the log tag
410 // strings with '\0'.
android_openEventTagMap(const char * fileName)411 LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName) {
412   EventTagMap* newTagMap;
413   off_t end[NUM_MAPS];
414   int save_errno, fd[NUM_MAPS];
415   size_t which;
416 
417   memset(fd, -1, sizeof(fd));
418   memset(end, 0, sizeof(end));
419 
420   for (which = 0; which < NUM_MAPS; ++which) {
421     const char* tagfile = fileName ? fileName : eventTagFiles[which];
422 
423     fd[which] = open(tagfile, O_RDONLY | O_CLOEXEC);
424     if (fd[which] < 0) {
425       if (!which) {
426         save_errno = errno;
427         fprintf(stderr, OUT_TAG ": unable to open map '%s': %s\n", tagfile,
428                 strerror(save_errno));
429         goto fail_errno;
430       }
431       continue;
432     }
433     end[which] = lseek(fd[which], 0L, SEEK_END);
434     save_errno = errno;
435     (void)lseek(fd[which], 0L, SEEK_SET);
436     if (!which && (end[0] < 0)) {
437       fprintf(stderr, OUT_TAG ": unable to seek map '%s' %s\n", tagfile,
438               strerror(save_errno));
439       goto fail_close;
440     }
441     if (fileName) break;  // Only allow one as specified
442   }
443 
444   newTagMap = new EventTagMap;
445   if (newTagMap == NULL) {
446     save_errno = errno;
447     goto fail_close;
448   }
449 
450   for (which = 0; which < NUM_MAPS; ++which) {
451     if (fd[which] >= 0) {
452       newTagMap->mapAddr[which] =
453           mmap(NULL, end[which], which ? PROT_READ : PROT_READ | PROT_WRITE,
454                which ? MAP_SHARED : MAP_PRIVATE, fd[which], 0);
455       save_errno = errno;
456       close(fd[which]); /* fd DONE */
457       fd[which] = -1;
458       if ((newTagMap->mapAddr[which] != MAP_FAILED) &&
459           (newTagMap->mapAddr[which] != NULL)) {
460         newTagMap->mapLen[which] = end[which];
461       } else if (!which) {
462         const char* tagfile = fileName ? fileName : eventTagFiles[which];
463 
464         fprintf(stderr, OUT_TAG ": mmap(%s) failed: %s\n", tagfile,
465                 strerror(save_errno));
466         goto fail_unmap;
467       }
468     }
469   }
470 
471   for (which = 0; which < NUM_MAPS; ++which) {
472     if (parseMapLines(newTagMap, which) != 0) {
473       delete newTagMap;
474       return NULL;
475     }
476     /* See 'fd DONE' comments above and below, no need to clean up here */
477   }
478 
479   return newTagMap;
480 
481 fail_unmap:
482   save_errno = EINVAL;
483   delete newTagMap;
484 fail_close:
485   for (which = 0; which < NUM_MAPS; ++which) close(fd[which]); /* fd DONE */
486 fail_errno:
487   errno = save_errno;
488   return NULL;
489 }
490 
491 // Close the map.
android_closeEventTagMap(EventTagMap * map)492 LIBLOG_ABI_PUBLIC void android_closeEventTagMap(EventTagMap* map) {
493   if (map) delete map;
494 }
495 
496 // Cache miss, go to logd to acquire a public reference.
497 // Because we lack access to a SHARED PUBLIC /dev/event-log-tags file map?
__getEventTag(EventTagMap * map,unsigned int tag)498 static const TagFmt* __getEventTag(EventTagMap* map, unsigned int tag) {
499   // call event tag service to arrange for a new tag
500   char* buf = NULL;
501   // Can not use android::base::StringPrintf, asprintf + free instead.
502   static const char command_template[] = "getEventTag id=%u";
503   int ret = asprintf(&buf, command_template, tag);
504   if (ret > 0) {
505     // Add some buffer margin for an estimate of the full return content.
506     size_t size =
507         ret - strlen(command_template) +
508         strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
509     if (size > (size_t)ret) {
510       char* np = static_cast<char*>(realloc(buf, size));
511       if (np) {
512         buf = np;
513       } else {
514         size = ret;
515       }
516     } else {
517       size = ret;
518     }
519     // Ask event log tag service for an existing entry
520     if (__send_log_msg(buf, size) >= 0) {
521       buf[size - 1] = '\0';
522       char* ep;
523       unsigned long val = strtoul(buf, &ep, 10);  // return size
524       const char* cp = ep;
525       if ((buf != cp) && (val > 0) && (*cp == '\n')) {  // truncation OK
526         ++cp;
527         if (!scanTagLine(map, cp, 0)) {
528           free(buf);
529           return map->find(tag);
530         }
531       }
532     }
533     free(buf);
534   }
535   return NULL;
536 }
537 
538 // Look up an entry in the map.
android_lookupEventTag_len(const EventTagMap * map,size_t * len,unsigned int tag)539 LIBLOG_ABI_PUBLIC const char* android_lookupEventTag_len(const EventTagMap* map,
540                                                          size_t* len,
541                                                          unsigned int tag) {
542   if (len) *len = 0;
543   const TagFmt* str = map->find(tag);
544   if (!str) {
545     str = __getEventTag(const_cast<EventTagMap*>(map), tag);
546   }
547   if (!str) return NULL;
548   if (len) *len = str->first.length();
549   return str->first.data();
550 }
551 
552 // Look up an entry in the map.
android_lookupEventFormat_len(const EventTagMap * map,size_t * len,unsigned int tag)553 LIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
554     const EventTagMap* map, size_t* len, unsigned int tag) {
555   if (len) *len = 0;
556   const TagFmt* str = map->find(tag);
557   if (!str) {
558     str = __getEventTag(const_cast<EventTagMap*>(map), tag);
559   }
560   if (!str) return NULL;
561   if (len) *len = str->second.length();
562   return str->second.data();
563 }
564 
565 // This function is deprecated and replaced with android_lookupEventTag_len
566 // since it will cause the map to change from Shared and backed by a file,
567 // to Private Dirty and backed up by swap, albeit highly compressible. By
568 // deprecating this function everywhere, we save 100s of MB of memory space.
android_lookupEventTag(const EventTagMap * map,unsigned int tag)569 LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
570                                                      unsigned int tag) {
571   size_t len;
572   const char* tagStr = android_lookupEventTag_len(map, &len, tag);
573 
574   if (!tagStr) return tagStr;
575   char* cp = const_cast<char*>(tagStr);
576   cp += len;
577   if (*cp) *cp = '\0';  // Trigger copy on write :-( and why deprecated.
578   return tagStr;
579 }
580 
581 // Look up tagname, generate one if necessary, and return a tag
android_lookupEventTagNum(EventTagMap * map,const char * tagname,const char * format,int prio)582 LIBLOG_ABI_PUBLIC int android_lookupEventTagNum(EventTagMap* map,
583                                                 const char* tagname,
584                                                 const char* format, int prio) {
585   const char* ep = endOfTag(tagname);
586   size_t len = ep - tagname;
587   if (!len || *ep) {
588     errno = EINVAL;
589     return -1;
590   }
591 
592   if ((prio != ANDROID_LOG_UNKNOWN) && (prio < ANDROID_LOG_SILENT) &&
593       !__android_log_is_loggable_len(prio, tagname, len,
594                                      __android_log_is_debuggable()
595                                          ? ANDROID_LOG_VERBOSE
596                                          : ANDROID_LOG_DEBUG)) {
597     errno = EPERM;
598     return -1;
599   }
600 
601   if (!format) format = "";
602   ssize_t fmtLen = strlen(format);
603   int ret = map->find(TagFmt(
604       std::make_pair(MapString(tagname, len), MapString(format, fmtLen))));
605   if (ret != -1) return ret;
606 
607   // call event tag service to arrange for a new tag
608   char* buf = NULL;
609   // Can not use android::base::StringPrintf, asprintf + free instead.
610   static const char command_template[] = "getEventTag name=%s format=\"%s\"";
611   ret = asprintf(&buf, command_template, tagname, format);
612   if (ret > 0) {
613     // Add some buffer margin for an estimate of the full return content.
614     char* cp;
615     size_t size =
616         ret - strlen(command_template) +
617         strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
618     if (size > (size_t)ret) {
619       cp = static_cast<char*>(realloc(buf, size));
620       if (cp) {
621         buf = cp;
622       } else {
623         size = ret;
624       }
625     } else {
626       size = ret;
627     }
628     // Ask event log tag service for an allocation
629     if (__send_log_msg(buf, size) >= 0) {
630       buf[size - 1] = '\0';
631       unsigned long val = strtoul(buf, &cp, 10);        // return size
632       if ((buf != cp) && (val > 0) && (*cp == '\n')) {  // truncation OK
633         val = strtoul(cp + 1, &cp, 10);                 // allocated tag number
634         if ((val > 0) && (val < UINT32_MAX) && (*cp == '\t')) {
635           free(buf);
636           ret = val;
637           // cache
638           map->emplaceUnique(ret, TagFmt(std::make_pair(
639                                       MapString(std::string(tagname, len)),
640                                       MapString(std::string(format, fmtLen)))));
641           return ret;
642         }
643       }
644     }
645     free(buf);
646   }
647 
648   // Hail Mary
649   ret = map->find(MapString(tagname, len));
650   if (ret == -1) errno = ESRCH;
651   return ret;
652 }
653