1 /* 2 * Copyright (C) 2014 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 <ctype.h> 18 #include <fcntl.h> 19 #include <inttypes.h> 20 #include <pwd.h> 21 #include <stdio.h> 22 #include <string.h> 23 #include <sys/types.h> 24 #include <unistd.h> 25 26 #include <list> 27 28 #include <private/android_logger.h> 29 30 #include "LogStatistics.h" 31 32 static const uint64_t hourSec = 60 * 60; 33 static const uint64_t monthSec = 31 * 24 * hourSec; 34 35 size_t LogStatistics::SizesTotal; 36 37 LogStatistics::LogStatistics() : enable(false) { 38 log_time now(CLOCK_REALTIME); 39 log_id_for_each(id) { 40 mSizes[id] = 0; 41 mElements[id] = 0; 42 mDroppedElements[id] = 0; 43 mSizesTotal[id] = 0; 44 mElementsTotal[id] = 0; 45 mOldest[id] = now; 46 mNewest[id] = now; 47 mNewestDropped[id] = now; 48 } 49 } 50 51 namespace android { 52 53 size_t sizesTotal() { 54 return LogStatistics::sizesTotal(); 55 } 56 57 // caller must own and free character string 58 char* pidToName(pid_t pid) { 59 char* retval = NULL; 60 if (pid == 0) { // special case from auditd/klogd for kernel 61 retval = strdup("logd"); 62 } else { 63 char buffer[512]; 64 snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid); 65 int fd = open(buffer, O_RDONLY); 66 if (fd >= 0) { 67 ssize_t ret = read(fd, buffer, sizeof(buffer)); 68 if (ret > 0) { 69 buffer[sizeof(buffer) - 1] = '\0'; 70 // frameworks intermediate state 71 if (fastcmp<strcmp>(buffer, "<pre-initialized>")) { 72 retval = strdup(buffer); 73 } 74 } 75 close(fd); 76 } 77 } 78 return retval; 79 } 80 } 81 82 void LogStatistics::addTotal(LogBufferElement* element) { 83 if (element->getDropped()) return; 84 85 log_id_t log_id = element->getLogId(); 86 unsigned short size = element->getMsgLen(); 87 mSizesTotal[log_id] += size; 88 SizesTotal += size; 89 ++mElementsTotal[log_id]; 90 } 91 92 void LogStatistics::add(LogBufferElement* element) { 93 log_id_t log_id = element->getLogId(); 94 unsigned short size = element->getMsgLen(); 95 mSizes[log_id] += size; 96 ++mElements[log_id]; 97 98 // When caller adding a chatty entry, they will have already 99 // called add() and subtract() for each entry as they are 100 // evaluated and trimmed, thus recording size and number of 101 // elements, but we must recognize the manufactured dropped 102 // entry as not contributing to the lifetime totals. 103 if (element->getDropped()) { 104 ++mDroppedElements[log_id]; 105 } else { 106 mSizesTotal[log_id] += size; 107 SizesTotal += size; 108 ++mElementsTotal[log_id]; 109 } 110 111 log_time stamp(element->getRealTime()); 112 if (mNewest[log_id] < stamp) { 113 // A major time update invalidates the statistics :-( 114 log_time diff = stamp - mNewest[log_id]; 115 mNewest[log_id] = stamp; 116 117 if (diff.tv_sec > hourSec) { 118 // approximate Do-Your-Best fixup 119 diff += mOldest[log_id]; 120 if ((diff > stamp) && ((diff - stamp).tv_sec < hourSec)) { 121 diff = stamp; 122 } 123 if (diff <= stamp) { 124 mOldest[log_id] = diff; 125 if (mNewestDropped[log_id] < diff) { 126 mNewestDropped[log_id] = diff; 127 } 128 } 129 } 130 } 131 132 if (log_id == LOG_ID_KERNEL) { 133 return; 134 } 135 136 uidTable[log_id].add(element->getUid(), element); 137 if (element->getUid() == AID_SYSTEM) { 138 pidSystemTable[log_id].add(element->getPid(), element); 139 } 140 141 if (!enable) { 142 return; 143 } 144 145 pidTable.add(element->getPid(), element); 146 tidTable.add(element->getTid(), element); 147 148 uint32_t tag = element->getTag(); 149 if (tag) { 150 if (log_id == LOG_ID_SECURITY) { 151 securityTagTable.add(tag, element); 152 } else { 153 tagTable.add(tag, element); 154 } 155 } 156 157 if (!element->getDropped()) { 158 tagNameTable.add(TagNameKey(element), element); 159 } 160 } 161 162 void LogStatistics::subtract(LogBufferElement* element) { 163 log_id_t log_id = element->getLogId(); 164 unsigned short size = element->getMsgLen(); 165 mSizes[log_id] -= size; 166 --mElements[log_id]; 167 if (element->getDropped()) { 168 --mDroppedElements[log_id]; 169 } 170 171 if (mOldest[log_id] < element->getRealTime()) { 172 mOldest[log_id] = element->getRealTime(); 173 } 174 175 if (log_id == LOG_ID_KERNEL) { 176 return; 177 } 178 179 uidTable[log_id].subtract(element->getUid(), element); 180 if (element->getUid() == AID_SYSTEM) { 181 pidSystemTable[log_id].subtract(element->getPid(), element); 182 } 183 184 if (!enable) { 185 return; 186 } 187 188 pidTable.subtract(element->getPid(), element); 189 tidTable.subtract(element->getTid(), element); 190 191 uint32_t tag = element->getTag(); 192 if (tag) { 193 if (log_id == LOG_ID_SECURITY) { 194 securityTagTable.subtract(tag, element); 195 } else { 196 tagTable.subtract(tag, element); 197 } 198 } 199 200 if (!element->getDropped()) { 201 tagNameTable.subtract(TagNameKey(element), element); 202 } 203 } 204 205 // Atomically set an entry to drop 206 // entry->setDropped(1) must follow this call, caller should do this explicitly. 207 void LogStatistics::drop(LogBufferElement* element) { 208 log_id_t log_id = element->getLogId(); 209 unsigned short size = element->getMsgLen(); 210 mSizes[log_id] -= size; 211 ++mDroppedElements[log_id]; 212 213 if (mNewestDropped[log_id] < element->getRealTime()) { 214 mNewestDropped[log_id] = element->getRealTime(); 215 } 216 217 uidTable[log_id].drop(element->getUid(), element); 218 if (element->getUid() == AID_SYSTEM) { 219 pidSystemTable[log_id].drop(element->getPid(), element); 220 } 221 222 if (!enable) { 223 return; 224 } 225 226 pidTable.drop(element->getPid(), element); 227 tidTable.drop(element->getTid(), element); 228 229 uint32_t tag = element->getTag(); 230 if (tag) { 231 if (log_id == LOG_ID_SECURITY) { 232 securityTagTable.drop(tag, element); 233 } else { 234 tagTable.drop(tag, element); 235 } 236 } 237 238 tagNameTable.subtract(TagNameKey(element), element); 239 } 240 241 // caller must own and free character string 242 // Requires parent LogBuffer::wrlock() to be held 243 const char* LogStatistics::uidToName(uid_t uid) const { 244 // Local hard coded favourites 245 if (uid == AID_LOGD) { 246 return strdup("auditd"); 247 } 248 249 // Android system 250 if (uid < AID_APP) { 251 // in bionic, thread safe as long as we copy the results 252 struct passwd* pwd = getpwuid(uid); 253 if (pwd) { 254 return strdup(pwd->pw_name); 255 } 256 } 257 258 // Parse /data/system/packages.list 259 uid_t userId = uid % AID_USER_OFFSET; 260 const char* name = android::uidToName(userId); 261 if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) { 262 name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP)); 263 } 264 if (name) { 265 return name; 266 } 267 268 // Android application 269 if (uid >= AID_APP) { 270 struct passwd* pwd = getpwuid(uid); 271 if (pwd) { 272 return strdup(pwd->pw_name); 273 } 274 } 275 276 // report uid -> pid(s) -> pidToName if unique 277 for (pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end(); 278 ++it) { 279 const PidEntry& entry = it->second; 280 281 if (entry.getUid() == uid) { 282 const char* nameTmp = entry.getName(); 283 284 if (nameTmp) { 285 if (!name) { 286 name = strdup(nameTmp); 287 } else if (fastcmp<strcmp>(name, nameTmp)) { 288 free(const_cast<char*>(name)); 289 name = NULL; 290 break; 291 } 292 } 293 } 294 } 295 296 // No one 297 return name; 298 } 299 300 std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const { 301 bool isprune = worstUidEnabledForLogid(id); 302 return formatLine(android::base::StringPrintf(name.c_str(), 303 android_log_id_to_name(id)), 304 std::string("Size"), 305 std::string(isprune ? "+/- Pruned" : "")) + 306 formatLine(std::string("UID PACKAGE"), std::string("BYTES"), 307 std::string(isprune ? "NUM" : "")); 308 } 309 310 // Helper to truncate name, if too long, and add name dressings 311 static void formatTmp(const LogStatistics& stat, const char* nameTmp, uid_t uid, 312 std::string& name, std::string& size, size_t nameLen) { 313 const char* allocNameTmp = nullptr; 314 if (!nameTmp) nameTmp = allocNameTmp = stat.uidToName(uid); 315 if (nameTmp) { 316 size_t lenSpace = std::max(nameLen - name.length(), (size_t)1); 317 size_t len = EntryBaseConstants::total_len - 318 EntryBaseConstants::pruned_len - size.length() - 319 name.length() - lenSpace - 2; 320 size_t lenNameTmp = strlen(nameTmp); 321 while ((len < lenNameTmp) && (lenSpace > 1)) { 322 ++len; 323 --lenSpace; 324 } 325 name += android::base::StringPrintf("%*s", (int)lenSpace, ""); 326 if (len < lenNameTmp) { 327 name += "..."; 328 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1); 329 } 330 name += nameTmp; 331 free(const_cast<char*>(allocNameTmp)); 332 } 333 } 334 335 std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const { 336 uid_t uid = getUid(); 337 std::string name = android::base::StringPrintf("%u", uid); 338 std::string size = android::base::StringPrintf("%zu", getSizes()); 339 340 formatTmp(stat, nullptr, uid, name, size, 6); 341 342 std::string pruned = ""; 343 if (worstUidEnabledForLogid(id)) { 344 size_t totalDropped = 0; 345 for (LogStatistics::uidTable_t::const_iterator it = 346 stat.uidTable[id].begin(); 347 it != stat.uidTable[id].end(); ++it) { 348 totalDropped += it->second.getDropped(); 349 } 350 size_t sizes = stat.sizes(id); 351 size_t totalSize = stat.sizesTotal(id); 352 size_t totalElements = stat.elementsTotal(id); 353 float totalVirtualSize = 354 (float)sizes + (float)totalDropped * totalSize / totalElements; 355 size_t entrySize = getSizes(); 356 float virtualEntrySize = entrySize; 357 int realPermille = virtualEntrySize * 1000.0 / sizes; 358 size_t dropped = getDropped(); 359 if (dropped) { 360 pruned = android::base::StringPrintf("%zu", dropped); 361 virtualEntrySize += (float)dropped * totalSize / totalElements; 362 } 363 int virtualPermille = virtualEntrySize * 1000.0 / totalVirtualSize; 364 int permille = 365 (realPermille - virtualPermille) * 1000L / (virtualPermille ?: 1); 366 if ((permille < -1) || (1 < permille)) { 367 std::string change; 368 const char* units = "%"; 369 const char* prefix = (permille > 0) ? "+" : ""; 370 371 if (permille > 999) { 372 permille = (permille + 1000) / 100; // Now tenths fold 373 units = "X"; 374 prefix = ""; 375 } 376 if ((-99 < permille) && (permille < 99)) { 377 change = android::base::StringPrintf( 378 "%s%d.%u%s", prefix, permille / 10, 379 ((permille < 0) ? (-permille % 10) : (permille % 10)), 380 units); 381 } else { 382 change = android::base::StringPrintf( 383 "%s%d%s", prefix, (permille + 5) / 10, units); 384 } 385 ssize_t spaces = EntryBaseConstants::pruned_len - 2 - 386 pruned.length() - change.length(); 387 if ((spaces <= 0) && pruned.length()) { 388 spaces = 1; 389 } 390 if (spaces > 0) { 391 change += android::base::StringPrintf("%*s", (int)spaces, ""); 392 } 393 pruned = change + pruned; 394 } 395 } 396 397 std::string output = formatLine(name, size, pruned); 398 399 if (uid != AID_SYSTEM) { 400 return output; 401 } 402 403 static const size_t maximum_sorted_entries = 32; 404 std::unique_ptr<const PidEntry* []> sorted = 405 stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries); 406 407 if (!sorted.get()) { 408 return output; 409 } 410 std::string byPid; 411 size_t index; 412 bool hasDropped = false; 413 for (index = 0; index < maximum_sorted_entries; ++index) { 414 const PidEntry* entry = sorted[index]; 415 if (!entry) { 416 break; 417 } 418 if (entry->getSizes() <= (getSizes() / 100)) { 419 break; 420 } 421 if (entry->getDropped()) { 422 hasDropped = true; 423 } 424 byPid += entry->format(stat, id); 425 } 426 if (index > 1) { // print this only if interesting 427 std::string ditto("\" "); 428 output += formatLine(std::string(" PID/UID COMMAND LINE"), ditto, 429 hasDropped ? ditto : std::string("")); 430 output += byPid; 431 } 432 433 return output; 434 } 435 436 std::string PidEntry::formatHeader(const std::string& name, 437 log_id_t /* id */) const { 438 return formatLine(name, std::string("Size"), std::string("Pruned")) + 439 formatLine(std::string(" PID/UID COMMAND LINE"), 440 std::string("BYTES"), std::string("NUM")); 441 } 442 443 std::string PidEntry::format(const LogStatistics& stat, 444 log_id_t /* id */) const { 445 uid_t uid = getUid(); 446 pid_t pid = getPid(); 447 std::string name = android::base::StringPrintf("%5u/%u", pid, uid); 448 std::string size = android::base::StringPrintf("%zu", getSizes()); 449 450 formatTmp(stat, getName(), uid, name, size, 12); 451 452 std::string pruned = ""; 453 size_t dropped = getDropped(); 454 if (dropped) { 455 pruned = android::base::StringPrintf("%zu", dropped); 456 } 457 458 return formatLine(name, size, pruned); 459 } 460 461 std::string TidEntry::formatHeader(const std::string& name, 462 log_id_t /* id */) const { 463 return formatLine(name, std::string("Size"), std::string("Pruned")) + 464 formatLine(std::string(" TID/UID COMM"), std::string("BYTES"), 465 std::string("NUM")); 466 } 467 468 std::string TidEntry::format(const LogStatistics& stat, 469 log_id_t /* id */) const { 470 uid_t uid = getUid(); 471 std::string name = android::base::StringPrintf("%5u/%u", getTid(), uid); 472 std::string size = android::base::StringPrintf("%zu", getSizes()); 473 474 formatTmp(stat, getName(), uid, name, size, 12); 475 476 std::string pruned = ""; 477 size_t dropped = getDropped(); 478 if (dropped) { 479 pruned = android::base::StringPrintf("%zu", dropped); 480 } 481 482 return formatLine(name, size, pruned); 483 } 484 485 std::string TagEntry::formatHeader(const std::string& name, log_id_t id) const { 486 bool isprune = worstUidEnabledForLogid(id); 487 return formatLine(name, std::string("Size"), 488 std::string(isprune ? "Prune" : "")) + 489 formatLine(std::string(" TAG/UID TAGNAME"), 490 std::string("BYTES"), std::string(isprune ? "NUM" : "")); 491 } 492 493 std::string TagEntry::format(const LogStatistics& /* stat */, 494 log_id_t /* id */) const { 495 std::string name; 496 uid_t uid = getUid(); 497 if (uid == (uid_t)-1) { 498 name = android::base::StringPrintf("%7u", getKey()); 499 } else { 500 name = android::base::StringPrintf("%7u/%u", getKey(), uid); 501 } 502 const char* nameTmp = getName(); 503 if (nameTmp) { 504 name += android::base::StringPrintf( 505 "%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", nameTmp); 506 } 507 508 std::string size = android::base::StringPrintf("%zu", getSizes()); 509 510 std::string pruned = ""; 511 size_t dropped = getDropped(); 512 if (dropped) { 513 pruned = android::base::StringPrintf("%zu", dropped); 514 } 515 516 return formatLine(name, size, pruned); 517 } 518 519 std::string TagNameEntry::formatHeader(const std::string& name, 520 log_id_t /* id */) const { 521 return formatLine(name, std::string("Size"), std::string("")) + 522 formatLine(std::string(" TID/PID/UID LOG_TAG NAME"), 523 std::string("BYTES"), std::string("")); 524 } 525 526 std::string TagNameEntry::format(const LogStatistics& /* stat */, 527 log_id_t /* id */) const { 528 std::string name; 529 pid_t tid = getTid(); 530 pid_t pid = getPid(); 531 std::string pidstr; 532 if (pid != (pid_t)-1) { 533 pidstr = android::base::StringPrintf("%u", pid); 534 if ((tid != (pid_t)-1) && (tid != pid)) pidstr = "/" + pidstr; 535 } 536 int len = 9 - pidstr.length(); 537 if (len < 0) len = 0; 538 if ((tid == (pid_t)-1) || (tid == pid)) { 539 name = android::base::StringPrintf("%*s", len, ""); 540 } else { 541 name = android::base::StringPrintf("%*u", len, tid); 542 } 543 name += pidstr; 544 uid_t uid = getUid(); 545 if (uid != (uid_t)-1) { 546 name += android::base::StringPrintf("/%u", uid); 547 } 548 549 std::string size = android::base::StringPrintf("%zu", getSizes()); 550 551 const char* nameTmp = getName(); 552 if (nameTmp) { 553 size_t lenSpace = std::max(16 - name.length(), (size_t)1); 554 size_t len = EntryBaseConstants::total_len - 555 EntryBaseConstants::pruned_len - size.length() - 556 name.length() - lenSpace - 2; 557 size_t lenNameTmp = strlen(nameTmp); 558 while ((len < lenNameTmp) && (lenSpace > 1)) { 559 ++len; 560 --lenSpace; 561 } 562 name += android::base::StringPrintf("%*s", (int)lenSpace, ""); 563 if (len < lenNameTmp) { 564 name += "..."; 565 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1); 566 } 567 name += nameTmp; 568 } 569 570 std::string pruned = ""; 571 572 return formatLine(name, size, pruned); 573 } 574 575 static std::string formatMsec(uint64_t val) { 576 static const unsigned subsecDigits = 3; 577 static const uint64_t sec = MS_PER_SEC; 578 579 static const uint64_t minute = 60 * sec; 580 static const uint64_t hour = 60 * minute; 581 static const uint64_t day = 24 * hour; 582 583 std::string output; 584 if (val < sec) return output; 585 586 if (val >= day) { 587 output = android::base::StringPrintf("%" PRIu64 "d ", val / day); 588 val = (val % day) + day; 589 } 590 if (val >= minute) { 591 if (val >= hour) { 592 output += android::base::StringPrintf("%" PRIu64 ":", 593 (val / hour) % (day / hour)); 594 } 595 output += android::base::StringPrintf( 596 (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":", 597 (val / minute) % (hour / minute)); 598 } 599 output += 600 android::base::StringPrintf((val >= minute) ? "%02" PRIu64 : "%" PRIu64, 601 (val / sec) % (minute / sec)); 602 val %= sec; 603 unsigned digits = subsecDigits; 604 while (digits && ((val % 10) == 0)) { 605 val /= 10; 606 --digits; 607 } 608 if (digits) { 609 output += android::base::StringPrintf(".%0*" PRIu64, digits, val); 610 } 611 return output; 612 } 613 614 std::string LogStatistics::format(uid_t uid, pid_t pid, 615 unsigned int logMask) const { 616 static const unsigned short spaces_total = 19; 617 618 // Report on total logging, current and for all time 619 620 std::string output = "size/num"; 621 size_t oldLength; 622 short spaces = 1; 623 624 log_id_for_each(id) { 625 if (!(logMask & (1 << id))) continue; 626 oldLength = output.length(); 627 if (spaces < 0) spaces = 0; 628 output += android::base::StringPrintf("%*s%s", spaces, "", 629 android_log_id_to_name(id)); 630 spaces += spaces_total + oldLength - output.length(); 631 } 632 if (spaces < 0) spaces = 0; 633 output += android::base::StringPrintf("%*sTotal", spaces, ""); 634 635 static const char TotalStr[] = "\nTotal"; 636 spaces = 10 - strlen(TotalStr); 637 output += TotalStr; 638 639 size_t totalSize = 0; 640 size_t totalEls = 0; 641 log_id_for_each(id) { 642 if (!(logMask & (1 << id))) continue; 643 oldLength = output.length(); 644 if (spaces < 0) spaces = 0; 645 size_t szs = sizesTotal(id); 646 totalSize += szs; 647 size_t els = elementsTotal(id); 648 totalEls += els; 649 output += 650 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els); 651 spaces += spaces_total + oldLength - output.length(); 652 } 653 if (spaces < 0) spaces = 0; 654 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize, 655 totalEls); 656 657 static const char NowStr[] = "\nNow"; 658 spaces = 10 - strlen(NowStr); 659 output += NowStr; 660 661 totalSize = 0; 662 totalEls = 0; 663 log_id_for_each(id) { 664 if (!(logMask & (1 << id))) continue; 665 666 size_t els = elements(id); 667 if (els) { 668 oldLength = output.length(); 669 if (spaces < 0) spaces = 0; 670 size_t szs = sizes(id); 671 totalSize += szs; 672 totalEls += els; 673 output += 674 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els); 675 spaces -= output.length() - oldLength; 676 } 677 spaces += spaces_total; 678 } 679 if (spaces < 0) spaces = 0; 680 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize, 681 totalEls); 682 683 static const char SpanStr[] = "\nLogspan"; 684 spaces = 10 - strlen(SpanStr); 685 output += SpanStr; 686 687 // Total reports the greater of the individual maximum time span, or the 688 // validated minimum start and maximum end time span if it makes sense. 689 uint64_t minTime = UINT64_MAX; 690 uint64_t maxTime = 0; 691 uint64_t maxSpan = 0; 692 totalSize = 0; 693 694 log_id_for_each(id) { 695 if (!(logMask & (1 << id))) continue; 696 697 // validity checking 698 uint64_t oldest = mOldest[id].msec(); 699 uint64_t newest = mNewest[id].msec(); 700 if (newest <= oldest) { 701 spaces += spaces_total; 702 continue; 703 } 704 705 uint64_t span = newest - oldest; 706 if (span > (monthSec * MS_PER_SEC)) { 707 spaces += spaces_total; 708 continue; 709 } 710 711 // total span 712 if (minTime > oldest) minTime = oldest; 713 if (maxTime < newest) maxTime = newest; 714 if (span > maxSpan) maxSpan = span; 715 totalSize += span; 716 717 uint64_t dropped = mNewestDropped[id].msec(); 718 if (dropped < oldest) dropped = oldest; 719 if (dropped > newest) dropped = newest; 720 721 oldLength = output.length(); 722 output += android::base::StringPrintf("%*s%s", spaces, "", 723 formatMsec(span).c_str()); 724 unsigned permille = ((newest - dropped) * 1000 + (span / 2)) / span; 725 if ((permille > 1) && (permille < 999)) { 726 output += android::base::StringPrintf("(%u", permille / 10); 727 permille %= 10; 728 if (permille) { 729 output += android::base::StringPrintf(".%u", permille); 730 } 731 output += android::base::StringPrintf("%%)"); 732 } 733 spaces -= output.length() - oldLength; 734 spaces += spaces_total; 735 } 736 if ((maxTime > minTime) && ((maxTime -= minTime) < totalSize) && 737 (maxTime > maxSpan)) { 738 maxSpan = maxTime; 739 } 740 if (spaces < 0) spaces = 0; 741 output += android::base::StringPrintf("%*s%s", spaces, "", 742 formatMsec(maxSpan).c_str()); 743 744 static const char OverheadStr[] = "\nOverhead"; 745 spaces = 10 - strlen(OverheadStr); 746 output += OverheadStr; 747 748 totalSize = 0; 749 log_id_for_each(id) { 750 if (!(logMask & (1 << id))) continue; 751 752 size_t els = elements(id); 753 if (els) { 754 oldLength = output.length(); 755 if (spaces < 0) spaces = 0; 756 // estimate the std::list overhead. 757 static const size_t overhead = 758 ((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) & 759 -sizeof(uint64_t)) + 760 sizeof(std::list<LogBufferElement*>); 761 size_t szs = sizes(id) + els * overhead; 762 totalSize += szs; 763 output += android::base::StringPrintf("%*s%zu", spaces, "", szs); 764 spaces -= output.length() - oldLength; 765 } 766 spaces += spaces_total; 767 } 768 totalSize += sizeOf(); 769 if (spaces < 0) spaces = 0; 770 output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize); 771 772 // Report on Chattiest 773 774 std::string name; 775 776 // Chattiest by application (UID) 777 log_id_for_each(id) { 778 if (!(logMask & (1 << id))) continue; 779 780 name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:" 781 : "Logging for your UID in %s log buffer:"; 782 output += uidTable[id].format(*this, uid, pid, name, id); 783 } 784 785 if (enable) { 786 name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:" 787 : "Logging for this PID:"; 788 output += pidTable.format(*this, uid, pid, name); 789 name = "Chattiest TIDs"; 790 if (pid) name += android::base::StringPrintf(" for PID %d", pid); 791 name += ":"; 792 output += tidTable.format(*this, uid, pid, name); 793 } 794 795 if (enable && (logMask & (1 << LOG_ID_EVENTS))) { 796 name = "Chattiest events log buffer TAGs"; 797 if (pid) name += android::base::StringPrintf(" for PID %d", pid); 798 name += ":"; 799 output += tagTable.format(*this, uid, pid, name, LOG_ID_EVENTS); 800 } 801 802 if (enable && (logMask & (1 << LOG_ID_SECURITY))) { 803 name = "Chattiest security log buffer TAGs"; 804 if (pid) name += android::base::StringPrintf(" for PID %d", pid); 805 name += ":"; 806 output += 807 securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY); 808 } 809 810 if (enable) { 811 name = "Chattiest TAGs"; 812 if (pid) name += android::base::StringPrintf(" for PID %d", pid); 813 name += ":"; 814 output += tagNameTable.format(*this, uid, pid, name); 815 } 816 817 return output; 818 } 819 820 namespace android { 821 822 uid_t pidToUid(pid_t pid) { 823 char buffer[512]; 824 snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid); 825 FILE* fp = fopen(buffer, "r"); 826 if (fp) { 827 while (fgets(buffer, sizeof(buffer), fp)) { 828 int uid = AID_LOGD; 829 char space = 0; 830 if ((sscanf(buffer, "Uid: %d%c", &uid, &space) == 2) && 831 isspace(space)) { 832 fclose(fp); 833 return uid; 834 } 835 } 836 fclose(fp); 837 } 838 return AID_LOGD; // associate this with the logger 839 } 840 841 pid_t tidToPid(pid_t tid) { 842 char buffer[512]; 843 snprintf(buffer, sizeof(buffer), "/proc/%u/status", tid); 844 FILE* fp = fopen(buffer, "r"); 845 if (fp) { 846 while (fgets(buffer, sizeof(buffer), fp)) { 847 int pid = tid; 848 char space = 0; 849 if ((sscanf(buffer, "Tgid: %d%c", &pid, &space) == 2) && 850 isspace(space)) { 851 fclose(fp); 852 return pid; 853 } 854 } 855 fclose(fp); 856 } 857 return tid; 858 } 859 } 860 861 uid_t LogStatistics::pidToUid(pid_t pid) { 862 return pidTable.add(pid)->second.getUid(); 863 } 864 865 pid_t LogStatistics::tidToPid(pid_t tid) { 866 return tidTable.add(tid)->second.getPid(); 867 } 868 869 // caller must free character string 870 const char* LogStatistics::pidToName(pid_t pid) const { 871 // An inconvenient truth ... getName() can alter the object 872 pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable); 873 const char* name = writablePidTable.add(pid)->second.getName(); 874 if (!name) { 875 return NULL; 876 } 877 return strdup(name); 878 } 879