summaryrefslogtreecommitdiff
path: root/cmds/incident_helper
diff options
context:
space:
mode:
authorYi Jin <jinyithu@google.com>2017-12-22 17:36:47 -0800
committerYi Jin <jinyithu@google.com>2018-01-06 20:33:14 -0800
commit3c034c987e1eeb49660fb62d3426c292a01412c9 (patch)
tree168d3f0040e3e74ac1b2741f91d2dbfcee166535 /cmds/incident_helper
parenta598c05d632d303a49ba06fe306136e0039c785d (diff)
Implement a new type of section which reads from logd and dumps proto.
And implement a file section which reads from event-log-tags for decoding binary logs. Bug: 70936599 Test: atest incidentd_test && atest incident_helper_test and flush on device and test log sections and event_log_tag_map Change-Id: Ib3d35e317f355de69f01ded012482486e9a43da6
Diffstat (limited to 'cmds/incident_helper')
-rw-r--r--cmds/incident_helper/src/ih_util.cpp13
-rw-r--r--cmds/incident_helper/src/ih_util.h7
-rw-r--r--cmds/incident_helper/src/main.cpp3
-rw-r--r--cmds/incident_helper/src/parsers/EventLogTagsParser.cpp84
-rw-r--r--cmds/incident_helper/src/parsers/EventLogTagsParser.h35
-rw-r--r--cmds/incident_helper/testdata/event-log-tags.txt6
-rw-r--r--cmds/incident_helper/tests/EventLogTagsParser_test.cpp125
-rw-r--r--cmds/incident_helper/tests/ih_util_test.cpp19
8 files changed, 292 insertions, 0 deletions
diff --git a/cmds/incident_helper/src/ih_util.cpp b/cmds/incident_helper/src/ih_util.cpp
index e23e80ae21e8..847b26a39ffe 100644
--- a/cmds/incident_helper/src/ih_util.cpp
+++ b/cmds/incident_helper/src/ih_util.cpp
@@ -208,6 +208,19 @@ bool stripSuffix(std::string* line, const char* key, bool endAtDelimiter) {
return true;
}
+std::string behead(std::string* line, const char cut) {
+ auto found = line->find_first_of(cut);
+ if (found == std::string::npos) {
+ std::string head = line->substr(0);
+ line->assign("");
+ return head;
+ }
+ std::string head = line->substr(0, found);
+ while(line->at(found) == cut) found++; // trim more cut of the rest
+ line->assign(line->substr(found));
+ return head;
+}
+
int toInt(const std::string& s) {
return atoi(s.c_str());
}
diff --git a/cmds/incident_helper/src/ih_util.h b/cmds/incident_helper/src/ih_util.h
index b063b2fe0bba..53f443873e4d 100644
--- a/cmds/incident_helper/src/ih_util.h
+++ b/cmds/incident_helper/src/ih_util.h
@@ -34,6 +34,8 @@ const std::string DEFAULT_WHITESPACE = " \t";
const std::string DEFAULT_NEWLINE = "\r\n";
const std::string TAB_DELIMITER = "\t";
const std::string COMMA_DELIMITER = ",";
+const std::string PIPE_DELIMITER = "|";
+const std::string PARENTHESES_DELIMITER = "()";
// returns true if c is a-zA-Z0-9 or underscore
bool isValidChar(char c);
@@ -89,6 +91,11 @@ bool stripPrefix(std::string* line, const char* key, bool endAtDelimiter = false
bool stripSuffix(std::string* line, const char* key, bool endAtDelimiter = false);
/**
+ * behead the given line by the cut, return the head and reassign the line to be the rest.
+ */
+std::string behead(std::string* line, const char cut);
+
+/**
* Converts string to the desired type
*/
int toInt(const std::string& s);
diff --git a/cmds/incident_helper/src/main.cpp b/cmds/incident_helper/src/main.cpp
index 8c6cd78d3bf2..418dc3fad761 100644
--- a/cmds/incident_helper/src/main.cpp
+++ b/cmds/incident_helper/src/main.cpp
@@ -19,6 +19,7 @@
#include "parsers/BatteryTypeParser.h"
#include "parsers/CpuFreqParser.h"
#include "parsers/CpuInfoParser.h"
+#include "parsers/EventLogTagsParser.h"
#include "parsers/KernelWakesParser.h"
#include "parsers/PageTypeInfoParser.h"
#include "parsers/ProcrankParser.h"
@@ -55,6 +56,8 @@ static TextParserBase* selectParser(int section) {
// IDs larger than 1 are section ids reserved in incident.proto
case 1000:
return new SystemPropertiesParser();
+ case 1100:
+ return new EventLogTagsParser();
case 2000:
return new ProcrankParser();
case 2001:
diff --git a/cmds/incident_helper/src/parsers/EventLogTagsParser.cpp b/cmds/incident_helper/src/parsers/EventLogTagsParser.cpp
new file mode 100644
index 000000000000..73e37bd166cd
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/EventLogTagsParser.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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/util/event_log_tags.proto.h"
+#include "ih_util.h"
+#include "EventLogTagsParser.h"
+
+status_t
+EventLogTagsParser::Parse(const int in, const int out) const
+{
+ Reader reader(in);
+ string line;
+
+ ProtoOutputStream proto;
+
+ // parse line by line
+ while (reader.readLine(&line)) {
+ if (line.empty()) continue;
+ string debug = line;
+ string tagNumber = behead(&line, ' ');
+ string tagName = behead(&line, ' ');
+ if (tagNumber == "" || tagName == "") {
+ fprintf(stderr, "Bad line, expect at least two parts: %s[%s, %s]\n",
+ debug.c_str(), tagNumber.c_str(), tagName.c_str());
+ continue;
+ }
+
+ long long token = proto.start(EventLogTagMapProto::EVENT_LOG_TAGS);
+ proto.write(EventLogTag::TAG_NUMBER, toInt(tagNumber));
+ proto.write(EventLogTag::TAG_NAME, tagName);
+
+ record_t valueDescriptors = parseRecord(line, PARENTHESES_DELIMITER);
+ for (size_t i = 0; i < valueDescriptors.size(); i++) {
+ record_t valueDescriptor = parseRecord(valueDescriptors[i], PIPE_DELIMITER);
+ if (valueDescriptor.size() != 2 && valueDescriptor.size() != 3) {
+ // If the parts doesn't contains pipe, then skips it.
+ continue;
+ }
+ long long descriptorToken = proto.start(EventLogTag::VALUE_DESCRIPTORS);
+ proto.write(EventLogTag::ValueDescriptor::NAME, valueDescriptor[0]);
+ proto.write(EventLogTag::ValueDescriptor::TYPE, toInt(valueDescriptor[1]));
+ if (valueDescriptor.size() == 3) {
+ char c = valueDescriptor[2][0];
+ int unit = 0;
+ if (c < '0' || c > '9') {
+ unit = (int) c;
+ } else {
+ unit = toInt(valueDescriptor[2]);
+ }
+ proto.write(EventLogTag::ValueDescriptor::UNIT, unit);
+ }
+ proto.end(descriptorToken);
+ }
+ 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/EventLogTagsParser.h b/cmds/incident_helper/src/parsers/EventLogTagsParser.h
new file mode 100644
index 000000000000..79057ce0b3ca
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/EventLogTagsParser.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 EVENT_LOG_TAGS_PARSER_H
+#define EVENT_LOG_TAGS_PARSER_H
+
+#include "TextParserBase.h"
+
+using namespace android;
+
+/**
+ * event.logtags parser, parse file in /system/etc/event-log-tags
+ */
+class EventLogTagsParser : public TextParserBase {
+public:
+ EventLogTagsParser() : TextParserBase(String8("EventLogTagsParser")) {};
+ ~EventLogTagsParser() {};
+
+ virtual status_t Parse(const int in, const int out) const;
+};
+
+#endif // EVENT_LOG_TAGS_PARSER_H
diff --git a/cmds/incident_helper/testdata/event-log-tags.txt b/cmds/incident_helper/testdata/event-log-tags.txt
new file mode 100644
index 000000000000..35396bfb4250
--- /dev/null
+++ b/cmds/incident_helper/testdata/event-log-tags.txt
@@ -0,0 +1,6 @@
+42 answer (to life the universe etc|3)
+314 pi
+1004 chatty (dropped|3)
+1005 tag_def (tag|1),(name|3),(format|3)
+2747 contacts_aggregation (aggregation time|2|3), (count|1|1)
+1397638484 snet_event_log (subtag|3) (uid|1) (message|3|s) \ No newline at end of file
diff --git a/cmds/incident_helper/tests/EventLogTagsParser_test.cpp b/cmds/incident_helper/tests/EventLogTagsParser_test.cpp
new file mode 100644
index 000000000000..d0d1f1e023a8
--- /dev/null
+++ b/cmds/incident_helper/tests/EventLogTagsParser_test.cpp
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+#include "EventLogTagsParser.h"
+
+#include "frameworks/base/core/proto/android/util/event_log_tags.pb.h"
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/message_lite.h>
+#include <gtest/gtest.h>
+#include <string.h>
+#include <fcntl.h>
+
+using namespace android::base;
+using namespace android::util;
+using namespace std;
+using ::testing::StrEq;
+using ::testing::Test;
+using ::testing::internal::CaptureStderr;
+using ::testing::internal::CaptureStdout;
+using ::testing::internal::GetCapturedStderr;
+using ::testing::internal::GetCapturedStdout;
+
+class EventLogTagsParserTest : public Test {
+public:
+ virtual void SetUp() override {
+ ASSERT_TRUE(tf.fd != -1);
+ }
+
+protected:
+ TemporaryFile tf;
+
+ const string kTestPath = GetExecutableDirectory();
+ const string kTestDataPath = kTestPath + "/testdata/";
+};
+
+TEST_F(EventLogTagsParserTest, Success) {
+ const string testFile = kTestDataPath + "event-log-tags.txt";
+
+ EventLogTagsParser parser;
+ EventLogTagMapProto expected;
+
+ EventLogTag* eventLogTag;
+ EventLogTag::ValueDescriptor* desp;
+
+ eventLogTag = expected.add_event_log_tags();
+ eventLogTag->set_tag_number(42);
+ eventLogTag->set_tag_name("answer");
+ desp = eventLogTag->add_value_descriptors();
+ desp->set_name("to life the universe etc");
+ desp->set_type(EventLogTag_ValueDescriptor_DataType_STRING);
+
+ eventLogTag = expected.add_event_log_tags();
+ eventLogTag->set_tag_number(314);
+ eventLogTag->set_tag_name("pi");
+
+ eventLogTag = expected.add_event_log_tags();
+ eventLogTag->set_tag_number(1004);
+ eventLogTag->set_tag_name("chatty");
+ desp = eventLogTag->add_value_descriptors();
+ desp->set_name("dropped");
+ desp->set_type(EventLogTag_ValueDescriptor_DataType_STRING);
+
+ eventLogTag = expected.add_event_log_tags();
+ eventLogTag->set_tag_number(1005);
+ eventLogTag->set_tag_name("tag_def");
+ desp = eventLogTag->add_value_descriptors();
+ desp->set_name("tag");
+ desp->set_type(EventLogTag_ValueDescriptor_DataType_INT);
+ desp = eventLogTag->add_value_descriptors();
+ desp->set_name("name");
+ desp->set_type(EventLogTag_ValueDescriptor_DataType_STRING);
+ desp = eventLogTag->add_value_descriptors();
+ desp->set_name("format");
+ desp->set_type(EventLogTag_ValueDescriptor_DataType_STRING);
+
+ eventLogTag = expected.add_event_log_tags();
+ eventLogTag->set_tag_number(2747);
+ eventLogTag->set_tag_name("contacts_aggregation");
+ desp = eventLogTag->add_value_descriptors();
+ desp->set_name("aggregation time");
+ desp->set_type(EventLogTag_ValueDescriptor_DataType_LONG);
+ desp->set_unit(EventLogTag_ValueDescriptor_DataUnit_MILLISECONDS);
+ desp = eventLogTag->add_value_descriptors();
+ desp->set_name("count");
+ desp->set_type(EventLogTag_ValueDescriptor_DataType_INT);
+ desp->set_unit(EventLogTag_ValueDescriptor_DataUnit_OBJECTS);
+
+ eventLogTag = expected.add_event_log_tags();
+ eventLogTag->set_tag_number(1397638484);
+ eventLogTag->set_tag_name("snet_event_log");
+ desp = eventLogTag->add_value_descriptors();
+ desp->set_name("subtag");
+ desp->set_type(EventLogTag_ValueDescriptor_DataType_STRING);
+ desp = eventLogTag->add_value_descriptors();
+ desp->set_name("uid");
+ desp->set_type(EventLogTag_ValueDescriptor_DataType_INT);
+ desp = eventLogTag->add_value_descriptors();
+ desp->set_name("message");
+ desp->set_type(EventLogTag_ValueDescriptor_DataType_STRING);
+ desp->set_unit(EventLogTag_ValueDescriptor_DataUnit_SECONDS);
+
+ int fd = open(testFile.c_str(), O_RDONLY);
+ ASSERT_TRUE(fd != -1);
+
+ CaptureStdout();
+ ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
+ EXPECT_EQ(GetCapturedStdout(), expected.SerializeAsString());
+ close(fd);
+}
diff --git a/cmds/incident_helper/tests/ih_util_test.cpp b/cmds/incident_helper/tests/ih_util_test.cpp
index 7b8cf52c8bee..efe714d98b18 100644
--- a/cmds/incident_helper/tests/ih_util_test.cpp
+++ b/cmds/incident_helper/tests/ih_util_test.cpp
@@ -60,6 +60,9 @@ TEST(IhUtilTest, ParseRecord) {
result = parseRecord("123,456,78_9", ",");
expected = { "123", "456", "78_9" };
EXPECT_EQ(expected, result);
+
+ result = parseRecord("", " ");
+ EXPECT_TRUE(result.empty());
}
TEST(IhUtilTest, ParseRecordByColumns) {
@@ -133,6 +136,22 @@ TEST(IhUtilTest, stripSuffix) {
EXPECT_THAT(data4, StrEq(" 243%abc"));
}
+TEST(IhUtilTest, behead) {
+ string testcase1 = "81002 dropbox_file_copy (a)(b)";
+ EXPECT_THAT(behead(&testcase1, ' '), StrEq("81002"));
+ EXPECT_THAT(behead(&testcase1, ' '), StrEq("dropbox_file_copy"));
+ EXPECT_THAT(testcase1, "(a)(b)");
+
+ string testcase2 = "adbce,erwqr";
+ EXPECT_THAT(behead(&testcase2, ' '), StrEq("adbce,erwqr"));
+ EXPECT_THAT(testcase2, "");
+
+ string testcase3 = "first second";
+ EXPECT_THAT(behead(&testcase3, ' '), StrEq("first"));
+ EXPECT_THAT(behead(&testcase3, ' '), StrEq("second"));
+ EXPECT_THAT(testcase3, "");
+}
+
TEST(IhUtilTest, Reader) {
TemporaryFile tf;
ASSERT_NE(tf.fd, -1);