Loading cmds/incident/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ cc_binary { ], static_libs: [ "libplatformprotos", "libprotoutil", ], cflags: [ Loading cmds/incident/main.cpp +26 −4 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <android/os/BnIncidentReportStatusListener.h> #include <android/os/IIncidentManager.h> #include <android/os/IncidentReportArgs.h> #include <android/util/ProtoOutputStream.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <utils/Looper.h> Loading @@ -36,6 +37,9 @@ using namespace android; using namespace android::base; using namespace android::binder; using namespace android::os; using android::util::FIELD_COUNT_SINGLE; using android::util::FIELD_TYPE_STRING; using android::util::ProtoOutputStream; // ================================================================================ class StatusListener : public BnIncidentReportStatusListener { Loading Loading @@ -129,11 +133,11 @@ static void section_list(FILE* out) { static IncidentSection const* find_section(const char* name) { size_t low = 0; size_t high = INCIDENT_SECTION_COUNT - 1; ssize_t low = 0; ssize_t high = INCIDENT_SECTION_COUNT - 1; while (low <= high) { size_t mid = (low + high) >> 1; ssize_t mid = (low + high) / 2; IncidentSection const* section = INCIDENT_SECTIONS + mid; int cmp = strcmp(section->name, name); Loading Loading @@ -208,6 +212,7 @@ usage(FILE* out) fprintf(out, "and one of these destinations:\n"); fprintf(out, " -b (default) print the report to stdout (in proto format)\n"); fprintf(out, " -d send the report into dropbox\n"); fprintf(out, " -r REASON human readable description of why the report is taken.\n"); fprintf(out, " -s PKG/CLS send broadcast to the broadcast receiver.\n"); fprintf(out, "\n"); fprintf(out, " SECTION the field numbers of the incident report fields to include\n"); Loading @@ -221,11 +226,12 @@ main(int argc, char** argv) IncidentReportArgs args; enum { DEST_UNSET, DEST_DROPBOX, DEST_STDOUT, DEST_BROADCAST } destination = DEST_UNSET; int privacyPolicy = PRIVACY_POLICY_AUTOMATIC; string reason; string receiverArg; // Parse the args int opt; while ((opt = getopt(argc, argv, "bhdlp:s:")) != -1) { while ((opt = getopt(argc, argv, "bhdlp:r:s:")) != -1) { switch (opt) { case 'h': usage(stdout); Loading @@ -250,6 +256,13 @@ main(int argc, char** argv) case 'p': privacyPolicy = get_privacy_policy(optarg); break; case 'r': if (reason.size() > 0) { usage(stderr); return 1; } reason = optarg; break; case 's': if (destination != DEST_UNSET) { usage(stderr); Loading Loading @@ -291,6 +304,7 @@ main(int argc, char** argv) } else { IncidentSection const* ic = find_section(arg); if (ic == NULL) { ALOGD("Invalid section: %s\n", arg); fprintf(stderr, "Invalid section: %s\n", arg); return 1; } Loading @@ -301,6 +315,14 @@ main(int argc, char** argv) } args.setPrivacyPolicy(privacyPolicy); if (reason.size() > 0) { ProtoOutputStream proto; proto.write(/* reason field id */ 2 | FIELD_TYPE_STRING | FIELD_COUNT_SINGLE, reason); vector<uint8_t> header; proto.serializeToVector(&header); args.addHeader(header); } // Start the thread pool. sp<ProcessState> ps(ProcessState::self()); ps->startThreadPool(); Loading libs/protoutil/include/android/util/ProtoOutputStream.h +2 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <cstdint> #include <string> #include <vector> #include <android/util/EncodedBuffer.h> Loading Loading @@ -124,6 +125,7 @@ public: sp<ProtoReader> data(); // Get the reader apis of the data. bool flush(int fd); // Flush data directly to a file descriptor. bool serializeToString(std::string* out); // Serializes the proto to a string. bool serializeToVector(std::vector<uint8_t>* out); // Serializes the proto to a vector<uint8_t>. /** * Clears the ProtoOutputStream so the buffer can be reused instead of deallocation/allocation again. Loading libs/protoutil/src/ProtoOutputStream.cpp +17 −1 Original line number Diff line number Diff line Loading @@ -454,7 +454,6 @@ ProtoOutputStream::serializeToString(std::string* out) if (out == nullptr) return false; if (!compact()) return false; sp<ProtoReader> reader = mBuffer->read(); out->reserve(reader->size()); while (reader->hasNext()) { Loading @@ -465,6 +464,23 @@ ProtoOutputStream::serializeToString(std::string* out) return true; } bool ProtoOutputStream::serializeToVector(std::vector<uint8_t>* out) { if (out == nullptr) return false; if (!compact()) return false; sp<ProtoReader> reader = mBuffer->read(); out->reserve(reader->size()); while (reader->hasNext()) { const uint8_t* buf = reader->readBuffer(); size_t size = reader->currentToRead(); out->insert(out->end(), buf, buf + size); reader->move(size); } return true; } sp<ProtoReader> ProtoOutputStream::data() { Loading libs/protoutil/tests/ProtoOutputStream_test.cpp +47 −0 Original line number Diff line number Diff line Loading @@ -132,6 +132,53 @@ TEST(ProtoOutputStreamTest, SerializeToStringPrimitives) { EXPECT_EQ(primitives.val_enum(), PrimitiveProto_Count_TWO); } TEST(ProtoOutputStreamTest, SerializeToVectorPrimitives) { std::string s = "hello"; const char b[5] = { 'a', 'p', 'p', 'l', 'e' }; ProtoOutputStream proto; EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | PrimitiveProto::kValInt32FieldNumber, 123)); EXPECT_TRUE(proto.write(FIELD_TYPE_INT64 | PrimitiveProto::kValInt64FieldNumber, -1LL)); EXPECT_TRUE(proto.write(FIELD_TYPE_FLOAT | PrimitiveProto::kValFloatFieldNumber, -23.5f)); EXPECT_TRUE(proto.write(FIELD_TYPE_DOUBLE | PrimitiveProto::kValDoubleFieldNumber, 324.5)); EXPECT_TRUE(proto.write(FIELD_TYPE_UINT32 | PrimitiveProto::kValUint32FieldNumber, 3424)); EXPECT_TRUE(proto.write(FIELD_TYPE_UINT64 | PrimitiveProto::kValUint64FieldNumber, 57LL)); EXPECT_TRUE(proto.write(FIELD_TYPE_FIXED32 | PrimitiveProto::kValFixed32FieldNumber, -20)); EXPECT_TRUE(proto.write(FIELD_TYPE_FIXED64 | PrimitiveProto::kValFixed64FieldNumber, -37LL)); EXPECT_TRUE(proto.write(FIELD_TYPE_BOOL | PrimitiveProto::kValBoolFieldNumber, true)); EXPECT_TRUE(proto.write(FIELD_TYPE_STRING | PrimitiveProto::kValStringFieldNumber, s)); EXPECT_TRUE(proto.write(FIELD_TYPE_BYTES | PrimitiveProto::kValBytesFieldNumber, b, 5)); EXPECT_TRUE(proto.write(FIELD_TYPE_SFIXED32 | PrimitiveProto::kValSfixed32FieldNumber, 63)); EXPECT_TRUE(proto.write(FIELD_TYPE_SFIXED64 | PrimitiveProto::kValSfixed64FieldNumber, -54)); EXPECT_TRUE(proto.write(FIELD_TYPE_SINT32 | PrimitiveProto::kValSint32FieldNumber, -533)); EXPECT_TRUE(proto.write(FIELD_TYPE_SINT64 | PrimitiveProto::kValSint64FieldNumber, -61224762453LL)); EXPECT_TRUE(proto.write(FIELD_TYPE_ENUM | PrimitiveProto::kValEnumFieldNumber, 2)); PrimitiveProto primitives; std::vector<uint8_t> vec; ASSERT_TRUE(proto.serializeToVector(&vec)); std::string serialized(vec.data(), vec.data() + vec.size()); ASSERT_TRUE(primitives.ParseFromString(serialized)); EXPECT_EQ(primitives.val_int32(), 123); EXPECT_EQ(primitives.val_int64(), -1); EXPECT_EQ(primitives.val_float(), -23.5f); EXPECT_EQ(primitives.val_double(), 324.5f); EXPECT_EQ(primitives.val_uint32(), 3424); EXPECT_EQ(primitives.val_uint64(), 57); EXPECT_EQ(primitives.val_fixed32(), -20); EXPECT_EQ(primitives.val_fixed64(), -37); EXPECT_EQ(primitives.val_bool(), true); EXPECT_THAT(primitives.val_string(), StrEq(s.c_str())); EXPECT_THAT(primitives.val_bytes(), StrEq("apple")); EXPECT_EQ(primitives.val_sfixed32(), 63); EXPECT_EQ(primitives.val_sfixed64(), -54); EXPECT_EQ(primitives.val_sint32(), -533); EXPECT_EQ(primitives.val_sint64(), -61224762453LL); EXPECT_EQ(primitives.val_enum(), PrimitiveProto_Count_TWO); } TEST(ProtoOutputStreamTest, Complex) { std::string name1 = "cat"; std::string name2 = "dog"; Loading Loading
cmds/incident/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ cc_binary { ], static_libs: [ "libplatformprotos", "libprotoutil", ], cflags: [ Loading
cmds/incident/main.cpp +26 −4 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <android/os/BnIncidentReportStatusListener.h> #include <android/os/IIncidentManager.h> #include <android/os/IncidentReportArgs.h> #include <android/util/ProtoOutputStream.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <utils/Looper.h> Loading @@ -36,6 +37,9 @@ using namespace android; using namespace android::base; using namespace android::binder; using namespace android::os; using android::util::FIELD_COUNT_SINGLE; using android::util::FIELD_TYPE_STRING; using android::util::ProtoOutputStream; // ================================================================================ class StatusListener : public BnIncidentReportStatusListener { Loading Loading @@ -129,11 +133,11 @@ static void section_list(FILE* out) { static IncidentSection const* find_section(const char* name) { size_t low = 0; size_t high = INCIDENT_SECTION_COUNT - 1; ssize_t low = 0; ssize_t high = INCIDENT_SECTION_COUNT - 1; while (low <= high) { size_t mid = (low + high) >> 1; ssize_t mid = (low + high) / 2; IncidentSection const* section = INCIDENT_SECTIONS + mid; int cmp = strcmp(section->name, name); Loading Loading @@ -208,6 +212,7 @@ usage(FILE* out) fprintf(out, "and one of these destinations:\n"); fprintf(out, " -b (default) print the report to stdout (in proto format)\n"); fprintf(out, " -d send the report into dropbox\n"); fprintf(out, " -r REASON human readable description of why the report is taken.\n"); fprintf(out, " -s PKG/CLS send broadcast to the broadcast receiver.\n"); fprintf(out, "\n"); fprintf(out, " SECTION the field numbers of the incident report fields to include\n"); Loading @@ -221,11 +226,12 @@ main(int argc, char** argv) IncidentReportArgs args; enum { DEST_UNSET, DEST_DROPBOX, DEST_STDOUT, DEST_BROADCAST } destination = DEST_UNSET; int privacyPolicy = PRIVACY_POLICY_AUTOMATIC; string reason; string receiverArg; // Parse the args int opt; while ((opt = getopt(argc, argv, "bhdlp:s:")) != -1) { while ((opt = getopt(argc, argv, "bhdlp:r:s:")) != -1) { switch (opt) { case 'h': usage(stdout); Loading @@ -250,6 +256,13 @@ main(int argc, char** argv) case 'p': privacyPolicy = get_privacy_policy(optarg); break; case 'r': if (reason.size() > 0) { usage(stderr); return 1; } reason = optarg; break; case 's': if (destination != DEST_UNSET) { usage(stderr); Loading Loading @@ -291,6 +304,7 @@ main(int argc, char** argv) } else { IncidentSection const* ic = find_section(arg); if (ic == NULL) { ALOGD("Invalid section: %s\n", arg); fprintf(stderr, "Invalid section: %s\n", arg); return 1; } Loading @@ -301,6 +315,14 @@ main(int argc, char** argv) } args.setPrivacyPolicy(privacyPolicy); if (reason.size() > 0) { ProtoOutputStream proto; proto.write(/* reason field id */ 2 | FIELD_TYPE_STRING | FIELD_COUNT_SINGLE, reason); vector<uint8_t> header; proto.serializeToVector(&header); args.addHeader(header); } // Start the thread pool. sp<ProcessState> ps(ProcessState::self()); ps->startThreadPool(); Loading
libs/protoutil/include/android/util/ProtoOutputStream.h +2 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <cstdint> #include <string> #include <vector> #include <android/util/EncodedBuffer.h> Loading Loading @@ -124,6 +125,7 @@ public: sp<ProtoReader> data(); // Get the reader apis of the data. bool flush(int fd); // Flush data directly to a file descriptor. bool serializeToString(std::string* out); // Serializes the proto to a string. bool serializeToVector(std::vector<uint8_t>* out); // Serializes the proto to a vector<uint8_t>. /** * Clears the ProtoOutputStream so the buffer can be reused instead of deallocation/allocation again. Loading
libs/protoutil/src/ProtoOutputStream.cpp +17 −1 Original line number Diff line number Diff line Loading @@ -454,7 +454,6 @@ ProtoOutputStream::serializeToString(std::string* out) if (out == nullptr) return false; if (!compact()) return false; sp<ProtoReader> reader = mBuffer->read(); out->reserve(reader->size()); while (reader->hasNext()) { Loading @@ -465,6 +464,23 @@ ProtoOutputStream::serializeToString(std::string* out) return true; } bool ProtoOutputStream::serializeToVector(std::vector<uint8_t>* out) { if (out == nullptr) return false; if (!compact()) return false; sp<ProtoReader> reader = mBuffer->read(); out->reserve(reader->size()); while (reader->hasNext()) { const uint8_t* buf = reader->readBuffer(); size_t size = reader->currentToRead(); out->insert(out->end(), buf, buf + size); reader->move(size); } return true; } sp<ProtoReader> ProtoOutputStream::data() { Loading
libs/protoutil/tests/ProtoOutputStream_test.cpp +47 −0 Original line number Diff line number Diff line Loading @@ -132,6 +132,53 @@ TEST(ProtoOutputStreamTest, SerializeToStringPrimitives) { EXPECT_EQ(primitives.val_enum(), PrimitiveProto_Count_TWO); } TEST(ProtoOutputStreamTest, SerializeToVectorPrimitives) { std::string s = "hello"; const char b[5] = { 'a', 'p', 'p', 'l', 'e' }; ProtoOutputStream proto; EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | PrimitiveProto::kValInt32FieldNumber, 123)); EXPECT_TRUE(proto.write(FIELD_TYPE_INT64 | PrimitiveProto::kValInt64FieldNumber, -1LL)); EXPECT_TRUE(proto.write(FIELD_TYPE_FLOAT | PrimitiveProto::kValFloatFieldNumber, -23.5f)); EXPECT_TRUE(proto.write(FIELD_TYPE_DOUBLE | PrimitiveProto::kValDoubleFieldNumber, 324.5)); EXPECT_TRUE(proto.write(FIELD_TYPE_UINT32 | PrimitiveProto::kValUint32FieldNumber, 3424)); EXPECT_TRUE(proto.write(FIELD_TYPE_UINT64 | PrimitiveProto::kValUint64FieldNumber, 57LL)); EXPECT_TRUE(proto.write(FIELD_TYPE_FIXED32 | PrimitiveProto::kValFixed32FieldNumber, -20)); EXPECT_TRUE(proto.write(FIELD_TYPE_FIXED64 | PrimitiveProto::kValFixed64FieldNumber, -37LL)); EXPECT_TRUE(proto.write(FIELD_TYPE_BOOL | PrimitiveProto::kValBoolFieldNumber, true)); EXPECT_TRUE(proto.write(FIELD_TYPE_STRING | PrimitiveProto::kValStringFieldNumber, s)); EXPECT_TRUE(proto.write(FIELD_TYPE_BYTES | PrimitiveProto::kValBytesFieldNumber, b, 5)); EXPECT_TRUE(proto.write(FIELD_TYPE_SFIXED32 | PrimitiveProto::kValSfixed32FieldNumber, 63)); EXPECT_TRUE(proto.write(FIELD_TYPE_SFIXED64 | PrimitiveProto::kValSfixed64FieldNumber, -54)); EXPECT_TRUE(proto.write(FIELD_TYPE_SINT32 | PrimitiveProto::kValSint32FieldNumber, -533)); EXPECT_TRUE(proto.write(FIELD_TYPE_SINT64 | PrimitiveProto::kValSint64FieldNumber, -61224762453LL)); EXPECT_TRUE(proto.write(FIELD_TYPE_ENUM | PrimitiveProto::kValEnumFieldNumber, 2)); PrimitiveProto primitives; std::vector<uint8_t> vec; ASSERT_TRUE(proto.serializeToVector(&vec)); std::string serialized(vec.data(), vec.data() + vec.size()); ASSERT_TRUE(primitives.ParseFromString(serialized)); EXPECT_EQ(primitives.val_int32(), 123); EXPECT_EQ(primitives.val_int64(), -1); EXPECT_EQ(primitives.val_float(), -23.5f); EXPECT_EQ(primitives.val_double(), 324.5f); EXPECT_EQ(primitives.val_uint32(), 3424); EXPECT_EQ(primitives.val_uint64(), 57); EXPECT_EQ(primitives.val_fixed32(), -20); EXPECT_EQ(primitives.val_fixed64(), -37); EXPECT_EQ(primitives.val_bool(), true); EXPECT_THAT(primitives.val_string(), StrEq(s.c_str())); EXPECT_THAT(primitives.val_bytes(), StrEq("apple")); EXPECT_EQ(primitives.val_sfixed32(), 63); EXPECT_EQ(primitives.val_sfixed64(), -54); EXPECT_EQ(primitives.val_sint32(), -533); EXPECT_EQ(primitives.val_sint64(), -61224762453LL); EXPECT_EQ(primitives.val_enum(), PrimitiveProto_Count_TWO); } TEST(ProtoOutputStreamTest, Complex) { std::string name1 = "cat"; std::string name2 = "dog"; Loading