diff options
-rw-r--r-- | cmds/incidentd/Android.mk | 10 | ||||
-rw-r--r-- | cmds/incidentd/src/EncodedBuffer.cpp | 195 | ||||
-rw-r--r-- | cmds/incidentd/src/FdBuffer.cpp | 152 | ||||
-rw-r--r-- | cmds/incidentd/src/FdBuffer.h | 43 | ||||
-rw-r--r-- | cmds/incidentd/src/PrivacyBuffer.cpp | 168 | ||||
-rw-r--r-- | cmds/incidentd/src/PrivacyBuffer.h (renamed from cmds/incidentd/src/EncodedBuffer.h) | 29 | ||||
-rw-r--r-- | cmds/incidentd/src/Section.cpp | 36 | ||||
-rw-r--r-- | cmds/incidentd/tests/FdBuffer_test.cpp | 49 | ||||
-rw-r--r-- | cmds/incidentd/tests/PrivacyBuffer_test.cpp (renamed from cmds/incidentd/tests/EncodedBuffer_test.cpp) | 77 | ||||
-rw-r--r-- | libs/protoutil/Android.mk | 39 | ||||
-rw-r--r-- | libs/protoutil/include/android/util/EncodedBuffer.h | 170 | ||||
-rw-r--r-- | libs/protoutil/include/android/util/protobuf.h (renamed from cmds/incidentd/src/protobuf.h) | 28 | ||||
-rw-r--r-- | libs/protoutil/src/EncodedBuffer.cpp | 237 | ||||
-rw-r--r-- | libs/protoutil/src/protobuf.cpp (renamed from cmds/incidentd/src/protobuf.cpp) | 34 |
14 files changed, 758 insertions, 509 deletions
diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk index 830bf9e66cde..cb5fd02ef30b 100644 --- a/cmds/incidentd/Android.mk +++ b/cmds/incidentd/Android.mk @@ -23,7 +23,7 @@ include $(CLEAR_VARS) 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 @@ LOCAL_SRC_FILES := \ src/Section.cpp \ src/io_util.cpp \ src/main.cpp \ - src/protobuf.cpp \ src/report_directory.cpp LOCAL_CFLAGS += \ @@ -54,6 +53,7 @@ LOCAL_SHARED_LIBRARIES := \ libcutils \ libincident \ liblog \ + libprotoutil \ libselinux \ libservices \ libutils @@ -93,16 +93,15 @@ LOCAL_CFLAGS := -Werror -Wall -Wno-unused-variable -Wunused-parameter 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 @@ LOCAL_SHARED_LIBRARIES := \ 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 e8f2c1171672..000000000000 --- 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 bb399b57b8cd..b7633a435653 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 BUFFER_SIZE = 16 * 1024; // 16 KB 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() 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 @@ FdBuffer::read(int fd, int64_t timeout) 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 @@ FdBuffer::read(int fd, int64_t timeout) 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 @@ FdBuffer::read(int fd, int64_t timeout) } else if (amt == 0) { break; } - mCurrentWritten += amt; + mBuffer.wp()->move(amt); } } } - mFinishTime = uptimeMillis(); return NO_ERROR; } @@ -132,20 +116,12 @@ FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeou 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 @@ FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeou } // 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 @@ FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeou } else if (amt == 0) { break; } else { - mCurrentWritten += amt; + mBuffer.wp()->move(amt); } } @@ -242,105 +218,11 @@ FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeou size_t FdBuffer::size() const { - if (mBuffers.empty()) return 0; - return ((mBuffers.size() - 1) * BUFFER_SIZE) + mCurrentWritten; -} - -status_t -FdBuffer::flush(int fd) 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; + return mBuffer.size(); } -bool -FdBuffer::iterator::outOfBound() const +EncodedBuffer::iterator +FdBuffer::data() const { - return bytesRead() > mFdBuffer.size(); + return mBuffer.begin(); } diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h index dfe39c62de42..8857ae714dac 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 @@ public: 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 000000000000..07a064cf044b --- /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 index ea8603a585d7..720b38e7dae8 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 @@ public: 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 166fef08441a..892bcca17b86 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 @@ static status_t 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 @@ write_report_requests(const int id, const FdBuffer& buffer, ReportRequestSet* re 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 d1436b2cc36f..2afa778b734c 100644 --- a/cmds/incidentd/tests/FdBuffer_test.cpp +++ b/cmds/incidentd/tests/FdBuffer_test.cpp @@ -49,12 +49,11 @@ public: 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, ReadAndWrite) { } 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 @@ TEST_F(FdBufferTest, ReadAndIterate) { 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 @@ TEST_F(FdBufferTest, ReadInStreamMoreThan4MB) { 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 index 37a938a6de07..8f6e35548e78 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 FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1 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 @@ public: 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 @@ public: 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 @@ private: } }; -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 @@ TEST_F(EncodedBufferTest, StripVarintAndString) { 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 @@ TEST_F(EncodedBufferTest, StripVarintAndFixed64) { 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 000000000000..a5348169513f --- /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 000000000000..cf096091c055 --- /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 index 263c864dc2cc..f4e8d092ba52 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_raw_varint(uint8_t* buf, uint32_t val); */ 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); - -/** - * 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 -}; +} // util +} // android -#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 000000000000..84dc5b6d7852 --- /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 index 4fffec1e80b9..ec5325c57bd1 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 @@ write_length_delimited_tag_header(uint8_t* buf, uint32_t fieldId, size_t size) 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 |