summaryrefslogtreecommitdiff
path: root/cmds/incident_helper
diff options
context:
space:
mode:
authorYi Jin <jinyithu@google.com>2017-08-14 14:45:28 -0700
committerYi Jin <jinyithu@google.com>2017-08-14 18:53:10 -0700
commit4ef28b73533765867aa4d61ba6e0d27a7632ff02 (patch)
tree57ac34f7c9e73f41daf9dd9b865a6e727da5e6eb /cmds/incident_helper
parent4abbe93dce8d04d1564c8f9a604d8b8861926e7c (diff)
Use Descriptor and Reflection to set table-like data, in this case
protobuf-cpp-full is worth using. Test: tested it locally by running the command in README.md Change-Id: I1c38bd7fee6d914c4a579ed82b9be4a8177e45b9
Diffstat (limited to 'cmds/incident_helper')
-rw-r--r--cmds/incident_helper/IncidentHelper.cpp104
-rw-r--r--cmds/incident_helper/ih_util.cpp37
-rw-r--r--cmds/incident_helper/ih_util.h9
-rw-r--r--cmds/incident_helper/tests/ih_util_test.cpp31
4 files changed, 94 insertions, 87 deletions
diff --git a/cmds/incident_helper/IncidentHelper.cpp b/cmds/incident_helper/IncidentHelper.cpp
index 664c48f75f9f..fba5e662b7c1 100644
--- a/cmds/incident_helper/IncidentHelper.cpp
+++ b/cmds/incident_helper/IncidentHelper.cpp
@@ -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());
+ }
}
}
diff --git a/cmds/incident_helper/ih_util.cpp b/cmds/incident_helper/ih_util.cpp
index bbb625f28c48..b2fda23ac391 100644
--- a/cmds/incident_helper/ih_util.cpp
+++ b/cmds/incident_helper/ih_util.cpp
@@ -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;
- }
- }
- return true;
+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;
+}
+
+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) {};
diff --git a/cmds/incident_helper/ih_util.h b/cmds/incident_helper/ih_util.h
index 9e0c18ee7498..5598eed8d824 100644
--- a/cmds/incident_helper/ih_util.h
+++ b/cmds/incident_helper/ih_util.h
@@ -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.
diff --git a/cmds/incident_helper/tests/ih_util_test.cpp b/cmds/incident_helper/tests/ih_util_test.cpp
index 5158e0a285bc..3b9ed403b77a 100644
--- a/cmds/incident_helper/tests/ih_util_test.cpp
+++ b/cmds/incident_helper/tests/ih_util_test.cpp
@@ -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);
}