Fixes regarding to comments in ag/2839267

1. use struct {} to instantiate privacy fields for efficiency reason
2. use vector<uint8_t>* instead of vector<uint8_t>& to indicate the
caller knows the value gets changed.
3. binary search privay policy for sections

Bug: 65595927
Test: unit test covers
Change-Id: Ic58c2f607465d1a7f10352b9a38c3d8b1a5cf352
diff --git a/Android.bp b/Android.bp
index 33acffa..72ea24c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,6 +42,7 @@
                 "core/proto/android/os/kernelwake.proto",
                 "core/proto/android/os/procrank.proto",
                 "core/proto/android/service/graphicsstats.proto",
+                "libs/incident/proto/android/privacy.proto",
             ],
             shared: {
                 enabled: false,
diff --git a/cmds/incidentd/src/EncodedBuffer.cpp b/cmds/incidentd/src/EncodedBuffer.cpp
index 3d20548..e8f2c11 100644
--- a/cmds/incidentd/src/EncodedBuffer.cpp
+++ b/cmds/incidentd/src/EncodedBuffer.cpp
@@ -27,15 +27,15 @@
  * Return the number of bytes of the varint.
  */
 static uint32_t
-read_raw_varint(FdBuffer::iterator& it)
+read_raw_varint(FdBuffer::iterator* it)
 {
     uint32_t val = 0;
     int i = 0;
     bool hasNext = true;
     while (hasNext) {
-        hasNext = ((*it & 0x80) != 0);
-        val += (*it & 0x7F) << (7*i);
-        it++;
+        hasNext = ((**it & 0x80) != 0);
+        val += (**it & 0x7F) << (7*i);
+        (*it)++;
         i++;
     }
     return val;
@@ -46,21 +46,21 @@
  * If skip is set to true, no data will be written to buf. Return number of bytes written.
  */
 static size_t
-write_field_or_skip(FdBuffer::iterator &iterator, vector<uint8_t> &buf, uint8_t wireType, bool skip)
+write_field_or_skip(FdBuffer::iterator* iter, vector<uint8_t>* buf, uint8_t wireType, bool skip)
 {
-    FdBuffer::iterator snapshot = iterator.snapshot();
+    FdBuffer::iterator snapshot = iter->snapshot();
     size_t bytesToWrite = 0;
     uint32_t varint = 0;
     switch (wireType) {
         case WIRE_TYPE_VARINT:
-            varint = read_raw_varint(iterator);
+            varint = read_raw_varint(iter);
             if(!skip) return write_raw_varint(buf, varint);
             break;
         case WIRE_TYPE_FIXED64:
             bytesToWrite = 8;
             break;
         case WIRE_TYPE_LENGTH_DELIMITED:
-            bytesToWrite = read_raw_varint(iterator);
+            bytesToWrite = read_raw_varint(iter);
             if(!skip) write_raw_varint(buf, bytesToWrite);
             break;
         case WIRE_TYPE_FIXED32:
@@ -68,14 +68,14 @@
             break;
     }
     if (skip) {
-        iterator += bytesToWrite;
+        *iter += bytesToWrite;
     } else {
         for (size_t i=0; i<bytesToWrite; i++) {
-            buf.push_back(*iterator);
-            iterator++;
+            buf->push_back(**iter);
+            (*iter)++;
         }
     }
-    return skip ? 0 : iterator - snapshot;
+    return skip ? 0 : *iter - snapshot;
 }
 
 /**
@@ -86,30 +86,30 @@
  * After exit with NO_ERROR, iterator points to the next protobuf field's head.
  */
 static status_t
-stripField(FdBuffer::iterator &iterator, vector<uint8_t> &buf, const Privacy* parentPolicy, const PrivacySpec& spec)
+stripField(FdBuffer::iterator* iter, vector<uint8_t>* buf, const Privacy* parentPolicy, const PrivacySpec& spec)
 {
-    if (iterator.outOfBound() || parentPolicy == NULL) return BAD_VALUE;
+    if (iter->outOfBound() || parentPolicy == NULL) return BAD_VALUE;
 
-    uint32_t varint = read_raw_varint(iterator);
+    uint32_t varint = read_raw_varint(iter);
     uint8_t wireType = read_wire_type(varint);
     uint32_t fieldId = read_field_id(varint);
     const Privacy* policy = parentPolicy->lookup(fieldId);
 
     if (policy == NULL || !policy->IsMessageType() || !policy->HasChildren()) {
         bool skip = !spec.CheckPremission(policy);
-        size_t amt = buf.size();
+        size_t amt = buf->size();
         if (!skip) amt += write_header(buf, fieldId, wireType);
-        amt += write_field_or_skip(iterator, buf, wireType, skip); // point to head of next field
-        return buf.size() != amt ? BAD_VALUE : NO_ERROR;
+        amt += write_field_or_skip(iter, buf, wireType, skip); // point to head of next field
+        return buf->size() != amt ? BAD_VALUE : NO_ERROR;
     }
     // current field is message type and its sub-fields have extra privacy policies
     deque<vector<uint8_t>> q;
-    uint32_t msgSize = read_raw_varint(iterator);
+    uint32_t msgSize = read_raw_varint(iter);
     size_t finalSize = 0;
-    FdBuffer::iterator start = iterator.snapshot();
-    while ((iterator - start) != (int)msgSize) {
+    FdBuffer::iterator start = iter->snapshot();
+    while ((*iter - start) != (int)msgSize) {
         vector<uint8_t> v;
-        status_t err = stripField(iterator, v, policy, spec);
+        status_t err = stripField(iter, &v, policy, spec);
         if (err != NO_ERROR) return err;
         if (v.empty()) continue;
         q.push_back(v);
@@ -118,11 +118,11 @@
 
     write_header(buf, fieldId, wireType);
     write_raw_varint(buf, finalSize);
-    buf.reserve(finalSize);
+    buf->reserve(finalSize); // reserve the size of the field
     while (!q.empty()) {
         vector<uint8_t> subField = q.front();
         for (vector<uint8_t>::iterator it = subField.begin(); it != subField.end(); it++) {
-            buf.push_back(*it);
+            buf->push_back(*it);
         }
         q.pop_front();
     }
@@ -156,7 +156,7 @@
     field.reserve(BUFFER_SIZE);
 
     while (it != mFdBuffer.end()) {
-        status_t err = stripField(it, field, mPolicy, spec);
+        status_t err = stripField(&it, &field, mPolicy, spec);
         if (err != NO_ERROR) return err;
         if (field.size() > BUFFER_SIZE) { // rotate to another chunk if buffer size exceeds
             mBuffers.push_back(field);
diff --git a/cmds/incidentd/src/Privacy.cpp b/cmds/incidentd/src/Privacy.cpp
index dbab548..e7969e7 100644
--- a/cmds/incidentd/src/Privacy.cpp
+++ b/cmds/incidentd/src/Privacy.cpp
@@ -16,6 +16,8 @@
 
 #include "Privacy.h"
 
+#include <stdlib.h>
+
 // DESTINATION enum value
 const uint8_t DEST_LOCAL = 0;
 const uint8_t DEST_EXPLICIT = 1;
@@ -25,33 +27,6 @@
 const uint8_t TYPE_STRING = 9;
 const uint8_t TYPE_MESSAGE = 11;
 
-Privacy::Privacy(uint32_t field_id, uint8_t type, uint8_t dest)
-    : field_id(field_id),
-      type(type),
-      children(NULL),
-      dest(dest),
-      patterns(NULL)
-{
-}
-
-Privacy::Privacy(uint32_t field_id, const Privacy** children)
-    : field_id(field_id),
-      type(TYPE_MESSAGE),
-      children(children),
-      dest(DEST_DEFAULT_VALUE), // this will be ignored
-      patterns(NULL)
-{
-}
-
-Privacy::Privacy(uint32_t field_id, uint8_t dest, const char** patterns)
-    : field_id(field_id),
-      type(TYPE_STRING),
-      children(NULL),
-      dest(dest),
-      patterns(patterns)
-{
-}
-
 bool
 Privacy::IsMessageType() const { return type == TYPE_MESSAGE; }
 
diff --git a/cmds/incidentd/src/Privacy.h b/cmds/incidentd/src/Privacy.h
index c56ba9b8..7f1977e 100644
--- a/cmds/incidentd/src/Privacy.h
+++ b/cmds/incidentd/src/Privacy.h
@@ -30,17 +30,13 @@
     uint32_t field_id;
     uint8_t type;
     // ignore parent's privacy flags if children are set, NULL-terminated
-    const Privacy** children;
+    Privacy** children;
 
     // the following fields are identitical to
     // frameworks/base/libs/incident/proto/android/privacy.proto
     uint8_t dest;
     const char** patterns; // only set when type is string
 
-    Privacy(uint32_t field_id, uint8_t type, uint8_t dest); // generic constructor
-    Privacy(uint32_t field_id, const Privacy** children); // used for message type
-    Privacy(uint32_t field_id, uint8_t dest, const char** patterns); // used for string type
-
     bool IsMessageType() const;
     bool IsStringType() const;
     bool HasChildren() const;
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 6f052de..166fef0 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -97,13 +97,19 @@
 static const Privacy*
 get_privacy_of_section(int id)
 {
-    if (id < 0) return NULL;
-    int i=0;
-    while (PRIVACY_POLICY_LIST[i] != NULL) {
-        const Privacy* p = PRIVACY_POLICY_LIST[i];
-        if (p->field_id == (uint32_t)id) return p;
-        if (p->field_id > (uint32_t)id) return NULL;
-        i++;
+    int l = 0;
+    int r = PRIVACY_POLICY_COUNT - 1;
+    while (l <= r) {
+        int mid = (l + r) >> 1;
+        const Privacy* p = PRIVACY_POLICY_LIST[mid];
+
+        if (p->field_id < (uint32_t)id) {
+            l = mid + 1;
+        } else if (p->field_id > (uint32_t)id) {
+            r = mid - 1;
+        } else {
+            return p;
+        }
     }
     return NULL;
 }
diff --git a/cmds/incidentd/src/protobuf.cpp b/cmds/incidentd/src/protobuf.cpp
index 05de831..4fffec1 100644
--- a/cmds/incidentd/src/protobuf.cpp
+++ b/cmds/incidentd/src/protobuf.cpp
@@ -50,23 +50,23 @@
 }
 
 size_t
-write_raw_varint(vector<uint8_t> &buf, uint32_t val)
+write_raw_varint(vector<uint8_t>* buf, uint32_t val)
 {
     size_t size = 0;
     while (true) {
         size++;
         if ((val & ~0x7F) == 0) {
-            buf.push_back((uint8_t) val);
+            buf->push_back((uint8_t) val);
             return size;
         } else {
-            buf.push_back((uint8_t)((val & 0x7F) | 0x80));
+            buf->push_back((uint8_t)((val & 0x7F) | 0x80));
             val >>= 7;
         }
     }
 }
 
 size_t
-write_header(vector<uint8_t> &buf, uint32_t fieldId, uint8_t wireType)
+write_header(vector<uint8_t>* buf, uint32_t fieldId, uint8_t wireType)
 {
     return write_raw_varint(buf, (fieldId << 3) | wireType);
 }
\ No newline at end of file
diff --git a/cmds/incidentd/src/protobuf.h b/cmds/incidentd/src/protobuf.h
index fb0d69d..263c864 100644
--- a/cmds/incidentd/src/protobuf.h
+++ b/cmds/incidentd/src/protobuf.h
@@ -53,12 +53,12 @@
 /**
  * Write a varint into a vector. Return the size of the varint.
  */
-size_t write_raw_varint(vector<uint8_t> &buf, uint32_t val);
+size_t write_raw_varint(vector<uint8_t>* buf, uint32_t val);
 
 /**
  * Write a protobuf header. Return the size of the header.
  */
-size_t write_header(vector<uint8_t> &buf, uint32_t fieldId, uint8_t wireType);
+size_t write_header(vector<uint8_t>* buf, uint32_t fieldId, uint8_t wireType);
 
 enum {
     // IncidentProto.header
diff --git a/cmds/incidentd/src/section_list.h b/cmds/incidentd/src/section_list.h
index 4d9efd7..da82b00 100644
--- a/cmds/incidentd/src/section_list.h
+++ b/cmds/incidentd/src/section_list.h
@@ -22,15 +22,17 @@
 
 /**
  * This is the mapping of section IDs to the commands that are run to get those commands.
- * The section IDs are guaranteed in ascending order
+ * The section IDs are guaranteed in ascending order, NULL-terminated.
  */
 extern const Section* SECTION_LIST[];
 
 /**
  * This is the mapping of section IDs to each section's privacy policy.
- * The section IDs are guaranteed in ascending order
+ * The section IDs are guaranteed in ascending order, not NULL-terminated since size is provided.
  */
 extern const Privacy* PRIVACY_POLICY_LIST[];
 
+extern const int PRIVACY_POLICY_COUNT;
+
 #endif // SECTION_LIST_H
 
diff --git a/cmds/incidentd/tests/EncodedBuffer_test.cpp b/cmds/incidentd/tests/EncodedBuffer_test.cpp
index c51520b..98c39bd 100644
--- a/cmds/incidentd/tests/EncodedBuffer_test.cpp
+++ b/cmds/incidentd/tests/EncodedBuffer_test.cpp
@@ -42,6 +42,38 @@
 const string FIX32_FIELD_4 = "\x25\xff\xff\xff\xff"; // -1
 const string MESSAGE_FIELD_5 = "\x2a\x10" + VARINT_FIELD_1 + STRING_FIELD_2;
 
+static Privacy* create_privacy(uint32_t field_id, uint8_t type, uint8_t dest) {
+  struct Privacy* p = (struct Privacy*)malloc(sizeof(struct Privacy));
+  p->field_id = field_id;
+  p->type = type;
+  p->children = NULL;
+  p->dest = dest;
+  p->patterns = NULL;
+  return p;
+}
+
+static Privacy* create_message_privacy(uint32_t field_id, Privacy** children)
+{
+  struct Privacy* p = (struct Privacy*)malloc(sizeof(struct Privacy));
+  p->field_id = field_id;
+  p->type = MESSAGE_TYPE;
+  p->children = children;
+  p->dest = EXPLICIT;
+  p->patterns = NULL;
+  return p;
+}
+
+static Privacy* create_string_privacy(uint32_t field_id, uint8_t dest, const char** patterns)
+{
+  struct Privacy* p = (struct Privacy*)malloc(sizeof(struct Privacy));
+  p->field_id = field_id;
+  p->type = STRING_TYPE;
+  p->children = NULL;
+  p->dest = dest;
+  p->patterns = patterns;
+  return p;
+}
+
 class EncodedBufferTest : public Test {
 public:
     virtual void SetUp() override {
@@ -78,7 +110,7 @@
         }
         va_end(args);
         list[size] = NULL;
-        assertStrip(dest, expected, new Privacy(300, const_cast<const Privacy**>(list)));
+        assertStrip(dest, expected, create_message_privacy(300, list));
     }
 
     FdBuffer buffer;
@@ -88,62 +120,62 @@
 
 TEST_F(EncodedBufferTest, NullFieldPolicy) {
     writeToFdBuffer(STRING_FIELD_0);
-    assertStrip(EXPLICIT, STRING_FIELD_0, new Privacy(300, NULL));
+    assertStrip(EXPLICIT, STRING_FIELD_0, create_string_privacy(300, AUTOMATIC, NULL));
 }
 
 TEST_F(EncodedBufferTest, StripSpecNotAllowed) {
     writeToFdBuffer(STRING_FIELD_0);
-    assertStripByFields(AUTOMATIC, "", 1, new Privacy(0, STRING_TYPE, EXPLICIT));
+    assertStripByFields(AUTOMATIC, "", 1, create_privacy(0, STRING_TYPE, EXPLICIT));
 }
 
 TEST_F(EncodedBufferTest, StripVarintField) {
     writeToFdBuffer(VARINT_FIELD_1);
-    assertStripByFields(EXPLICIT, "", 1, new Privacy(1, OTHER_TYPE, LOCAL));
+    assertStripByFields(EXPLICIT, "", 1, create_privacy(1, OTHER_TYPE, LOCAL));
 }
 
 TEST_F(EncodedBufferTest, StripLengthDelimitedField_String) {
     writeToFdBuffer(STRING_FIELD_2);
-    assertStripByFields(EXPLICIT, "", 1, new Privacy(2, STRING_TYPE, LOCAL));
+    assertStripByFields(EXPLICIT, "", 1, create_privacy(2, STRING_TYPE, LOCAL));
 }
 
 TEST_F(EncodedBufferTest, StripFixed64Field) {
     writeToFdBuffer(FIX64_FIELD_3);
-    assertStripByFields(EXPLICIT, "", 1, new Privacy(3, OTHER_TYPE, LOCAL));
+    assertStripByFields(EXPLICIT, "", 1, create_privacy(3, OTHER_TYPE, LOCAL));
 }
 
 TEST_F(EncodedBufferTest, StripFixed32Field) {
     writeToFdBuffer(FIX32_FIELD_4);
-    assertStripByFields(EXPLICIT, "", 1, new Privacy(4, OTHER_TYPE, LOCAL));
+    assertStripByFields(EXPLICIT, "", 1, create_privacy(4, OTHER_TYPE, LOCAL));
 }
 
 TEST_F(EncodedBufferTest, StripLengthDelimitedField_Message) {
     writeToFdBuffer(MESSAGE_FIELD_5);
-    assertStripByFields(EXPLICIT, "", 1, new Privacy(5, MESSAGE_TYPE, LOCAL));
+    assertStripByFields(EXPLICIT, "", 1, create_privacy(5, MESSAGE_TYPE, LOCAL));
 }
 
 TEST_F(EncodedBufferTest, NoStripVarintField) {
     writeToFdBuffer(VARINT_FIELD_1);
-    assertStripByFields(EXPLICIT, VARINT_FIELD_1, 1, new Privacy(1, OTHER_TYPE, AUTOMATIC));
+    assertStripByFields(EXPLICIT, VARINT_FIELD_1, 1, create_privacy(1, OTHER_TYPE, AUTOMATIC));
 }
 
 TEST_F(EncodedBufferTest, NoStripLengthDelimitedField_String) {
     writeToFdBuffer(STRING_FIELD_2);
-    assertStripByFields(EXPLICIT, STRING_FIELD_2, 1, new Privacy(2, STRING_TYPE, AUTOMATIC));
+    assertStripByFields(EXPLICIT, STRING_FIELD_2, 1, create_privacy(2, STRING_TYPE, AUTOMATIC));
 }
 
 TEST_F(EncodedBufferTest, NoStripFixed64Field) {
     writeToFdBuffer(FIX64_FIELD_3);
-    assertStripByFields(EXPLICIT, FIX64_FIELD_3, 1, new Privacy(3, OTHER_TYPE, AUTOMATIC));
+    assertStripByFields(EXPLICIT, FIX64_FIELD_3, 1, create_privacy(3, OTHER_TYPE, AUTOMATIC));
 }
 
 TEST_F(EncodedBufferTest, NoStripFixed32Field) {
     writeToFdBuffer(FIX32_FIELD_4);
-    assertStripByFields(EXPLICIT, FIX32_FIELD_4, 1, new Privacy(4, OTHER_TYPE, AUTOMATIC));
+    assertStripByFields(EXPLICIT, FIX32_FIELD_4, 1, create_privacy(4, OTHER_TYPE, AUTOMATIC));
 }
 
 TEST_F(EncodedBufferTest, NoStripLengthDelimitedField_Message) {
     writeToFdBuffer(MESSAGE_FIELD_5);
-    assertStripByFields(EXPLICIT, MESSAGE_FIELD_5, 1, new Privacy(5, MESSAGE_TYPE, AUTOMATIC));
+    assertStripByFields(EXPLICIT, MESSAGE_FIELD_5, 1, create_privacy(5, MESSAGE_TYPE, AUTOMATIC));
 }
 
 TEST_F(EncodedBufferTest, StripVarintAndString) {
@@ -151,7 +183,7 @@
             + FIX64_FIELD_3 + FIX32_FIELD_4);
     string expected = STRING_FIELD_0 + FIX64_FIELD_3 + FIX32_FIELD_4;
     assertStripByFields(EXPLICIT, expected, 2,
-            new Privacy(1, OTHER_TYPE, LOCAL), new Privacy(2, STRING_TYPE, LOCAL));
+            create_privacy(1, OTHER_TYPE, LOCAL), create_privacy(2, STRING_TYPE, LOCAL));
 }
 
 TEST_F(EncodedBufferTest, StripVarintAndFixed64) {
@@ -159,28 +191,28 @@
             + FIX64_FIELD_3 + FIX32_FIELD_4);
     string expected = STRING_FIELD_0 + STRING_FIELD_2 + FIX32_FIELD_4;
     assertStripByFields(EXPLICIT, expected, 2,
-            new Privacy(1, OTHER_TYPE, LOCAL), new Privacy(3, OTHER_TYPE, LOCAL));
+            create_privacy(1, OTHER_TYPE, LOCAL), create_privacy(3, OTHER_TYPE, LOCAL));
 }
 
 TEST_F(EncodedBufferTest, StripVarintInNestedMessage) {
     writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5);
-    const Privacy* list[] = { new Privacy(1, OTHER_TYPE, LOCAL), NULL };
+    Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
     string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
-    assertStripByFields(EXPLICIT, expected, 1, new Privacy(5, list));
+    assertStripByFields(EXPLICIT, expected, 1, create_message_privacy(5, list));
 }
 
 TEST_F(EncodedBufferTest, StripFix64AndVarintInNestedMessage) {
     writeToFdBuffer(STRING_FIELD_0 + FIX64_FIELD_3 + MESSAGE_FIELD_5);
-    const Privacy* list[] = { new Privacy(1, OTHER_TYPE, LOCAL), NULL };
+    Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
     string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
-    assertStripByFields(EXPLICIT, expected, 2, new Privacy(3, OTHER_TYPE, LOCAL), new Privacy(5, list));
+    assertStripByFields(EXPLICIT, expected, 2, create_privacy(3, OTHER_TYPE, LOCAL), create_message_privacy(5, list));
 }
 
 TEST_F(EncodedBufferTest, ClearAndStrip) {
     string data = STRING_FIELD_0 + VARINT_FIELD_1;
     writeToFdBuffer(data);
-    const Privacy* list[] = { new Privacy(1, OTHER_TYPE, LOCAL), NULL };
-    EncodedBuffer encodedBuf(buffer, new Privacy(300, list));
+    Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
+    EncodedBuffer encodedBuf(buffer, create_message_privacy(300, list));
     PrivacySpec spec1(EXPLICIT), spec2(LOCAL);
 
     ASSERT_EQ(encodedBuf.strip(spec1), NO_ERROR);
@@ -191,17 +223,17 @@
 
 TEST_F(EncodedBufferTest, BadDataInFdBuffer) {
     writeToFdBuffer("iambaddata");
-    const Privacy* list[] = { new Privacy(4, OTHER_TYPE, AUTOMATIC), NULL };
-    EncodedBuffer encodedBuf(buffer, new Privacy(300, list));
+    Privacy* list[] = { create_privacy(4, OTHER_TYPE, AUTOMATIC), NULL };
+    EncodedBuffer encodedBuf(buffer, create_message_privacy(300, list));
     PrivacySpec spec;
     ASSERT_EQ(encodedBuf.strip(spec), BAD_VALUE);
 }
 
 TEST_F(EncodedBufferTest, BadDataInNestedMessage) {
     writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5 + "aoeoe");
-    const Privacy* list[] = { new Privacy(1, OTHER_TYPE, LOCAL), NULL };
-    const Privacy* field5[] = { new Privacy(5, list), NULL };
-    EncodedBuffer encodedBuf(buffer, new Privacy(300, field5));
+    Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
+    Privacy* field5[] = { create_message_privacy(5, list), NULL };
+    EncodedBuffer encodedBuf(buffer, create_message_privacy(300, field5));
     PrivacySpec spec;
     ASSERT_EQ(encodedBuf.strip(spec), BAD_VALUE);
 }
diff --git a/cmds/incidentd/tests/section_list.cpp b/cmds/incidentd/tests/section_list.cpp
index 3722c72..e47b61cf 100644
--- a/cmds/incidentd/tests/section_list.cpp
+++ b/cmds/incidentd/tests/section_list.cpp
@@ -9,13 +9,20 @@
 const uint8_t EXPLICIT = 1;
 const uint8_t AUTOMATIC = 2;
 
-const Privacy* list[] = {
-    new Privacy(1, 1, LOCAL),
-    new Privacy(2, AUTOMATIC, (const char**)NULL),
+Privacy sub_field_1 { 1, 1, NULL, LOCAL, NULL };
+Privacy sub_field_2 { 2, 9, NULL, 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 };
+
 const Privacy* PRIVACY_POLICY_LIST[] = {
-    new Privacy(0, list),
-    new Privacy(1, 9, AUTOMATIC),
-    NULL
-};
\ No newline at end of file
+    &field_0,
+    &field_1
+};
+
+const int PRIVACY_POLICY_COUNT = 2;
\ No newline at end of file
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 7966d88..900690c 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -135,7 +135,7 @@
                 if (generatePrivacyFlags(field->message_type(), field_name, msgNames) &&
                     isDefaultDest(field)) break;
 
-                printf("Privacy %s(%d, %s_LIST);\n", field_name, field->number(), field_name);
+                printf("Privacy %s { %d, %d, %s_LIST, %d, NULL };\n", field_name, field->number(), field->type(), field_name, p.dest());
                 hasDefaultFlags[i] = false;
                 break;
             case FieldDescriptor::TYPE_STRING:
@@ -147,12 +147,12 @@
                     printf("    \"%s\",\n", replaceAll(p.patterns(i), '\\', "\\\\").c_str());
                 }
                 printf("    NULL };\n");
-                printf("Privacy %s(%d, %d, %s_patterns);\n", field_name, field->number(), p.dest(), field_name);
+                printf("Privacy %s { %d, %d, NULL, %d, %s_patterns };\n", field_name, field->number(), field->type(), p.dest(), field_name);
                 hasDefaultFlags[i] = false;
                 break;
             default:
                 if (isDefaultDest(field)) break;
-                printf("Privacy %s(%d, %d, %d);\n", field_name, field->number(), (int) field->type(), p.dest());
+                printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", field_name, field->number(), field->type(), p.dest());
                 hasDefaultFlags[i] = false;
         }
         // add the field name to message map, true means it has default flags
@@ -166,13 +166,23 @@
     if (allDefaults) return true;
 
     emptyline();
-    printf("const Privacy* %s_LIST[] = {\n", alias);
+
+    bool needConst = strcmp(alias, "PRIVACY_POLICY") == 0;
+    int policyCount = 0;
+
+    printf("%s Privacy* %s_LIST[] = {\n", needConst ? "const" : "", alias);
     for (int i=0; i<descriptor->field_count(); i++) {
         const FieldDescriptor* field = descriptor->field(i);
         if (hasDefaultFlags[i]) continue;
         printf("    &%s,\n", replaceAll(field->full_name(), '.', "__").c_str());
+        policyCount++;
     }
-    printf("    NULL };\n");
+    if (needConst) {
+        printf("};\n\n");
+        printf("const int PRIVACY_POLICY_COUNT = %d;\n", policyCount);
+    } else {
+        printf("    NULL };\n");
+    }
     emptyline();
     return false;
 }
@@ -214,7 +224,8 @@
     map<string, bool> messageNames;
     if (generatePrivacyFlags(descriptor, "PRIVACY_POLICY", messageNames)) {
         // if no privacy options set at all, define an empty list
-        printf("const Privacy* PRIVACY_POLICY_LIST[] = { NULL };\n");
+        printf("const Privacy* PRIVACY_POLICY_LIST[] = {};\n");
+        printf("const int PRIVACY_POLICY_COUNT = 0;\n");
     }
 
     return true;