Loading Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ cc_library { "core/proto/android/os/kernelwake.proto", "core/proto/android/os/pagetypeinfo.proto", "core/proto/android/os/procrank.proto", "core/proto/android/os/system_properties.proto", "core/proto/android/service/graphicsstats.proto", "tools/streaming_proto/stream.proto", ], Loading @@ -86,6 +87,7 @@ gensrcs { "core/proto/android/os/kernelwake.proto", "core/proto/android/os/pagetypeinfo.proto", "core/proto/android/os/procrank.proto", "core/proto/android/os/system_properties.proto", ], // Append protoc-gen-cppstream tool's PATH otherwise aprotoc can't find the plugin tool Loading cmds/incident_helper/src/ih_util.cpp +81 −68 Original line number Diff line number Diff line Loading @@ -30,22 +30,26 @@ bool isValidChar(char c) { || (v == (uint8_t)'_'); } static std::string trim(const std::string& s, const std::string& chars) { const auto head = s.find_first_not_of(chars); std::string trim(const std::string& s, const std::string& charset) { const auto head = s.find_first_not_of(charset); if (head == std::string::npos) return ""; const auto tail = s.find_last_not_of(chars); const auto tail = s.find_last_not_of(charset); return s.substr(head, tail - head + 1); } static std::string trimDefault(const std::string& s) { static inline std::string toLowerStr(const std::string& s) { std::string res(s); std::transform(res.begin(), res.end(), res.begin(), ::tolower); return res; } static inline std::string trimDefault(const std::string& s) { return trim(s, DEFAULT_WHITESPACE); } static std::string trimHeader(const std::string& s) { std::string res = trimDefault(s); std::transform(res.begin(), res.end(), res.begin(), ::tolower); return res; static inline std::string trimHeader(const std::string& s) { return toLowerStr(trimDefault(s)); } // This is similiar to Split in android-base/file.h, but it won't add empty string Loading Loading @@ -188,97 +192,106 @@ bool Reader::ok(std::string* error) { } // ============================================================================== static int lookupName(const char** names, const int size, const char* name) Table::Table(const char* names[], const uint64_t ids[], const int count) :mEnums(), mEnumValuesByName() { for (int i=0; i<size; i++) { if (strcmp(name, names[i]) == 0) { return i; map<std::string, uint64_t> fields; for (int i = 0; i < count; i++) { fields[names[i]] = ids[i]; } } return -1; } EnumTypeMap::EnumTypeMap(const char* enumNames[], const uint32_t enumValues[], const int enumCount) :mEnumNames(enumNames), mEnumValues(enumValues), mEnumCount(enumCount) { mFields = fields; } EnumTypeMap::~EnumTypeMap() Table::~Table() { } int EnumTypeMap::parseValue(const std::string& value) void Table::addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize) { int index = lookupName(mEnumNames, mEnumCount, value.c_str()); if (index < 0) return mEnumValues[0]; // Assume value 0 is default return mEnumValues[index]; } if (mFields.find(field) == mFields.end()) return; Table::Table(const char* names[], const uint64_t ids[], const int count) :mFieldNames(names), mFieldIds(ids), mFieldCount(count), mEnums() { map<std::string, int> enu; for (int i = 0; i < enumSize; i++) { enu[enumNames[i]] = enumValues[i]; } Table::~Table() { mEnums[field] = enu; } void Table::addEnumTypeMap(const char* field, const char* enumNames[], const uint32_t enumValues[], const int enumSize) Table::addEnumNameToValue(const char* enumName, const int enumValue) { int index = lookupName(mFieldNames, mFieldCount, field); if (index < 0) return; EnumTypeMap enu(enumNames, enumValues, enumSize); mEnums[index] = enu; mEnumValuesByName[enumName] = enumValue; } bool Table::insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value) { int index = lookupName(mFieldNames, mFieldCount, name.c_str()); if (index < 0) return false; if (mFields.find(name) == mFields.end()) return false; uint64_t found = mFieldIds[index]; switch (found & FIELD_TYPE_MASK) { case FIELD_TYPE_DOUBLE: case FIELD_TYPE_FLOAT: uint64_t found = mFields[name]; record_t repeats; // used for repeated fields switch ((found & FIELD_COUNT_MASK) | (found & FIELD_TYPE_MASK)) { case FIELD_COUNT_SINGLE | FIELD_TYPE_DOUBLE: case FIELD_COUNT_SINGLE | FIELD_TYPE_FLOAT: proto->write(found, toDouble(value)); break; case FIELD_TYPE_STRING: case FIELD_TYPE_BYTES: case FIELD_COUNT_SINGLE | FIELD_TYPE_STRING: case FIELD_COUNT_SINGLE | FIELD_TYPE_BYTES: proto->write(found, value); break; case FIELD_TYPE_INT64: case FIELD_TYPE_SINT64: case FIELD_TYPE_UINT64: case FIELD_TYPE_FIXED64: case FIELD_TYPE_SFIXED64: case FIELD_COUNT_SINGLE | FIELD_TYPE_INT64: case FIELD_COUNT_SINGLE | FIELD_TYPE_SINT64: case FIELD_COUNT_SINGLE | FIELD_TYPE_UINT64: case FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED64: case FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED64: proto->write(found, toLongLong(value)); break; case FIELD_TYPE_BOOL: case FIELD_COUNT_SINGLE | FIELD_TYPE_BOOL: if (strcmp(toLowerStr(value).c_str(), "true") == 0 || strcmp(value.c_str(), "1") == 0) { proto->write(found, true); break; } if (strcmp(toLowerStr(value).c_str(), "false") == 0 || strcmp(value.c_str(), "0") == 0) { proto->write(found, false); break; } return false; case FIELD_TYPE_ENUM: if (mEnums.find(index) == mEnums.end()) { // forget to add enum type mapping case FIELD_COUNT_SINGLE | FIELD_TYPE_ENUM: // if the field has its own enum mapping, use this, otherwise use general name to value mapping. if (mEnums.find(name) != mEnums.end()) { if (mEnums[name].find(value) != mEnums[name].end()) { proto->write(found, mEnums[name][value]); } else { proto->write(found, 0); // TODO: should get the default enum value (Unknown) } } else if (mEnumValuesByName.find(value) != mEnumValuesByName.end()) { proto->write(found, mEnumValuesByName[value]); } else { return false; } proto->write(found, mEnums[index].parseValue(value)); break; case FIELD_TYPE_INT32: case FIELD_TYPE_SINT32: case FIELD_TYPE_UINT32: case FIELD_TYPE_FIXED32: case FIELD_TYPE_SFIXED32: case FIELD_COUNT_SINGLE | FIELD_TYPE_INT32: case FIELD_COUNT_SINGLE | FIELD_TYPE_SINT32: case FIELD_COUNT_SINGLE | FIELD_TYPE_UINT32: case FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED32: case FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED32: proto->write(found, toInt(value)); break; // REPEATED TYPE below: case FIELD_COUNT_REPEATED | FIELD_TYPE_INT32: repeats = parseRecord(value, COMMA_DELIMITER); for (size_t i=0; i<repeats.size(); i++) { proto->write(found, toInt(repeats[i])); } break; case FIELD_COUNT_REPEATED | FIELD_TYPE_STRING: repeats = parseRecord(value, COMMA_DELIMITER); for (size_t i=0; i<repeats.size(); i++) { proto->write(found, repeats[i]); } break; default: return false; } Loading cmds/incident_helper/src/ih_util.h +10 −20 Original line number Diff line number Diff line Loading @@ -37,6 +37,9 @@ const std::string COMMA_DELIMITER = ","; // returns true if c is a-zA-Z0-9 or underscore _ bool isValidChar(char c); // trim the string with the given charset std::string trim(const std::string& s, const std::string& charset); /** * When a text has a table format like this * line 1: HeadA HeadB HeadC Loading Loading @@ -98,21 +101,6 @@ private: std::string mStatus; }; class EnumTypeMap { public: EnumTypeMap() {}; EnumTypeMap(const char* enumNames[], const uint32_t enumValues[], const int enumCount); ~EnumTypeMap(); int parseValue(const std::string& value); private: const char** mEnumNames; const uint32_t* mEnumValues; int mEnumCount; }; /** * The class contains a mapping between table headers to its field ids. * And allow users to insert the field values to proto based on its header name. Loading @@ -124,14 +112,16 @@ public: ~Table(); // Add enum names to values for parsing purpose. void addEnumTypeMap(const char* field, const char* enumNames[], const uint32_t enumValues[], const int enumSize); void addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize); // manually add enum names to values mapping, useful when an Enum type is used by a lot of fields, and there are no name conflicts void addEnumNameToValue(const char* enumName, const int enumValue); bool insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value); private: const char** mFieldNames; const uint64_t* mFieldIds; const int mFieldCount; map<int, EnumTypeMap> mEnums; map<std::string, uint64_t> mFields; map<std::string, map<std::string, int>> mEnums; map<std::string, int> mEnumValuesByName; }; #endif // INCIDENT_HELPER_UTIL_H cmds/incident_helper/src/main.cpp +3 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "parsers/KernelWakesParser.h" #include "parsers/PageTypeInfoParser.h" #include "parsers/ProcrankParser.h" #include "parsers/SystemPropertiesParser.h" #include <android-base/file.h> #include <getopt.h> Loading Loading @@ -49,6 +50,8 @@ static TextParserBase* selectParser(int section) { return new ReverseParser(); /* ========================================================================= */ // IDs larger than 1 are section ids reserved in incident.proto case 1000: return new SystemPropertiesParser(); case 2000: return new ProcrankParser(); case 2001: Loading cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp 0 → 100644 +89 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "incident_helper" #include <android/util/ProtoOutputStream.h> #include "frameworks/base/core/proto/android/os/system_properties.proto.h" #include "ih_util.h" #include "SystemPropertiesParser.h" using namespace android::os; const string LINE_DELIMITER = "]: ["; // system properties' names sometimes are not valid proto field names, make the names valid. static string convertToFieldName(const string& name) { int len = (int)name.length(); char cstr[len + 1]; strcpy(cstr, name.c_str()); for (int i = 0; i < len; i++) { if (!isValidChar(cstr[i])) { cstr[i] = '_'; } } return string(cstr); } status_t SystemPropertiesParser::Parse(const int in, const int out) const { Reader reader(in); string line; string name; // the name of the property string value; // the string value of the property ProtoOutputStream proto; Table table(SystemPropertiesProto::_FIELD_NAMES, SystemPropertiesProto::_FIELD_IDS, SystemPropertiesProto::_FIELD_COUNT); table.addEnumNameToValue("running", SystemPropertiesProto::STATUS_RUNNING); table.addEnumNameToValue("stopped", SystemPropertiesProto::STATUS_STOPPED); // parse line by line while (reader.readLine(&line)) { if (line.empty()) continue; line = line.substr(1, line.size() - 2); // trim [] size_t index = line.find(LINE_DELIMITER); // split by "]: [" if (index == string::npos) { fprintf(stderr, "Bad Line %s\n", line.c_str()); continue; } name = line.substr(0, index); value = trim(line.substr(index + 4), DEFAULT_WHITESPACE); if (value.empty()) continue; // if the property name couldn't be found in proto definition or the value has mistype, // add to extra properties with its name and value if (!table.insertField(&proto, convertToFieldName(name), value)) { long long token = proto.start(SystemPropertiesProto::EXTRA_PROPERTIES); proto.write(SystemPropertiesProto::Property::NAME, name); proto.write(SystemPropertiesProto::Property::VALUE, value); proto.end(token); } } if (!reader.ok(&line)) { fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str()); return -1; } if (!proto.flush(out)) { fprintf(stderr, "[%s]Error writing proto back\n", this->name.string()); return -1; } fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size()); return NO_ERROR; } Loading
Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ cc_library { "core/proto/android/os/kernelwake.proto", "core/proto/android/os/pagetypeinfo.proto", "core/proto/android/os/procrank.proto", "core/proto/android/os/system_properties.proto", "core/proto/android/service/graphicsstats.proto", "tools/streaming_proto/stream.proto", ], Loading @@ -86,6 +87,7 @@ gensrcs { "core/proto/android/os/kernelwake.proto", "core/proto/android/os/pagetypeinfo.proto", "core/proto/android/os/procrank.proto", "core/proto/android/os/system_properties.proto", ], // Append protoc-gen-cppstream tool's PATH otherwise aprotoc can't find the plugin tool Loading
cmds/incident_helper/src/ih_util.cpp +81 −68 Original line number Diff line number Diff line Loading @@ -30,22 +30,26 @@ bool isValidChar(char c) { || (v == (uint8_t)'_'); } static std::string trim(const std::string& s, const std::string& chars) { const auto head = s.find_first_not_of(chars); std::string trim(const std::string& s, const std::string& charset) { const auto head = s.find_first_not_of(charset); if (head == std::string::npos) return ""; const auto tail = s.find_last_not_of(chars); const auto tail = s.find_last_not_of(charset); return s.substr(head, tail - head + 1); } static std::string trimDefault(const std::string& s) { static inline std::string toLowerStr(const std::string& s) { std::string res(s); std::transform(res.begin(), res.end(), res.begin(), ::tolower); return res; } static inline std::string trimDefault(const std::string& s) { return trim(s, DEFAULT_WHITESPACE); } static std::string trimHeader(const std::string& s) { std::string res = trimDefault(s); std::transform(res.begin(), res.end(), res.begin(), ::tolower); return res; static inline std::string trimHeader(const std::string& s) { return toLowerStr(trimDefault(s)); } // This is similiar to Split in android-base/file.h, but it won't add empty string Loading Loading @@ -188,97 +192,106 @@ bool Reader::ok(std::string* error) { } // ============================================================================== static int lookupName(const char** names, const int size, const char* name) Table::Table(const char* names[], const uint64_t ids[], const int count) :mEnums(), mEnumValuesByName() { for (int i=0; i<size; i++) { if (strcmp(name, names[i]) == 0) { return i; map<std::string, uint64_t> fields; for (int i = 0; i < count; i++) { fields[names[i]] = ids[i]; } } return -1; } EnumTypeMap::EnumTypeMap(const char* enumNames[], const uint32_t enumValues[], const int enumCount) :mEnumNames(enumNames), mEnumValues(enumValues), mEnumCount(enumCount) { mFields = fields; } EnumTypeMap::~EnumTypeMap() Table::~Table() { } int EnumTypeMap::parseValue(const std::string& value) void Table::addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize) { int index = lookupName(mEnumNames, mEnumCount, value.c_str()); if (index < 0) return mEnumValues[0]; // Assume value 0 is default return mEnumValues[index]; } if (mFields.find(field) == mFields.end()) return; Table::Table(const char* names[], const uint64_t ids[], const int count) :mFieldNames(names), mFieldIds(ids), mFieldCount(count), mEnums() { map<std::string, int> enu; for (int i = 0; i < enumSize; i++) { enu[enumNames[i]] = enumValues[i]; } Table::~Table() { mEnums[field] = enu; } void Table::addEnumTypeMap(const char* field, const char* enumNames[], const uint32_t enumValues[], const int enumSize) Table::addEnumNameToValue(const char* enumName, const int enumValue) { int index = lookupName(mFieldNames, mFieldCount, field); if (index < 0) return; EnumTypeMap enu(enumNames, enumValues, enumSize); mEnums[index] = enu; mEnumValuesByName[enumName] = enumValue; } bool Table::insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value) { int index = lookupName(mFieldNames, mFieldCount, name.c_str()); if (index < 0) return false; if (mFields.find(name) == mFields.end()) return false; uint64_t found = mFieldIds[index]; switch (found & FIELD_TYPE_MASK) { case FIELD_TYPE_DOUBLE: case FIELD_TYPE_FLOAT: uint64_t found = mFields[name]; record_t repeats; // used for repeated fields switch ((found & FIELD_COUNT_MASK) | (found & FIELD_TYPE_MASK)) { case FIELD_COUNT_SINGLE | FIELD_TYPE_DOUBLE: case FIELD_COUNT_SINGLE | FIELD_TYPE_FLOAT: proto->write(found, toDouble(value)); break; case FIELD_TYPE_STRING: case FIELD_TYPE_BYTES: case FIELD_COUNT_SINGLE | FIELD_TYPE_STRING: case FIELD_COUNT_SINGLE | FIELD_TYPE_BYTES: proto->write(found, value); break; case FIELD_TYPE_INT64: case FIELD_TYPE_SINT64: case FIELD_TYPE_UINT64: case FIELD_TYPE_FIXED64: case FIELD_TYPE_SFIXED64: case FIELD_COUNT_SINGLE | FIELD_TYPE_INT64: case FIELD_COUNT_SINGLE | FIELD_TYPE_SINT64: case FIELD_COUNT_SINGLE | FIELD_TYPE_UINT64: case FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED64: case FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED64: proto->write(found, toLongLong(value)); break; case FIELD_TYPE_BOOL: case FIELD_COUNT_SINGLE | FIELD_TYPE_BOOL: if (strcmp(toLowerStr(value).c_str(), "true") == 0 || strcmp(value.c_str(), "1") == 0) { proto->write(found, true); break; } if (strcmp(toLowerStr(value).c_str(), "false") == 0 || strcmp(value.c_str(), "0") == 0) { proto->write(found, false); break; } return false; case FIELD_TYPE_ENUM: if (mEnums.find(index) == mEnums.end()) { // forget to add enum type mapping case FIELD_COUNT_SINGLE | FIELD_TYPE_ENUM: // if the field has its own enum mapping, use this, otherwise use general name to value mapping. if (mEnums.find(name) != mEnums.end()) { if (mEnums[name].find(value) != mEnums[name].end()) { proto->write(found, mEnums[name][value]); } else { proto->write(found, 0); // TODO: should get the default enum value (Unknown) } } else if (mEnumValuesByName.find(value) != mEnumValuesByName.end()) { proto->write(found, mEnumValuesByName[value]); } else { return false; } proto->write(found, mEnums[index].parseValue(value)); break; case FIELD_TYPE_INT32: case FIELD_TYPE_SINT32: case FIELD_TYPE_UINT32: case FIELD_TYPE_FIXED32: case FIELD_TYPE_SFIXED32: case FIELD_COUNT_SINGLE | FIELD_TYPE_INT32: case FIELD_COUNT_SINGLE | FIELD_TYPE_SINT32: case FIELD_COUNT_SINGLE | FIELD_TYPE_UINT32: case FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED32: case FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED32: proto->write(found, toInt(value)); break; // REPEATED TYPE below: case FIELD_COUNT_REPEATED | FIELD_TYPE_INT32: repeats = parseRecord(value, COMMA_DELIMITER); for (size_t i=0; i<repeats.size(); i++) { proto->write(found, toInt(repeats[i])); } break; case FIELD_COUNT_REPEATED | FIELD_TYPE_STRING: repeats = parseRecord(value, COMMA_DELIMITER); for (size_t i=0; i<repeats.size(); i++) { proto->write(found, repeats[i]); } break; default: return false; } Loading
cmds/incident_helper/src/ih_util.h +10 −20 Original line number Diff line number Diff line Loading @@ -37,6 +37,9 @@ const std::string COMMA_DELIMITER = ","; // returns true if c is a-zA-Z0-9 or underscore _ bool isValidChar(char c); // trim the string with the given charset std::string trim(const std::string& s, const std::string& charset); /** * When a text has a table format like this * line 1: HeadA HeadB HeadC Loading Loading @@ -98,21 +101,6 @@ private: std::string mStatus; }; class EnumTypeMap { public: EnumTypeMap() {}; EnumTypeMap(const char* enumNames[], const uint32_t enumValues[], const int enumCount); ~EnumTypeMap(); int parseValue(const std::string& value); private: const char** mEnumNames; const uint32_t* mEnumValues; int mEnumCount; }; /** * The class contains a mapping between table headers to its field ids. * And allow users to insert the field values to proto based on its header name. Loading @@ -124,14 +112,16 @@ public: ~Table(); // Add enum names to values for parsing purpose. void addEnumTypeMap(const char* field, const char* enumNames[], const uint32_t enumValues[], const int enumSize); void addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize); // manually add enum names to values mapping, useful when an Enum type is used by a lot of fields, and there are no name conflicts void addEnumNameToValue(const char* enumName, const int enumValue); bool insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value); private: const char** mFieldNames; const uint64_t* mFieldIds; const int mFieldCount; map<int, EnumTypeMap> mEnums; map<std::string, uint64_t> mFields; map<std::string, map<std::string, int>> mEnums; map<std::string, int> mEnumValuesByName; }; #endif // INCIDENT_HELPER_UTIL_H
cmds/incident_helper/src/main.cpp +3 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "parsers/KernelWakesParser.h" #include "parsers/PageTypeInfoParser.h" #include "parsers/ProcrankParser.h" #include "parsers/SystemPropertiesParser.h" #include <android-base/file.h> #include <getopt.h> Loading Loading @@ -49,6 +50,8 @@ static TextParserBase* selectParser(int section) { return new ReverseParser(); /* ========================================================================= */ // IDs larger than 1 are section ids reserved in incident.proto case 1000: return new SystemPropertiesParser(); case 2000: return new ProcrankParser(); case 2001: Loading
cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp 0 → 100644 +89 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "incident_helper" #include <android/util/ProtoOutputStream.h> #include "frameworks/base/core/proto/android/os/system_properties.proto.h" #include "ih_util.h" #include "SystemPropertiesParser.h" using namespace android::os; const string LINE_DELIMITER = "]: ["; // system properties' names sometimes are not valid proto field names, make the names valid. static string convertToFieldName(const string& name) { int len = (int)name.length(); char cstr[len + 1]; strcpy(cstr, name.c_str()); for (int i = 0; i < len; i++) { if (!isValidChar(cstr[i])) { cstr[i] = '_'; } } return string(cstr); } status_t SystemPropertiesParser::Parse(const int in, const int out) const { Reader reader(in); string line; string name; // the name of the property string value; // the string value of the property ProtoOutputStream proto; Table table(SystemPropertiesProto::_FIELD_NAMES, SystemPropertiesProto::_FIELD_IDS, SystemPropertiesProto::_FIELD_COUNT); table.addEnumNameToValue("running", SystemPropertiesProto::STATUS_RUNNING); table.addEnumNameToValue("stopped", SystemPropertiesProto::STATUS_STOPPED); // parse line by line while (reader.readLine(&line)) { if (line.empty()) continue; line = line.substr(1, line.size() - 2); // trim [] size_t index = line.find(LINE_DELIMITER); // split by "]: [" if (index == string::npos) { fprintf(stderr, "Bad Line %s\n", line.c_str()); continue; } name = line.substr(0, index); value = trim(line.substr(index + 4), DEFAULT_WHITESPACE); if (value.empty()) continue; // if the property name couldn't be found in proto definition or the value has mistype, // add to extra properties with its name and value if (!table.insertField(&proto, convertToFieldName(name), value)) { long long token = proto.start(SystemPropertiesProto::EXTRA_PROPERTIES); proto.write(SystemPropertiesProto::Property::NAME, name); proto.write(SystemPropertiesProto::Property::VALUE, value); proto.end(token); } } if (!reader.ok(&line)) { fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str()); return -1; } if (!proto.flush(out)) { fprintf(stderr, "[%s]Error writing proto back\n", this->name.string()); return -1; } fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size()); return NO_ERROR; }