Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -728,6 +728,7 @@ gensrcs { "core/proto/android/os/kernelwake.proto", "core/proto/android/os/pagetypeinfo.proto", "core/proto/android/os/procrank.proto", "core/proto/android/os/ps.proto", "core/proto/android/os/system_properties.proto", ], Loading cmds/incident_helper/src/ih_util.cpp +71 −4 Original line number Diff line number Diff line Loading @@ -52,6 +52,12 @@ static inline std::string trimHeader(const std::string& s) { return toLowerStr(trimDefault(s)); } static inline bool isNumber(const std::string& s) { std::string::const_iterator it = s.begin(); while (it != s.end() && std::isdigit(*it)) ++it; return !s.empty() && it == s.end(); } // This is similiar to Split in android-base/file.h, but it won't add empty string static void split(const std::string& line, std::vector<std::string>& words, const trans_func& func, const std::string& delimiters) { Loading Loading @@ -86,24 +92,80 @@ record_t parseRecord(const std::string& line, const std::string& delimiters) { return record; } bool getColumnIndices(std::vector<int>& indices, const char** headerNames, const std::string& line) { indices.clear(); size_t lastIndex = 0; int i = 0; while (headerNames[i] != NULL) { string s = headerNames[i]; lastIndex = line.find(s, lastIndex); if (lastIndex == string::npos) { fprintf(stderr, "Bad Task Header: %s\n", line.c_str()); return false; } lastIndex += s.length(); indices.push_back(lastIndex); i++; } return true; } record_t parseRecordByColumns(const std::string& line, const std::vector<int>& indices, const std::string& delimiters) { record_t record; int lastIndex = 0; int lastBeginning = 0; int lineSize = (int)line.size(); for (std::vector<int>::const_iterator it = indices.begin(); it != indices.end(); ++it) { int idx = *it; if (lastIndex > idx || idx > lineSize) { record.clear(); // The indices is wrong, return empty; if (idx <= lastIndex) { // We saved up until lastIndex last time, so we should start at // lastIndex + 1 this time. idx = lastIndex + 1; } if (idx > lineSize) { if (lastIndex < idx && lastIndex < lineSize) { // There's a little bit more for us to save, which we'll do // outside of the loop. break; } // If we're past the end of the line AND we've already saved everything up to the end. fprintf(stderr, "index wrong: lastIndex: %d, idx: %d, lineSize: %d\n", lastIndex, idx, lineSize); record.clear(); // The indices are wrong, return empty. return record; } while (idx < lineSize && delimiters.find(line[idx++]) == std::string::npos); record.push_back(trimDefault(line.substr(lastIndex, idx - lastIndex))); lastBeginning = lastIndex; lastIndex = idx; } record.push_back(trimDefault(line.substr(lastIndex, lineSize - lastIndex))); if (lineSize - lastIndex > 0) { int beginning = lastIndex; if (record.size() == indices.size()) { // We've already encountered all of the columns...put whatever is // left in the last column. record.pop_back(); beginning = lastBeginning; } record.push_back(trimDefault(line.substr(beginning, lineSize - beginning))); } return record; } void printRecord(const record_t& record) { fprintf(stderr, "Record: { "); if (record.size() == 0) { fprintf(stderr, "}\n"); return; } for(size_t i = 0; i < record.size(); ++i) { if(i != 0) fprintf(stderr, "\", "); fprintf(stderr, "\"%s", record[i].c_str()); } fprintf(stderr, "\" }\n"); } bool stripPrefix(std::string* line, const char* key, bool endAtDelimiter) { const auto head = line->find_first_not_of(DEFAULT_WHITESPACE); if (head == std::string::npos) return false; Loading Loading @@ -210,7 +272,10 @@ Table::~Table() void Table::addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize) { if (mFields.find(field) == mFields.end()) return; if (mFields.find(field) == mFields.end()) { fprintf(stderr, "Field '%s' not found", string(field).c_str()); return; } map<std::string, int> enu; for (int i = 0; i < enumSize; i++) { Loading Loading @@ -268,6 +333,8 @@ Table::insertField(ProtoOutputStream* proto, const std::string& name, const std: } } else if (mEnumValuesByName.find(value) != mEnumValuesByName.end()) { proto->write(found, mEnumValuesByName[value]); } else if (isNumber(value)) { proto->write(found, toInt(value)); } else { return false; } Loading cmds/incident_helper/src/ih_util.h +11 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,14 @@ std::string trim(const std::string& s, const std::string& charset); 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); /** * Gets the list of end indices of each word in the line and places it in the given vector, * clearing out the vector beforehand. These indices can be used with parseRecordByColumns. * Will return false if there was a problem getting the indices. headerNames * must be NULL terminated. */ bool getColumnIndices(std::vector<int>& indices, const char* headerNames[], const std::string& line); /** * When a text-format table aligns by its vertical position, it is not possible to split them by purely delimiters. * This function allows to parse record by its header's column position' indices, must in ascending order. Loading @@ -62,6 +70,9 @@ record_t parseRecord(const std::string& line, const std::string& delimiters = DE */ record_t parseRecordByColumns(const std::string& line, const std::vector<int>& indices, const std::string& delimiters = DEFAULT_WHITESPACE); /** Prints record_t to stderr */ void printRecord(const record_t& record); /** * When the line starts/ends with the given key, the function returns true * as well as the line argument is changed to the rest trimmed part of the original. Loading cmds/incident_helper/src/main.cpp +3 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include "parsers/KernelWakesParser.h" #include "parsers/PageTypeInfoParser.h" #include "parsers/ProcrankParser.h" #include "parsers/PsParser.h" #include "parsers/SystemPropertiesParser.h" #include <android-base/file.h> Loading Loading @@ -64,6 +65,8 @@ static TextParserBase* selectParser(int section) { return new CpuInfoParser(); case 2004: return new CpuFreqParser(); case 2005: return new PsParser(); case 2006: return new BatteryTypeParser(); default: Loading cmds/incident_helper/src/parsers/CpuInfoParser.cpp +15 −14 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ CpuInfoParser::Parse(const int in, const int out) const vector<int> columnIndices; // task table can't be split by purely delimiter, needs column positions. record_t record; int nline = 0; int diff = 0; bool nextToSwap = false; bool nextToUsage = false; Loading Loading @@ -107,19 +108,11 @@ CpuInfoParser::Parse(const int in, const int out) const header = parseHeader(line, "[ %]"); nextToUsage = false; // NAME is not in the list since the last split index is default to the end of line. const char* headerNames[11] = { "PID", "TID", "USER", "PR", "NI", "CPU", "S", "VIRT", "RES", "PCY", "CMD" }; size_t lastIndex = 0; for (int i = 0; i < 11; i++) { string s = headerNames[i]; lastIndex = line.find(s, lastIndex); if (lastIndex == string::npos) { fprintf(stderr, "Bad Task Header: %s\n", line.c_str()); // NAME is not in the list since we need to modify the end of the CMD index. const char* headerNames[] = { "PID", "TID", "USER", "PR", "NI", "CPU", "S", "VIRT", "RES", "PCY", "CMD", NULL }; if (!getColumnIndices(columnIndices, headerNames, line)) { return -1; } lastIndex += s.length(); columnIndices.push_back(lastIndex); } // Need to remove the end index of CMD and use the start index of NAME because CMD values contain spaces. // for example: ... CMD NAME // ... Jit thread pool com.google.android.gms.feedback Loading @@ -128,12 +121,20 @@ CpuInfoParser::Parse(const int in, const int out) const int endCMD = columnIndices.back(); columnIndices.pop_back(); columnIndices.push_back(line.find("NAME", endCMD) - 1); // Add NAME index to complete the column list. columnIndices.push_back(columnIndices.back() + 4); continue; } record = parseRecordByColumns(line, columnIndices); if (record.size() != header.size()) { fprintf(stderr, "[%s]Line %d has missing fields:\n%s\n", this->name.string(), nline, line.c_str()); diff = record.size() - header.size(); if (diff < 0) { fprintf(stderr, "[%s]Line %d has %d missing fields\n%s\n", this->name.string(), nline, -diff, line.c_str()); printRecord(record); continue; } else if (diff > 0) { fprintf(stderr, "[%s]Line %d has %d extra fields\n%s\n", this->name.string(), nline, diff, line.c_str()); printRecord(record); continue; } Loading Loading
Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -728,6 +728,7 @@ gensrcs { "core/proto/android/os/kernelwake.proto", "core/proto/android/os/pagetypeinfo.proto", "core/proto/android/os/procrank.proto", "core/proto/android/os/ps.proto", "core/proto/android/os/system_properties.proto", ], Loading
cmds/incident_helper/src/ih_util.cpp +71 −4 Original line number Diff line number Diff line Loading @@ -52,6 +52,12 @@ static inline std::string trimHeader(const std::string& s) { return toLowerStr(trimDefault(s)); } static inline bool isNumber(const std::string& s) { std::string::const_iterator it = s.begin(); while (it != s.end() && std::isdigit(*it)) ++it; return !s.empty() && it == s.end(); } // This is similiar to Split in android-base/file.h, but it won't add empty string static void split(const std::string& line, std::vector<std::string>& words, const trans_func& func, const std::string& delimiters) { Loading Loading @@ -86,24 +92,80 @@ record_t parseRecord(const std::string& line, const std::string& delimiters) { return record; } bool getColumnIndices(std::vector<int>& indices, const char** headerNames, const std::string& line) { indices.clear(); size_t lastIndex = 0; int i = 0; while (headerNames[i] != NULL) { string s = headerNames[i]; lastIndex = line.find(s, lastIndex); if (lastIndex == string::npos) { fprintf(stderr, "Bad Task Header: %s\n", line.c_str()); return false; } lastIndex += s.length(); indices.push_back(lastIndex); i++; } return true; } record_t parseRecordByColumns(const std::string& line, const std::vector<int>& indices, const std::string& delimiters) { record_t record; int lastIndex = 0; int lastBeginning = 0; int lineSize = (int)line.size(); for (std::vector<int>::const_iterator it = indices.begin(); it != indices.end(); ++it) { int idx = *it; if (lastIndex > idx || idx > lineSize) { record.clear(); // The indices is wrong, return empty; if (idx <= lastIndex) { // We saved up until lastIndex last time, so we should start at // lastIndex + 1 this time. idx = lastIndex + 1; } if (idx > lineSize) { if (lastIndex < idx && lastIndex < lineSize) { // There's a little bit more for us to save, which we'll do // outside of the loop. break; } // If we're past the end of the line AND we've already saved everything up to the end. fprintf(stderr, "index wrong: lastIndex: %d, idx: %d, lineSize: %d\n", lastIndex, idx, lineSize); record.clear(); // The indices are wrong, return empty. return record; } while (idx < lineSize && delimiters.find(line[idx++]) == std::string::npos); record.push_back(trimDefault(line.substr(lastIndex, idx - lastIndex))); lastBeginning = lastIndex; lastIndex = idx; } record.push_back(trimDefault(line.substr(lastIndex, lineSize - lastIndex))); if (lineSize - lastIndex > 0) { int beginning = lastIndex; if (record.size() == indices.size()) { // We've already encountered all of the columns...put whatever is // left in the last column. record.pop_back(); beginning = lastBeginning; } record.push_back(trimDefault(line.substr(beginning, lineSize - beginning))); } return record; } void printRecord(const record_t& record) { fprintf(stderr, "Record: { "); if (record.size() == 0) { fprintf(stderr, "}\n"); return; } for(size_t i = 0; i < record.size(); ++i) { if(i != 0) fprintf(stderr, "\", "); fprintf(stderr, "\"%s", record[i].c_str()); } fprintf(stderr, "\" }\n"); } bool stripPrefix(std::string* line, const char* key, bool endAtDelimiter) { const auto head = line->find_first_not_of(DEFAULT_WHITESPACE); if (head == std::string::npos) return false; Loading Loading @@ -210,7 +272,10 @@ Table::~Table() void Table::addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize) { if (mFields.find(field) == mFields.end()) return; if (mFields.find(field) == mFields.end()) { fprintf(stderr, "Field '%s' not found", string(field).c_str()); return; } map<std::string, int> enu; for (int i = 0; i < enumSize; i++) { Loading Loading @@ -268,6 +333,8 @@ Table::insertField(ProtoOutputStream* proto, const std::string& name, const std: } } else if (mEnumValuesByName.find(value) != mEnumValuesByName.end()) { proto->write(found, mEnumValuesByName[value]); } else if (isNumber(value)) { proto->write(found, toInt(value)); } else { return false; } Loading
cmds/incident_helper/src/ih_util.h +11 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,14 @@ std::string trim(const std::string& s, const std::string& charset); 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); /** * Gets the list of end indices of each word in the line and places it in the given vector, * clearing out the vector beforehand. These indices can be used with parseRecordByColumns. * Will return false if there was a problem getting the indices. headerNames * must be NULL terminated. */ bool getColumnIndices(std::vector<int>& indices, const char* headerNames[], const std::string& line); /** * When a text-format table aligns by its vertical position, it is not possible to split them by purely delimiters. * This function allows to parse record by its header's column position' indices, must in ascending order. Loading @@ -62,6 +70,9 @@ record_t parseRecord(const std::string& line, const std::string& delimiters = DE */ record_t parseRecordByColumns(const std::string& line, const std::vector<int>& indices, const std::string& delimiters = DEFAULT_WHITESPACE); /** Prints record_t to stderr */ void printRecord(const record_t& record); /** * When the line starts/ends with the given key, the function returns true * as well as the line argument is changed to the rest trimmed part of the original. Loading
cmds/incident_helper/src/main.cpp +3 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include "parsers/KernelWakesParser.h" #include "parsers/PageTypeInfoParser.h" #include "parsers/ProcrankParser.h" #include "parsers/PsParser.h" #include "parsers/SystemPropertiesParser.h" #include <android-base/file.h> Loading Loading @@ -64,6 +65,8 @@ static TextParserBase* selectParser(int section) { return new CpuInfoParser(); case 2004: return new CpuFreqParser(); case 2005: return new PsParser(); case 2006: return new BatteryTypeParser(); default: Loading
cmds/incident_helper/src/parsers/CpuInfoParser.cpp +15 −14 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ CpuInfoParser::Parse(const int in, const int out) const vector<int> columnIndices; // task table can't be split by purely delimiter, needs column positions. record_t record; int nline = 0; int diff = 0; bool nextToSwap = false; bool nextToUsage = false; Loading Loading @@ -107,19 +108,11 @@ CpuInfoParser::Parse(const int in, const int out) const header = parseHeader(line, "[ %]"); nextToUsage = false; // NAME is not in the list since the last split index is default to the end of line. const char* headerNames[11] = { "PID", "TID", "USER", "PR", "NI", "CPU", "S", "VIRT", "RES", "PCY", "CMD" }; size_t lastIndex = 0; for (int i = 0; i < 11; i++) { string s = headerNames[i]; lastIndex = line.find(s, lastIndex); if (lastIndex == string::npos) { fprintf(stderr, "Bad Task Header: %s\n", line.c_str()); // NAME is not in the list since we need to modify the end of the CMD index. const char* headerNames[] = { "PID", "TID", "USER", "PR", "NI", "CPU", "S", "VIRT", "RES", "PCY", "CMD", NULL }; if (!getColumnIndices(columnIndices, headerNames, line)) { return -1; } lastIndex += s.length(); columnIndices.push_back(lastIndex); } // Need to remove the end index of CMD and use the start index of NAME because CMD values contain spaces. // for example: ... CMD NAME // ... Jit thread pool com.google.android.gms.feedback Loading @@ -128,12 +121,20 @@ CpuInfoParser::Parse(const int in, const int out) const int endCMD = columnIndices.back(); columnIndices.pop_back(); columnIndices.push_back(line.find("NAME", endCMD) - 1); // Add NAME index to complete the column list. columnIndices.push_back(columnIndices.back() + 4); continue; } record = parseRecordByColumns(line, columnIndices); if (record.size() != header.size()) { fprintf(stderr, "[%s]Line %d has missing fields:\n%s\n", this->name.string(), nline, line.c_str()); diff = record.size() - header.size(); if (diff < 0) { fprintf(stderr, "[%s]Line %d has %d missing fields\n%s\n", this->name.string(), nline, -diff, line.c_str()); printRecord(record); continue; } else if (diff > 0) { fprintf(stderr, "[%s]Line %d has %d extra fields\n%s\n", this->name.string(), nline, diff, line.c_str()); printRecord(record); continue; } Loading