Implement c++ native lib for streaming proto, part 1

Extract protobuf class out and creates EncodedBuffer class
which holds protobuf data.
Next step is to create a ProtoOutputStream and let incident helper
adapt the change as well.
please see frameworks/base/core/java/android/util/proto

Bug: 65641021
Test: unit tested
Change-Id: I0dd343b2e62d60f091c8f857fae3452ec8da6b96
diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk
index 830bf9e..cb5fd02 100644
--- a/cmds/incidentd/Android.mk
+++ b/cmds/incidentd/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_MODULE := incidentd
 
 LOCAL_SRC_FILES := \
-        src/EncodedBuffer.cpp \
+        src/PrivacyBuffer.cpp \
         src/FdBuffer.cpp \
         src/IncidentService.cpp \
         src/Privacy.cpp \
@@ -31,7 +31,6 @@
         src/Section.cpp \
         src/io_util.cpp \
         src/main.cpp \
-        src/protobuf.cpp \
         src/report_directory.cpp
 
 LOCAL_CFLAGS += \
@@ -54,6 +53,7 @@
         libcutils \
         libincident \
         liblog \
+        libprotoutil \
         libselinux \
         libservices \
         libutils
@@ -93,16 +93,15 @@
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
 
 LOCAL_SRC_FILES := \
-    src/EncodedBuffer.cpp \
+    src/PrivacyBuffer.cpp \
     src/FdBuffer.cpp \
     src/Privacy.cpp \
     src/Reporter.cpp \
     src/Section.cpp \
     src/io_util.cpp \
-    src/protobuf.cpp \
     src/report_directory.cpp \
     tests/section_list.cpp \
-    tests/EncodedBuffer_test.cpp \
+    tests/PrivacyBuffer_test.cpp \
     tests/FdBuffer_test.cpp \
     tests/Reporter_test.cpp \
     tests/Section_test.cpp \
@@ -116,6 +115,7 @@
     libcutils \
     libincident \
     liblog \
+    libprotoutil \
     libselinux \
     libservices \
     libutils \
diff --git a/cmds/incidentd/src/EncodedBuffer.cpp b/cmds/incidentd/src/EncodedBuffer.cpp
deleted file mode 100644
index e8f2c11..0000000
--- a/cmds/incidentd/src/EncodedBuffer.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "EncodedBuffer.h"
-#include "io_util.h"
-#include "protobuf.h"
-
-#include <deque>
-
-const size_t BUFFER_SIZE = 4 * 1024; // 4 KB
-
-/**
- * Read varint from iterator, the iterator will point to next available byte.
- * Return the number of bytes of the varint.
- */
-static uint32_t
-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)++;
-        i++;
-    }
-    return val;
-}
-
-/**
- * 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.
- */
-static size_t
-write_field_or_skip(FdBuffer::iterator* iter, vector<uint8_t>* buf, uint8_t wireType, bool skip)
-{
-    FdBuffer::iterator snapshot = iter->snapshot();
-    size_t bytesToWrite = 0;
-    uint32_t varint = 0;
-    switch (wireType) {
-        case WIRE_TYPE_VARINT:
-            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(iter);
-            if(!skip) write_raw_varint(buf, bytesToWrite);
-            break;
-        case WIRE_TYPE_FIXED32:
-            bytesToWrite = 4;
-            break;
-    }
-    if (skip) {
-        *iter += bytesToWrite;
-    } else {
-        for (size_t i=0; i<bytesToWrite; i++) {
-            buf->push_back(**iter);
-            (*iter)++;
-        }
-    }
-    return skip ? 0 : *iter - snapshot;
-}
-
-/**
- * Strip next field based on its private policy and request spec, then stores data in buf.
- * Return NO_ERROR if succeeds, otherwise BAD_VALUE is returned to indicate bad data in FdBuffer.
- *
- * The iterator must point to the head of a protobuf formatted field for successful operation.
- * After exit with NO_ERROR, iterator points to the next protobuf field's head.
- */
-static status_t
-stripField(FdBuffer::iterator* iter, vector<uint8_t>* buf, const Privacy* parentPolicy, const PrivacySpec& spec)
-{
-    if (iter->outOfBound() || parentPolicy == NULL) return BAD_VALUE;
-
-    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();
-        if (!skip) amt += write_header(buf, fieldId, wireType);
-        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(iter);
-    size_t finalSize = 0;
-    FdBuffer::iterator start = iter->snapshot();
-    while ((*iter - start) != (int)msgSize) {
-        vector<uint8_t> v;
-        status_t err = stripField(iter, &v, policy, spec);
-        if (err != NO_ERROR) return err;
-        if (v.empty()) continue;
-        q.push_back(v);
-        finalSize += v.size();
-    }
-
-    write_header(buf, fieldId, wireType);
-    write_raw_varint(buf, 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);
-        }
-        q.pop_front();
-    }
-    return NO_ERROR;
-}
-
-// ================================================================================
-EncodedBuffer::EncodedBuffer(const FdBuffer& buffer, const Privacy* policy)
-        : mFdBuffer(buffer),
-          mPolicy(policy),
-          mBuffers(),
-          mSize(0)
-{
-}
-
-EncodedBuffer::~EncodedBuffer()
-{
-}
-
-status_t
-EncodedBuffer::strip(const PrivacySpec& spec)
-{
-    // optimization when no strip happens
-    if (mPolicy == NULL || !mPolicy->HasChildren() || spec.RequireAll()) {
-        if (spec.CheckPremission(mPolicy)) mSize = mFdBuffer.size();
-        return NO_ERROR;
-    }
-
-    FdBuffer::iterator it = mFdBuffer.begin();
-    vector<uint8_t> field;
-    field.reserve(BUFFER_SIZE);
-
-    while (it != mFdBuffer.end()) {
-        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);
-            mSize += field.size();
-            field.clear();
-        }
-    }
-    if (!field.empty()) {
-        mBuffers.push_back(field);
-        mSize += field.size();
-    }
-    return NO_ERROR;
-}
-
-void
-EncodedBuffer::clear()
-{
-    mSize = 0;
-    mBuffers.clear();
-}
-
-size_t
-EncodedBuffer::size() const { return mSize; }
-
-status_t
-EncodedBuffer::flush(int fd)
-{
-    if (size() == mFdBuffer.size()) return mFdBuffer.flush(fd);
-
-    for (vector<vector<uint8_t>>::iterator it = mBuffers.begin(); it != mBuffers.end(); it++) {
-        status_t err = write_all(fd, it->data(), it->size());
-        if (err != NO_ERROR) return err;
-    }
-    return NO_ERROR;
-}
-
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index bb399b5..b7633a4 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -17,7 +17,6 @@
 #define LOG_TAG "incidentd"
 
 #include "FdBuffer.h"
-#include "io_util.h"
 
 #include <cutils/log.h>
 #include <utils/SystemClock.h>
@@ -31,10 +30,9 @@
 const ssize_t MAX_BUFFER_COUNT = 256; // 4 MB max
 
 FdBuffer::FdBuffer()
-    :mBuffers(),
+    :mBuffer(BUFFER_SIZE),
      mStartTime(-1),
      mFinishTime(-1),
-     mCurrentWritten(-1),
      mTimedOut(false),
      mTruncated(false)
 {
@@ -42,11 +40,6 @@
 
 FdBuffer::~FdBuffer()
 {
-    const int N = mBuffers.size();
-    for (int i=0; i<N; i++) {
-        uint8_t* buf = mBuffers[i];
-        free(buf);
-    }
 }
 
 status_t
@@ -60,20 +53,12 @@
 
     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
 
-    uint8_t* buf = NULL;
     while (true) {
-        if (mCurrentWritten >= BUFFER_SIZE || mCurrentWritten < 0) {
-            if (mBuffers.size() == MAX_BUFFER_COUNT) {
-                mTruncated = true;
-                break;
-            }
-            buf = (uint8_t*)malloc(BUFFER_SIZE);
-            if (buf == NULL) {
-                return NO_MEMORY;
-            }
-            mBuffers.push_back(buf);
-            mCurrentWritten = 0;
+        if (mBuffer.size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
+            mTruncated = true;
+            break;
         }
+        if (mBuffer.writeBuffer() == NULL) return NO_MEMORY;
 
         int64_t remainingTime = (mStartTime + timeout) - uptimeMillis();
         if (remainingTime <= 0) {
@@ -91,7 +76,7 @@
             if ((pfds.revents & POLLERR) != 0) {
                 return errno != 0 ? -errno : UNKNOWN_ERROR;
             } else {
-                ssize_t amt = ::read(fd, buf + mCurrentWritten, BUFFER_SIZE - mCurrentWritten);
+                ssize_t amt = ::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
                 if (amt < 0) {
                     if (errno == EAGAIN || errno == EWOULDBLOCK) {
                         continue;
@@ -101,11 +86,10 @@
                 } else if (amt == 0) {
                     break;
                 }
-                mCurrentWritten += amt;
+                mBuffer.wp()->move(amt);
             }
         }
     }
-
     mFinishTime = uptimeMillis();
     return NO_ERROR;
 }
@@ -132,20 +116,12 @@
     int rpos = 0, wpos = 0;
 
     // This is the buffer used to store processed data
-    uint8_t* buf = NULL;
     while (true) {
-        if (mCurrentWritten >= BUFFER_SIZE || mCurrentWritten < 0) {
-            if (mBuffers.size() == MAX_BUFFER_COUNT) {
-                mTruncated = true;
-                break;
-            }
-            buf = (uint8_t*)malloc(BUFFER_SIZE);
-            if (buf == NULL) {
-                return NO_MEMORY;
-            }
-            mBuffers.push_back(buf);
-            mCurrentWritten = 0;
+        if (mBuffer.size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
+            mTruncated = true;
+            break;
         }
+        if (mBuffer.writeBuffer() == NULL) return NO_MEMORY;
 
         int64_t remainingTime = (mStartTime + timeoutMs) - uptimeMillis();
         if (remainingTime <= 0) {
@@ -223,7 +199,7 @@
         }
 
         // read from parsing process
-        ssize_t amt = ::read(fromFd, buf + mCurrentWritten, BUFFER_SIZE - mCurrentWritten);
+        ssize_t amt = ::read(fromFd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
         if (amt < 0) {
             if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
                 return -errno;
@@ -231,7 +207,7 @@
         } else if (amt == 0) {
             break;
         } else {
-            mCurrentWritten += amt;
+            mBuffer.wp()->move(amt);
         }
     }
 
@@ -242,105 +218,11 @@
 size_t
 FdBuffer::size() const
 {
-    if (mBuffers.empty()) return 0;
-    return ((mBuffers.size() - 1) * BUFFER_SIZE) + mCurrentWritten;
+    return mBuffer.size();
 }
 
-status_t
-FdBuffer::flush(int fd) const
+EncodedBuffer::iterator
+FdBuffer::data() const
 {
-    size_t i=0;
-    status_t err = NO_ERROR;
-    for (i=0; i<mBuffers.size()-1; i++) {
-        err = write_all(fd, mBuffers[i], BUFFER_SIZE);
-        if (err != NO_ERROR) return err;
-    }
-    return write_all(fd, mBuffers[i], mCurrentWritten);
-}
-
-FdBuffer::iterator
-FdBuffer::begin() const
-{
-    return iterator(*this, 0, 0);
-}
-
-FdBuffer::iterator
-FdBuffer::end() const
-{
-    if (mBuffers.empty() || mCurrentWritten < 0) return begin();
-    if (mCurrentWritten == BUFFER_SIZE)
-        // FdBuffer doesn't allocate another buf since no more bytes to read.
-        return FdBuffer::iterator(*this, mBuffers.size(), 0);
-    return FdBuffer::iterator(*this, mBuffers.size() - 1, mCurrentWritten);
-}
-
-// ===============================================================================
-FdBuffer::iterator::iterator(const FdBuffer& buffer, ssize_t index, ssize_t offset)
-        : mFdBuffer(buffer),
-          mIndex(index),
-          mOffset(offset)
-{
-}
-
-FdBuffer::iterator&
-FdBuffer::iterator::operator=(iterator& other) const { return other; }
-
-FdBuffer::iterator&
-FdBuffer::iterator::operator+(size_t offset)
-{
-    size_t newOffset = mOffset + offset;
-    while (newOffset >= BUFFER_SIZE) {
-        mIndex++;
-        newOffset -= BUFFER_SIZE;
-    }
-    mOffset = newOffset;
-    return *this;
-}
-
-FdBuffer::iterator&
-FdBuffer::iterator::operator+=(size_t offset) { return *this + offset; }
-
-FdBuffer::iterator&
-FdBuffer::iterator::operator++() { return *this + 1; }
-
-FdBuffer::iterator
-FdBuffer::iterator::operator++(int) { return *this + 1; }
-
-bool
-FdBuffer::iterator::operator==(iterator other) const
-{
-    return mIndex == other.mIndex && mOffset == other.mOffset;
-}
-
-bool
-FdBuffer::iterator::operator!=(iterator other) const { return !(*this == other); }
-
-int
-FdBuffer::iterator::operator-(iterator other) const
-{
-    return (int)bytesRead() - (int)other.bytesRead();
-}
-
-FdBuffer::iterator::reference
-FdBuffer::iterator::operator*() const
-{
-    return mFdBuffer.mBuffers[mIndex][mOffset];
-}
-
-FdBuffer::iterator
-FdBuffer::iterator::snapshot() const
-{
-    return FdBuffer::iterator(mFdBuffer, mIndex, mOffset);
-}
-
-size_t
-FdBuffer::iterator::bytesRead() const
-{
-    return mIndex * BUFFER_SIZE + mOffset;
-}
-
-bool
-FdBuffer::iterator::outOfBound() const
-{
-    return bytesRead() > mFdBuffer.size();
+    return mBuffer.begin();
 }
diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h
index dfe39c6..8857ae7 100644
--- a/cmds/incidentd/src/FdBuffer.h
+++ b/cmds/incidentd/src/FdBuffer.h
@@ -17,11 +17,11 @@
 #ifndef FD_BUFFER_H
 #define FD_BUFFER_H
 
+#include <android/util/EncodedBuffer.h>
 #include <utils/Errors.h>
 
-#include <vector>
-
 using namespace android;
+using namespace android::util;
 using namespace std;
 
 /**
@@ -71,52 +71,19 @@
     size_t size() const;
 
     /**
-     * Flush all the data to given file descriptor;
-     */
-    status_t flush(int fd) const;
-
-    /**
      * How long the read took in milliseconds.
      */
     int64_t durationMs() const { return mFinishTime - mStartTime; }
 
     /**
-     * Read data stored in FdBuffer
+     * Reader API for data stored in FdBuffer
      */
-    class iterator;
-    friend class iterator;
-    class iterator : public std::iterator<std::random_access_iterator_tag, uint8_t> {
-    public:
-        iterator(const FdBuffer& buffer, ssize_t index, ssize_t offset);
-        iterator& operator=(iterator& other) const;
-        iterator& operator+(size_t offset);
-        iterator& operator+=(size_t offset);
-        iterator& operator++();
-        iterator operator++(int);
-        bool operator==(iterator other) const;
-        bool operator!=(iterator other) const;
-        int operator-(iterator other) const;
-        reference operator*() const;
-
-        // return the snapshot of the current iterator
-        iterator snapshot() const;
-        // how many bytes are read
-        size_t bytesRead() const;
-        // random access could make the iterator out of bound
-        bool outOfBound() const;
-    private:
-        const FdBuffer& mFdBuffer;
-        size_t mIndex;
-        size_t mOffset;
-    };
-    iterator begin() const;
-    iterator end() const;
+    EncodedBuffer::iterator data() const;
 
 private:
-    vector<uint8_t*> mBuffers;
+    EncodedBuffer mBuffer;
     int64_t mStartTime;
     int64_t mFinishTime;
-    ssize_t mCurrentWritten;
     bool mTimedOut;
     bool mTruncated;
 };
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
new file mode 100644
index 0000000..07a064cf
--- /dev/null
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+#include "PrivacyBuffer.h"
+#include "io_util.h"
+
+#include <android/util/protobuf.h>
+#include <deque>
+
+using namespace android::util;
+
+/**
+ * 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.
+ */
+static size_t
+write_field_or_skip(EncodedBuffer::iterator* iter, EncodedBuffer* buf, uint8_t wireType, bool skip)
+{
+    EncodedBuffer::Pointer snapshot = iter->rp()->copy();
+    size_t bytesToWrite = 0;
+    uint32_t varint = 0;
+    switch (wireType) {
+        case WIRE_TYPE_VARINT:
+            varint = iter->readRawVarint();
+            if(!skip) return buf->writeRawVarint(varint);
+            break;
+        case WIRE_TYPE_FIXED64:
+            bytesToWrite = 8;
+            break;
+        case WIRE_TYPE_LENGTH_DELIMITED:
+            bytesToWrite = iter->readRawVarint();
+            if(!skip) buf->writeRawVarint(bytesToWrite);
+            break;
+        case WIRE_TYPE_FIXED32:
+            bytesToWrite = 4;
+            break;
+    }
+    if (skip) {
+        iter->rp()->move(bytesToWrite);
+    } else {
+        for (size_t i=0; i<bytesToWrite; i++) {
+            *buf->writeBuffer() = iter->next();
+            buf->wp()->move();
+        }
+    }
+    return skip ? 0 : iter->rp()->pos() - snapshot.pos();
+}
+
+/**
+ * Strip next field based on its private policy and request spec, then stores data in buf.
+ * Return NO_ERROR if succeeds, otherwise BAD_VALUE is returned to indicate bad data in FdBuffer.
+ *
+ * The iterator must point to the head of a protobuf formatted field for successful operation.
+ * After exit with NO_ERROR, iterator points to the next protobuf field's head.
+ */
+static status_t
+stripField(EncodedBuffer::iterator* iter, EncodedBuffer* buf, const Privacy* parentPolicy, const PrivacySpec& spec)
+{
+    if (!iter->hasNext() || parentPolicy == NULL) return BAD_VALUE;
+    uint32_t varint = iter->readRawVarint();
+    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();
+        if (!skip) amt += buf->writeHeader(fieldId, wireType);
+        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<EncodedBuffer*> q;
+    uint32_t msgSize = iter->readRawVarint();
+    size_t finalSize = 0;
+    EncodedBuffer::Pointer start = iter->rp()->copy();
+    while (iter->rp()->pos() - start.pos() != msgSize) {
+        EncodedBuffer* v = new EncodedBuffer();
+        status_t err = stripField(iter, v, policy, spec);
+        if (err != NO_ERROR) return err;
+        if (v->size() == 0) continue;
+        q.push_back(v);
+        finalSize += v->size();
+    }
+
+    buf->writeHeader(fieldId, wireType);
+    buf->writeRawVarint(finalSize);
+    while (!q.empty()) {
+        EncodedBuffer* subField = q.front();
+        EncodedBuffer::iterator it = subField->begin();
+        while (it.hasNext()) {
+            *buf->writeBuffer() = it.next();
+            buf->wp()->move();
+        }
+        q.pop_front();
+        delete subField;
+    }
+    return NO_ERROR;
+}
+
+// ================================================================================
+PrivacyBuffer::PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data)
+        :mPolicy(policy),
+         mData(data),
+         mBuffer(0),
+         mSize(0)
+{
+}
+
+PrivacyBuffer::~PrivacyBuffer()
+{
+}
+
+status_t
+PrivacyBuffer::strip(const PrivacySpec& spec)
+{
+    // optimization when no strip happens
+    if (mPolicy == NULL || !mPolicy->HasChildren() || spec.RequireAll()) {
+        if (spec.CheckPremission(mPolicy)) mSize = mData.size();
+        return NO_ERROR;
+    }
+    while (mData.hasNext()) {
+        status_t err = stripField(&mData, &mBuffer, mPolicy, spec);
+        if (err != NO_ERROR) return err;
+    }
+    if (mData.bytesRead() != mData.size()) return BAD_VALUE;
+    mSize = mBuffer.size();
+    mData.rp()->rewind(); // rewind the read pointer back to beginning after the strip.
+    return NO_ERROR;
+}
+
+void
+PrivacyBuffer::clear()
+{
+    mSize = 0;
+    mBuffer.wp()->rewind();
+}
+
+size_t
+PrivacyBuffer::size() const { return mSize; }
+
+status_t
+PrivacyBuffer::flush(int fd)
+{
+    status_t err = NO_ERROR;
+    EncodedBuffer::iterator iter = size() == mData.size() ? mData : mBuffer.begin();
+    while (iter.readBuffer() != NULL) {
+        err = write_all(fd, iter.readBuffer(), iter.currentToRead());
+        iter.rp()->move(iter.currentToRead());
+        if (err != NO_ERROR) return err;
+    }
+    return NO_ERROR;
+}
diff --git a/cmds/incidentd/src/EncodedBuffer.h b/cmds/incidentd/src/PrivacyBuffer.h
similarity index 69%
rename from cmds/incidentd/src/EncodedBuffer.h
rename to cmds/incidentd/src/PrivacyBuffer.h
index ea8603a..720b38e 100644
--- a/cmds/incidentd/src/EncodedBuffer.h
+++ b/cmds/incidentd/src/PrivacyBuffer.h
@@ -14,25 +14,27 @@
  * limitations under the License.
  */
 
-#ifndef ENCODED_BUFFER_H
-#define ENCODED_BUFFER_H
+#ifndef PRIVACY_BUFFER_H
+#define PRIVACY_BUFFER_H
 
-#include "FdBuffer.h"
 #include "Privacy.h"
 
+#include <android/util/EncodedBuffer.h>
 #include <stdint.h>
-#include <vector>
+#include <utils/Errors.h>
+
+using namespace android;
+using namespace android::util;
 
 /**
- * EncodedBuffer is constructed from FdBuffer which holds original protobuf formatted data and
- * its privacy policy in its tagged proto message. The class strips PII-sensitive fields
- * based on the request and holds stripped data in its buffer for output.
+ * PrivacyBuffer holds the original protobuf data and strips PII-sensitive fields
+ * based on the request and holds stripped data in its own buffer for output.
  */
-class EncodedBuffer
+class PrivacyBuffer
 {
 public:
-    EncodedBuffer(const FdBuffer& buffer, const Privacy* policy);
-    ~EncodedBuffer();
+    PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data);
+    ~PrivacyBuffer();
 
     /**
      * Strip based on the request and hold data in its own buffer. Return NO_ERROR if strip succeeds.
@@ -55,10 +57,11 @@
     status_t flush(int fd);
 
 private:
-    const FdBuffer& mFdBuffer;
     const Privacy* mPolicy;
-    vector<vector<uint8_t>> mBuffers;
+    EncodedBuffer::iterator& mData;
+
+    EncodedBuffer mBuffer;
     size_t mSize;
 };
 
-#endif // ENCODED_BUFFER_H
\ No newline at end of file
+#endif // PRIVACY_BUFFER_H
\ No newline at end of file
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 166fef0..892bcca 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -16,15 +16,15 @@
 
 #define LOG_TAG "incidentd"
 
-#include "EncodedBuffer.h"
 #include "FdBuffer.h"
 #include "Privacy.h"
+#include "PrivacyBuffer.h"
 #include "Section.h"
 
 #include "io_util.h"
-#include "protobuf.h"
 #include "section_list.h"
 
+#include <android/util/protobuf.h>
 #include <private/android_filesystem_config.h>
 #include <binder/IServiceManager.h>
 #include <map>
@@ -32,8 +32,13 @@
 #include <wait.h>
 #include <unistd.h>
 
+using namespace android::util;
 using namespace std;
 
+// special section ids
+const int FIELD_ID_INCIDENT_HEADER = 1;
+
+// incident section parameters
 const int   WAIT_MAX = 5;
 const struct timespec WAIT_INTERVAL_NS = {0, 200 * 1000 * 1000};
 const char* INCIDENT_HELPER = "/system/bin/incident_helper";
@@ -127,7 +132,8 @@
 write_report_requests(const int id, const FdBuffer& buffer, ReportRequestSet* requests)
 {
     status_t err = -EBADF;
-    EncodedBuffer encodedBuffer(buffer, get_privacy_of_section(id));
+    EncodedBuffer::iterator data = buffer.data();
+    PrivacyBuffer privacyBuffer(get_privacy_of_section(id), data);
     int writeable = 0;
 
     // The streaming ones, group requests by spec in order to save unnecessary strip operations
@@ -143,34 +149,34 @@
 
     for (map<PrivacySpec, vector<sp<ReportRequest>>>::iterator mit = requestsBySpec.begin(); mit != requestsBySpec.end(); mit++) {
         PrivacySpec spec = mit->first;
-        err = encodedBuffer.strip(spec);
-        if (err != NO_ERROR) return err; // it means the encodedBuffer data is corrupted.
-        if (encodedBuffer.size() == 0) continue;
+        err = privacyBuffer.strip(spec);
+        if (err != NO_ERROR) return err; // it means the privacyBuffer data is corrupted.
+        if (privacyBuffer.size() == 0) continue;
 
         for (vector<sp<ReportRequest>>::iterator it = mit->second.begin(); it != mit->second.end(); it++) {
             sp<ReportRequest> request = *it;
-            err = write_section_header(request->fd, id, encodedBuffer.size());
+            err = write_section_header(request->fd, id, privacyBuffer.size());
             if (err != NO_ERROR) { request->err = err; continue; }
-            err = encodedBuffer.flush(request->fd);
+            err = privacyBuffer.flush(request->fd);
             if (err != NO_ERROR) { request->err = err; continue; }
             writeable++;
-            ALOGD("Section %d flushed %zu bytes to fd %d with spec %d", id, encodedBuffer.size(), request->fd, spec.dest);
+            ALOGD("Section %d flushed %zu bytes to fd %d with spec %d", id, privacyBuffer.size(), request->fd, spec.dest);
         }
-        encodedBuffer.clear();
+        privacyBuffer.clear();
     }
 
     // The dropbox file
     if (requests->mainFd() >= 0) {
-        err = encodedBuffer.strip(get_default_dropbox_spec());
+        err = privacyBuffer.strip(get_default_dropbox_spec());
         if (err != NO_ERROR) return err; // the buffer data is corrupted.
-        if (encodedBuffer.size() == 0) goto DONE;
+        if (privacyBuffer.size() == 0) goto DONE;
 
-        err = write_section_header(requests->mainFd(), id, encodedBuffer.size());
+        err = write_section_header(requests->mainFd(), id, privacyBuffer.size());
         if (err != NO_ERROR) { requests->setMainFd(-1); goto DONE; }
-        err = encodedBuffer.flush(requests->mainFd());
+        err = privacyBuffer.flush(requests->mainFd());
         if (err != NO_ERROR) { requests->setMainFd(-1); goto DONE; }
         writeable++;
-        ALOGD("Section %d flushed %zu bytes to dropbox %d", id, encodedBuffer.size(), requests->mainFd());
+        ALOGD("Section %d flushed %zu bytes to dropbox %d", id, privacyBuffer.size(), requests->mainFd());
     }
 
 DONE:
diff --git a/cmds/incidentd/tests/FdBuffer_test.cpp b/cmds/incidentd/tests/FdBuffer_test.cpp
index d1436b2..2afa778 100644
--- a/cmds/incidentd/tests/FdBuffer_test.cpp
+++ b/cmds/incidentd/tests/FdBuffer_test.cpp
@@ -49,12 +49,11 @@
 
     void AssertBufferContent(const char* expected) {
         int i=0;
-        FdBuffer::iterator it = buffer.begin();
-        while (expected[i] != '\0') {
-            ASSERT_EQ(*it, expected[i++]);
-            it++;
+        EncodedBuffer::iterator it = buffer.data();
+        while (it.hasNext()) {
+            ASSERT_EQ(it.next(), expected[i++]);
         }
-        ASSERT_EQ(it, buffer.end());
+        EXPECT_EQ(expected[i], '\0');
     }
 
     bool DoDataStream(int rFd, int wFd) {
@@ -92,20 +91,8 @@
 }
 
 TEST_F(FdBufferTest, IterateEmpty) {
-    FdBuffer::iterator it = buffer.begin();
-    EXPECT_EQ(it, buffer.end());
-    it += 1;
-    EXPECT_TRUE(it.outOfBound());
-}
-
-TEST_F(FdBufferTest, IteratorSnapshot) {
-    FdBuffer::iterator it = buffer.begin();
-    it += 4;
-    FdBuffer::iterator snapshot = it.snapshot();
-    it += 5;
-    EXPECT_TRUE(snapshot != it);
-    EXPECT_EQ(it - snapshot, 5);
-    EXPECT_EQ(snapshot - it, -5);
+    EncodedBuffer::iterator it = buffer.data();
+    EXPECT_FALSE(it.hasNext());
 }
 
 TEST_F(FdBufferTest, ReadAndIterate) {
@@ -114,15 +101,15 @@
     ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
 
     int i=0;
-    for (FdBuffer::iterator it = buffer.begin(); it != buffer.end(); ++it) {
-        EXPECT_EQ(*it, (uint8_t)testdata[i++]);
+    EncodedBuffer::iterator it = buffer.data();
+    while (it.hasNext()) {
+        EXPECT_EQ(it.next(), (uint8_t)testdata[i++]);
     }
 
-    FdBuffer::iterator it = buffer.begin();
-    it += buffer.size();
-    EXPECT_EQ(it, buffer.end());
+    it.rp()->rewind();
+    it.rp()->move(buffer.size());
     EXPECT_EQ(it.bytesRead(), testdata.size());
-    EXPECT_FALSE(it.outOfBound());
+    EXPECT_FALSE(it.hasNext());
 }
 
 TEST_F(FdBufferTest, ReadTimeout) {
@@ -258,13 +245,15 @@
         EXPECT_FALSE(buffer.timedOut());
         EXPECT_TRUE(buffer.truncated());
         wait(&pid);
-        FdBuffer::iterator it = buffer.begin();
-        it += fourMB;
+        EncodedBuffer::iterator it = buffer.data();
+        it.rp()->move(fourMB);
         EXPECT_EQ(it.bytesRead(), fourMB);
-        EXPECT_EQ(it, buffer.end());
-        for (FdBuffer::iterator it = buffer.begin(); it != buffer.end(); it++) {
+        EXPECT_FALSE(it.hasNext());
+
+        it.rp()->rewind();
+        while (it.hasNext()) {
             char c = 'A' + (it.bytesRead() % 64 / 8);
-            ASSERT_TRUE(*it == c);
+            ASSERT_TRUE(it.next() == c);
         }
     }
 }
diff --git a/cmds/incidentd/tests/EncodedBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
similarity index 77%
rename from cmds/incidentd/tests/EncodedBuffer_test.cpp
rename to cmds/incidentd/tests/PrivacyBuffer_test.cpp
index 37a938a..8f6e355 100644
--- a/cmds/incidentd/tests/EncodedBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -12,7 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "EncodedBuffer.h"
+#include "FdBuffer.h"
+#include "PrivacyBuffer.h"
 
 #include <android-base/file.h>
 #include <android-base/test_utils.h>
@@ -42,9 +43,10 @@
 const string FIX32_FIELD_4 = "\x25\xff\xff\xff\xff"; // -1
 const string MESSAGE_FIELD_5 = "\x2a\x10" + VARINT_FIELD_1 + STRING_FIELD_2;
 
-class EncodedBufferTest : public Test {
+
+class PrivacyBufferTest : public Test {
 public:
-    virtual ~EncodedBufferTest() {
+    virtual ~PrivacyBufferTest() {
         // Delete in reverse order of construction, to be consistent with
         // regular allocation/deallocation.
         while (!privacies.empty()) {
@@ -60,9 +62,10 @@
     void writeToFdBuffer(string str) {
         ASSERT_TRUE(WriteStringToFile(str, tf.path, false));
         ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, 10000));
+        ASSERT_EQ(str.size(), buffer.size());
     }
 
-    void assertBuffer(EncodedBuffer& buf, string expected) {
+    void assertBuffer(PrivacyBuffer& buf, string expected) {
         ASSERT_EQ(buf.size(), expected.size());
         CaptureStdout();
         ASSERT_EQ(buf.flush(STDOUT_FILENO), NO_ERROR);
@@ -71,9 +74,10 @@
 
     void assertStrip(uint8_t dest, string expected, Privacy* policy) {
         PrivacySpec spec(dest);
-        EncodedBuffer encodedBuf(buffer, policy);
-        ASSERT_EQ(encodedBuf.strip(spec), NO_ERROR);
-        assertBuffer(encodedBuf, expected);
+        EncodedBuffer::iterator bufData = buffer.data();
+        PrivacyBuffer privacyBuf(policy, bufData);
+        ASSERT_EQ(privacyBuf.strip(spec), NO_ERROR);
+        assertBuffer(privacyBuf, expected);
     }
 
     void assertStripByFields(uint8_t dest, string expected, int size, Privacy* privacy, ...) {
@@ -134,67 +138,67 @@
     }
 };
 
-TEST_F(EncodedBufferTest, NullFieldPolicy) {
+TEST_F(PrivacyBufferTest, NullFieldPolicy) {
     writeToFdBuffer(STRING_FIELD_0);
     assertStrip(EXPLICIT, STRING_FIELD_0, create_string_privacy(300, AUTOMATIC, NULL));
 }
 
-TEST_F(EncodedBufferTest, StripSpecNotAllowed) {
+TEST_F(PrivacyBufferTest, StripSpecNotAllowed) {
     writeToFdBuffer(STRING_FIELD_0);
     assertStripByFields(AUTOMATIC, "", 1, create_privacy(0, STRING_TYPE, EXPLICIT));
 }
 
-TEST_F(EncodedBufferTest, StripVarintField) {
+TEST_F(PrivacyBufferTest, StripVarintField) {
     writeToFdBuffer(VARINT_FIELD_1);
     assertStripByFields(EXPLICIT, "", 1, create_privacy(1, OTHER_TYPE, LOCAL));
 }
 
-TEST_F(EncodedBufferTest, StripLengthDelimitedField_String) {
+TEST_F(PrivacyBufferTest, StripLengthDelimitedField_String) {
     writeToFdBuffer(STRING_FIELD_2);
     assertStripByFields(EXPLICIT, "", 1, create_privacy(2, STRING_TYPE, LOCAL));
 }
 
-TEST_F(EncodedBufferTest, StripFixed64Field) {
+TEST_F(PrivacyBufferTest, StripFixed64Field) {
     writeToFdBuffer(FIX64_FIELD_3);
     assertStripByFields(EXPLICIT, "", 1, create_privacy(3, OTHER_TYPE, LOCAL));
 }
 
-TEST_F(EncodedBufferTest, StripFixed32Field) {
+TEST_F(PrivacyBufferTest, StripFixed32Field) {
     writeToFdBuffer(FIX32_FIELD_4);
     assertStripByFields(EXPLICIT, "", 1, create_privacy(4, OTHER_TYPE, LOCAL));
 }
 
-TEST_F(EncodedBufferTest, StripLengthDelimitedField_Message) {
+TEST_F(PrivacyBufferTest, StripLengthDelimitedField_Message) {
     writeToFdBuffer(MESSAGE_FIELD_5);
     assertStripByFields(EXPLICIT, "", 1, create_privacy(5, MESSAGE_TYPE, LOCAL));
 }
 
-TEST_F(EncodedBufferTest, NoStripVarintField) {
+TEST_F(PrivacyBufferTest, NoStripVarintField) {
     writeToFdBuffer(VARINT_FIELD_1);
     assertStripByFields(EXPLICIT, VARINT_FIELD_1, 1, create_privacy(1, OTHER_TYPE, AUTOMATIC));
 }
 
-TEST_F(EncodedBufferTest, NoStripLengthDelimitedField_String) {
+TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_String) {
     writeToFdBuffer(STRING_FIELD_2);
     assertStripByFields(EXPLICIT, STRING_FIELD_2, 1, create_privacy(2, STRING_TYPE, AUTOMATIC));
 }
 
-TEST_F(EncodedBufferTest, NoStripFixed64Field) {
+TEST_F(PrivacyBufferTest, NoStripFixed64Field) {
     writeToFdBuffer(FIX64_FIELD_3);
     assertStripByFields(EXPLICIT, FIX64_FIELD_3, 1, create_privacy(3, OTHER_TYPE, AUTOMATIC));
 }
 
-TEST_F(EncodedBufferTest, NoStripFixed32Field) {
+TEST_F(PrivacyBufferTest, NoStripFixed32Field) {
     writeToFdBuffer(FIX32_FIELD_4);
     assertStripByFields(EXPLICIT, FIX32_FIELD_4, 1, create_privacy(4, OTHER_TYPE, AUTOMATIC));
 }
 
-TEST_F(EncodedBufferTest, NoStripLengthDelimitedField_Message) {
+TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_Message) {
     writeToFdBuffer(MESSAGE_FIELD_5);
     assertStripByFields(EXPLICIT, MESSAGE_FIELD_5, 1, create_privacy(5, MESSAGE_TYPE, AUTOMATIC));
 }
 
-TEST_F(EncodedBufferTest, StripVarintAndString) {
+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;
@@ -202,7 +206,7 @@
             create_privacy(1, OTHER_TYPE, LOCAL), create_privacy(2, STRING_TYPE, LOCAL));
 }
 
-TEST_F(EncodedBufferTest, StripVarintAndFixed64) {
+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;
@@ -210,46 +214,49 @@
             create_privacy(1, OTHER_TYPE, LOCAL), create_privacy(3, OTHER_TYPE, LOCAL));
 }
 
-TEST_F(EncodedBufferTest, StripVarintInNestedMessage) {
+TEST_F(PrivacyBufferTest, StripVarintInNestedMessage) {
     writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5);
     Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
     string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
     assertStripByFields(EXPLICIT, expected, 1, create_message_privacy(5, list));
 }
 
-TEST_F(EncodedBufferTest, StripFix64AndVarintInNestedMessage) {
+TEST_F(PrivacyBufferTest, StripFix64AndVarintInNestedMessage) {
     writeToFdBuffer(STRING_FIELD_0 + FIX64_FIELD_3 + MESSAGE_FIELD_5);
     Privacy* list[] = { create_privacy(1, OTHER_TYPE, 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));
 }
 
-TEST_F(EncodedBufferTest, ClearAndStrip) {
+TEST_F(PrivacyBufferTest, ClearAndStrip) {
     string data = STRING_FIELD_0 + VARINT_FIELD_1;
     writeToFdBuffer(data);
     Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), NULL };
-    EncodedBuffer encodedBuf(buffer, create_message_privacy(300, list));
+    EncodedBuffer::iterator bufData = buffer.data();
+    PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData);
     PrivacySpec spec1(EXPLICIT), spec2(LOCAL);
 
-    ASSERT_EQ(encodedBuf.strip(spec1), NO_ERROR);
-    assertBuffer(encodedBuf, STRING_FIELD_0);
-    ASSERT_EQ(encodedBuf.strip(spec2), NO_ERROR);
-    assertBuffer(encodedBuf, data);
+    ASSERT_EQ(privacyBuf.strip(spec1), NO_ERROR);
+    assertBuffer(privacyBuf, STRING_FIELD_0);
+    ASSERT_EQ(privacyBuf.strip(spec2), NO_ERROR);
+    assertBuffer(privacyBuf, data);
 }
 
-TEST_F(EncodedBufferTest, BadDataInFdBuffer) {
+TEST_F(PrivacyBufferTest, BadDataInFdBuffer) {
     writeToFdBuffer("iambaddata");
     Privacy* list[] = { create_privacy(4, OTHER_TYPE, AUTOMATIC), NULL };
-    EncodedBuffer encodedBuf(buffer, create_message_privacy(300, list));
+    EncodedBuffer::iterator bufData = buffer.data();
+    PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData);
     PrivacySpec spec;
-    ASSERT_EQ(encodedBuf.strip(spec), BAD_VALUE);
+    ASSERT_EQ(privacyBuf.strip(spec), BAD_VALUE);
 }
 
-TEST_F(EncodedBufferTest, BadDataInNestedMessage) {
+TEST_F(PrivacyBufferTest, BadDataInNestedMessage) {
     writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5 + "aoeoe");
     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));
+    EncodedBuffer::iterator bufData = buffer.data();
+    PrivacyBuffer privacyBuf(create_message_privacy(300, field5), bufData);
     PrivacySpec spec;
-    ASSERT_EQ(encodedBuf.strip(spec), BAD_VALUE);
+    ASSERT_EQ(privacyBuf.strip(spec), BAD_VALUE);
 }
diff --git a/libs/protoutil/Android.mk b/libs/protoutil/Android.mk
new file mode 100644
index 0000000..a534816
--- /dev/null
+++ b/libs/protoutil/Android.mk
@@ -0,0 +1,39 @@
+#
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotoutil
+
+LOCAL_CFLAGS := \
+        -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
+
+LOCAL_SHARED_LIBRARIES := \
+        libbinder \
+        liblog \
+        libutils
+
+LOCAL_C_INCLUDES := \
+        $(LOCAL_PATH)/include
+
+LOCAL_SRC_FILES := \
+        src/EncodedBuffer.cpp \
+        src/protobuf.cpp \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/libs/protoutil/include/android/util/EncodedBuffer.h b/libs/protoutil/include/android/util/EncodedBuffer.h
new file mode 100644
index 0000000..cf09609
--- /dev/null
+++ b/libs/protoutil/include/android/util/EncodedBuffer.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UTIL_ENCODED_BUFFER_H
+#define ANDROID_UTIL_ENCODED_BUFFER_H
+
+#include <stdint.h>
+#include <vector>
+
+namespace android {
+namespace util {
+
+using namespace std;
+
+/**
+ * A stream of bytes containing a read pointer and a write pointer,
+ * backed by a set of fixed-size buffers.  There are write functions for the
+ * primitive types stored by protocol buffers, but none of the logic
+ * for tags, inner objects, or any of that.
+ *
+ * Terminology:
+ *      *Pos:       Position in the whole data set (as if it were a single buffer).
+ *      *Index:     Index of a buffer within the mBuffers list.
+ *      *Offset:    Position within a buffer.
+ */
+class EncodedBuffer
+{
+public:
+    EncodedBuffer();
+    EncodedBuffer(size_t chunkSize);
+    ~EncodedBuffer();
+
+    class Pointer {
+    public:
+        Pointer();
+        Pointer(size_t chunkSize);
+
+        size_t pos() const;
+        size_t index() const;
+        size_t offset() const;
+
+        void move(size_t amt);
+        inline void move() { move(1); };
+
+        void rewind();
+        Pointer copy() const;
+
+    private:
+        size_t mChunkSize;
+        size_t mIndex;
+        size_t mOffset;
+    };
+
+    /******************************** Write APIs ************************************************/
+
+    /**
+     * Returns the number of bytes written in the buffer
+     */
+    size_t size() const;
+
+    /**
+     * Returns the write pointer.
+     */
+    Pointer* wp();
+
+    /**
+     * Returns the current position of write pointer, if the write buffer is full, it will automatically
+     * rotate to a new buffer with given chunkSize. If NULL is returned, it means NO_MEMORY
+     */
+    uint8_t* writeBuffer();
+
+    /**
+     * Returns the writeable size in the current write buffer .
+     */
+    size_t currentToWrite();
+
+    /**
+     * Write a varint into a vector. Return the size of the varint.
+     */
+    size_t writeRawVarint(uint32_t val);
+
+    /**
+     * Write a protobuf header. Return the size of the header.
+     */
+    size_t writeHeader(uint32_t fieldId, uint8_t wireType);
+
+    /********************************* Read APIs ************************************************/
+    class iterator;
+    friend class iterator;
+    class iterator {
+    public:
+        iterator(const EncodedBuffer& buffer);
+
+        /**
+         * Returns the number of bytes written in the buffer
+         */
+        size_t size() const;
+
+        /**
+         * Returns the size of total bytes read.
+         */
+        size_t bytesRead() const;
+
+        /**
+         * Returns the read pointer.
+         */
+        Pointer* rp();
+
+        /**
+         * Returns the current position of read pointer, if NULL is returned, it reaches end of buffer.
+         */
+        uint8_t const* readBuffer();
+
+        /**
+         * Returns the readable size in the current read buffer.
+         */
+        size_t currentToRead();
+
+        /**
+         * Returns true if next bytes is available for read.
+         */
+        bool hasNext();
+
+        /**
+         * Reads the current byte and moves pointer 1 bit.
+         */
+        uint8_t next();
+
+        /**
+         * Read varint from iterator, the iterator will point to next available byte.
+         * Return the number of bytes of the varint.
+         */
+        uint32_t readRawVarint();
+
+    private:
+        const EncodedBuffer& mData;
+        Pointer mRp;
+    };
+
+    /**
+     * Returns the iterator of EncodedBuffer so it guarantees consumers won't be able to modified the buffer.
+     */
+    iterator begin() const;
+
+private:
+    size_t mChunkSize;
+    vector<uint8_t*> mBuffers;
+
+    Pointer mWp;
+
+    inline uint8_t* at(const Pointer& p) const; // helper function to get value
+};
+
+} // util
+} // android
+
+#endif // ANDROID_UTIL_ENCODED_BUFFER_H
\ No newline at end of file
diff --git a/cmds/incidentd/src/protobuf.h b/libs/protoutil/include/android/util/protobuf.h
similarity index 74%
rename from cmds/incidentd/src/protobuf.h
rename to libs/protoutil/include/android/util/protobuf.h
index 263c864..f4e8d09 100644
--- a/cmds/incidentd/src/protobuf.h
+++ b/libs/protoutil/include/android/util/protobuf.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef PROTOBUF_H
-#define PROTOBUF_H
+#ifndef ANDROID_UTIL_PROTOBUF_H
+#define ANDROID_UTIL_PROTOBUF_H
 
 #include <stdint.h>
-#include <vector>
+
+namespace android {
+namespace util {
 
 using namespace std;
 
@@ -50,19 +52,7 @@
  */
 uint8_t* write_length_delimited_tag_header(uint8_t* buf, uint32_t fieldId, size_t size);
 
-/**
- * Write a varint into a vector. Return the size of the varint.
- */
-size_t write_raw_varint(vector<uint8_t>* buf, uint32_t val);
+} // util
+} // android
 
-/**
- * Write a protobuf header. Return the size of the header.
- */
-size_t write_header(vector<uint8_t>* buf, uint32_t fieldId, uint8_t wireType);
-
-enum {
-    // IncidentProto.header
-    FIELD_ID_INCIDENT_HEADER = 1
-};
-
-#endif  // PROTOBUF_H
+#endif  // ANDROID_UTIL_PROTOUBUF_H
diff --git a/libs/protoutil/src/EncodedBuffer.cpp b/libs/protoutil/src/EncodedBuffer.cpp
new file mode 100644
index 0000000..84dc5b6
--- /dev/null
+++ b/libs/protoutil/src/EncodedBuffer.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/util/EncodedBuffer.h>
+
+#include <stdlib.h>
+
+namespace android {
+namespace util {
+
+const size_t BUFFER_SIZE = 8 * 1024; // 8 KB
+
+EncodedBuffer::Pointer::Pointer() : Pointer(BUFFER_SIZE)
+{
+}
+
+EncodedBuffer::Pointer::Pointer(size_t chunkSize)
+        :mIndex(0),
+         mOffset(0)
+{
+    mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
+}
+
+size_t
+EncodedBuffer::Pointer::pos() const
+{
+    return mIndex * mChunkSize + mOffset;
+}
+
+size_t
+EncodedBuffer::Pointer::index() const
+{
+    return mIndex;
+}
+
+size_t
+EncodedBuffer::Pointer::offset() const
+{
+    return mOffset;
+}
+
+void
+EncodedBuffer::Pointer::move(size_t amt)
+{
+    size_t newOffset = mOffset + amt;
+    mIndex += newOffset / mChunkSize;
+    mOffset = newOffset % mChunkSize;
+}
+
+void
+EncodedBuffer::Pointer::rewind()
+{
+    mIndex = 0;
+    mOffset = 0;
+}
+
+EncodedBuffer::Pointer
+EncodedBuffer::Pointer::copy() const
+{
+    Pointer p = Pointer(mChunkSize);
+    p.mIndex = mIndex;
+    p.mOffset = mOffset;
+    return p;
+}
+
+// ===========================================================
+EncodedBuffer::EncodedBuffer() : EncodedBuffer(0)
+{
+}
+
+EncodedBuffer::EncodedBuffer(size_t chunkSize)
+        :mBuffers()
+{
+    mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
+    mWp = Pointer(mChunkSize);
+}
+
+EncodedBuffer::~EncodedBuffer()
+{
+    for (size_t i=0; i<mBuffers.size(); i++) {
+        uint8_t* buf = mBuffers[i];
+        free(buf);
+    }
+}
+
+inline uint8_t*
+EncodedBuffer::at(const Pointer& p) const
+{
+    return mBuffers[p.index()] + p.offset();
+}
+
+/******************************** Write APIs ************************************************/
+size_t
+EncodedBuffer::size() const
+{
+    return mWp.pos();
+}
+
+EncodedBuffer::Pointer*
+EncodedBuffer::wp()
+{
+    return &mWp;
+}
+
+uint8_t*
+EncodedBuffer::writeBuffer()
+{
+    // This prevents write pointer move too fast than allocating the buffer.
+    if (mWp.index() > mBuffers.size()) return NULL;
+    uint8_t* buf = NULL;
+    if (mWp.index() == mBuffers.size()) {
+        buf = (uint8_t*)malloc(mChunkSize);
+
+        if (buf == NULL) return NULL; // This indicates NO_MEMORY
+
+        mBuffers.push_back(buf);
+    }
+    return at(mWp);
+}
+
+size_t
+EncodedBuffer::currentToWrite()
+{
+    return mChunkSize - mWp.offset();
+}
+
+size_t
+EncodedBuffer::writeRawVarint(uint32_t val)
+{
+    size_t size = 0;
+    while (true) {
+        size++;
+        if ((val & ~0x7F) == 0) {
+            *writeBuffer() = (uint8_t) val;
+            mWp.move();
+            return size;
+        } else {
+            *writeBuffer() = (uint8_t)((val & 0x7F) | 0x80);
+            mWp.move();
+            val >>= 7;
+        }
+    }
+}
+
+size_t
+EncodedBuffer::writeHeader(uint32_t fieldId, uint8_t wireType)
+{
+    return writeRawVarint((fieldId << 3) | wireType);
+}
+
+/********************************* Read APIs ************************************************/
+EncodedBuffer::iterator
+EncodedBuffer::begin() const
+{
+    return EncodedBuffer::iterator(*this);
+}
+
+EncodedBuffer::iterator::iterator(const EncodedBuffer& buffer)
+        :mData(buffer),
+         mRp(buffer.mChunkSize)
+{
+}
+
+size_t
+EncodedBuffer::iterator::size() const
+{
+    return mData.size();
+}
+
+size_t
+EncodedBuffer::iterator::bytesRead() const
+{
+    return mRp.pos();
+}
+
+EncodedBuffer::Pointer*
+EncodedBuffer::iterator::rp()
+{
+    return &mRp;
+}
+
+uint8_t const*
+EncodedBuffer::iterator::readBuffer()
+{
+    return hasNext() ? const_cast<uint8_t const*>(mData.at(mRp)) : NULL;
+}
+
+size_t
+EncodedBuffer::iterator::currentToRead()
+{
+    return (mData.mWp.index() > mRp.index()) ?
+            mData.mChunkSize - mRp.offset() :
+            mData.mWp.offset() - mRp.offset();
+}
+
+bool
+EncodedBuffer::iterator::hasNext()
+{
+    return mRp.pos() < mData.mWp.pos();
+}
+
+uint8_t
+EncodedBuffer::iterator::next()
+{
+    uint8_t res = *(mData.at(mRp));
+    mRp.move();
+    return res;
+}
+
+uint32_t
+EncodedBuffer::iterator::readRawVarint()
+{
+    uint32_t val = 0, shift = 0;
+    while (true) {
+        uint8_t byte = next();
+        val += (byte & 0x7F) << shift;
+        if ((byte & 0x80) == 0) break;
+        shift += 7;
+    }
+    return val;
+}
+
+} // util
+} // android
diff --git a/cmds/incidentd/src/protobuf.cpp b/libs/protoutil/src/protobuf.cpp
similarity index 67%
rename from cmds/incidentd/src/protobuf.cpp
rename to libs/protoutil/src/protobuf.cpp
index 4fffec1..ec5325c 100644
--- a/cmds/incidentd/src/protobuf.cpp
+++ b/libs/protoutil/src/protobuf.cpp
@@ -14,14 +14,19 @@
  * limitations under the License.
  */
 
-#include "protobuf.h"
+#include <android/util/protobuf.h>
 
-uint8_t read_wire_type(uint32_t varint)
+namespace android {
+namespace util {
+
+uint8_t
+read_wire_type(uint32_t varint)
 {
     return (uint8_t) (varint & 0x07);
 }
 
-uint32_t read_field_id(uint32_t varint)
+uint32_t
+read_field_id(uint32_t varint)
 {
     return varint >> 3;
 }
@@ -49,24 +54,5 @@
     return buf;
 }
 
-size_t
-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);
-            return size;
-        } else {
-            buf->push_back((uint8_t)((val & 0x7F) | 0x80));
-            val >>= 7;
-        }
-    }
-}
-
-size_t
-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
+} // util
+} // android