summaryrefslogtreecommitdiff
path: root/cmds/incident_helper/src
diff options
context:
space:
mode:
Diffstat (limited to 'cmds/incident_helper/src')
-rw-r--r--cmds/incident_helper/src/ih_util.cpp149
-rw-r--r--cmds/incident_helper/src/ih_util.h30
-rw-r--r--cmds/incident_helper/src/main.cpp3
-rw-r--r--cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp89
-rw-r--r--cmds/incident_helper/src/parsers/SystemPropertiesParser.h35
5 files changed, 218 insertions, 88 deletions
diff --git a/cmds/incident_helper/src/ih_util.cpp b/cmds/incident_helper/src/ih_util.cpp
index 0b51e66c2108..db4f586c7e31 100644
--- a/cmds/incident_helper/src/ih_util.cpp
+++ b/cmds/incident_helper/src/ih_util.cpp
@@ -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
@@ -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)
-{
-}
-
-EnumTypeMap::~EnumTypeMap()
-{
+ mFields = fields;
}
-int
-EnumTypeMap::parseValue(const std::string& value)
+Table::~Table()
{
- int index = lookupName(mEnumNames, mEnumCount, value.c_str());
- if (index < 0) return mEnumValues[0]; // Assume value 0 is default
- return mEnumValues[index];
}
-Table::Table(const char* names[], const uint64_t ids[], const int count)
- :mFieldNames(names),
- mFieldIds(ids),
- mFieldCount(count),
- mEnums()
+void
+Table::addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize)
{
-}
+ if (mFields.find(field) == mFields.end()) return;
-Table::~Table()
-{
+ map<std::string, int> enu;
+ for (int i = 0; i < enumSize; i++) {
+ enu[enumNames[i]] = enumValues[i];
+ }
+ 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;
}
diff --git a/cmds/incident_helper/src/ih_util.h b/cmds/incident_helper/src/ih_util.h
index e8366fa599e2..4a5fe1dd7a42 100644
--- a/cmds/incident_helper/src/ih_util.h
+++ b/cmds/incident_helper/src/ih_util.h
@@ -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
@@ -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.
@@ -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
diff --git a/cmds/incident_helper/src/main.cpp b/cmds/incident_helper/src/main.cpp
index 5c9a468dea0b..c8a0883d493c 100644
--- a/cmds/incident_helper/src/main.cpp
+++ b/cmds/incident_helper/src/main.cpp
@@ -21,6 +21,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>
@@ -50,6 +51,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:
diff --git a/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp b/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
new file mode 100644
index 000000000000..ee5feb03242e
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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;
+}
diff --git a/cmds/incident_helper/src/parsers/SystemPropertiesParser.h b/cmds/incident_helper/src/parsers/SystemPropertiesParser.h
new file mode 100644
index 000000000000..c4016006a48a
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/SystemPropertiesParser.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#ifndef SYSTEM_PROPERTIES_PARSER_H
+#define SYSTEM_PROPERTIES_PARSER_H
+
+#include "TextParserBase.h"
+
+using namespace android;
+
+/**
+ * SystemProperties parser, parses text produced by command getprop.
+ */
+class SystemPropertiesParser : public TextParserBase {
+public:
+ SystemPropertiesParser() : TextParserBase(String8("SystemPropertiesParser")) {};
+ ~SystemPropertiesParser() {};
+
+ virtual status_t Parse(const int in, const int out) const;
+};
+
+#endif // SYSTEM_PROPERTIES_PARSER_H