Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -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: { Loading cmds/incident_helper/Android.bp +2 −1 Original line number Diff line number Diff line Loading @@ -10,7 +10,7 @@ cc_defaults { srcs: [ "IncidentHelper.cpp", "strutil.cpp", "ih_util.cpp", ], shared_libs: [ Loading Loading @@ -38,6 +38,7 @@ cc_test { srcs: [ "tests/IncidentHelper_test.cpp", "tests/ih_util_test.cpp", ], data: [ Loading cmds/incident_helper/IncidentHelper.cpp +111 −31 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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! Loading @@ -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 cmds/incident_helper/IncidentHelper.h +13 −0 Original line number Diff line number Diff line Loading @@ -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 cmds/incident_helper/README.md +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: Loading @@ -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
Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -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: { Loading
cmds/incident_helper/Android.bp +2 −1 Original line number Diff line number Diff line Loading @@ -10,7 +10,7 @@ cc_defaults { srcs: [ "IncidentHelper.cpp", "strutil.cpp", "ih_util.cpp", ], shared_libs: [ Loading Loading @@ -38,6 +38,7 @@ cc_test { srcs: [ "tests/IncidentHelper_test.cpp", "tests/ih_util_test.cpp", ], data: [ Loading
cmds/incident_helper/IncidentHelper.cpp +111 −31 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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! Loading @@ -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
cmds/incident_helper/IncidentHelper.h +13 −0 Original line number Diff line number Diff line Loading @@ -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
cmds/incident_helper/README.md +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: Loading @@ -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 ```