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

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

Merge "Implement PageTypeInfo section"

parents 647d6264 810b14f5
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/pagetypeinfo.proto",
                "core/proto/android/os/procrank.proto",
                "core/proto/android/service/graphicsstats.proto",
                "libs/incident/proto/android/privacy.proto",
+139 −19
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include "ih_util.h"

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

#include <android-base/file.h>
@@ -32,6 +33,22 @@ using namespace android::os;
using namespace google::protobuf;
using namespace std;


static const string TAB_DELIMITER = "\t";
static const string COMMA_DELIMITER = ",";

static inline int toInt(const string& s) {
    return atoi(s.c_str());
}

static inline long toLong(const string& s) {
    return atol(s.c_str());
}

/**
 * Sets the given protobuf message when the field name matches one of the
 * fields. It is useful to set values to proto from table-like plain texts.
 */
static bool
SetTableField(::google::protobuf::Message* message, string field_name, string field_value) {
    const Descriptor* descriptor = message->GetDescriptor();
@@ -43,16 +60,16 @@ SetTableField(::google::protobuf::Message* message, string field_name, string fi
            reflection->SetString(message, field, field_value);
            return true;
        case FieldDescriptor::TYPE_INT64:
            reflection->SetInt64(message, field, atol(field_value.c_str()));
            reflection->SetInt64(message, field, toLong(field_value));
            return true;
        case FieldDescriptor::TYPE_UINT64:
            reflection->SetUInt64(message, field, atol(field_value.c_str()));
            reflection->SetUInt64(message, field, toLong(field_value));
            return true;
        case FieldDescriptor::TYPE_INT32:
            reflection->SetInt32(message, field, atoi(field_value.c_str()));
            reflection->SetInt32(message, field, toInt(field_value));
            return true;
        case FieldDescriptor::TYPE_UINT32:
            reflection->SetUInt32(message, field, atoi(field_value.c_str()));
            reflection->SetUInt32(message, field, toInt(field_value));
            return true;
        default:
            // Add new scalar types
@@ -93,8 +110,6 @@ status_t ReverseParser::Parse(const int in, const int out) const
}

// ================================================================================
static const string KERNEL_WAKEUP_LINE_DELIMITER = "\t";

status_t KernelWakesParser::Parse(const int in, const int out) const {
    Reader reader(in);
    string line;
@@ -105,16 +120,16 @@ status_t KernelWakesParser::Parse(const int in, const int out) const {
    KernelWakeSources proto;

    // parse line by line
    while (reader.readLine(line)) {
    while (reader.readLine(&line)) {
        if (line.empty()) continue;
        // parse head line
        if (nline++ == 0) {
            header = parseHeader(line, KERNEL_WAKEUP_LINE_DELIMITER);
            header = parseHeader(line, TAB_DELIMITER);
            continue;
        }

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

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

    if (!reader.ok(line)) {
    if (!reader.ok(&line)) {
        fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
        return -1;
    }
@@ -147,7 +162,7 @@ status_t KernelWakesParser::Parse(const int in, const int out) const {
// ================================================================================
status_t ProcrankParser::Parse(const int in, const int out) const {
    Reader reader(in);
    string line, content;
    string line;
    header_t header;  // the header of /d/wakeup_sources
    record_t record;  // retain each record
    int nline = 0;
@@ -155,7 +170,7 @@ status_t ProcrankParser::Parse(const int in, const int out) const {
    Procrank proto;

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

        // parse head line
@@ -164,6 +179,15 @@ status_t ProcrankParser::Parse(const int in, const int out) const {
            continue;
        }

        if (hasPrefix(&line, "ZRAM:")) {
            proto.mutable_summary()->mutable_zram()->set_raw_text(line);
            continue;
        }
        if (hasPrefix(&line, "RAM:")) {
            proto.mutable_summary()->mutable_ram()->set_raw_text(line);
            continue;
        }

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

    if (!reader.ok(line)) {
    if (!reader.ok(&line)) {
        fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
        return -1;
    }
@@ -205,3 +223,105 @@ status_t ProcrankParser::Parse(const int in, const int out) const {
    fprintf(stderr, "[%s]Proto size: %d bytes\n", this->name.string(), proto.ByteSize());
    return NO_ERROR;
}

// ================================================================================
status_t PageTypeInfoParser::Parse(const int in, const int out) const {
    Reader reader(in);
    string line;
    bool migrateTypeSession = false;
    int pageBlockOrder;
    header_t blockHeader;

    PageTypeInfo pageTypeInfo;

    while (reader.readLine(&line)) {
        if (line.empty()) {
            migrateTypeSession = false;
            blockHeader.clear();
            continue;
        }

        if (hasPrefix(&line, "Page block order:")) {
            pageBlockOrder = toInt(line);
            pageTypeInfo.set_page_block_order(pageBlockOrder);
            continue;
        }
        if (hasPrefix(&line, "Pages per block:")) {
            pageTypeInfo.set_pages_per_block(toInt(line));
            continue;
        }
        if (hasPrefix(&line, "Free pages count per migrate type at order")) {
            migrateTypeSession = true;
            continue;
        }
        if (hasPrefix(&line, "Number of blocks type")) {
            blockHeader = parseHeader(line);
            continue;
        }

        record_t record = parseRecord(line, COMMA_DELIMITER);
        if (migrateTypeSession && record.size() == 3) {
            MigrateTypeProto* migrateType = pageTypeInfo.add_migrate_types();
            // expect part 0 starts with "Node"
            if (hasPrefix(&record[0], "Node")) {
                migrateType->set_node(toInt(record[0]));
            } else goto ERROR;
            // expect part 1 starts with "zone"
            if (hasPrefix(&record[1], "zone")) {
                migrateType->set_zone(record[1]);
            } else goto ERROR;
            // expect part 2 starts with "type"
            if (hasPrefix(&record[2], "type")) {
                // expect the rest of part 2 has number of (pageBlockOrder + 2) parts
                // An example looks like:
                // header line:      type    0   1   2 3 4 5 6 7 8 9 10
                // record line: Unmovable  426 279 226 1 1 1 0 0 2 2  0
                // The pageBlockOrder = 10 and it's zero-indexed. so total parts
                // are 10 + 1(zero-indexed) + 1(the type part) = 12.
                record_t pageCounts = parseRecord(record[2]);
                int pageCountsSize = pageBlockOrder + 2;
                if ((int)pageCounts.size() != pageCountsSize) goto ERROR;

                migrateType->set_type(pageCounts[0]);
                for (auto i=1; i<pageCountsSize; i++) {
                    migrateType->add_free_pages_count(toInt(pageCounts[i]));
                }
            } else goto ERROR;
            continue;
        }

        if (!blockHeader.empty() && record.size() == 2) {
            BlockProto* block = pageTypeInfo.add_blocks();

            if (hasPrefix(&record[0], "Node")) {
                block->set_node(toInt(record[0]));
            } else goto ERROR;

            if (hasPrefix(&record[1], "zone")) {
                record_t blockCounts = parseRecord(record[1]);
                block->set_zone(blockCounts[0]);
                for (size_t i=0; i<blockHeader.size(); i++) {
                    if (!SetTableField(block, blockHeader[i], blockCounts[i+1])) goto ERROR;
                }
            } else goto ERROR;

            continue;
        }

ERROR:  // print out error for this single line and continue parsing
        fprintf(stderr, "[%s]Bad line: %s\n", this->name.string(), line.c_str());
    }

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

    if (!pageTypeInfo.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(), pageTypeInfo.ByteSize());
    return NO_ERROR;
}
+11 −0
Original line number Diff line number Diff line
@@ -79,6 +79,17 @@ public:
    virtual status_t Parse(const int in, const int out) const;
};

/**
 * PageTypeInfo parser, parses text to protobuf in /proc/pageinfotype
 */
class PageTypeInfoParser : public TextParserBase {
public:
    PageTypeInfoParser() : TextParserBase(String8("PageTypeInfo")) {};
    ~PageTypeInfoParser() {};

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

/**
 * Procrank parser, parses text produced by command procrank
 */
+20 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include "ih_util.h"

#include <algorithm>
#include <sstream>
#include <unistd.h>

@@ -72,6 +73,20 @@ record_t parseRecord(const std::string& line, const std::string& delimiters) {
    return record;
}

bool hasPrefix(std::string* line, const char* key) {
    const auto head = line->find_first_not_of(DEFAULT_WHITESPACE);
    if (head == std::string::npos) return false;
    auto i = 0;
    auto j = head;
    while (key[i] != '\0') {
        if (j >= line->size() || key[i++] != line->at(j++)) {
            return false;
        }
    }
    line->assign(trim(line->substr(j)));
    return true;
}

Reader::Reader(const int fd) : Reader(fd, BUFFER_SIZE) {};

Reader::Reader(const int fd, const size_t capacity)
@@ -86,8 +101,9 @@ Reader::~Reader()
    free(mBuf);
}

bool Reader::readLine(std::string& line, const char newline) {
bool Reader::readLine(std::string* line, const char newline) {
    if (!ok(line)) return false; // bad status
    line->clear();
    std::stringstream ss;
    while (!EOR()) {
        // read if available
@@ -124,14 +140,14 @@ bool Reader::readLine(std::string& line, const char newline) {
        if (mFlushed >= (int) mMaxSize) mFlushed = 0;

        if (EOR() || meetsNewLine) {
            line.assign(ss.str());
            line->assign(ss.str());
            return true;
        }
    }
    return false;
}

bool Reader::ok(std::string& error) {
    error.assign(mStatus);
bool Reader::ok(std::string* error) {
    error->assign(mStatus);
    return mStatus.empty();
}
+22 −2
Original line number Diff line number Diff line
@@ -28,9 +28,29 @@ typedef std::string (*trans_func) (const std::string&);
const char DEFAULT_NEWLINE = '\n';
const std::string DEFAULT_WHITESPACE = " \t";

/**
 * When a text has a table format like this
 * line 1: HeadA HeadB HeadC
 * line 2: v1    v2    v3
 * line 3: v11   v12   v13
 *
 * We want to parse the line in structure given the delimiter.
 * parseHeader is used to parse the firse line of the table and returns a list of strings in lower case
 * parseRecord is used to parse other lines and returns a list of strings
 * empty strings are skipped
 */
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);

/**
 * When the line starts with the given key, the function returns true
 * as well as the line argument is changed to the rest part of the original.
 * e.g. "ZRAM: 6828K physical used for 31076K in swap (524284K total swap)" becomes
 * "6828K physical used for 31076K in swap (524284K total swap)" when given key "ZRAM:",
 * otherwise the line is not changed.
 */
bool hasPrefix(std::string* line, const char* key);

/**
 * Reader class reads data from given fd in streaming fashion.
 * The buffer size is controlled by capacity parameter.
@@ -42,8 +62,8 @@ public:
    Reader(const int fd, const size_t capacity);
    ~Reader();

    bool readLine(std::string& line, const char newline = DEFAULT_NEWLINE);
    bool ok(std::string& error);
    bool readLine(std::string* line, const char newline = DEFAULT_NEWLINE);
    bool ok(std::string* error);

private:
    int mFd; // set mFd to -1 when read EOF()
Loading