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