diff options
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | cmds/incidentd/src/Privacy.cpp | 59 | ||||
-rw-r--r-- | cmds/incidentd/src/Privacy.h | 44 | ||||
-rw-r--r-- | cmds/incidentd/src/PrivacyBuffer.cpp | 23 | ||||
-rw-r--r-- | cmds/incidentd/src/Section.cpp | 4 | ||||
-rw-r--r-- | cmds/incidentd/src/io_util.cpp | 2 | ||||
-rw-r--r-- | cmds/incidentd/tests/PrivacyBuffer_test.cpp | 85 | ||||
-rw-r--r-- | cmds/incidentd/tests/Reporter_test.cpp | 2 | ||||
-rw-r--r-- | cmds/incidentd/tests/Section_test.cpp | 4 | ||||
-rw-r--r-- | cmds/incidentd/tests/section_list.cpp | 12 | ||||
-rw-r--r-- | core/proto/android/os/incident.proto | 4 | ||||
-rw-r--r-- | core/proto/android/os/procrank.proto | 10 | ||||
-rw-r--r-- | libs/incident/include/android/os/IncidentReportArgs.h | 12 | ||||
-rw-r--r-- | libs/incident/proto/android/privacy.proto | 19 | ||||
-rw-r--r-- | libs/incident/src/IncidentReportArgs.cpp | 4 | ||||
-rw-r--r-- | tools/incident_section_gen/main.cpp | 259 |
16 files changed, 317 insertions, 227 deletions
diff --git a/Android.bp b/Android.bp index 2ea489442b89..d8027c1315ec 100644 --- a/Android.bp +++ b/Android.bp @@ -65,6 +65,7 @@ cc_library { "core/proto/android/os/procrank.proto", "core/proto/android/os/system_properties.proto", "core/proto/android/service/graphicsstats.proto", + "libs/incident/proto/android/privacy.proto", "tools/streaming_proto/stream.proto", ], shared: { diff --git a/cmds/incidentd/src/Privacy.cpp b/cmds/incidentd/src/Privacy.cpp index 140b12c8c97a..5db2239810e2 100644 --- a/cmds/incidentd/src/Privacy.cpp +++ b/cmds/incidentd/src/Privacy.cpp @@ -16,37 +16,18 @@ #include "Privacy.h" +#include <android/os/IncidentReportArgs.h> #include <stdlib.h> -// DESTINATION enum value -const uint8_t DEST_LOCAL = 0; -const uint8_t DEST_EXPLICIT = 1; -const uint8_t DEST_AUTOMATIC = 2; +uint64_t encode_field_id(const Privacy* p) { return (uint64_t)p->type << 32 | p->field_id; } -// type of the field, identitical to protobuf definition -const uint8_t TYPE_STRING = 9; -const uint8_t TYPE_MESSAGE = 11; - -bool -Privacy::IsMessageType() const { return type == TYPE_MESSAGE; } - -uint64_t -Privacy::EncodedFieldId() const { return (uint64_t)type << 32 | field_id; } - -bool -Privacy::IsStringType() const { return type == TYPE_STRING; } - -bool -Privacy::HasChildren() const { return children != NULL && children[0] != NULL; } - -const Privacy* -Privacy::lookup(uint32_t fieldId) const +const Privacy* lookup(const Privacy* p, uint32_t fieldId) { - if (children == NULL) return NULL; - for (int i=0; children[i] != NULL; i++) { - if (children[i]->field_id == fieldId) return children[i]; - // This assumes the list's field id is in ascending order and must be true. - if (children[i]->field_id > fieldId) return NULL; + if (p->children == NULL) return NULL; + for (int i=0; p->children[i] != NULL; i++) { // NULL-terminated. + if (p->children[i]->field_id == fieldId) return p->children[i]; + // Incident section gen tool guarantees field ids in ascending order. + if (p->children[i]->field_id > fieldId) return NULL; } return NULL; } @@ -54,11 +35,14 @@ Privacy::lookup(uint32_t fieldId) const static bool allowDest(const uint8_t dest, const uint8_t policy) { switch (policy) { - case DEST_LOCAL: - return dest == DEST_LOCAL; - case DEST_EXPLICIT: - return dest == DEST_LOCAL || dest == DEST_EXPLICIT; - case DEST_AUTOMATIC: + case android::os::DEST_LOCAL: + return dest == android::os::DEST_LOCAL; + case android::os::DEST_EXPLICIT: + case DEST_UNSET: + return dest == android::os::DEST_LOCAL || + dest == android::os::DEST_EXPLICIT || + dest == DEST_UNSET; + case android::os::DEST_AUTOMATIC: return true; default: return false; @@ -72,18 +56,19 @@ PrivacySpec::operator<(const PrivacySpec& other) const } bool -PrivacySpec::CheckPremission(const Privacy* privacy) const +PrivacySpec::CheckPremission(const Privacy* privacy, const uint8_t defaultDest) const { - uint8_t policy = privacy == NULL ? DEST_DEFAULT_VALUE : privacy->dest; + uint8_t policy = privacy != NULL ? privacy->dest : defaultDest; return allowDest(dest, policy); } bool -PrivacySpec::RequireAll() const { return dest == DEST_LOCAL; } +PrivacySpec::RequireAll() const { return dest == android::os::DEST_LOCAL; } -PrivacySpec new_spec_from_args(int dest) { +PrivacySpec new_spec_from_args(int dest) +{ if (dest < 0) return PrivacySpec(); return PrivacySpec(dest); } -PrivacySpec get_default_dropbox_spec() { return PrivacySpec(DEST_AUTOMATIC); }
\ No newline at end of file +PrivacySpec get_default_dropbox_spec() { return PrivacySpec(android::os::DEST_AUTOMATIC); }
\ No newline at end of file diff --git a/cmds/incidentd/src/Privacy.h b/cmds/incidentd/src/Privacy.h index f514f196a205..9e15ff43be06 100644 --- a/cmds/incidentd/src/Privacy.h +++ b/cmds/incidentd/src/Privacy.h @@ -19,35 +19,46 @@ #include <stdint.h> -// This is the default value of DEST enum -const uint8_t DEST_DEFAULT_VALUE = 1; +// This is the default value of DEST enum, sync with privacy.proto +const uint8_t DEST_UNSET = 255; // DEST_UNSET is not exposed to libincident +const uint8_t DEST_DEFAULT_VALUE = DEST_UNSET; /* - * In order not to depend on libprotobuf-cpp-full nor libplatformprotos in incidentd, - * privacy options's data structure are explicitly redefined in this file. + * In order to NOT auto-generate large chuck of code by proto compiler in incidentd, + * privacy options's data structure are explicitly redefined here and + * the values are populated by incident_section_gen tool. + * + * Each proto field will have a Privacy when it is different from its parent, otherwise + * it uses its parent's tag. A message type will have an array of Privacy. */ struct Privacy { + // The field number uint32_t field_id; + + // The field type, see external/protobuf/src/google/protobuf/descriptor.h uint8_t type; - // ignore parent's privacy flags if children are set, NULL-terminated + + // If children is null, it is a primitive field, + // otherwise it is a message field which could have overridden privacy tags here. + // This array is NULL-terminated. Privacy** children; - // the following fields are identitical to - // frameworks/base/libs/incident/proto/android/privacy.proto + // DESTINATION Enum in frameworks/base/libs/incident/proto/android/privacy.proto. uint8_t dest; - const char** patterns; // only set when type is string + // A list of regexp rules for stripping string fields in proto. + const char** patterns; +}; - bool IsMessageType() const; - bool IsStringType() const; - bool HasChildren() const; - uint64_t EncodedFieldId() const; +// Encode field id used by ProtoOutputStream. +uint64_t encode_field_id(const Privacy* p); - const Privacy* lookup(uint32_t fieldId) const; -}; +// Look up the child with given fieldId, if not found, return NULL. +const Privacy* lookup(const Privacy* p, uint32_t fieldId); /** * PrivacySpec defines the request has what level of privacy authorization. * For example, a device without user consent should only be able to upload AUTOMATIC fields. + * DEST_UNSET are treated as DEST_EXPLICIT. */ class PrivacySpec { public: @@ -58,7 +69,10 @@ public: bool operator<(const PrivacySpec& other) const; - bool CheckPremission(const Privacy* privacy) const; + // check permission of a policy, if returns true, don't strip the data. + bool CheckPremission(const Privacy* privacy, const uint8_t defaultDest = DEST_DEFAULT_VALUE) const; + + // if returns true, no data need to be stripped. bool RequireAll() const; }; diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp index 77ae1a7ec730..03faa9290666 100644 --- a/cmds/incidentd/src/PrivacyBuffer.cpp +++ b/cmds/incidentd/src/PrivacyBuffer.cpp @@ -14,15 +14,18 @@ * limitations under the License. */ - +#define LOG_TAG "incidentd" #include "PrivacyBuffer.h" #include "io_util.h" #include <android/util/protobuf.h> +#include <cutils/log.h> using namespace android::util; +const bool DEBUG = false; + /** * Write the field to buf based on the wire type, iterator will point to next field. * If skip is set to true, no data will be written to buf. Return number of bytes written. @@ -30,6 +33,9 @@ using namespace android::util; void PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip) { + if (DEBUG) ALOGD("%s field %d (wiretype = %d)", skip ? "skip" : "write", + read_field_id(fieldTag), read_wire_type(fieldTag)); + uint8_t wireType = read_wire_type(fieldTag); size_t bytesToWrite = 0; uint32_t varint = 0; @@ -55,6 +61,7 @@ PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip) bytesToWrite = 4; break; } + if (DEBUG) ALOGD("%s %d bytes of data", skip ? "skip" : "write", (int)bytesToWrite); if (skip) { mData.rp()->move(bytesToWrite); } else { @@ -76,10 +83,13 @@ PrivacyBuffer::stripField(const Privacy* parentPolicy, const PrivacySpec& spec) { if (!mData.hasNext() || parentPolicy == NULL) return BAD_VALUE; uint32_t fieldTag = mData.readRawVarint(); - const Privacy* policy = parentPolicy->lookup(read_field_id(fieldTag)); + const Privacy* policy = lookup(parentPolicy, read_field_id(fieldTag)); + + if (policy == NULL || policy->children == NULL) { + if (DEBUG) ALOGD("Not a message field %d: dest(%d)", read_field_id(fieldTag), + policy != NULL ? policy->dest : parentPolicy->dest); - if (policy == NULL || !policy->IsMessageType() || !policy->HasChildren()) { - bool skip = !spec.CheckPremission(policy); + bool skip = !spec.CheckPremission(policy, parentPolicy->dest); // iterator will point to head of next field writeFieldOrSkip(fieldTag, skip); return NO_ERROR; @@ -87,7 +97,7 @@ PrivacyBuffer::stripField(const Privacy* parentPolicy, const PrivacySpec& spec) // current field is message type and its sub-fields have extra privacy policies uint32_t msgSize = mData.readRawVarint(); EncodedBuffer::Pointer start = mData.rp()->copy(); - long long token = mProto.start(policy->EncodedFieldId()); + long long token = mProto.start(encode_field_id(policy)); while (mData.rp()->pos() - start.pos() != msgSize) { status_t err = stripField(policy, spec); if (err != NO_ERROR) return err; @@ -112,8 +122,9 @@ PrivacyBuffer::~PrivacyBuffer() status_t PrivacyBuffer::strip(const PrivacySpec& spec) { + if (DEBUG) ALOGD("Strip with spec %d", spec.dest); // optimization when no strip happens - if (mPolicy == NULL || !mPolicy->HasChildren() || spec.RequireAll()) { + if (mPolicy == NULL || mPolicy->children == NULL || spec.RequireAll()) { if (spec.CheckPremission(mPolicy)) mSize = mData.size(); return NO_ERROR; } diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp index c08b9ea80c04..1bf795bb6557 100644 --- a/cmds/incidentd/src/Section.cpp +++ b/cmds/incidentd/src/Section.cpp @@ -210,9 +210,9 @@ HeaderSection::Execute(ReportRequestSet* requests) const { for (ReportRequestSet::iterator it=requests->begin(); it!=requests->end(); it++) { const sp<ReportRequest> request = *it; - const vector<vector<int8_t>>& headers = request->args.headers(); + const vector<vector<uint8_t>>& headers = request->args.headers(); - for (vector<vector<int8_t>>::const_iterator buf=headers.begin(); buf!=headers.end(); buf++) { + for (vector<vector<uint8_t>>::const_iterator buf=headers.begin(); buf!=headers.end(); buf++) { if (buf->empty()) continue; // So the idea is only requests with negative fd are written to dropbox file. diff --git a/cmds/incidentd/src/io_util.cpp b/cmds/incidentd/src/io_util.cpp index f043d367d982..af4a35cc0015 100644 --- a/cmds/incidentd/src/io_util.cpp +++ b/cmds/incidentd/src/io_util.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define LOG_TAG "incidentd" + #include "io_util.h" #include <unistd.h> diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp index ca9462394493..32b9e42d270c 100644 --- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp +++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp @@ -12,27 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. +#define LOG_TAG "incidentd" + #include "FdBuffer.h" #include "PrivacyBuffer.h" #include <android-base/file.h> #include <android-base/test_utils.h> +#include <android/os/IncidentReportArgs.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <string.h> using namespace android; using namespace android::base; +using namespace android::os; using namespace std; using ::testing::StrEq; using ::testing::Test; using ::testing::internal::CaptureStdout; using ::testing::internal::GetCapturedStdout; -const uint8_t LOCAL = 0; -const uint8_t EXPLICIT = 1; -const uint8_t AUTOMATIC = 2; - const uint8_t OTHER_TYPE = 1; const uint8_t STRING_TYPE = 9; const uint8_t MESSAGE_TYPE = 11; @@ -109,21 +109,11 @@ public: p->field_id = field_id; p->type = MESSAGE_TYPE; p->children = children; - p->dest = EXPLICIT; + p->dest = DEST_DEFAULT_VALUE; p->patterns = NULL; return p; } - Privacy* create_string_privacy(uint32_t field_id, uint8_t dest, const char** patterns) { - Privacy* p = new_uninit_privacy(); - p->field_id = field_id; - p->type = STRING_TYPE; - p->children = NULL; - p->dest = dest; - p->patterns = patterns; - return p; - } - FdBuffer buffer; private: TemporaryFile tf; @@ -138,103 +128,103 @@ private: } }; -TEST_F(PrivacyBufferTest, NullFieldPolicy) { +TEST_F(PrivacyBufferTest, NullPolicy) { writeToFdBuffer(STRING_FIELD_0); - assertStrip(EXPLICIT, STRING_FIELD_0, create_string_privacy(300, AUTOMATIC, NULL)); + assertStrip(DEST_EXPLICIT, STRING_FIELD_0, NULL); } -TEST_F(PrivacyBufferTest, StripSpecNotAllowed) { +TEST_F(PrivacyBufferTest, StripUnsetField) { writeToFdBuffer(STRING_FIELD_0); - assertStripByFields(AUTOMATIC, "", 1, create_privacy(0, STRING_TYPE, EXPLICIT)); + assertStripByFields(DEST_AUTOMATIC, "", 1, create_privacy(0, STRING_TYPE, DEST_UNSET)); } TEST_F(PrivacyBufferTest, StripVarintField) { writeToFdBuffer(VARINT_FIELD_1); - assertStripByFields(EXPLICIT, "", 1, create_privacy(1, OTHER_TYPE, LOCAL)); + assertStripByFields(DEST_EXPLICIT, "", 1, create_privacy(1, OTHER_TYPE, DEST_LOCAL)); } TEST_F(PrivacyBufferTest, StripLengthDelimitedField_String) { writeToFdBuffer(STRING_FIELD_2); - assertStripByFields(EXPLICIT, "", 1, create_privacy(2, STRING_TYPE, LOCAL)); + assertStripByFields(DEST_EXPLICIT, "", 1, create_privacy(2, STRING_TYPE, DEST_LOCAL)); } TEST_F(PrivacyBufferTest, StripFixed64Field) { writeToFdBuffer(FIX64_FIELD_3); - assertStripByFields(EXPLICIT, "", 1, create_privacy(3, OTHER_TYPE, LOCAL)); + assertStripByFields(DEST_EXPLICIT, "", 1, create_privacy(3, OTHER_TYPE, DEST_LOCAL)); } TEST_F(PrivacyBufferTest, StripFixed32Field) { writeToFdBuffer(FIX32_FIELD_4); - assertStripByFields(EXPLICIT, "", 1, create_privacy(4, OTHER_TYPE, LOCAL)); + assertStripByFields(DEST_EXPLICIT, "", 1, create_privacy(4, OTHER_TYPE, DEST_LOCAL)); } TEST_F(PrivacyBufferTest, StripLengthDelimitedField_Message) { writeToFdBuffer(MESSAGE_FIELD_5); - assertStripByFields(EXPLICIT, "", 1, create_privacy(5, MESSAGE_TYPE, LOCAL)); + assertStripByFields(DEST_EXPLICIT, "", 1, create_privacy(5, MESSAGE_TYPE, DEST_LOCAL)); } TEST_F(PrivacyBufferTest, NoStripVarintField) { writeToFdBuffer(VARINT_FIELD_1); - assertStripByFields(EXPLICIT, VARINT_FIELD_1, 1, create_privacy(1, OTHER_TYPE, AUTOMATIC)); + assertStripByFields(DEST_EXPLICIT, VARINT_FIELD_1, 1, create_privacy(1, OTHER_TYPE, DEST_AUTOMATIC)); } TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_String) { writeToFdBuffer(STRING_FIELD_2); - assertStripByFields(EXPLICIT, STRING_FIELD_2, 1, create_privacy(2, STRING_TYPE, AUTOMATIC)); + assertStripByFields(DEST_EXPLICIT, STRING_FIELD_2, 1, create_privacy(2, STRING_TYPE, DEST_AUTOMATIC)); } TEST_F(PrivacyBufferTest, NoStripFixed64Field) { writeToFdBuffer(FIX64_FIELD_3); - assertStripByFields(EXPLICIT, FIX64_FIELD_3, 1, create_privacy(3, OTHER_TYPE, AUTOMATIC)); + assertStripByFields(DEST_EXPLICIT, FIX64_FIELD_3, 1, create_privacy(3, OTHER_TYPE, DEST_AUTOMATIC)); } TEST_F(PrivacyBufferTest, NoStripFixed32Field) { writeToFdBuffer(FIX32_FIELD_4); - assertStripByFields(EXPLICIT, FIX32_FIELD_4, 1, create_privacy(4, OTHER_TYPE, AUTOMATIC)); + assertStripByFields(DEST_EXPLICIT, FIX32_FIELD_4, 1, create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC)); } TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_Message) { writeToFdBuffer(MESSAGE_FIELD_5); - assertStripByFields(EXPLICIT, MESSAGE_FIELD_5, 1, create_privacy(5, MESSAGE_TYPE, AUTOMATIC)); + assertStripByFields(DEST_EXPLICIT, MESSAGE_FIELD_5, 1, create_privacy(5, MESSAGE_TYPE, DEST_AUTOMATIC)); } TEST_F(PrivacyBufferTest, StripVarintAndString) { writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3 + FIX32_FIELD_4); string expected = STRING_FIELD_0 + FIX64_FIELD_3 + FIX32_FIELD_4; - assertStripByFields(EXPLICIT, expected, 2, - create_privacy(1, OTHER_TYPE, LOCAL), create_privacy(2, STRING_TYPE, LOCAL)); + assertStripByFields(DEST_EXPLICIT, expected, 2, + create_privacy(1, OTHER_TYPE, DEST_LOCAL), create_privacy(2, STRING_TYPE, DEST_LOCAL)); } TEST_F(PrivacyBufferTest, StripVarintAndFixed64) { writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3 + FIX32_FIELD_4); string expected = STRING_FIELD_0 + STRING_FIELD_2 + FIX32_FIELD_4; - assertStripByFields(EXPLICIT, expected, 2, - create_privacy(1, OTHER_TYPE, LOCAL), create_privacy(3, OTHER_TYPE, LOCAL)); + assertStripByFields(DEST_EXPLICIT, expected, 2, + create_privacy(1, OTHER_TYPE, DEST_LOCAL), create_privacy(3, OTHER_TYPE, DEST_LOCAL)); } TEST_F(PrivacyBufferTest, StripVarintInNestedMessage) { writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5); - Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL }; + Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL }; string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2; - assertStripByFields(EXPLICIT, expected, 1, create_message_privacy(5, list)); + assertStripByFields(DEST_EXPLICIT, expected, 1, create_message_privacy(5, list)); } TEST_F(PrivacyBufferTest, StripFix64AndVarintInNestedMessage) { writeToFdBuffer(STRING_FIELD_0 + FIX64_FIELD_3 + MESSAGE_FIELD_5); - Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL }; + Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL }; string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2; - assertStripByFields(EXPLICIT, expected, 2, create_privacy(3, OTHER_TYPE, LOCAL), create_message_privacy(5, list)); + assertStripByFields(DEST_EXPLICIT, expected, 2, create_privacy(3, OTHER_TYPE, DEST_LOCAL), create_message_privacy(5, list)); } TEST_F(PrivacyBufferTest, ClearAndStrip) { string data = STRING_FIELD_0 + VARINT_FIELD_1; writeToFdBuffer(data); - Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL }; + Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL }; EncodedBuffer::iterator bufData = buffer.data(); PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData); - PrivacySpec spec1(EXPLICIT), spec2(LOCAL); + PrivacySpec spec1(DEST_EXPLICIT), spec2(DEST_LOCAL); ASSERT_EQ(privacyBuf.strip(spec1), NO_ERROR); assertBuffer(privacyBuf, STRING_FIELD_0); @@ -244,7 +234,7 @@ TEST_F(PrivacyBufferTest, ClearAndStrip) { TEST_F(PrivacyBufferTest, BadDataInFdBuffer) { writeToFdBuffer("iambaddata"); - Privacy* list[] = { create_privacy(4, OTHER_TYPE, AUTOMATIC), NULL }; + Privacy* list[] = { create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC), NULL }; EncodedBuffer::iterator bufData = buffer.data(); PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData); PrivacySpec spec; @@ -253,7 +243,7 @@ TEST_F(PrivacyBufferTest, BadDataInFdBuffer) { TEST_F(PrivacyBufferTest, BadDataInNestedMessage) { writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5 + "aoeoe"); - Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL }; + Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL }; Privacy* field5[] = { create_message_privacy(5, list), NULL }; EncodedBuffer::iterator bufData = buffer.data(); PrivacyBuffer privacyBuf(create_message_privacy(300, field5), bufData); @@ -265,8 +255,17 @@ TEST_F(PrivacyBufferTest, SelfRecursionMessage) { string input = "\x2a\"" + VARINT_FIELD_1 + STRING_FIELD_2 + MESSAGE_FIELD_5; writeToFdBuffer(input); Privacy* field5 = create_message_privacy(5, NULL); - Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), field5, NULL }; + Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), field5, NULL }; field5->children = list; string expected = "\x2a\x1c" + STRING_FIELD_2 + "\x2a\xd" + STRING_FIELD_2; - assertStrip(EXPLICIT, expected, field5); + assertStrip(DEST_EXPLICIT, expected, field5); } + +TEST_F(PrivacyBufferTest, AutoMessage) { + writeToFdBuffer(STRING_FIELD_2 + MESSAGE_FIELD_5); + Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL }; + Privacy* autoMsg = create_privacy(5, MESSAGE_TYPE, DEST_AUTOMATIC); + autoMsg->children = list; + string expected = "\x2a\xd" + STRING_FIELD_2; + assertStripByFields(DEST_AUTOMATIC, expected, 1, autoMsg); +}
\ No newline at end of file diff --git a/cmds/incidentd/tests/Reporter_test.cpp b/cmds/incidentd/tests/Reporter_test.cpp index 8d99fc7dbbbc..531c9f29bf03 100644 --- a/cmds/incidentd/tests/Reporter_test.cpp +++ b/cmds/incidentd/tests/Reporter_test.cpp @@ -141,7 +141,7 @@ TEST_F(ReporterTest, RunReportWithHeaders) { IncidentReportArgs args1, args2; args1.addSection(1); args2.addSection(2); - std::vector<int8_t> header {'a', 'b', 'c', 'd', 'e'}; + std::vector<uint8_t> header {'a', 'b', 'c', 'd', 'e'}; args2.addHeader(header); sp<ReportRequest> r1 = new ReportRequest(args1, l, tf.fd); sp<ReportRequest> r2 = new ReportRequest(args2, l, tf.fd); diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp index 649e908a83c4..0c7876c1ecfb 100644 --- a/cmds/incidentd/tests/Section_test.cpp +++ b/cmds/incidentd/tests/Section_test.cpp @@ -66,12 +66,12 @@ TEST(SectionTest, HeaderSection) { args1.addSection(2); args2.setAll(true); - vector<int8_t> head1; + vector<uint8_t> head1; head1.push_back('a'); head1.push_back('x'); head1.push_back('e'); - vector<int8_t> head2; + vector<uint8_t> head2; head2.push_back('p'); head2.push_back('u'); head2.push_back('p'); diff --git a/cmds/incidentd/tests/section_list.cpp b/cmds/incidentd/tests/section_list.cpp index 4acc4298ab82..1d6213fd19b3 100644 --- a/cmds/incidentd/tests/section_list.cpp +++ b/cmds/incidentd/tests/section_list.cpp @@ -5,20 +5,16 @@ const Section* SECTION_LIST[] = { NULL }; -const uint8_t LOCAL = 0; -const uint8_t EXPLICIT = 1; -const uint8_t AUTOMATIC = 2; - -Privacy sub_field_1 { 1, 1, NULL, LOCAL, NULL }; -Privacy sub_field_2 { 2, 9, NULL, AUTOMATIC, NULL }; +Privacy sub_field_1 { 1, 1, NULL, DEST_LOCAL, NULL }; +Privacy sub_field_2 { 2, 9, NULL, DEST_AUTOMATIC, NULL }; Privacy* list[] = { &sub_field_1, &sub_field_2, NULL }; -Privacy field_0 { 0, 11, list, EXPLICIT, NULL }; -Privacy field_1 { 1, 9, NULL, AUTOMATIC, NULL }; +Privacy field_0 { 0, 11, list, DEST_EXPLICIT, NULL }; +Privacy field_1 { 1, 9, NULL, DEST_AUTOMATIC, NULL }; Privacy* final_list[] = { &field_0, diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto index ecdabcf98f39..29888d71856f 100644 --- a/core/proto/android/os/incident.proto +++ b/core/proto/android/os/incident.proto @@ -18,8 +18,6 @@ syntax = "proto2"; option java_multiple_files = true; option java_outer_classname = "IncidentProtoMetadata"; -import "frameworks/base/libs/incident/proto/android/privacy.proto"; -import "frameworks/base/libs/incident/proto/android/section.proto"; import "frameworks/base/core/proto/android/os/cpufreq.proto"; import "frameworks/base/core/proto/android/os/cpuinfo.proto"; import "frameworks/base/core/proto/android/os/incidentheader.proto"; @@ -42,6 +40,8 @@ import "frameworks/base/core/proto/android/service/notification.proto"; import "frameworks/base/core/proto/android/service/package.proto"; import "frameworks/base/core/proto/android/service/print.proto"; import "frameworks/base/core/proto/android/service/procstats.proto"; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; +import "frameworks/base/libs/incident/proto/android/section.proto"; package android.os; diff --git a/core/proto/android/os/procrank.proto b/core/proto/android/os/procrank.proto index 9945f2e792a9..f684c84c12e9 100644 --- a/core/proto/android/os/procrank.proto +++ b/core/proto/android/os/procrank.proto @@ -18,12 +18,15 @@ syntax = "proto2"; option java_multiple_files = true; option java_outer_classname = "ProcrankProto"; +import "frameworks/base/libs/incident/proto/android/privacy.proto"; import "frameworks/base/tools/streaming_proto/stream.proto"; package android.os; //Memory usage of running processes message Procrank { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + // Currently running process repeated ProcessProto processes = 1; @@ -34,6 +37,7 @@ message Procrank { // Next Tag: 11 message ProcessProto { option (stream_proto.stream_msg).enable_fields_mapping = true; + option (android.msg_privacy).dest = DEST_AUTOMATIC; // ID of the process optional int32 pid = 1; @@ -68,6 +72,8 @@ message ProcessProto { // Next Tag: 3 message SummaryProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + optional ProcessProto total = 1; optional ZramProto zram = 2; @@ -77,9 +83,13 @@ message SummaryProto { // TODO: sync on how to use these values message ZramProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + optional string raw_text = 1; } message RamProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + optional string raw_text = 1; } diff --git a/libs/incident/include/android/os/IncidentReportArgs.h b/libs/incident/include/android/os/IncidentReportArgs.h index da8098970962..2849d580d88b 100644 --- a/libs/incident/include/android/os/IncidentReportArgs.h +++ b/libs/incident/include/android/os/IncidentReportArgs.h @@ -29,6 +29,12 @@ namespace os { using namespace std; +// DESTINATION enum value, sync with proto/android/privacy.proto +const uint8_t DEST_LOCAL = 0; +const uint8_t DEST_EXPLICIT = 100; +const uint8_t DEST_AUTOMATIC = 200; + + class IncidentReportArgs : public Parcelable { public: IncidentReportArgs(); @@ -41,19 +47,19 @@ public: void setAll(bool all); void setDest(int dest); void addSection(int section); - void addHeader(const vector<int8_t>& header); + void addHeader(const vector<uint8_t>& header); inline bool all() const { return mAll; } bool containsSection(int section) const; inline int dest() const { return mDest; } inline const set<int>& sections() const { return mSections; } - inline const vector<vector<int8_t>>& headers() const { return mHeaders; } + inline const vector<vector<uint8_t>>& headers() const { return mHeaders; } void merge(const IncidentReportArgs& that); private: set<int> mSections; - vector<vector<int8_t>> mHeaders; + vector<vector<uint8_t>> mHeaders; bool mAll; int mDest; }; diff --git a/libs/incident/proto/android/privacy.proto b/libs/incident/proto/android/privacy.proto index 5fd75d6f2809..7590b22486c5 100644 --- a/libs/incident/proto/android/privacy.proto +++ b/libs/incident/proto/android/privacy.proto @@ -34,21 +34,23 @@ enum Destination { // Fields or messages annotated with DEST_EXPLICIT can be sent // off the device with an explicit user action. - DEST_EXPLICIT = 1; + DEST_EXPLICIT = 100; // Fields or messages annotated with DEST_AUTOMATIC can be sent by // automatic means, without per-sending user consent. The user // still must have previously accepted a consent to share this // information. - DEST_AUTOMATIC = 2; + DEST_AUTOMATIC = 200; - // There is no more permissive option than DEST_AUTOMATIC. + // This is the default value, which could be overridden by other values. + // The reason to pick 255 is it fits into one byte. + DEST_UNSET = 255; + + // Currently use 0, 100, 200 and 255, values in between are reserved for futures. } message PrivacyFlags { - optional Destination dest = 1 [ - default = DEST_EXPLICIT - ]; + optional Destination dest = 1 [ default = DEST_UNSET ]; // regex to filter pii sensitive info from a string field type repeated string patterns = 2; @@ -58,3 +60,8 @@ extend google.protobuf.FieldOptions { // Flags for automatically filtering statistics optional PrivacyFlags privacy = 102672883; } + +extend google.protobuf.MessageOptions { + // Flags used to annotate a message which all its unset primitive types inhert this tag. + optional PrivacyFlags msg_privacy = 102672883; +} diff --git a/libs/incident/src/IncidentReportArgs.cpp b/libs/incident/src/IncidentReportArgs.cpp index e62872238387..bd9c8eeb1d74 100644 --- a/libs/incident/src/IncidentReportArgs.cpp +++ b/libs/incident/src/IncidentReportArgs.cpp @@ -69,7 +69,7 @@ IncidentReportArgs::writeToParcel(Parcel* out) const return err; } - for (vector<vector<int8_t>>::const_iterator it = mHeaders.begin(); it != mHeaders.end(); it++) { + for (vector<vector<uint8_t>>::const_iterator it = mHeaders.begin(); it != mHeaders.end(); it++) { err = out->writeByteVector(*it); if (err != NO_ERROR) { return err; @@ -161,7 +161,7 @@ IncidentReportArgs::addSection(int section) } void -IncidentReportArgs::addHeader(const vector<int8_t>& header) +IncidentReportArgs::addHeader(const vector<uint8_t>& header) { mHeaders.push_back(header); } diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp index 674bee139186..765079507513 100644 --- a/tools/incident_section_gen/main.cpp +++ b/tools/incident_section_gen/main.cpp @@ -59,24 +59,31 @@ using namespace std; * * #include "section_list.h" * ... - * Privacy WindowState_state { 1, 9, NULL, LOCAL, NULL }; // first two integers are values for field id and proto type. - * Privacy WindowState_child_windows { 3, 11, NULL, DEFAULT, NULL }; // reserved for WindowState_LIST - * Privacy* WindowState_MSG_[] = { + * Privacy WindowState__state { 1, 9, NULL, LOCAL, NULL }; // first two integers are values for field id and proto type. + * Privacy WindowState__child_windows { 3, 11, NULL, UNSET, NULL }; // reserved for WindowState_LIST + * Privacy* WindowState__MSG__UNSET[] = { * &WindowState_state, * // display id is default, nothing is generated. * &WindowState_child_windows, * NULL // terminator of the array * }; - * Privacy WindowState_my_window { 1, 11, WindowState_my_window_LIST, DEFAULT, NULL }; + * Privacy WindowState__my_window { 1, 11, WindowState__MSG__UNSET, UNSET, NULL }; * * createList() { * ... - * WindowState_child_windows.children = WindowState_my_window_LIST; // point to its own definition after the list is defined. + * WindowState_child_windows.children = WindowState__MSG_UNSET; // point to its own definition after the list is defined. * ... * } * * const Privacy** PRIVACY_POLICY_LIST = createList(); * const int PRIVACY_POLICY_COUNT = 1; + * + * Privacy Value Inheritance rules: + * 1. Both field and message can be tagged with DESTINATION: LOCAL(L), EXPLICIT(E), AUTOMATIC(A). + * 2. Primitives inherits containing message's tag unless defined explicitly. + * 3. Containing message's tag doesn't apply to message fields, even when unset (in this case, uses its default message tag). + * 4. Message field tag overrides its default message tag. + * 5. UNSET tag defaults to EXPLICIT. */ // The assignments will be called when constructs PRIVACY_POLICY_LIST, has to be global variable @@ -164,14 +171,13 @@ static string replaceAll(const string& fieldName, const char oldC, const string& return result; } -static string getFieldName(const FieldDescriptor* field) { - return replaceAll(field->full_name(), '.', "__"); -} - -static string getMessageTypeName(const Descriptor* descriptor) { - return replaceAll(descriptor->full_name(), '.', "_") + "_MSG_"; +static inline void printPrivacy(const string& name, const FieldDescriptor* field, const string& children, + const Destination dest, const string& patterns, const string& comments = "") { + printf("Privacy %s = { %d, %d, %s, %d, %s };%s\n", name.c_str(), field->number(), field->type(), + children.c_str(), dest, patterns.c_str(), comments.c_str()); } +// Get Custom Options ================================================================================ static inline SectionFlags getSectionFlags(const FieldDescriptor* field) { return field->options().GetExtension(section); } @@ -180,24 +186,64 @@ static inline PrivacyFlags getPrivacyFlags(const FieldDescriptor* field) { return field->options().GetExtension(privacy); } -static inline bool isDefaultField(const FieldDescriptor* field) { - return getPrivacyFlags(field).dest() == PrivacyFlags::default_instance().dest(); +static inline PrivacyFlags getPrivacyFlags(const Descriptor* descriptor) { + return descriptor->options().GetExtension(msg_privacy); +} + +// Get Destinations =================================================================================== +static inline Destination getMessageDest(const Descriptor* descriptor, const Destination overridden) { + return overridden != DEST_UNSET ? overridden : getPrivacyFlags(descriptor).dest(); } -static bool isDefaultMessageImpl(const Descriptor* descriptor, set<string>* parents) { - int N = descriptor->field_count(); +// Returns field's own dest, when it is a message field, uses its message default tag if unset. +static inline Destination getFieldDest(const FieldDescriptor* field) { + Destination fieldDest = getPrivacyFlags(field).dest(); + return field->type() != FieldDescriptor::TYPE_MESSAGE ? fieldDest : + getMessageDest(field->message_type(), fieldDest); +} + +// Get Names =========================================================================================== +static inline string getFieldName(const FieldDescriptor* field) { + // replace . with double underscores to avoid name conflicts since fields use snake naming convention + return replaceAll(field->full_name(), '.', "__"); +} + + +static inline string getMessageName(const Descriptor* descriptor, const Destination overridden) { + // replace . with one underscore since messages use camel naming convention + return replaceAll(descriptor->full_name(), '.', "_") + "__MSG__" + + to_string(getMessageDest(descriptor, overridden)); +} + +// IsDefault ============================================================================================ +// Returns true if a field is default. Default is defined as this field has same dest as its containing message. +// For message fields, it only looks at its field tag and own default mesaage tag, doesn't recursively go deeper. +static inline bool isDefaultField(const FieldDescriptor* field, const Destination containerDest) { + Destination fieldDest = getFieldDest(field); + if (field->type() != FieldDescriptor::TYPE_MESSAGE) { + return fieldDest == containerDest || (fieldDest == DEST_UNSET); + } else { + return fieldDest == containerDest || + (containerDest == DEST_UNSET && fieldDest == DEST_EXPLICIT) || + (containerDest == DEST_EXPLICIT && fieldDest == DEST_UNSET); + } +} + +static bool isDefaultMessageImpl(const Descriptor* descriptor, const Destination dest, set<string>* parents) { + const int N = descriptor->field_count(); + const Destination messageDest = getMessageDest(descriptor, dest); parents->insert(descriptor->full_name()); for (int i=0; i<N; ++i) { const FieldDescriptor* field = descriptor->field(i); - // look at if the current field is default or not, return false immediately - if (!isDefaultField(field)) return false; - + const Destination fieldDest = getFieldDest(field); + // If current field is not default, return false immediately + if (!isDefaultField(field, messageDest)) return false; switch (field->type()) { case FieldDescriptor::TYPE_MESSAGE: // if self recursion, don't go deep. if (parents->find(field->message_type()->full_name()) != parents->end()) break; // if is a default message, just continue - if (isDefaultMessageImpl(field->message_type(), parents)) break; + if (isDefaultMessageImpl(field->message_type(), fieldDest, parents)) break; // sub message is not default, so this message is always not default return false; case FieldDescriptor::TYPE_STRING: @@ -210,106 +256,118 @@ static bool isDefaultMessageImpl(const Descriptor* descriptor, set<string>* pare return true; } -static bool isDefaultMessage(const Descriptor* descriptor) { +// Recursively look at if this message is default, meaning all its fields and sub-messages +// can be described by the same dest. +static bool isDefaultMessage(const Descriptor* descriptor, const Destination dest) { set<string> parents; - return isDefaultMessageImpl(descriptor, &parents); + return isDefaultMessageImpl(descriptor, dest, &parents); +} + +// =============================================================================================================== +static bool numberInOrder(const FieldDescriptor* f1, const FieldDescriptor* f2) { + return f1->number() < f2->number(); } -// This function is called for looking at privacy tags for a message type and recursively its sub-messages -// It prints out each fields's privacy tags and a List of Privacy of the message itself (don't print default values) +// field numbers are possibly out of order, sort them here. +static vector<const FieldDescriptor*> sortFields(const Descriptor* descriptor) { + vector<const FieldDescriptor*> fields; + fields.reserve(descriptor->field_count()); + for (int i=0; i<descriptor->field_count(); i++) { + fields.push_back(descriptor->field(i)); + } + std::sort(fields.begin(), fields.end(), numberInOrder); + return fields; +} + +// This function looks for privacy tags of a message type and recursively its sub-messages. +// It generates Privacy objects for each non-default fields including non-default sub-messages. +// And if the message has Privacy objects generated, it returns a list of them. // Returns false if the descriptor doesn't have any non default privacy flags set, including its submessages -static bool generatePrivacyFlags(const Descriptor* descriptor, map<string, bool> &msgNames, set<string>* parents) { - bool hasDefaultFlags[descriptor->field_count()]; - - string messageTypeName = getMessageTypeName(descriptor); - // if the message is already defined, skip it. - if (msgNames.find(messageTypeName) != msgNames.end()) { - bool hasDefault = msgNames[messageTypeName]; - return !hasDefault; // don't generate if it has default privacy. +static bool generatePrivacyFlags(const Descriptor* descriptor, const Destination overridden, + map<string, bool> &variableNames, set<string>* parents) { + const string messageName = getMessageName(descriptor, overridden); + const Destination messageDest = getMessageDest(descriptor, overridden); + + if (variableNames.find(messageName) != variableNames.end()) { + bool hasDefault = variableNames[messageName]; + return !hasDefault; // if has default, then don't generate privacy flags. } // insert the message type name so sub-message will figure out if self-recursion occurs - parents->insert(messageTypeName); - - // iterate though its field and generate sub flags first - for (int i=0; i<descriptor->field_count(); i++) { - hasDefaultFlags[i] = true; // set default to true + parents->insert(messageName); - const FieldDescriptor* field = descriptor->field(i); + // sort fields based on number, iterate though them and generate sub flags first + vector<const FieldDescriptor*> fieldsInOrder = sortFields(descriptor); + bool hasDefaultFlags[fieldsInOrder.size()]; + for (size_t i=0; i<fieldsInOrder.size(); i++) { + const FieldDescriptor* field = fieldsInOrder[i]; const string fieldName = getFieldName(field); - // check if the same field name is already defined. - if (msgNames.find(fieldName) != msgNames.end()) { - hasDefaultFlags[i] = msgNames[fieldName]; + const Destination fieldDest = getFieldDest(field); + + if (variableNames.find(fieldName) != variableNames.end()) { + hasDefaultFlags[i] = variableNames[fieldName]; continue; - }; + } + hasDefaultFlags[i] = isDefaultField(field, messageDest); - PrivacyFlags p = getPrivacyFlags(field); string fieldMessageName; + PrivacyFlags p = getPrivacyFlags(field); switch (field->type()) { case FieldDescriptor::TYPE_MESSAGE: - fieldMessageName = getMessageTypeName(field->message_type()); + fieldMessageName = getMessageName(field->message_type(), fieldDest); if (parents->find(fieldMessageName) != parents->end()) { // Self-Recursion proto definition - if (isDefaultField(field)) { - hasDefaultFlags[i] = isDefaultMessage(field->message_type()); - } else { - hasDefaultFlags[i] = false; + if (hasDefaultFlags[i]) { + hasDefaultFlags[i] = isDefaultMessage(field->message_type(), fieldDest); } if (!hasDefaultFlags[i]) { - printf("Privacy %s = { %d, %d, NULL, %d, NULL }; // self recursion field of %s\n", - fieldName.c_str(), field->number(), field->type(), p.dest(), fieldMessageName.c_str()); + printPrivacy(fieldName, field, "NULL", fieldDest, "NULL", + " // self recursion field of " + fieldMessageName); // generate the assignment and used to construct createList function later on. gSelfRecursionAssignments.push_back(fieldName + ".children = " + fieldMessageName); } - break; - } else if (generatePrivacyFlags(field->message_type(), msgNames, parents)) { - printf("Privacy %s = { %d, %d, %s, %d, NULL };\n", fieldName.c_str(), field->number(), - field->type(), fieldMessageName.c_str(), p.dest()); - } else if (isDefaultField(field)) { - // don't create a new privacy if the value is default. - break; - } else { - printf("Privacy %s = { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(), - field->type(), p.dest()); + } else if (generatePrivacyFlags(field->message_type(), p.dest(), variableNames, parents)) { + if (variableNames.find(fieldName) == variableNames.end()) { + printPrivacy(fieldName, field, fieldMessageName, fieldDest, "NULL"); + } + hasDefaultFlags[i] = false; + } else if (!hasDefaultFlags[i]) { + printPrivacy(fieldName, field, "NULL", fieldDest, "NULL"); } - hasDefaultFlags[i] = false; break; case FieldDescriptor::TYPE_STRING: - if (isDefaultField(field) && p.patterns_size() == 0) break; - - printf("const char* %s_patterns[] = {\n", fieldName.c_str()); - for (int i=0; i<p.patterns_size(); i++) { - // the generated string need to escape backslash as well, need to dup it here - printf(" \"%s\",\n", replaceAll(p.patterns(i), '\\', "\\\\").c_str()); + if (p.patterns_size() != 0) { // if patterns are specified + if (hasDefaultFlags[i]) break; + printf("const char* %s_patterns[] = {\n", fieldName.c_str()); + for (int j=0; j<p.patterns_size(); j++) { + // generated string needs to escape backslash too, duplicate it to allow escape again. + printf(" \"%s\",\n", replaceAll(p.patterns(j), '\\', "\\\\").c_str()); + } + printf(" NULL };\n"); + printPrivacy(fieldName, field, "NULL", fieldDest, fieldName + "_patterns"); + break; } - printf(" NULL };\n"); - printf("Privacy %s = { %d, %d, NULL, %d, %s_patterns };\n", fieldName.c_str(), field->number(), - field->type(), p.dest(), fieldName.c_str()); - hasDefaultFlags[i] = false; - break; + // else treat string field as primitive field and goes to default default: - if (isDefaultField(field)) break; - printf("Privacy %s = { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(), - field->type(), p.dest()); - hasDefaultFlags[i] = false; + if (!hasDefaultFlags[i]) printPrivacy(fieldName, field, "NULL", fieldDest, "NULL"); } - // add the field name to message map, true means it has default flags - msgNames[fieldName] = hasDefaultFlags[i]; + // Don't generate a variable twice + if (!hasDefaultFlags[i]) variableNames[fieldName] = false; } bool allDefaults = true; - for (int i=0; i<descriptor->field_count(); i++) { + for (size_t i=0; i<fieldsInOrder.size(); i++) { allDefaults &= hasDefaultFlags[i]; } - parents->erase(messageTypeName); // erase the message type name when exit the message. - msgNames[messageTypeName] = allDefaults; // store the privacy tags of the message here to avoid overhead. + parents->erase(messageName); // erase the message type name when exit the message. + variableNames[messageName] = allDefaults; // store the privacy tags of the message here to avoid overhead. if (allDefaults) return false; emptyline(); int policyCount = 0; - printf("Privacy* %s[] = {\n", messageTypeName.c_str()); - for (int i=0; i<descriptor->field_count(); i++) { - const FieldDescriptor* field = descriptor->field(i); + printf("Privacy* %s[] = {\n", messageName.c_str()); + for (size_t i=0; i<fieldsInOrder.size(); i++) { + const FieldDescriptor* field = fieldsInOrder[i]; if (hasDefaultFlags[i]) continue; printf(" &%s,\n", getFieldName(field).c_str()); policyCount++; @@ -359,29 +417,30 @@ static bool generateSectionListCpp(Descriptor const* descriptor) { // generates PRIVACY_POLICY_LIST printf("// Generate PRIVACY_POLICY_LIST.\n\n"); - map<string, bool> messageNames; + map<string, bool> variableNames; set<string> parents; - bool skip[descriptor->field_count()]; + vector<const FieldDescriptor*> fieldsInOrder = sortFields(descriptor); + bool skip[fieldsInOrder.size()]; + const Destination incidentDest = getPrivacyFlags(descriptor).dest(); - for (int i=0; i<descriptor->field_count(); i++) { - const FieldDescriptor* field = descriptor->field(i); + for (size_t i=0; i<fieldsInOrder.size(); i++) { + const FieldDescriptor* field = fieldsInOrder[i]; const string fieldName = getFieldName(field); - PrivacyFlags p = getPrivacyFlags(field); + const Destination fieldDest = getFieldDest(field); + const string fieldMessageName = getMessageName(field->message_type(), fieldDest); skip[i] = true; if (field->type() != FieldDescriptor::TYPE_MESSAGE) { continue; } - // generate privacy flags for each field. - if (generatePrivacyFlags(field->message_type(), messageNames, &parents)) { - printf("Privacy %s { %d, %d, %s, %d, NULL };\n", fieldName.c_str(), field->number(), - field->type(), getMessageTypeName(field->message_type()).c_str(), p.dest()); - } else if (isDefaultField(field)) { + // generate privacy flags for each section. + if (generatePrivacyFlags(field->message_type(), fieldDest, variableNames, &parents)) { + printPrivacy(fieldName, field, fieldMessageName, fieldDest, "NULL"); + } else if (isDefaultField(field, incidentDest)) { continue; // don't create a new privacy if the value is default. } else { - printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(), - field->type(), p.dest()); + printPrivacy(fieldName, field, "NULL", fieldDest, "NULL"); } skip[i] = false; } @@ -391,16 +450,16 @@ static bool generateSectionListCpp(Descriptor const* descriptor) { int policyCount = 0; if (gSelfRecursionAssignments.empty()) { printf("Privacy* privacyArray[] = {\n"); - for (int i=0; i<descriptor->field_count(); i++) { + for (size_t i=0; i<fieldsInOrder.size(); i++) { if (skip[i]) continue; - printf(" &%s,\n", getFieldName(descriptor->field(i)).c_str()); + printf(" &%s,\n", getFieldName(fieldsInOrder[i]).c_str()); policyCount++; } printf("};\n\n"); printf("const Privacy** PRIVACY_POLICY_LIST = const_cast<const Privacy**>(privacyArray);\n\n"); printf("const int PRIVACY_POLICY_COUNT = %d;\n", policyCount); } else { - for (int i=0; i<descriptor->field_count(); i++) { + for (size_t i=0; i<fieldsInOrder.size(); i++) { if (!skip[i]) policyCount++; } @@ -410,9 +469,9 @@ static bool generateSectionListCpp(Descriptor const* descriptor) { } printf(" Privacy** privacyArray = (Privacy**)malloc(%d * sizeof(Privacy**));\n", policyCount); policyCount = 0; // reset - for (int i=0; i<descriptor->field_count(); i++) { + for (size_t i=0; i<fieldsInOrder.size(); i++) { if (skip[i]) continue; - printf(" privacyArray[%d] = &%s;\n", policyCount++, getFieldName(descriptor->field(i)).c_str()); + printf(" privacyArray[%d] = &%s;\n", policyCount++, getFieldName(fieldsInOrder[i]).c_str()); } printf(" return const_cast<const Privacy**>(privacyArray);\n"); printf("}\n\n"); |