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 // 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. 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. 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'. 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. 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? 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. 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. 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. 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 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