예제 #1
0
void LogKlog::sniffTime(log_time &now, const char **buf, bool reverse) {
    const char *cp;
    if ((cp = now.strptime(*buf, "[ %s.%q]"))) {
        static const char suspend[] = "PM: suspend entry ";
        static const char resume[] = "PM: suspend exit ";
        static const char healthd[] = "healthd: battery ";
        static const char suspended[] = "Suspended for ";

        if (isspace(*cp)) {
            ++cp;
        }
        if (!strncmp(cp, suspend, sizeof(suspend) - 1)) {
            calculateCorrection(now, cp + sizeof(suspend) - 1);
        } else if (!strncmp(cp, resume, sizeof(resume) - 1)) {
            calculateCorrection(now, cp + sizeof(resume) - 1);
        } else if (!strncmp(cp, healthd, sizeof(healthd) - 1)) {
            // look for " 2???-??-?? ??:??:??.????????? ???"
            const char *tp;
            for (tp = cp + sizeof(healthd) - 1; *tp && (*tp != '\n'); ++tp) {
                if ((tp[0] == ' ') && (tp[1] == '2') && (tp[5] == '-')) {
                    calculateCorrection(now, tp + 1);
                    break;
                }
            }
        } else if (!strncmp(cp, suspended, sizeof(suspended) - 1)) {
            log_time real;
            char *endp;
            real.tv_sec = strtol(cp + sizeof(suspended) - 1, &endp, 10);
            if (*endp == '.') {
                real.tv_nsec = strtol(endp + 1, &endp, 10) * 1000000L;
                if (reverse) {
                    correction -= real;
                } else {
                    correction += real;
                }
            }
        }

        convertMonotonicToReal(now);
        *buf = cp;
    } else {
        now = log_time(CLOCK_REALTIME);
    }
}
예제 #2
0
void LogKlog::sniffTime(log_time &now,
                        const char **buf, size_t len,
                        bool reverse) {
    const char *cp = now.strptime(*buf, "[ %s.%q]");
    if (cp && (cp >= &(*buf)[len])) {
        cp = NULL;
    }
    if (cp) {
        static const char healthd[] = "healthd";
        static const char battery[] = ": battery ";

        len -= cp - *buf;
        if (len && isspace(*cp)) {
            ++cp;
            --len;
        }
        *buf = cp;

        if (isMonotonic()) {
            return;
        }

        const char *b;
        if (((b = strnstr(cp, len, suspendStr)))
                && ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
            len -= b - cp;
            calculateCorrection(now, b, len);
        } else if (((b = strnstr(cp, len, resumeStr)))
                && ((size_t)((b += sizeof(resumeStr) - 1) - cp) < len)) {
            len -= b - cp;
            calculateCorrection(now, b, len);
        } else if (((b = strnstr(cp, len, healthd)))
                && ((size_t)((b += sizeof(healthd) - 1) - cp) < len)
                && ((b = strnstr(b, len -= b - cp, battery)))
                && ((size_t)((b += sizeof(battery) - 1) - cp) < len)) {
            // NB: healthd is roughly 150us late, so we use it instead to
            //     trigger a check for ntp-induced or hardware clock drift.
            log_time real(CLOCK_REALTIME);
            log_time mono(CLOCK_MONOTONIC);
            correction = (real < mono) ? log_time::EPOCH : (real - mono);
        } else if (((b = strnstr(cp, len, suspendedStr)))
                && ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
            len -= b - cp;
            log_time real;
            char *endp;
            real.tv_sec = strtol(b, &endp, 10);
            if ((*endp == '.') && ((size_t)(endp - b) < len)) {
                unsigned long multiplier = NS_PER_SEC;
                real.tv_nsec = 0;
                len -= endp - b;
                while (--len && isdigit(*++endp) && (multiplier /= 10)) {
                    real.tv_nsec += (*endp - '0') * multiplier;
                }
                if (reverse) {
                    if (real > correction) {
                        correction = log_time::EPOCH;
                    } else {
                        correction -= real;
                    }
                } else {
                    correction += real;
                }
            }
        }

        convertMonotonicToReal(now);
    } else {
        if (isMonotonic()) {
            now = log_time(CLOCK_MONOTONIC);
        } else {
            now = log_time(CLOCK_REALTIME);
        }
    }
}
예제 #3
0
void LogKlog::sniffTime(log_time& now, const char*& buf, ssize_t len,
                        bool reverse) {
    if (len <= 0) return;

    const char* cp = nullptr;
    if ((len > 10) && (*buf == '[')) {
        cp = now.strptime(buf, "[ %s.%q]");  // can index beyond buffer bounds
        if (cp && (cp > &buf[len - 1])) cp = nullptr;
    }
    if (cp) {
        len -= cp - buf;
        if ((len > 0) && isspace(*cp)) {
            ++cp;
            --len;
        }
        buf = cp;

        if (isMonotonic()) return;

        const char* b;
        if (((b = android::strnstr(cp, len, suspendStr))) &&
            (((b += strlen(suspendStr)) - cp) < len)) {
            len -= b - cp;
            calculateCorrection(now, b, len);
        } else if (((b = android::strnstr(cp, len, resumeStr))) &&
                   (((b += strlen(resumeStr)) - cp) < len)) {
            len -= b - cp;
            calculateCorrection(now, b, len);
        } else if (((b = android::strnstr(cp, len, healthdStr))) &&
                   (((b += strlen(healthdStr)) - cp) < len) &&
                   ((b = android::strnstr(b, len -= b - cp, batteryStr))) &&
                   (((b += strlen(batteryStr)) - cp) < len)) {
            // NB: healthd is roughly 150us late, so we use it instead to
            //     trigger a check for ntp-induced or hardware clock drift.
            log_time real(CLOCK_REALTIME);
            log_time mono(CLOCK_MONOTONIC);
            correction = (real < mono) ? log_time::EPOCH : (real - mono);
        } else if (((b = android::strnstr(cp, len, suspendedStr))) &&
                   (((b += strlen(suspendStr)) - cp) < len)) {
            len -= b - cp;
            log_time real;
            char* endp;
            real.tv_sec = strtol(b, &endp, 10);
            if ((*endp == '.') && ((endp - b) < len)) {
                unsigned long multiplier = NS_PER_SEC;
                real.tv_nsec = 0;
                len -= endp - b;
                while (--len && isdigit(*++endp) && (multiplier /= 10)) {
                    real.tv_nsec += (*endp - '0') * multiplier;
                }
                if (reverse) {
                    if (real > correction) {
                        correction = log_time::EPOCH;
                    } else {
                        correction -= real;
                    }
                } else {
                    correction += real;
                }
            }
        }

        convertMonotonicToReal(now);
    } else {
        if (isMonotonic()) {
            now = log_time(CLOCK_MONOTONIC);
        } else {
            now = log_time(CLOCK_REALTIME);
        }
    }
}
예제 #4
0
void LogKlog::sniffTime(log_time &now,
                        const char **buf, size_t len,
                        bool reverse) {
    const char *cp = now.strptime(*buf, "[ %s.%q]");
    if (cp && (cp >= &(*buf)[len])) {
        cp = NULL;
    }
    len -= cp - *buf;
    if (cp) {
        static const char healthd[] = "healthd";
        static const char battery[] = ": battery ";

        if (len && isspace(*cp)) {
            ++cp;
            --len;
        }
        *buf = cp;

        const char *b;
        if (((b = strnstr(cp, len, suspendStr)))
                && ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
            len -= b - cp;
            calculateCorrection(now, b, len);
        } else if (((b = strnstr(cp, len, resumeStr)))
                && ((size_t)((b += sizeof(resumeStr) - 1) - cp) < len)) {
            len -= b - cp;
            calculateCorrection(now, b, len);
        } else if (((b = strnstr(cp, len, healthd)))
                && ((size_t)((b += sizeof(healthd) - 1) - cp) < len)
                && ((b = strnstr(b, len -= b - cp, battery)))
                && ((size_t)((b += sizeof(battery) - 1) - cp) < len)) {
            len -= b - cp;
            // NB: healthd is roughly 150us late, worth the price to deal with
            //     ntp-induced or hardware clock drift.
            // look for " 2???-??-?? ??:??:??.????????? ???"
            for (; len && *b && (*b != '\n'); ++b, --len) {
                if ((b[0] == ' ') && (b[1] == '2') && (b[5] == '-')) {
                    calculateCorrection(now, b + 1, len - 1);
                    break;
                }
            }
        } else if (((b = strnstr(cp, len, suspendedStr)))
                && ((size_t)((b += sizeof(suspendStr) - 1) - cp) < len)) {
            len -= b - cp;
            log_time real;
            char *endp;
            real.tv_sec = strtol(b, &endp, 10);
            if ((*endp == '.') && ((size_t)(endp - b) < len)) {
                unsigned long multiplier = NS_PER_SEC;
                real.tv_nsec = 0;
                len -= endp - b;
                while (--len && isdigit(*++endp) && (multiplier /= 10)) {
                    real.tv_nsec += (*endp - '0') * multiplier;
                }
                if (reverse) {
                    correction -= real;
                } else {
                    correction += real;
                }
            }
        }

        convertMonotonicToReal(now);
    } else {
        now = log_time(CLOCK_REALTIME);
    }
}
예제 #5
0
void LogStatistics::format(char **buf,
                           uid_t uid, unsigned int logMask, log_time oldest) {
    static const unsigned short spaces_current = 13;
    static const unsigned short spaces_total = 19;

    if (*buf) {
        free(*buf);
        *buf = NULL;
    }

    android::String8 string("        span -> size/num");
    size_t oldLength;
    short spaces = 2;

    log_id_for_each(i) {
        if (!(logMask & (1 << i))) {
            continue;
        }
        oldLength = string.length();
        if (spaces < 0) {
            spaces = 0;
        }
        string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
        spaces += spaces_total + oldLength - string.length();

        LidStatistics &l = id(i);
        l.sort();

        UidStatisticsCollection::iterator iu;
        for (iu = l.begin(); iu != l.end(); ++iu) {
            (*iu)->sort();
        }
    }

    spaces = 1;
    log_time t(CLOCK_MONOTONIC);
    unsigned long long d;
    if (mStatistics) {
        d = t.nsec() - start.nsec();
        string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu",
                  d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
                  (d / NS_PER_SEC) % 60, d % NS_PER_SEC);

        log_id_for_each(i) {
            if (!(logMask & (1 << i))) {
                continue;
            }
            oldLength = string.length();
            if (spaces < 0) {
                spaces = 0;
            }
            string.appendFormat("%*s%zu/%zu", spaces, "",
                                sizesTotal(i), elementsTotal(i));
            spaces += spaces_total + oldLength - string.length();
        }
        spaces = 1;
    }

    d = t.nsec() - oldest.nsec();
    string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu",
                  d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
                  (d / NS_PER_SEC) % 60, d % NS_PER_SEC);

    log_id_for_each(i) {
        if (!(logMask & (1 << i))) {
            continue;
        }

        size_t els = elements(i);
        if (els) {
            oldLength = string.length();
            if (spaces < 0) {
                spaces = 0;
            }
            string.appendFormat("%*s%zu/%zu", spaces, "", sizes(i), els);
            spaces -= string.length() - oldLength;
        }
        spaces += spaces_total;
    }

    // Construct list of worst spammers by Pid
    static const unsigned char num_spammers = 10;
    bool header = false;

    log_id_for_each(i) {
        if (!(logMask & (1 << i))) {
            continue;
        }

        PidStatisticsCollection pids;
        pids.clear();

        LidStatistics &l = id(i);
        UidStatisticsCollection::iterator iu;
        for (iu = l.begin(); iu != l.end(); ++iu) {
            UidStatistics &u = *(*iu);
            PidStatisticsCollection::iterator ip;
            for (ip = u.begin(); ip != u.end(); ++ip) {
                PidStatistics *p = (*ip);
                if (p->getPid() == p->gone) {
                    break;
                }

                size_t mySizes = p->sizes();

                PidStatisticsCollection::iterator q;
                unsigned char num = 0;
                for (q = pids.begin(); q != pids.end(); ++q) {
                    if (mySizes > (*q)->sizes()) {
                        pids.insert(q, p);
                        break;
                    }
                    // do we need to traverse deeper in the list?
                    if (++num > num_spammers) {
                        break;
                    }
                }
                if (q == pids.end()) {
                   pids.push_back(p);
                }
            }
        }

        size_t threshold = sizes(i);
        if (threshold < 65536) {
            threshold = 65536;
        }
        threshold /= 100;

        PidStatisticsCollection::iterator pt = pids.begin();

        for(int line = 0;
                (pt != pids.end()) && (line < num_spammers);
                ++line, pt = pids.erase(pt)) {
            PidStatistics *p = *pt;

            size_t sizes = p->sizes();
            if (sizes < threshold) {
                break;
            }

            char *name = p->getName();
            pid_t pid = p->getPid();
            if (!name || !*name) {
                name = pidToName(pid);
                if (name) {
                    if (*name) {
                        p->setName(name);
                    } else {
                        free(name);
                        name = NULL;
                    }
                }
            }

            if (!header) {
                string.appendFormat("\n\nChattiest clients:\n"
                                    "log id %-*s PID[?] name",
                                    spaces_total, "size/total");
                header = true;
            }

            size_t sizesTotal = p->sizesTotal();

            android::String8 sz("");
            sz.appendFormat((sizes != sizesTotal) ? "%zu/%zu" : "%zu",
                            sizes, sizesTotal);

            android::String8 pd("");
            pd.appendFormat("%u%c", pid, p->pidGone() ? '?' : ' ');

            string.appendFormat("\n%-7s%-*s %-7s%s",
                                line ? "" : android_log_id_to_name(i),
                                spaces_total, sz.string(), pd.string(),
                                name ? name : "");
        }

        pids.clear();
    }

    if (dgramQlenStatistics) {
        const unsigned short spaces_time = 6;
        const unsigned long long max_seconds = 100000;
        spaces = 0;
        string.append("\n\nMinimum time between log events per max_dgram_qlen:\n");
        for(unsigned short i = 0; dgramQlen(i); ++i) {
            oldLength = string.length();
            if (spaces < 0) {
                spaces = 0;
            }
            string.appendFormat("%*s%u", spaces, "", dgramQlen(i));
            spaces += spaces_time + oldLength - string.length();
        }
        string.append("\n");
        spaces = 0;
        unsigned short n;
        for(unsigned short i = 0; (n = dgramQlen(i)); ++i) {
            unsigned long long duration = minimum(i);
            if (duration) {
                duration /= n;
                if (duration >= (NS_PER_SEC * max_seconds)) {
                    duration = NS_PER_SEC * (max_seconds - 1);
                }
                oldLength = string.length();
                if (spaces < 0) {
                    spaces = 0;
                }
                string.appendFormat("%*s", spaces, "");
                if (duration >= (NS_PER_SEC * 10)) {
                    string.appendFormat("%llu",
                        (duration + (NS_PER_SEC / 2))
                            / NS_PER_SEC);
                } else if (duration >= (NS_PER_SEC / (1000 / 10))) {
                    string.appendFormat("%llum",
                        (duration + (NS_PER_SEC / 2 / 1000))
                            / (NS_PER_SEC / 1000));
                } else if (duration >= (NS_PER_SEC / (1000000 / 10))) {
                    string.appendFormat("%lluu",
                        (duration + (NS_PER_SEC / 2 / 1000000))
                            / (NS_PER_SEC / 1000000));
                } else {
                    string.appendFormat("%llun", duration);
                }
                spaces -= string.length() - oldLength;
            }
            spaces += spaces_time;
        }
    }

    log_id_for_each(i) {
        if (!(logMask & (1 << i))) {
            continue;
        }

        header = false;
        bool first = true;

        UidStatisticsCollection::iterator ut;
        for(ut = id(i).begin(); ut != id(i).end(); ++ut) {
            UidStatistics *up = *ut;
            if ((uid != AID_ROOT) && (uid != up->getUid())) {
                continue;
            }

            PidStatisticsCollection::iterator pt = up->begin();
            if (pt == up->end()) {
                continue;
            }

            android::String8 intermediate;

            if (!header) {
                // header below tuned to match spaces_total and spaces_current
                spaces = 0;
                intermediate = string.format("%s: UID/PID Total size/num",
                                             android_log_id_to_name(i));
                string.appendFormat("\n\n%-31sNow          "
                                         "UID/PID[?]  Total              Now",
                                    intermediate.string());
                intermediate.clear();
                header = true;
            }

            bool oneline = ++pt == up->end();
            --pt;

            if (!oneline) {
                first = true;
            } else if (!first && (spaces > 0)) {
                string.appendFormat("%*s", spaces, "");
            }
            spaces = 0;

            uid_t u = up->getUid();
            PidStatistics *pp = *pt;
            pid_t p = pp->getPid();

            intermediate = string.format(oneline
                                             ? ((p == PidStatistics::gone)
                                                 ? "%d/?"
                                                 : "%d/%d%c")
                                             : "%d",
                                         u, p, pp->pidGone() ? '?' : '\0');
            string.appendFormat(first ? "\n%-12s" : "%-12s",
                                intermediate.string());
            intermediate.clear();

            size_t elsTotal = up->elementsTotal();
            oldLength = string.length();
            string.appendFormat("%zu/%zu", up->sizesTotal(), elsTotal);
            spaces += spaces_total + oldLength - string.length();

            size_t els = up->elements();
            if (els == elsTotal) {
                if (spaces < 0) {
                    spaces = 0;
                }
                string.appendFormat("%*s=", spaces, "");
                spaces = -1;
            } else if (els) {
                oldLength = string.length();
                if (spaces < 0) {
                    spaces = 0;
                }
                string.appendFormat("%*s%zu/%zu", spaces, "", up->sizes(), els);
                spaces -= string.length() - oldLength;
            }
            spaces += spaces_current;

            first = !first;

            if (oneline) {
                continue;
            }

            size_t gone_szs = 0;
            size_t gone_els = 0;

            for(; pt != up->end(); ++pt) {
                pp = *pt;
                p = pp->getPid();

                // If a PID no longer has any current logs, and is not
                // active anymore, skip & report totals for gone.
                elsTotal = pp->elementsTotal();
                size_t szsTotal = pp->sizesTotal();
                if (p == pp->gone) {
                    gone_szs += szsTotal;
                    gone_els += elsTotal;
                    continue;
                }
                els = pp->elements();
                bool gone = pp->pidGone();
                if (gone && (els == 0)) {
                    // ToDo: garbage collection: move this statistical bucket
                    //       from its current UID/PID to UID/? (races and
                    //       wrap around are our achilles heel). Below is
                    //       merely lipservice to catch PIDs that were still
                    //       around when the stats were pruned to zero.
                    gone_szs += szsTotal;
                    gone_els += elsTotal;
                    continue;
                }

                if (!first && (spaces > 0)) {
                    string.appendFormat("%*s", spaces, "");
                }
                spaces = 0;

                intermediate = string.format(gone ? "%d/%d?" : "%d/%d", u, p);
                string.appendFormat(first ? "\n%-12s" : "%-12s",
                                    intermediate.string());
                intermediate.clear();

                oldLength = string.length();
                string.appendFormat("%zu/%zu", szsTotal, elsTotal);
                spaces += spaces_total + oldLength - string.length();

                if (els == elsTotal) {
                    if (spaces < 0) {
                        spaces = 0;
                    }
                    string.appendFormat("%*s=", spaces, "");
                    spaces = -1;
                } else if (els) {
                    oldLength = string.length();
                    if (spaces < 0) {
                        spaces = 0;
                    }
                    string.appendFormat("%*s%zu/%zu", spaces, "",
                                        pp->sizes(), els);
                    spaces -= string.length() - oldLength;
                }
                spaces += spaces_current;

                first = !first;
            }

            if (gone_els) {
                if (!first && (spaces > 0)) {
                    string.appendFormat("%*s", spaces, "");
                }

                intermediate = string.format("%d/?", u);
                string.appendFormat(first ? "\n%-12s" : "%-12s",
                                    intermediate.string());
                intermediate.clear();

                spaces = spaces_total + spaces_current;

                oldLength = string.length();
                string.appendFormat("%zu/%zu", gone_szs, gone_els);
                spaces -= string.length() - oldLength;

                first = !first;
            }
        }
    }

    *buf = strdup(string.string());
}