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/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/libs/protoutil/include/android/util/protobuf.h b/libs/protoutil/include/android/util/protobuf.h
new file mode 100644
index 0000000..f4e8d09
--- /dev/null
+++ b/libs/protoutil/include/android/util/protobuf.h
@@ -0,0 +1,58 @@
+/*
+ * 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_PROTOBUF_H
+#define ANDROID_UTIL_PROTOBUF_H
+
+#include <stdint.h>
+
+namespace android {
+namespace util {
+
+using namespace std;
+
+const uint8_t WIRE_TYPE_VARINT = 0;
+const uint8_t WIRE_TYPE_FIXED64 = 1;
+const uint8_t WIRE_TYPE_LENGTH_DELIMITED = 2;
+const uint8_t WIRE_TYPE_FIXED32 = 5;
+
+/**
+ * Read the wire type from varint, it is the smallest 3 bits.
+ */
+uint8_t read_wire_type(uint32_t varint);
+
+/**
+ * read field id from varint, it is varint >> 3;
+ */
+uint32_t read_field_id(uint32_t varint);
+
+/**
+ * Write a varint into the buffer. Return the next position to write at.
+ * There must be 10 bytes in the buffer. The same as
+ * EncodedBuffer.writeRawVarint32
+ */
+uint8_t* write_raw_varint(uint8_t* buf, uint32_t val);
+
+/**
+ * Write a protobuf WIRE_TYPE_LENGTH_DELIMITED header. Return the next position
+ * to write at. There must be 20 bytes in the buffer.
+ */
+uint8_t* write_length_delimited_tag_header(uint8_t* buf, uint32_t fieldId, size_t size);
+
+} // util
+} // android
+
+#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/libs/protoutil/src/protobuf.cpp b/libs/protoutil/src/protobuf.cpp
new file mode 100644
index 0000000..ec5325c
--- /dev/null
+++ b/libs/protoutil/src/protobuf.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 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/protobuf.h>
+
+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)
+{
+    return varint >> 3;
+}
+
+uint8_t*
+write_raw_varint(uint8_t* buf, uint32_t val)
+{
+    uint8_t* p = buf;
+    while (true) {
+        if ((val & ~0x7F) == 0) {
+            *p++ = (uint8_t)val;
+            return p;
+        } else {
+            *p++ = (uint8_t)((val & 0x7F) | 0x80);
+            val >>= 7;
+        }
+    }
+}
+
+uint8_t*
+write_length_delimited_tag_header(uint8_t* buf, uint32_t fieldId, size_t size)
+{
+    buf = write_raw_varint(buf, (fieldId << 3) | 2);
+    buf = write_raw_varint(buf, size);
+    return buf;
+}
+
+} // util
+} // android