incidentd can now handle multiple callers asking it for incident reports
Test: bit incident_test:* GtsIncidentManagerTestCases:*
Bug: 123543706
Change-Id: I9f671dd5d8b2ad139f952a23e575c2be16120459
diff --git a/libs/protoutil/src/ProtoFileReader.cpp b/libs/protoutil/src/ProtoFileReader.cpp
new file mode 100644
index 0000000..074170a
--- /dev/null
+++ b/libs/protoutil/src/ProtoFileReader.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+#define LOG_TAG "libprotoutil"
+
+#include <android/util/ProtoFileReader.h>
+#include <cutils/log.h>
+
+#include <cinttypes>
+#include <type_traits>
+
+#include <unistd.h>
+
+namespace android {
+namespace util {
+
+/**
+ * Get the amount of data remaining in the file in fd, or -1 if the file size can't be measured.
+ * It's not the whole file, but this allows us to skip any preamble that might have already
+ * been passed over.
+ */
+ssize_t get_file_size(int fd) {
+ off_t current = lseek(fd, 0, SEEK_CUR);
+ if (current < 0) {
+ return -1;
+ }
+ off_t end = lseek(fd, 0, SEEK_END);
+ if (end < 0) {
+ return -1;
+ }
+ off_t err = lseek(fd, current, SEEK_SET);
+ if (err < 0) {
+ ALOGW("get_file_size could do SEEK_END but not SEEK_SET. We might have skipped data.");
+ return -1;
+ }
+ return (ssize_t)(end-current);
+}
+
+// =========================================================================
+ProtoFileReader::ProtoFileReader(int fd)
+ :mFd(fd),
+ mStatus(NO_ERROR),
+ mSize(get_file_size(fd)),
+ mPos(0),
+ mOffset(0),
+ mChunkSize(sizeof(mBuffer)) {
+}
+
+ProtoFileReader::~ProtoFileReader() {
+}
+
+ssize_t
+ProtoFileReader::size() const
+{
+ return (ssize_t)mSize;
+}
+
+size_t
+ProtoFileReader::bytesRead() const
+{
+ return mPos;
+}
+
+uint8_t const*
+ProtoFileReader::readBuffer()
+{
+ return hasNext() ? mBuffer + mOffset : NULL;
+}
+
+size_t
+ProtoFileReader::currentToRead()
+{
+ return mMaxOffset - mOffset;
+}
+
+bool
+ProtoFileReader::hasNext()
+{
+ return ensure_data();
+}
+
+uint8_t
+ProtoFileReader::next()
+{
+ if (!ensure_data()) {
+ // Shouldn't get to here. Always call hasNext() before calling next().
+ return 0;
+ }
+ return mBuffer[mOffset++];
+}
+
+uint64_t
+ProtoFileReader::readRawVarint()
+{
+ uint64_t val = 0, shift = 0;
+ while (true) {
+ if (!hasNext()) {
+ ALOGW("readRawVarint() called without hasNext() called first.");
+ mStatus = NOT_ENOUGH_DATA;
+ return 0;
+ }
+ uint8_t byte = next();
+ val |= (INT64_C(0x7F) & byte) << shift;
+ if ((byte & 0x80) == 0) break;
+ shift += 7;
+ }
+ return val;
+}
+
+void
+ProtoFileReader::move(size_t amt)
+{
+ while (mStatus == NO_ERROR && amt > 0) {
+ if (!ensure_data()) {
+ return;
+ }
+ const size_t chunk = mMaxOffset - mOffset < amt ? amt : mMaxOffset - mOffset;
+ mOffset += chunk;
+ amt -= chunk;
+ }
+}
+
+status_t
+ProtoFileReader::getError() const {
+ return mStatus;
+}
+
+bool
+ProtoFileReader::ensure_data() {
+ if (mStatus != NO_ERROR) {
+ return false;
+ }
+ if (mOffset < mMaxOffset) {
+ return true;
+ }
+ ssize_t amt = TEMP_FAILURE_RETRY(read(mFd, mBuffer, mChunkSize));
+ if (amt == 0) {
+ return false;
+ } else if (amt < 0) {
+ mStatus = -errno;
+ return false;
+ } else {
+ mOffset = 0;
+ mMaxOffset = amt;
+ return true;
+ }
+}
+
+
+} // util
+} // android
+