Home | History | Annotate | Download | only in logd
      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 <fcntl.h>
     18 #include <stdio.h>
     19 #include <string.h>
     20 #include <unistd.h>
     21 
     22 #include <log/logger.h>
     23 
     24 #include "LogStatistics.h"
     25 
     26 LogStatistics::LogStatistics() : enable(false) {
     27     log_id_for_each(id) {
     28         mSizes[id] = 0;
     29         mElements[id] = 0;
     30         mDroppedElements[id] = 0;
     31         mSizesTotal[id] = 0;
     32         mElementsTotal[id] = 0;
     33     }
     34 }
     35 
     36 namespace android {
     37 
     38 // caller must own and free character string
     39 char *pidToName(pid_t pid) {
     40     char *retval = NULL;
     41     if (pid == 0) { // special case from auditd/klogd for kernel
     42         retval = strdup("logd");
     43     } else {
     44         char buffer[512];
     45         snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
     46         int fd = open(buffer, O_RDONLY);
     47         if (fd >= 0) {
     48             ssize_t ret = read(fd, buffer, sizeof(buffer));
     49             if (ret > 0) {
     50                 buffer[sizeof(buffer)-1] = '\0';
     51                 // frameworks intermediate state
     52                 if (fast<strcmp>(buffer, "<pre-initialized>")) {
     53                     retval = strdup(buffer);
     54                 }
     55             }
     56             close(fd);
     57         }
     58     }
     59     return retval;
     60 }
     61 
     62 }
     63 
     64 void LogStatistics::add(LogBufferElement *element) {
     65     log_id_t log_id = element->getLogId();
     66     unsigned short size = element->getMsgLen();
     67     mSizes[log_id] += size;
     68     ++mElements[log_id];
     69 
     70     mSizesTotal[log_id] += size;
     71     ++mElementsTotal[log_id];
     72 
     73     if (log_id == LOG_ID_KERNEL) {
     74         return;
     75     }
     76 
     77     uidTable[log_id].add(element->getUid(), element);
     78     if (element->getUid() == AID_SYSTEM) {
     79         pidSystemTable[log_id].add(element->getPid(), element);
     80     }
     81 
     82     if (!enable) {
     83         return;
     84     }
     85 
     86     pidTable.add(element->getPid(), element);
     87     tidTable.add(element->getTid(), element);
     88 
     89     uint32_t tag = element->getTag();
     90     if (tag) {
     91         if (log_id == LOG_ID_SECURITY) {
     92             securityTagTable.add(tag, element);
     93         } else {
     94             tagTable.add(tag, element);
     95         }
     96     }
     97 }
     98 
     99 void LogStatistics::subtract(LogBufferElement *element) {
    100     log_id_t log_id = element->getLogId();
    101     unsigned short size = element->getMsgLen();
    102     mSizes[log_id] -= size;
    103     --mElements[log_id];
    104     if (element->getDropped()) {
    105         --mDroppedElements[log_id];
    106     }
    107 
    108     if (log_id == LOG_ID_KERNEL) {
    109         return;
    110     }
    111 
    112     uidTable[log_id].subtract(element->getUid(), element);
    113     if (element->getUid() == AID_SYSTEM) {
    114         pidSystemTable[log_id].subtract(element->getPid(), element);
    115     }
    116 
    117     if (!enable) {
    118         return;
    119     }
    120 
    121     pidTable.subtract(element->getPid(), element);
    122     tidTable.subtract(element->getTid(), element);
    123 
    124     uint32_t tag = element->getTag();
    125     if (tag) {
    126         if (log_id == LOG_ID_SECURITY) {
    127             securityTagTable.subtract(tag, element);
    128         } else {
    129             tagTable.subtract(tag, element);
    130         }
    131     }
    132 }
    133 
    134 // Atomically set an entry to drop
    135 // entry->setDropped(1) must follow this call, caller should do this explicitly.
    136 void LogStatistics::drop(LogBufferElement *element) {
    137     log_id_t log_id = element->getLogId();
    138     unsigned short size = element->getMsgLen();
    139     mSizes[log_id] -= size;
    140     ++mDroppedElements[log_id];
    141 
    142     uidTable[log_id].drop(element->getUid(), element);
    143     if (element->getUid() == AID_SYSTEM) {
    144         pidSystemTable[log_id].drop(element->getPid(), element);
    145     }
    146 
    147     if (!enable) {
    148         return;
    149     }
    150 
    151     pidTable.drop(element->getPid(), element);
    152     tidTable.drop(element->getTid(), element);
    153 }
    154 
    155 // caller must own and free character string
    156 const char *LogStatistics::uidToName(uid_t uid) const {
    157     // Local hard coded favourites
    158     if (uid == AID_LOGD) {
    159         return strdup("auditd");
    160     }
    161 
    162     // Android hard coded
    163     const struct android_id_info *info = android_ids;
    164 
    165     for (size_t i = 0; i < android_id_count; ++i) {
    166         if (info->aid == uid) {
    167             return strdup(info->name);
    168         }
    169         ++info;
    170     }
    171 
    172     // Parse /data/system/packages.list
    173     uid_t userId = uid % AID_USER;
    174     const char *name = android::uidToName(userId);
    175     if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
    176         name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
    177     }
    178     if (name) {
    179         return name;
    180     }
    181 
    182     // report uid -> pid(s) -> pidToName if unique
    183     for(pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end(); ++it) {
    184         const PidEntry &entry = it->second;
    185 
    186         if (entry.getUid() == uid) {
    187             const char *nameTmp = entry.getName();
    188 
    189             if (nameTmp) {
    190                 if (!name) {
    191                     name = strdup(nameTmp);
    192                 } else if (fast<strcmp>(name, nameTmp)) {
    193                     free(const_cast<char *>(name));
    194                     name = NULL;
    195                     break;
    196                 }
    197             }
    198         }
    199     }
    200 
    201     // No one
    202     return name;
    203 }
    204 
    205 std::string UidEntry::formatHeader(const std::string &name, log_id_t id) const {
    206     bool isprune = worstUidEnabledForLogid(id);
    207     return formatLine(android::base::StringPrintf(
    208                           name.c_str(), android_log_id_to_name(id)),
    209                       std::string("Size"),
    210                       std::string(isprune ? "+/-  Pruned" : ""))
    211          + formatLine(std::string("UID   PACKAGE"),
    212                       std::string("BYTES"),
    213                       std::string(isprune ? "NUM" : ""));
    214 }
    215 
    216 std::string UidEntry::format(const LogStatistics &stat, log_id_t id) const {
    217     uid_t uid = getUid();
    218     std::string name = android::base::StringPrintf("%u", uid);
    219     const char *nameTmp = stat.uidToName(uid);
    220     if (nameTmp) {
    221         name += android::base::StringPrintf(
    222             "%*s%s", (int)std::max(6 - name.length(), (size_t)1),
    223             "", nameTmp);
    224         free(const_cast<char *>(nameTmp));
    225     }
    226 
    227     std::string size = android::base::StringPrintf("%zu", getSizes());
    228 
    229     std::string pruned = "";
    230     if (worstUidEnabledForLogid(id)) {
    231         size_t totalDropped = 0;
    232         for (LogStatistics::uidTable_t::const_iterator it = stat.uidTable[id].begin();
    233                 it != stat.uidTable[id].end(); ++it) {
    234             totalDropped += it->second.getDropped();
    235         }
    236         size_t sizes = stat.sizes(id);
    237         size_t totalSize = stat.sizesTotal(id);
    238         size_t totalElements = stat.elementsTotal(id);
    239         float totalVirtualSize = (float)sizes + (float)totalDropped * totalSize
    240                                 / totalElements;
    241         size_t entrySize = getSizes();
    242         float virtualEntrySize = entrySize;
    243         int realPermille = virtualEntrySize * 1000.0 / sizes;
    244         size_t dropped = getDropped();
    245         if (dropped) {
    246             pruned = android::base::StringPrintf("%zu", dropped);
    247             virtualEntrySize += (float)dropped * totalSize / totalElements;
    248         }
    249         int virtualPermille = virtualEntrySize * 1000.0 / totalVirtualSize;
    250         int permille = (realPermille - virtualPermille) * 1000L
    251                      / (virtualPermille ?: 1);
    252         if ((permille < -1) || (1 < permille)) {
    253             std::string change;
    254             const char *units = "%";
    255             const char *prefix = (permille > 0) ? "+" : "";
    256 
    257             if (permille > 999) {
    258                 permille = (permille + 1000) / 100; // Now tenths fold
    259                 units = "X";
    260                 prefix = "";
    261             }
    262             if ((-99 < permille) && (permille < 99)) {
    263                 change = android::base::StringPrintf("%s%d.%u%s",
    264                     prefix,
    265                     permille / 10,
    266                     ((permille < 0) ? (-permille % 10) : (permille % 10)),
    267                     units);
    268             } else {
    269                 change = android::base::StringPrintf("%s%d%s",
    270                     prefix,
    271                     (permille + 5) / 10, units);
    272             }
    273             ssize_t spaces = EntryBaseConstants::pruned_len
    274                            - 2 - pruned.length() - change.length();
    275             if ((spaces <= 0) && pruned.length()) {
    276                 spaces = 1;
    277             }
    278             if (spaces > 0) {
    279                 change += android::base::StringPrintf("%*s", (int)spaces, "");
    280             }
    281             pruned = change + pruned;
    282         }
    283     }
    284 
    285     std::string output = formatLine(name, size, pruned);
    286 
    287     if (uid != AID_SYSTEM) {
    288         return output;
    289     }
    290 
    291     static const size_t maximum_sorted_entries = 32;
    292     std::unique_ptr<const PidEntry *[]> sorted
    293         = stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries);
    294 
    295     if (!sorted.get()) {
    296         return output;
    297     }
    298     std::string byPid;
    299     size_t index;
    300     bool hasDropped = false;
    301     for (index = 0; index < maximum_sorted_entries; ++index) {
    302         const PidEntry *entry = sorted[index];
    303         if (!entry) {
    304             break;
    305         }
    306         if (entry->getSizes() <= (getSizes() / 100)) {
    307             break;
    308         }
    309         if (entry->getDropped()) {
    310             hasDropped = true;
    311         }
    312         byPid += entry->format(stat, id);
    313     }
    314     if (index > 1) { // print this only if interesting
    315         std::string ditto("\" ");
    316         output += formatLine(std::string("  PID/UID   COMMAND LINE"),
    317                              ditto, hasDropped ? ditto : std::string(""));
    318         output += byPid;
    319     }
    320 
    321     return output;
    322 }
    323 
    324 std::string PidEntry::formatHeader(const std::string &name, log_id_t /* id */) const {
    325     return formatLine(name,
    326                       std::string("Size"),
    327                       std::string("Pruned"))
    328          + formatLine(std::string("  PID/UID   COMMAND LINE"),
    329                       std::string("BYTES"),
    330                       std::string("NUM"));
    331 }
    332 
    333 std::string PidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
    334     uid_t uid = getUid();
    335     pid_t pid = getPid();
    336     std::string name = android::base::StringPrintf("%5u/%u", pid, uid);
    337     const char *nameTmp = getName();
    338     if (nameTmp) {
    339         name += android::base::StringPrintf(
    340             "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
    341             "", nameTmp);
    342     } else if ((nameTmp = stat.uidToName(uid))) {
    343         name += android::base::StringPrintf(
    344             "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
    345             "", nameTmp);
    346         free(const_cast<char *>(nameTmp));
    347     }
    348 
    349     std::string size = android::base::StringPrintf("%zu",
    350                                                    getSizes());
    351 
    352     std::string pruned = "";
    353     size_t dropped = getDropped();
    354     if (dropped) {
    355         pruned = android::base::StringPrintf("%zu", dropped);
    356     }
    357 
    358     return formatLine(name, size, pruned);
    359 }
    360 
    361 std::string TidEntry::formatHeader(const std::string &name, log_id_t /* id */) const {
    362     return formatLine(name,
    363                       std::string("Size"),
    364                       std::string("Pruned"))
    365          + formatLine(std::string("  TID/UID   COMM"),
    366                       std::string("BYTES"),
    367                       std::string("NUM"));
    368 }
    369 
    370 std::string TidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
    371     uid_t uid = getUid();
    372     std::string name = android::base::StringPrintf("%5u/%u",
    373                                                    getTid(), uid);
    374     const char *nameTmp = getName();
    375     if (nameTmp) {
    376         name += android::base::StringPrintf(
    377             "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
    378             "", nameTmp);
    379     } else if ((nameTmp = stat.uidToName(uid))) {
    380         // if we do not have a PID name, lets punt to try UID name?
    381         name += android::base::StringPrintf(
    382             "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
    383             "", nameTmp);
    384         free(const_cast<char *>(nameTmp));
    385         // We tried, better to not have a name at all, we still
    386         // have TID/UID by number to report in any case.
    387     }
    388 
    389     std::string size = android::base::StringPrintf("%zu",
    390                                                    getSizes());
    391 
    392     std::string pruned = "";
    393     size_t dropped = getDropped();
    394     if (dropped) {
    395         pruned = android::base::StringPrintf("%zu", dropped);
    396     }
    397 
    398     return formatLine(name, size, pruned);
    399 }
    400 
    401 std::string TagEntry::formatHeader(const std::string &name, log_id_t id) const {
    402     bool isprune = worstUidEnabledForLogid(id);
    403     return formatLine(name,
    404                       std::string("Size"),
    405                       std::string(isprune ? "Prune" : ""))
    406          + formatLine(std::string("    TAG/UID   TAGNAME"),
    407                       std::string("BYTES"),
    408                       std::string(isprune ? "NUM" : ""));
    409 }
    410 
    411 std::string TagEntry::format(const LogStatistics & /* stat */, log_id_t /* id */) const {
    412     std::string name;
    413     uid_t uid = getUid();
    414     if (uid == (uid_t)-1) {
    415         name = android::base::StringPrintf("%7u",
    416                                            getKey());
    417     } else {
    418         name = android::base::StringPrintf("%7u/%u",
    419                                            getKey(), uid);
    420     }
    421     const char *nameTmp = getName();
    422     if (nameTmp) {
    423         name += android::base::StringPrintf(
    424             "%*s%s", (int)std::max(14 - name.length(), (size_t)1),
    425             "", nameTmp);
    426     }
    427 
    428     std::string size = android::base::StringPrintf("%zu",
    429                                                    getSizes());
    430 
    431     std::string pruned = "";
    432 
    433     return formatLine(name, size, pruned);
    434 }
    435 
    436 std::string LogStatistics::format(uid_t uid, pid_t pid,
    437                                   unsigned int logMask) const {
    438     static const unsigned short spaces_total = 19;
    439 
    440     // Report on total logging, current and for all time
    441 
    442     std::string output = "size/num";
    443     size_t oldLength;
    444     short spaces = 1;
    445 
    446     log_id_for_each(id) {
    447         if (!(logMask & (1 << id))) {
    448             continue;
    449         }
    450         oldLength = output.length();
    451         if (spaces < 0) {
    452             spaces = 0;
    453         }
    454         output += android::base::StringPrintf("%*s%s", spaces, "",
    455                                               android_log_id_to_name(id));
    456         spaces += spaces_total + oldLength - output.length();
    457     }
    458 
    459     spaces = 4;
    460     output += "\nTotal";
    461 
    462     log_id_for_each(id) {
    463         if (!(logMask & (1 << id))) {
    464             continue;
    465         }
    466         oldLength = output.length();
    467         if (spaces < 0) {
    468             spaces = 0;
    469         }
    470         output += android::base::StringPrintf("%*s%zu/%zu", spaces, "",
    471                                               sizesTotal(id),
    472                                               elementsTotal(id));
    473         spaces += spaces_total + oldLength - output.length();
    474     }
    475 
    476     spaces = 6;
    477     output += "\nNow";
    478 
    479     log_id_for_each(id) {
    480         if (!(logMask & (1 << id))) {
    481             continue;
    482         }
    483 
    484         size_t els = elements(id);
    485         if (els) {
    486             oldLength = output.length();
    487             if (spaces < 0) {
    488                 spaces = 0;
    489             }
    490             output += android::base::StringPrintf("%*s%zu/%zu", spaces, "",
    491                                                   sizes(id), els);
    492             spaces -= output.length() - oldLength;
    493         }
    494         spaces += spaces_total;
    495     }
    496 
    497     // Report on Chattiest
    498 
    499     std::string name;
    500 
    501     // Chattiest by application (UID)
    502     log_id_for_each(id) {
    503         if (!(logMask & (1 << id))) {
    504             continue;
    505         }
    506 
    507         name = (uid == AID_ROOT)
    508             ? "Chattiest UIDs in %s log buffer:"
    509             : "Logging for your UID in %s log buffer:";
    510         output += uidTable[id].format(*this, uid, pid, name, id);
    511     }
    512 
    513     if (enable) {
    514         name = ((uid == AID_ROOT) && !pid)
    515             ? "Chattiest PIDs:"
    516             : "Logging for this PID:";
    517         output += pidTable.format(*this, uid, pid, name);
    518         name = "Chattiest TIDs";
    519         if (pid) {
    520             name += android::base::StringPrintf(" for PID %d", pid);
    521         }
    522         name += ":";
    523         output += tidTable.format(*this, uid, pid, name);
    524     }
    525 
    526     if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
    527         name = "Chattiest events log buffer TAGs";
    528         if (pid) {
    529             name += android::base::StringPrintf(" for PID %d", pid);
    530         }
    531         name += ":";
    532         output += tagTable.format(*this, uid, pid, name, LOG_ID_EVENTS);
    533     }
    534 
    535     if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
    536         name = "Chattiest security log buffer TAGs";
    537         if (pid) {
    538             name += android::base::StringPrintf(" for PID %d", pid);
    539         }
    540         name += ":";
    541         output += securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
    542     }
    543 
    544     return output;
    545 }
    546 
    547 namespace android {
    548 
    549 uid_t pidToUid(pid_t pid) {
    550     char buffer[512];
    551     snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
    552     FILE *fp = fopen(buffer, "r");
    553     if (fp) {
    554         while (fgets(buffer, sizeof(buffer), fp)) {
    555             int uid;
    556             if (sscanf(buffer, "Uid: %d", &uid) == 1) {
    557                 fclose(fp);
    558                 return uid;
    559             }
    560         }
    561         fclose(fp);
    562     }
    563     return AID_LOGD; // associate this with the logger
    564 }
    565 
    566 }
    567 
    568 uid_t LogStatistics::pidToUid(pid_t pid) {
    569     return pidTable.add(pid)->second.getUid();
    570 }
    571 
    572 // caller must free character string
    573 const char *LogStatistics::pidToName(pid_t pid) const {
    574     // An inconvenient truth ... getName() can alter the object
    575     pidTable_t &writablePidTable = const_cast<pidTable_t &>(pidTable);
    576     const char *name = writablePidTable.add(pid)->second.getName();
    577     if (!name) {
    578         return NULL;
    579     }
    580     return strdup(name);
    581 }
    582