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