summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--cmds/incident_helper/IncidentHelper.cpp158
-rw-r--r--cmds/incident_helper/IncidentHelper.h11
-rw-r--r--cmds/incident_helper/ih_util.cpp24
-rw-r--r--cmds/incident_helper/ih_util.h24
-rw-r--r--cmds/incident_helper/main.cpp2
-rw-r--r--cmds/incident_helper/testdata/pagetypeinfo.txt10
-rw-r--r--cmds/incident_helper/tests/IncidentHelper_test.cpp72
-rw-r--r--cmds/incident_helper/tests/ih_util_test.cpp46
-rw-r--r--core/proto/android/os/incident.proto10
-rw-r--r--core/proto/android/os/pagetypeinfo.proto81
11 files changed, 383 insertions, 56 deletions
diff --git a/Android.bp b/Android.bp
index 33acffa306da..d7254786efe2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -40,6 +40,7 @@ cc_library {
// needed by the device.
srcs: [
"core/proto/android/os/kernelwake.proto",
+ "core/proto/android/os/pagetypeinfo.proto",
"core/proto/android/os/procrank.proto",
"core/proto/android/service/graphicsstats.proto",
],
diff --git a/cmds/incident_helper/IncidentHelper.cpp b/cmds/incident_helper/IncidentHelper.cpp
index 787d3a1557d6..7b06d42cbb55 100644
--- a/cmds/incident_helper/IncidentHelper.cpp
+++ b/cmds/incident_helper/IncidentHelper.cpp
@@ -20,6 +20,7 @@
#include "ih_util.h"
#include "frameworks/base/core/proto/android/os/kernelwake.pb.h"
+#include "frameworks/base/core/proto/android/os/pagetypeinfo.pb.h"
#include "frameworks/base/core/proto/android/os/procrank.pb.h"
#include <android-base/file.h>
@@ -32,6 +33,22 @@ using namespace android::os;
using namespace google::protobuf;
using namespace std;
+
+static const string TAB_DELIMITER = "\t";
+static const string COMMA_DELIMITER = ",";
+
+static inline int toInt(const string& s) {
+ return atoi(s.c_str());
+}
+
+static inline long toLong(const string& s) {
+ return atol(s.c_str());
+}
+
+/**
+ * Sets the given protobuf message when the field name matches one of the
+ * fields. It is useful to set values to proto from table-like plain texts.
+ */
static bool
SetTableField(::google::protobuf::Message* message, string field_name, string field_value) {
const Descriptor* descriptor = message->GetDescriptor();
@@ -43,16 +60,16 @@ SetTableField(::google::protobuf::Message* message, string field_name, string fi
reflection->SetString(message, field, field_value);
return true;
case FieldDescriptor::TYPE_INT64:
- reflection->SetInt64(message, field, atol(field_value.c_str()));
+ reflection->SetInt64(message, field, toLong(field_value));
return true;
case FieldDescriptor::TYPE_UINT64:
- reflection->SetUInt64(message, field, atol(field_value.c_str()));
+ reflection->SetUInt64(message, field, toLong(field_value));
return true;
case FieldDescriptor::TYPE_INT32:
- reflection->SetInt32(message, field, atoi(field_value.c_str()));
+ reflection->SetInt32(message, field, toInt(field_value));
return true;
case FieldDescriptor::TYPE_UINT32:
- reflection->SetUInt32(message, field, atoi(field_value.c_str()));
+ reflection->SetUInt32(message, field, toInt(field_value));
return true;
default:
// Add new scalar types
@@ -93,8 +110,6 @@ status_t ReverseParser::Parse(const int in, const int out) const
}
// ================================================================================
-static const string KERNEL_WAKEUP_LINE_DELIMITER = "\t";
-
status_t KernelWakesParser::Parse(const int in, const int out) const {
Reader reader(in);
string line;
@@ -105,16 +120,16 @@ status_t KernelWakesParser::Parse(const int in, const int out) const {
KernelWakeSources proto;
// parse line by line
- while (reader.readLine(line)) {
+ while (reader.readLine(&line)) {
if (line.empty()) continue;
// parse head line
if (nline++ == 0) {
- header = parseHeader(line, KERNEL_WAKEUP_LINE_DELIMITER);
+ header = parseHeader(line, TAB_DELIMITER);
continue;
}
// parse for each record, the line delimiter is \t only!
- record = parseRecord(line, KERNEL_WAKEUP_LINE_DELIMITER);
+ record = parseRecord(line, TAB_DELIMITER);
if (record.size() != header.size()) {
// TODO: log this to incident report!
@@ -131,7 +146,7 @@ status_t KernelWakesParser::Parse(const int in, const int out) const {
}
}
- if (!reader.ok(line)) {
+ if (!reader.ok(&line)) {
fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
return -1;
}
@@ -147,7 +162,7 @@ status_t KernelWakesParser::Parse(const int in, const int out) const {
// ================================================================================
status_t ProcrankParser::Parse(const int in, const int out) const {
Reader reader(in);
- string line, content;
+ string line;
header_t header; // the header of /d/wakeup_sources
record_t record; // retain each record
int nline = 0;
@@ -155,7 +170,7 @@ status_t ProcrankParser::Parse(const int in, const int out) const {
Procrank proto;
// parse line by line
- while (reader.readLine(line)) {
+ while (reader.readLine(&line)) {
if (line.empty()) continue;
// parse head line
@@ -164,6 +179,15 @@ status_t ProcrankParser::Parse(const int in, const int out) const {
continue;
}
+ if (hasPrefix(&line, "ZRAM:")) {
+ proto.mutable_summary()->mutable_zram()->set_raw_text(line);
+ continue;
+ }
+ if (hasPrefix(&line, "RAM:")) {
+ proto.mutable_summary()->mutable_ram()->set_raw_text(line);
+ continue;
+ }
+
record = parseRecord(line);
if (record.size() != header.size()) {
if (record[record.size() - 1] == "TOTAL") { // TOTAL record
@@ -171,12 +195,6 @@ status_t ProcrankParser::Parse(const int in, const int out) const {
for (int i=1; i<=(int)record.size(); i++) {
SetTableField(total, header[header.size() - i], record[record.size() - i]);
}
- } else if (record[0] == "ZRAM:") {
- record = parseRecord(line, ":");
- proto.mutable_summary()->mutable_zram()->set_raw_text(record[1]);
- } else if (record[0] == "RAM:") {
- 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,
line.c_str());
@@ -193,7 +211,7 @@ status_t ProcrankParser::Parse(const int in, const int out) const {
}
}
- if (!reader.ok(line)) {
+ if (!reader.ok(&line)) {
fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
return -1;
}
@@ -205,3 +223,105 @@ status_t ProcrankParser::Parse(const int in, const int out) const {
fprintf(stderr, "[%s]Proto size: %d bytes\n", this->name.string(), proto.ByteSize());
return NO_ERROR;
}
+
+// ================================================================================
+status_t PageTypeInfoParser::Parse(const int in, const int out) const {
+ Reader reader(in);
+ string line;
+ bool migrateTypeSession = false;
+ int pageBlockOrder;
+ header_t blockHeader;
+
+ PageTypeInfo pageTypeInfo;
+
+ while (reader.readLine(&line)) {
+ if (line.empty()) {
+ migrateTypeSession = false;
+ blockHeader.clear();
+ continue;
+ }
+
+ if (hasPrefix(&line, "Page block order:")) {
+ pageBlockOrder = toInt(line);
+ pageTypeInfo.set_page_block_order(pageBlockOrder);
+ continue;
+ }
+ if (hasPrefix(&line, "Pages per block:")) {
+ pageTypeInfo.set_pages_per_block(toInt(line));
+ continue;
+ }
+ if (hasPrefix(&line, "Free pages count per migrate type at order")) {
+ migrateTypeSession = true;
+ continue;
+ }
+ if (hasPrefix(&line, "Number of blocks type")) {
+ blockHeader = parseHeader(line);
+ continue;
+ }
+
+ record_t record = parseRecord(line, COMMA_DELIMITER);
+ if (migrateTypeSession && record.size() == 3) {
+ MigrateTypeProto* migrateType = pageTypeInfo.add_migrate_types();
+ // expect part 0 starts with "Node"
+ if (hasPrefix(&record[0], "Node")) {
+ migrateType->set_node(toInt(record[0]));
+ } else goto ERROR;
+ // expect part 1 starts with "zone"
+ if (hasPrefix(&record[1], "zone")) {
+ migrateType->set_zone(record[1]);
+ } else goto ERROR;
+ // expect part 2 starts with "type"
+ if (hasPrefix(&record[2], "type")) {
+ // expect the rest of part 2 has number of (pageBlockOrder + 2) parts
+ // An example looks like:
+ // header line: type 0 1 2 3 4 5 6 7 8 9 10
+ // record line: Unmovable 426 279 226 1 1 1 0 0 2 2 0
+ // The pageBlockOrder = 10 and it's zero-indexed. so total parts
+ // are 10 + 1(zero-indexed) + 1(the type part) = 12.
+ record_t pageCounts = parseRecord(record[2]);
+ int pageCountsSize = pageBlockOrder + 2;
+ if ((int)pageCounts.size() != pageCountsSize) goto ERROR;
+
+ migrateType->set_type(pageCounts[0]);
+ for (auto i=1; i<pageCountsSize; i++) {
+ migrateType->add_free_pages_count(toInt(pageCounts[i]));
+ }
+ } else goto ERROR;
+ continue;
+ }
+
+ if (!blockHeader.empty() && record.size() == 2) {
+ BlockProto* block = pageTypeInfo.add_blocks();
+
+ if (hasPrefix(&record[0], "Node")) {
+ block->set_node(toInt(record[0]));
+ } else goto ERROR;
+
+ if (hasPrefix(&record[1], "zone")) {
+ record_t blockCounts = parseRecord(record[1]);
+ block->set_zone(blockCounts[0]);
+ for (size_t i=0; i<blockHeader.size(); i++) {
+ if (!SetTableField(block, blockHeader[i], blockCounts[i+1])) goto ERROR;
+ }
+ } else goto ERROR;
+
+ continue;
+ }
+
+ERROR: // print out error for this single line and continue parsing
+ fprintf(stderr, "[%s]Bad line: %s\n", this->name.string(), line.c_str());
+ }
+
+ if (!reader.ok(&line)) {
+ fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
+ return -1;
+ }
+
+ if (!pageTypeInfo.SerializeToFileDescriptor(out)) {
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ return -1;
+ }
+
+ fprintf(stderr, "[%s]Proto size: %d bytes\n", this->name.string(), pageTypeInfo.ByteSize());
+ return NO_ERROR;
+}
diff --git a/cmds/incident_helper/IncidentHelper.h b/cmds/incident_helper/IncidentHelper.h
index f6579a2d3736..d24d7173aa26 100644
--- a/cmds/incident_helper/IncidentHelper.h
+++ b/cmds/incident_helper/IncidentHelper.h
@@ -80,6 +80,17 @@ public:
};
/**
+ * PageTypeInfo parser, parses text to protobuf in /proc/pageinfotype
+ */
+class PageTypeInfoParser : public TextParserBase {
+public:
+ PageTypeInfoParser() : TextParserBase(String8("PageTypeInfo")) {};
+ ~PageTypeInfoParser() {};
+
+ virtual status_t Parse(const int in, const int out) const;
+};
+
+/**
* Procrank parser, parses text produced by command procrank
*/
class ProcrankParser : public TextParserBase {
diff --git a/cmds/incident_helper/ih_util.cpp b/cmds/incident_helper/ih_util.cpp
index b2fda23ac391..2ab4b54e193f 100644
--- a/cmds/incident_helper/ih_util.cpp
+++ b/cmds/incident_helper/ih_util.cpp
@@ -18,6 +18,7 @@
#include "ih_util.h"
+#include <algorithm>
#include <sstream>
#include <unistd.h>
@@ -72,6 +73,20 @@ record_t parseRecord(const std::string& line, const std::string& delimiters) {
return record;
}
+bool hasPrefix(std::string* line, const char* key) {
+ const auto head = line->find_first_not_of(DEFAULT_WHITESPACE);
+ if (head == std::string::npos) return false;
+ auto i = 0;
+ auto j = head;
+ while (key[i] != '\0') {
+ if (j >= line->size() || key[i++] != line->at(j++)) {
+ return false;
+ }
+ }
+ line->assign(trim(line->substr(j)));
+ return true;
+}
+
Reader::Reader(const int fd) : Reader(fd, BUFFER_SIZE) {};
Reader::Reader(const int fd, const size_t capacity)
@@ -86,8 +101,9 @@ Reader::~Reader()
free(mBuf);
}
-bool Reader::readLine(std::string& line, const char newline) {
+bool Reader::readLine(std::string* line, const char newline) {
if (!ok(line)) return false; // bad status
+ line->clear();
std::stringstream ss;
while (!EOR()) {
// read if available
@@ -124,14 +140,14 @@ bool Reader::readLine(std::string& line, const char newline) {
if (mFlushed >= (int) mMaxSize) mFlushed = 0;
if (EOR() || meetsNewLine) {
- line.assign(ss.str());
+ line->assign(ss.str());
return true;
}
}
return false;
}
-bool Reader::ok(std::string& error) {
- error.assign(mStatus);
+bool Reader::ok(std::string* error) {
+ error->assign(mStatus);
return mStatus.empty();
}
diff --git a/cmds/incident_helper/ih_util.h b/cmds/incident_helper/ih_util.h
index 5598eed8d824..ce5baeef0dc3 100644
--- a/cmds/incident_helper/ih_util.h
+++ b/cmds/incident_helper/ih_util.h
@@ -28,10 +28,30 @@ typedef std::string (*trans_func) (const std::string&);
const char DEFAULT_NEWLINE = '\n';
const std::string DEFAULT_WHITESPACE = " \t";
+/**
+ * When a text has a table format like this
+ * line 1: HeadA HeadB HeadC
+ * line 2: v1 v2 v3
+ * line 3: v11 v12 v13
+ *
+ * We want to parse the line in structure given the delimiter.
+ * parseHeader is used to parse the firse line of the table and returns a list of strings in lower case
+ * parseRecord is used to parse other lines and returns a list of strings
+ * empty strings are skipped
+ */
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);
/**
+ * When the line starts with the given key, the function returns true
+ * as well as the line argument is changed to the rest part of the original.
+ * e.g. "ZRAM: 6828K physical used for 31076K in swap (524284K total swap)" becomes
+ * "6828K physical used for 31076K in swap (524284K total swap)" when given key "ZRAM:",
+ * otherwise the line is not changed.
+ */
+bool hasPrefix(std::string* line, const char* key);
+
+/**
* Reader class reads data from given fd in streaming fashion.
* The buffer size is controlled by capacity parameter.
*/
@@ -42,8 +62,8 @@ public:
Reader(const int fd, const size_t capacity);
~Reader();
- bool readLine(std::string& line, const char newline = DEFAULT_NEWLINE);
- bool ok(std::string& error);
+ bool readLine(std::string* line, const char newline = DEFAULT_NEWLINE);
+ bool ok(std::string* error);
private:
int mFd; // set mFd to -1 when read EOF()
diff --git a/cmds/incident_helper/main.cpp b/cmds/incident_helper/main.cpp
index 296d3001b7bb..52ff77720d70 100644
--- a/cmds/incident_helper/main.cpp
+++ b/cmds/incident_helper/main.cpp
@@ -48,6 +48,8 @@ static TextParserBase* selectParser(int section) {
// IDs larger than 1 are section ids reserved in incident.proto
case 2000:
return new ProcrankParser();
+ case 2001:
+ return new PageTypeInfoParser();
case 2002:
return new KernelWakesParser();
default:
diff --git a/cmds/incident_helper/testdata/pagetypeinfo.txt b/cmds/incident_helper/testdata/pagetypeinfo.txt
new file mode 100644
index 000000000000..d45ddc408c0f
--- /dev/null
+++ b/cmds/incident_helper/testdata/pagetypeinfo.txt
@@ -0,0 +1,10 @@
+Page block order: 10
+Pages per block: 1024
+
+Free pages count per migrate type at order 0 1 2 3 4 5 6 7 8 9 10
+Node 0, zone DMA, type Unmovable 426 279 226 1 1 1 0 0 2 2 0
+Node 0, zone Normal, type Reclaimable 953 773 437 154 92 26 15 14 12 7 0
+
+Number of blocks type Unmovable Reclaimable Movable CMA Reserve Isolate
+Node 0, zone DMA 74 9 337 41 1 0
+Node 0, zone Normal 70 12 423 0 1 0
diff --git a/cmds/incident_helper/tests/IncidentHelper_test.cpp b/cmds/incident_helper/tests/IncidentHelper_test.cpp
index 04dd8de11a15..c44a163efa11 100644
--- a/cmds/incident_helper/tests/IncidentHelper_test.cpp
+++ b/cmds/incident_helper/tests/IncidentHelper_test.cpp
@@ -17,6 +17,7 @@
#include "IncidentHelper.h"
#include "frameworks/base/core/proto/android/os/kernelwake.pb.h"
+#include "frameworks/base/core/proto/android/os/pagetypeinfo.pb.h"
#include "frameworks/base/core/proto/android/os/procrank.pb.h"
#include <android-base/file.h>
@@ -29,6 +30,7 @@
using namespace android::base;
using namespace android::os;
+using namespace std;
using ::testing::StrEq;
using ::testing::Test;
using ::testing::internal::CaptureStderr;
@@ -42,8 +44,8 @@ public:
ASSERT_TRUE(tf.fd != -1);
}
- std::string getSerializedString(::google::protobuf::Message& message) {
- std::string expectedStr;
+ string getSerializedString(::google::protobuf::Message& message) {
+ string expectedStr;
message.SerializeToFileDescriptor(tf.fd);
ReadFileToString(tf.path, &expectedStr);
return expectedStr;
@@ -52,8 +54,8 @@ public:
protected:
TemporaryFile tf;
- const std::string kTestPath = GetExecutableDirectory();
- const std::string kTestDataPath = kTestPath + "/testdata/";
+ const string kTestPath = GetExecutableDirectory();
+ const string kTestDataPath = kTestPath + "/testdata/";
};
TEST_F(IncidentHelperTest, ReverseParser) {
@@ -69,7 +71,7 @@ TEST_F(IncidentHelperTest, ReverseParser) {
}
TEST_F(IncidentHelperTest, KernelWakesParser) {
- const std::string testFile = kTestDataPath + "kernel_wakeups.txt";
+ const string testFile = kTestDataPath + "kernel_wakeups.txt";
KernelWakesParser parser;
KernelWakeSources expected;
@@ -107,7 +109,7 @@ TEST_F(IncidentHelperTest, KernelWakesParser) {
}
TEST_F(IncidentHelperTest, ProcrankParser) {
- const std::string testFile = kTestDataPath + "procrank.txt";
+ const string testFile = kTestDataPath + "procrank.txt";
ProcrankParser parser;
Procrank expected;
@@ -159,7 +161,7 @@ TEST_F(IncidentHelperTest, ProcrankParser) {
}
TEST_F(IncidentHelperTest, ProcrankParserShortHeader) {
- const std::string testFile = kTestDataPath + "procrank_short.txt";
+ const string testFile = kTestDataPath + "procrank_short.txt";
ProcrankParser parser;
Procrank expected;
@@ -195,3 +197,59 @@ TEST_F(IncidentHelperTest, ProcrankParserShortHeader) {
EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
close(fd);
}
+
+TEST_F(IncidentHelperTest, PageTypeInfoParser) {
+ const string testFile = kTestDataPath + "pagetypeinfo.txt";
+ PageTypeInfoParser parser;
+ PageTypeInfo expected;
+
+ expected.set_page_block_order(10);
+ expected.set_pages_per_block(1024);
+
+ MigrateTypeProto* mt1 = expected.add_migrate_types();
+ mt1->set_node(0);
+ mt1->set_zone("DMA");
+ mt1->set_type("Unmovable");
+ int arr1[] = { 426, 279, 226, 1, 1, 1, 0, 0, 2, 2, 0};
+ for (auto i=0; i<11; i++) {
+ mt1->add_free_pages_count(arr1[i]);
+ }
+
+ MigrateTypeProto* mt2 = expected.add_migrate_types();
+ mt2->set_node(0);
+ mt2->set_zone("Normal");
+ mt2->set_type("Reclaimable");
+ int arr2[] = { 953, 773, 437, 154, 92, 26, 15, 14, 12, 7, 0};
+ for (auto i=0; i<11; i++) {
+ mt2->add_free_pages_count(arr2[i]);
+ }
+
+ BlockProto* block1 = expected.add_blocks();
+ block1->set_node(0);
+ block1->set_zone("DMA");
+ block1->set_unmovable(74);
+ block1->set_reclaimable(9);
+ block1->set_movable(337);
+ block1->set_cma(41);
+ block1->set_reserve(1);
+ block1->set_isolate(0);
+
+
+ BlockProto* block2 = expected.add_blocks();
+ block2->set_node(0);
+ block2->set_zone("Normal");
+ block2->set_unmovable(70);
+ block2->set_reclaimable(12);
+ block2->set_movable(423);
+ block2->set_cma(0);
+ block2->set_reserve(1);
+ block2->set_isolate(0);
+
+ 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(), getSerializedString(expected));
+ close(fd);
+} \ No newline at end of file
diff --git a/cmds/incident_helper/tests/ih_util_test.cpp b/cmds/incident_helper/tests/ih_util_test.cpp
index 3b9ed403b77a..da88ee3a0120 100644
--- a/cmds/incident_helper/tests/ih_util_test.cpp
+++ b/cmds/incident_helper/tests/ih_util_test.cpp
@@ -69,14 +69,14 @@ TEST(IhUtilTest, Reader) {
Reader r(tf.fd);
string line;
- ASSERT_TRUE(r.readLine(line));
+ ASSERT_TRUE(r.readLine(&line));
EXPECT_THAT(line, StrEq("test string"));
- ASSERT_TRUE(r.readLine(line));
+ ASSERT_TRUE(r.readLine(&line));
EXPECT_THAT(line, StrEq("second"));
- ASSERT_TRUE(r.readLine(line));
+ ASSERT_TRUE(r.readLine(&line));
EXPECT_THAT(line, StrEq("ooo"));
- ASSERT_FALSE(r.readLine(line));
- ASSERT_TRUE(r.ok(line));
+ ASSERT_FALSE(r.readLine(&line));
+ ASSERT_TRUE(r.ok(&line));
}
TEST(IhUtilTest, ReaderSmallBufSize) {
@@ -86,14 +86,14 @@ TEST(IhUtilTest, ReaderSmallBufSize) {
Reader r(tf.fd, 5);
string line;
- ASSERT_TRUE(r.readLine(line));
+ ASSERT_TRUE(r.readLine(&line));
EXPECT_THAT(line, StrEq("test string"));
- ASSERT_TRUE(r.readLine(line));
+ ASSERT_TRUE(r.readLine(&line));
EXPECT_THAT(line, StrEq("second"));
- ASSERT_TRUE(r.readLine(line));
+ ASSERT_TRUE(r.readLine(&line));
EXPECT_THAT(line, StrEq("ooiecccojreo"));
- ASSERT_FALSE(r.readLine(line));
- ASSERT_TRUE(r.ok(line));
+ ASSERT_FALSE(r.readLine(&line));
+ ASSERT_TRUE(r.ok(&line));
}
TEST(IhUtilTest, ReaderEmpty) {
@@ -103,10 +103,10 @@ TEST(IhUtilTest, ReaderEmpty) {
Reader r(tf.fd);
string line;
- ASSERT_TRUE(r.readLine(line));
+ ASSERT_TRUE(r.readLine(&line));
EXPECT_THAT(line, StrEq(""));
- ASSERT_FALSE(r.readLine(line));
- ASSERT_TRUE(r.ok(line));
+ ASSERT_FALSE(r.readLine(&line));
+ ASSERT_TRUE(r.ok(&line));
}
TEST(IhUtilTest, ReaderMultipleEmptyLines) {
@@ -116,35 +116,35 @@ TEST(IhUtilTest, ReaderMultipleEmptyLines) {
Reader r(tf.fd);
string line;
- ASSERT_TRUE(r.readLine(line));
+ ASSERT_TRUE(r.readLine(&line));
EXPECT_THAT(line, StrEq(""));
- ASSERT_TRUE(r.readLine(line));
+ ASSERT_TRUE(r.readLine(&line));
EXPECT_THAT(line, StrEq(""));
- ASSERT_FALSE(r.readLine(line));
+ ASSERT_FALSE(r.readLine(&line));
EXPECT_THAT(line, StrEq(""));
- ASSERT_TRUE(r.ok(line));
+ ASSERT_TRUE(r.ok(&line));
}
TEST(IhUtilTest, ReaderFailedNegativeFd) {
Reader r(-123);
string line;
- EXPECT_FALSE(r.readLine(line));
- EXPECT_FALSE(r.ok(line));
+ EXPECT_FALSE(r.readLine(&line));
+ EXPECT_FALSE(r.ok(&line));
EXPECT_THAT(line, StrEq("Negative fd"));
}
TEST(IhUtilTest, ReaderFailedZeroBufferSize) {
Reader r(23, 0);
string line;
- EXPECT_FALSE(r.readLine(line));
- EXPECT_FALSE(r.ok(line));
+ EXPECT_FALSE(r.readLine(&line));
+ EXPECT_FALSE(r.ok(&line));
EXPECT_THAT(line, StrEq("Zero buffer capacity"));
}
TEST(IhUtilTest, ReaderFailedBadFd) {
Reader r(1231432);
string line;
- EXPECT_FALSE(r.readLine(line));
- EXPECT_FALSE(r.ok(line));
+ EXPECT_FALSE(r.readLine(&line));
+ EXPECT_FALSE(r.ok(&line));
EXPECT_THAT(line, StrEq("Fail to read from fd"));
}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index aab4142d252f..7331a64789b5 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -33,6 +33,7 @@ import "frameworks/base/core/proto/android/service/print.proto";
import "frameworks/base/core/proto/android/providers/settings.proto";
import "frameworks/base/core/proto/android/os/incidentheader.proto";
import "frameworks/base/core/proto/android/os/kernelwake.proto";
+import "frameworks/base/core/proto/android/os/pagetypeinfo.proto";
import "frameworks/base/core/proto/android/os/procrank.proto";
package android.os;
@@ -52,17 +53,24 @@ message IncidentProto {
(section).type = SECTION_COMMAND,
(section).args = "/system/xbin/procrank"
];
- //PageTypeInfo page_type_info = 2001;
+
+ PageTypeInfo page_type_info = 2001 [
+ (section).type = SECTION_FILE,
+ (section).args = "/proc/pagetypeinfo"
+ ];
+
KernelWakeSources kernel_wake_sources = 2002 [
(section).type = SECTION_FILE,
(section).args = "/d/wakeup_sources"
];
+
// System Services
android.service.fingerprint.FingerprintServiceDumpProto fingerprint = 3000 [
(section).type = SECTION_DUMPSYS,
(section).args = "fingerprint --proto --incident"
];
+
android.service.NetworkStatsServiceDumpProto netstats = 3001;
android.providers.settings.SettingsServiceDumpProto settings = 3002;
android.service.appwidget.AppWidgetServiceDumpProto appwidget = 3003;
diff --git a/core/proto/android/os/pagetypeinfo.proto b/core/proto/android/os/pagetypeinfo.proto
new file mode 100644
index 000000000000..fbb4ee52c3b0
--- /dev/null
+++ b/core/proto/android/os/pagetypeinfo.proto
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_outer_classname = "PageTypeInfoProto";
+
+package android.os;
+
+/*
+ * /proc/pagetypeinfo exports free memory distributions.
+ *
+ * For example, the order of a page ranges form 0 to 10.
+ * An order-0 page is 4 KB in size and 4 KB aligned.
+ * An order-1 page is 8 KB in size and 8 KB aligned.
+ * An order-10 page is 4096 KB in size and 4096 aligned.
+ * The memory has multiple zones, e.g. DMA zone, Normal zone
+ * Each zone has 11 free area. Each free area corresponds to pages of the same order.
+ * Each free area has 6 free list. Each corresponds to one migration type.
+ * The six migration types are Unmovable, Reclaimable, Movable, Reserve, CMA, and Isolate.
+ * Each zone has 11 * 6 = 66 free list.
+ *
+ * Next tag: 5
+ */
+message PageTypeInfo {
+
+ int32 page_block_order = 1;
+
+ int32 pages_per_block = 2;
+
+ repeated MigrateTypeProto migrate_types = 3;
+
+ repeated BlockProto blocks = 4;
+}
+
+// Next tag: 5
+message MigrateTypeProto {
+
+ int32 node = 1;
+
+ string zone = 2;
+
+ string type = 3;
+
+ // order level starts from 0 for 4KB to page_block_order defined above, e.g. 10 for 4096KB
+ repeated int32 free_pages_count = 4;
+}
+
+// Next tag: 9
+message BlockProto {
+
+ int32 node = 1;
+
+ string zone = 2;
+
+ int32 unmovable = 3;
+
+ int32 reclaimable = 4;
+
+ int32 movable = 5;
+
+ int32 cma = 6;
+
+ int32 reserve = 7;
+
+ int32 isolate = 8;
+}