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: 50 operator const std::experimental::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::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> { 104 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: 130 EventTagMap() { 131 memset(mapAddr, 0, sizeof(mapAddr)); 132 memset(mapLen, 0, sizeof(mapLen)); 133 } 134 135 ~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 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 209 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 217 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 225 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. 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. 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. 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'. 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. 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? 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. 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. 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. 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 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