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

Commit 3a545873 authored by Yi Jin's avatar Yi Jin Committed by Android (Google) Code Review
Browse files

Merge "Use Descriptor and Reflection to set table-like data, in this case...

Merge "Use Descriptor and Reflection to set table-like data, in this case protobuf-cpp-full is worth using."
parents 931411e3 4ef28b73
Loading
Loading
Loading
Loading
+44 −60
Original line number Diff line number Diff line
@@ -29,8 +29,37 @@

using namespace android::base;
using namespace android::os;
using namespace google::protobuf;
using namespace std;

static bool
SetTableField(::google::protobuf::Message* message, string field_name, string field_value) {
    const Descriptor* descriptor = message->GetDescriptor();
    const Reflection* reflection = message->GetReflection();

    const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
    switch (field->type()) {
        case FieldDescriptor::TYPE_STRING:
            reflection->SetString(message, field, field_value);
            return true;
        case FieldDescriptor::TYPE_INT64:
            reflection->SetInt64(message, field, atol(field_value.c_str()));
            return true;
        case FieldDescriptor::TYPE_UINT64:
            reflection->SetUInt64(message, field, atol(field_value.c_str()));
            return true;
        case FieldDescriptor::TYPE_INT32:
            reflection->SetInt32(message, field, atoi(field_value.c_str()));
            return true;
        case FieldDescriptor::TYPE_UINT32:
            reflection->SetUInt32(message, field, atoi(field_value.c_str()));
            return true;
        default:
            // Add new scalar types
            return false;
    }
}

// ================================================================================
status_t ReverseParser::Parse(const int in, const int out) const
{
@@ -51,31 +80,6 @@ status_t ReverseParser::Parse(const int in, const int out) const
// ================================================================================
static const string KERNEL_WAKEUP_LINE_DELIMITER = "\t";

static void SetWakeupSourceField(WakeupSourceProto* source, string name, string value) {
    if (name == "name") {
        source->set_name(value.c_str());
    } else if (name == "active_count") {
        source->set_active_count(atoi(value.c_str()));
    } else if (name == "event_count") {
        source->set_event_count(atoi(value.c_str()));
    } else if (name == "wakeup_count") {
        source->set_wakeup_count(atoi(value.c_str()));
    } else if (name == "expire_count") {
        source->set_expire_count(atoi(value.c_str()));
    } else if (name == "active_count") {
        source->set_active_since(atol(value.c_str()));
    } else if (name == "total_time") {
        source->set_total_time(atol(value.c_str()));
    } else if (name == "max_time") {
        source->set_max_time(atol(value.c_str()));
    } else if (name == "last_change") {
        source->set_last_change(atol(value.c_str()));
    } else if (name == "prevent_suspend_time") {
        source->set_prevent_suspend_time(atol(value.c_str()));
    }
    // add new fields
}

status_t KernelWakesParser::Parse(const int in, const int out) const {
    Reader reader(in);
    string line;
@@ -90,12 +94,12 @@ status_t KernelWakesParser::Parse(const int in, const int out) const {
        if (line.empty()) continue;
        // parse head line
        if (nline++ == 0) {
            split(line, header, KERNEL_WAKEUP_LINE_DELIMITER);
            header = parseHeader(line, KERNEL_WAKEUP_LINE_DELIMITER);
            continue;
        }

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

        if (record.size() != header.size()) {
            // TODO: log this to incident report!
@@ -105,7 +109,10 @@ status_t KernelWakesParser::Parse(const int in, const int out) const {

        WakeupSourceProto* source = proto.add_wakeup_sources();
        for (int i=0; i<(int)record.size(); i++) {
            SetWakeupSourceField(source, header[i], record[i]);
            if (!SetTableField(source, header[i], record[i])) {
                fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
                        this->name.string(), nline, header[i].c_str(), record[i].c_str());
            }
        }
    }

@@ -123,32 +130,6 @@ status_t KernelWakesParser::Parse(const int in, const int out) const {
}

// ================================================================================
// Remove K for numeric fields
static void SetProcessField(ProcessProto* process, string name, string value) {
    ssize_t len = value.size();
    if (name == "PID") {
        process->set_pid(atoi(value.c_str()));
    } else if (name == "Vss") {
        process->set_vss(atol(value.substr(0, len - 1).c_str()));
    } else if (name == "Rss") {
        process->set_rss(atol(value.substr(0, len - 1).c_str()));
    } else if (name == "Pss") {
        process->set_pss(atol(value.substr(0, len - 1).c_str()));
    } else if (name == "Uss") {
        process->set_uss(atol(value.substr(0, len - 1).c_str()));
    } else if (name == "Swap") {
        process->set_swap(atol(value.substr(0, len - 1).c_str()));
    } else if (name == "PSwap") {
        process->set_pswap(atol(value.substr(0, len - 1).c_str()));
    } else if (name == "USwap") {
        process->set_uswap(atol(value.substr(0, len - 1).c_str()));
    } else if (name == "ZSwap") {
        process->set_zswap(atol(value.substr(0, len - 1).c_str()));
    } else if (name == "cmdline") {
        process->set_cmdline(value);
    }
}

status_t ProcrankParser::Parse(const int in, const int out) const {
    Reader reader(in);
    string line, content;
@@ -164,22 +145,22 @@ status_t ProcrankParser::Parse(const int in, const int out) const {

        // parse head line
        if (nline++ == 0) {
            split(line, header);
            header = parseHeader(line);
            continue;
        }

        split(line, record);
        record = parseRecord(line);
        if (record.size() != header.size()) {
            if (record[record.size() - 1] == "TOTAL") { // TOTAL record
                ProcessProto* total = proto.mutable_summary()->mutable_total();
                for (int i=1; i<=(int)record.size(); i++) {
                    SetProcessField(total, header[header.size() - i], record[record.size() - i]);
                    SetTableField(total, header[header.size() - i], record[record.size() - i]);
                }
            } else if (record[0] == "ZRAM:") {
                split(line, record, ":");
                record = parseRecord(line, ":");
                proto.mutable_summary()->mutable_zram()->set_raw_text(record[1]);
            } else if (record[0] == "RAM:") {
                split(line, record, ":");
                record = parseRecord(line, ":");
                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,
@@ -190,7 +171,10 @@ status_t ProcrankParser::Parse(const int in, const int out) const {

        ProcessProto* process = proto.add_processes();
        for (int i=0; i<(int)record.size(); i++) {
            SetProcessField(process, header[i], record[i]);
            if (!SetTableField(process, header[i], record[i])) {
                fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
                        this->name.string(), nline, header[i].c_str(), record[i].c_str());
            }
        }
    }

+25 −12
Original line number Diff line number Diff line
@@ -23,16 +23,24 @@

const ssize_t BUFFER_SIZE = 16 * 1024; // 4KB

std::string trim(const std::string& s, const std::string& whitespace) {
    const auto head = s.find_first_not_of(whitespace);

static std::string trim(const std::string& s) {
    const auto head = s.find_first_not_of(DEFAULT_WHITESPACE);
    if (head == std::string::npos) return "";

    const auto tail = s.find_last_not_of(whitespace);
    const auto tail = s.find_last_not_of(DEFAULT_WHITESPACE);
    return s.substr(head, tail - head + 1);
}

static std::string trimHeader(const std::string& s) {
    std::string res = trim(s);
    std::transform(res.begin(), res.end(), res.begin(), ::tolower);
    return res;
}

// This is similiar to Split in android-base/file.h, but it won't add empty string
void split(const std::string& line, std::vector<std::string>& words, const std::string& delimiters) {
static void split(const std::string& line, std::vector<std::string>& words,
        const trans_func& func, const std::string& delimiters) {
    words.clear();  // clear the buffer before split

    size_t base = 0;
@@ -40,7 +48,7 @@ void split(const std::string& line, std::vector<std::string>& words, const std::
    while (true) {
        found = line.find_first_of(delimiters, base);
        if (found != base) {
            std::string word = trim(line.substr(base, found - base));
            std::string word = (*func) (line.substr(base, found - base));
            if (!word.empty()) {
                words.push_back(word);
            }
@@ -50,13 +58,18 @@ void split(const std::string& line, std::vector<std::string>& words, const std::
    }
}

bool assertHeaders(const char* expected[], const std::vector<std::string>& actual) {
    for (size_t i = 0; i < actual.size(); i++) {
        if (expected[i] == NULL || std::string(expected[i]) != actual[i]) {
            return false;
header_t parseHeader(const std::string& line, const std::string& delimiters) {
    header_t header;
    trans_func f = &trimHeader;
    split(line, header, f, delimiters);
    return header;
}
    }
    return true;

record_t parseRecord(const std::string& line, const std::string& delimiters) {
    record_t record;
    trans_func f = &trim;
    split(line, record, f, delimiters);
    return record;
}

Reader::Reader(const int fd) : Reader(fd, BUFFER_SIZE) {};
+3 −6
Original line number Diff line number Diff line
@@ -23,16 +23,13 @@

typedef std::vector<std::string> header_t;
typedef std::vector<std::string> record_t;
typedef std::string (*trans_func) (const std::string&);

const char DEFAULT_NEWLINE = '\n';
const std::string DEFAULT_WHITESPACE = " \t";

std::string trim(const std::string& s, const std::string& whitespace = DEFAULT_WHITESPACE);

void split(const std::string& line, std::vector<std::string>& words,
    const std::string& delimiters = DEFAULT_WHITESPACE);

bool assertHeaders(const char* expected[], const std::vector<std::string>& actual);
header_t parseHeader(const std::string& line, const std::string& delimiters = DEFAULT_WHITESPACE);
record_t parseRecord(const std::string& line, const std::string& delimiters = DEFAULT_WHITESPACE);

/**
 * Reader class reads data from given fd in streaming fashion.
+22 −9
Original line number Diff line number Diff line
@@ -26,25 +26,38 @@ using namespace android::base;
using namespace std;
using ::testing::StrEq;

TEST(IhUtilTest, Trim) {
    EXPECT_THAT(trim(" \t 100 00\toooh \t wqrw  "), StrEq("100 00\toooh \t wqrw"));
    EXPECT_THAT(trim(" \t 100 00\toooh \t wqrw  ", " "), StrEq("\t 100 00\toooh \t wqrw"));
TEST(IhUtilTest, ParseHeader) {
    header_t result, expected;
    result = parseHeader(" \t \t\t ");
    EXPECT_EQ(expected, result);

    result = parseHeader(" \t 100 00\tOpQ \t wqrw");
    expected = { "100", "00", "opq", "wqrw" };
    EXPECT_EQ(expected, result);

    result = parseHeader(" \t 100 00\toooh \t wTF", "\t");
    expected = { "100 00", "oooh", "wtf" };
    EXPECT_EQ(expected, result);

    result = parseHeader("123,456,78_9", ",");
    expected = { "123", "456", "78_9" };
    EXPECT_EQ(expected, result);
}

TEST(IhUtilTest, Split) {
    vector<string> result, expected;
    split(" \t \t\t ", result);
TEST(IhUtilTest, ParseRecord) {
    record_t result, expected;
    result = parseRecord(" \t \t\t ");
    EXPECT_EQ(expected, result);

    split(" \t 100 00\toooh \t wqrw", result);
    result = parseRecord(" \t 100 00\toooh \t wqrw");
    expected = { "100", "00", "oooh", "wqrw" };
    EXPECT_EQ(expected, result);

    split(" \t 100 00\toooh \t wqrw", result, "\t");
    result = parseRecord(" \t 100 00\toooh \t wqrw", "\t");
    expected = { "100 00", "oooh", "wqrw" };
    EXPECT_EQ(expected, result);

    split("123,456,78_9", result, ",");
    result = parseRecord("123,456,78_9", ",");
    expected = { "123", "456", "78_9" };
    EXPECT_EQ(expected, result);
}
+5 −4
Original line number Diff line number Diff line
@@ -330,11 +330,13 @@ WorkerThreadSection::Execute(ReportRequestSet* requests) const
void CommandSection::init(const char* command, va_list args)
{
    va_list copied_args;
    va_copy(copied_args, args);
    int numOfArgs = 0;
    while(va_arg(args, const char*) != NULL) {

    va_copy(copied_args, args);
    while(va_arg(copied_args, const char*) != NULL) {
        numOfArgs++;
    }
    va_end(copied_args);

    // allocate extra 1 for command and 1 for NULL terminator
    mCommand = (const char**)malloc(sizeof(const char*) * (numOfArgs + 2));
@@ -342,13 +344,12 @@ void CommandSection::init(const char* command, va_list args)
    mCommand[0] = command;
    name = command;
    for (int i=0; i<numOfArgs; i++) {
        const char* arg = va_arg(copied_args, const char*);
        const char* arg = va_arg(args, const char*);
        mCommand[i+1] = arg;
        name += " ";
        name += arg;
    }
    mCommand[numOfArgs+1] = NULL;
    va_end(copied_args);
}

CommandSection::CommandSection(int id, const int64_t timeoutMs, const char* command, ...)