Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b44f7d46 authored by Yi Jin's avatar Yi Jin
Browse files

This cl implements CommandSection and use it to add procrank.proto Section

Bug: 63863444
Test: manual - create gtests for CommandSection and Procrank Parser following
instructions in the README.md of incidentd and incident_helper on how to
run them.

Change-Id: I099808fd13bf9ed9a564b122f1126b1691a83291
parent 85ef0c0e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ cc_library {
            // needed by the device.
            srcs: [
                "core/proto/android/os/kernelwake.proto",
                "core/proto/android/os/procrank.proto",
                "core/proto/android/service/graphicsstats.proto",
            ],
            shared: {
+2 −1
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@ cc_defaults {

    srcs: [
        "IncidentHelper.cpp",
        "strutil.cpp",
        "ih_util.cpp",
    ],

    shared_libs: [
@@ -38,6 +38,7 @@ cc_test {

    srcs: [
        "tests/IncidentHelper_test.cpp",
        "tests/ih_util_test.cpp",
    ],

    data: [
+111 −31
Original line number Diff line number Diff line
@@ -17,14 +17,13 @@
#define LOG_TAG "incident_helper"

#include "IncidentHelper.h"
#include "strutil.h"
#include "ih_util.h"

#include "frameworks/base/core/proto/android/os/kernelwake.pb.h"
#include "frameworks/base/core/proto/android/os/procrank.pb.h"

#include <algorithm>
#include <android-base/file.h>
#include <unistd.h>
#include <sstream>
#include <string>
#include <vector>

@@ -67,37 +66,29 @@ const char* kernel_wake_headers[] = {
const string KERNEL_WAKEUP_LINE_DELIMITER = "\t";

status_t KernelWakesParser::Parse(const int in, const int out) const {
    // read the content, this is not memory-efficient though since it loads everything
    // However the data will be held in proto anyway, and incident_helper is less critical
    string content;
    if (!ReadFdToString(in, &content)) {
        fprintf(stderr, "[%s]Failed to read data from incidentd\n", this->name.string());
        return -1;
    }

    istringstream iss(content);
    Reader reader(in);
    string line;
    vector<string> header;  // the header of /d/wakeup_sources
    vector<string> record;  // retain each record
    header_t header;  // the header of /d/wakeup_sources
    record_t record;  // retain each record
    int nline = 0;

    KernelWakeSources proto;

    // parse line by line
    while (getline(iss, line)) {
    while (reader.readLine(line)) {
        if (line.empty()) continue;
        // parse head line
        if (nline == 0) {
          split(line, &header);
        if (nline++ == 0) {
            split(line, header, KERNEL_WAKEUP_LINE_DELIMITER);
            if (!assertHeaders(kernel_wake_headers, header)) {
                fprintf(stderr, "[%s]Bad header:\n%s\n", this->name.string(), line.c_str());
                return BAD_VALUE;
            }
          nline++;
            continue;
        }

        // parse for each record, the line delimiter is \t only!
        split(line, &record, KERNEL_WAKEUP_LINE_DELIMITER);
        split(line, record, KERNEL_WAKEUP_LINE_DELIMITER);

        if (record.size() != header.size()) {
            // TODO: log this to incident report!
@@ -118,17 +109,106 @@ status_t KernelWakesParser::Parse(const int in, const int out) const {
        source->set_max_time(atol(record.at(7).c_str()));
        source->set_last_change(atol(record.at(8).c_str()));
        source->set_prevent_suspend_time(atol(record.at(9).c_str()));
    }

        nline++;
    if (!reader.ok(line)) {
        fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
        return -1;
    }

    if (!proto.SerializeToFileDescriptor(out)) {
        fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
        return -1;
    }
    fprintf(stderr, "[%s]Proto size: %d bytes\n", this->name.string(), proto.ByteSize());
    return NO_ERROR;
}

// ================================================================================
const char* procrank_headers[] = {
    "PID",          // id:  1
    "Vss",          // id:  2
    "Rss",          // id:  3
    "Pss",          // id:  4
    "Uss",          // id:  5
    "Swap",         // id:  6
    "PSwap",        // id:  7
    "USwap",        // id:  8
    "ZSwap",        // id:  9
    "cmdline",      // id: 10
};

status_t ProcrankParser::Parse(const int in, const int out) const {
    Reader reader(in);
    string line, content;
    header_t header;  // the header of /d/wakeup_sources
    record_t record;  // retain each record
    int nline = 0;

    Procrank proto;

    // parse line by line
    while (reader.readLine(line)) {
        if (line.empty()) continue;

        // parse head line
        if (nline++ == 0) {
            split(line, header);
            if (!assertHeaders(procrank_headers, header)) {
                fprintf(stderr, "[%s]Bad header:\n%s\n", this->name.string(), line.c_str());
                return BAD_VALUE;
            }
            continue;
        }

        split(line, record);
        if (record.size() != header.size()) {
            if (record[record.size() - 1] == "TOTAL") { // TOTAL record
                ProcessProto* total = proto.mutable_summary()->mutable_total();
                total->set_pss(atol(record.at(0).substr(0, record.at(0).size() - 1).c_str()));
                total->set_uss(atol(record.at(1).substr(0, record.at(1).size() - 1).c_str()));
                total->set_swap(atol(record.at(2).substr(0, record.at(2).size() - 1).c_str()));
                total->set_pswap(atol(record.at(3).substr(0, record.at(3).size() - 1).c_str()));
                total->set_uswap(atol(record.at(4).substr(0, record.at(4).size() - 1).c_str()));
                total->set_zswap(atol(record.at(5).substr(0, record.at(5).size() - 1).c_str()));
            } else if (record[0] == "ZRAM:") {
                split(line, record, ":");
                proto.mutable_summary()->mutable_zram()->set_raw_text(record[1]);
            } else if (record[0] == "RAM:") {
                split(line, record, ":");
                proto.mutable_summary()->mutable_ram()->set_raw_text(record[1]);
            } else {
                fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.string(), nline,
                    line.c_str());
            }
            continue;
        }

        ProcessProto* process = proto.add_processes();
        // int32
        process->set_pid(atoi(record.at(0).c_str()));
        // int64, remove 'K' at the end
        process->set_vss(atol(record.at(1).substr(0, record.at(1).size() - 1).c_str()));
        process->set_rss(atol(record.at(2).substr(0, record.at(2).size() - 1).c_str()));
        process->set_pss(atol(record.at(3).substr(0, record.at(3).size() - 1).c_str()));
        process->set_uss(atol(record.at(4).substr(0, record.at(4).size() - 1).c_str()));
        process->set_swap(atol(record.at(5).substr(0, record.at(5).size() - 1).c_str()));
        process->set_pswap(atol(record.at(6).substr(0, record.at(6).size() - 1).c_str()));
        process->set_uswap(atol(record.at(7).substr(0, record.at(7).size() - 1).c_str()));
        process->set_zswap(atol(record.at(8).substr(0, record.at(8).size() - 1).c_str()));
        // string
        process->set_cmdline(record.at(9));
    }

    if (!reader.ok(line)) {
        fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
        return -1;
    }

    if (!proto.SerializeToFileDescriptor(out)) {
        fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
        return -1;
    }
    close(out);

    fprintf(stderr, "[%s]Proto size: %d bytes\n", this->name.string(), proto.ByteSize());
    return NO_ERROR;
}
 No newline at end of file
+13 −0
Original line number Diff line number Diff line
@@ -70,4 +70,17 @@ public:
    virtual status_t Parse(const int in, const int out) const;
};

/**
 * Procrank parser, parses text produced by command procrank
 */
extern const char* procrank_headers[];

class ProcrankParser : public TextParserBase {
public:
    ProcrankParser() : TextParserBase(String8("ProcrankParser")) {};
    ~ProcrankParser() {};

    virtual status_t Parse(const int in, const int out) const;
};

#endif  // INCIDENT_HELPER_H
+9 −0
Original line number Diff line number Diff line
# incident_helper

It is an executable used to help parsing text format data to protobuf.

## How to build, deploy, unit test

For the first time, build the test and create an empty directly on device:
@@ -15,3 +17,10 @@ root$ mmm -j frameworks/base/cmds/incident_helper && \
adb push $OUT/data/nativetest64/incident_helper_test/* /data/nativetest64/incident_helper_test/ && \
adb shell /data/nativetest64/incident_helper_test/incident_helper_test 2>/dev/null
```
## How to adapt proto changes

If add a new proto file, add it in Android.bp under frameworks/base/ and make incident helper

```
root$ make -j48 incident_helper
```
Loading