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 // 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.
scanTagLine(EventTagMap * map,char ** pData,int lineNum)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.
parseMapLines(EventTagMap * map,size_t which)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'.
android_openEventTagMap(const char * fileName)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.
android_closeEventTagMap(EventTagMap * 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?
__getEventTag(EventTagMap * map,unsigned int tag)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.
android_lookupEventTag_len(const EventTagMap * map,size_t * len,unsigned int tag)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.
android_lookupEventFormat_len(const EventTagMap * map,size_t * len,unsigned int tag)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.
android_lookupEventTag(const EventTagMap * map,unsigned int tag)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
android_lookupEventTagNum(EventTagMap * map,const char * tagname,const char * format,int prio)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