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