This cl does the following things:
0) Implements a skeleton of incident_helper
1) Implements FileSection class which calls incident_helper to parse
file content to protobuf
2) Adds Kernel Wake Sources to incident.proto and makes it parsed by
FileSection
3) Adds basic gtests to test FdBuffer, io_utils, FileSection
implementation
Bug: 62923266
Bug: 62926061
Test: manual - push incidentd, incident_helper and incident to my device
and verify kernel wakeup sources file is able to be parsed.
Change-Id: I2aa6b6158d962ce70e6fa6c8a9c42213a45ff41c
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index 527d7ee..7743301 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -24,11 +24,11 @@
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>
+#include <wait.h>
-const ssize_t BUFFER_SIZE = 16 * 1024;
+const ssize_t BUFFER_SIZE = 16 * 1024; // 16 KB
const ssize_t MAX_BUFFER_COUNT = 256; // 4 MB max
-
FdBuffer::FdBuffer()
:mBuffers(),
mStartTime(-1),
@@ -109,6 +109,135 @@
return NO_ERROR;
}
+status_t
+FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs)
+{
+ struct pollfd pfds[] = {
+ { .fd = fd, .events = POLLIN },
+ { .fd = toFd, .events = POLLOUT },
+ { .fd = fromFd, .events = POLLIN },
+ };
+
+ mStartTime = uptimeMillis();
+
+ // mark all fds non blocking
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
+ fcntl(toFd, F_SETFL, fcntl(toFd, F_GETFL, 0) | O_NONBLOCK);
+ fcntl(fromFd, F_SETFL, fcntl(fromFd, F_GETFL, 0) | O_NONBLOCK);
+
+ // A circular buffer holds data read from fd and writes to parsing process
+ uint8_t cirBuf[BUFFER_SIZE];
+ size_t cirSize = 0;
+ 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;
+ }
+
+ int64_t remainingTime = (mStartTime + timeoutMs) - uptimeMillis();
+ if (remainingTime <= 0) {
+ mTimedOut = true;
+ break;
+ }
+
+ // wait for any pfds to be ready to perform IO
+ int count = poll(pfds, 3, remainingTime);
+ if (count == 0) {
+ mTimedOut = true;
+ break;
+ } else if (count < 0) {
+ return -errno;
+ }
+
+ // make sure no errors occur on any fds
+ for (int i = 0; i < 3; ++i) {
+ if ((pfds[i].revents & POLLERR) != 0) {
+ return errno != 0 ? -errno : UNKNOWN_ERROR;
+ }
+ }
+
+ // read from fd
+ if (cirSize != BUFFER_SIZE && pfds[0].fd != -1) {
+ ssize_t amt;
+ if (rpos >= wpos) {
+ amt = ::read(fd, cirBuf + rpos, BUFFER_SIZE - rpos);
+ } else {
+ amt = :: read(fd, cirBuf + rpos, wpos - rpos);
+ }
+ if (amt < 0) {
+ if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
+ return -errno;
+ } // otherwise just continue
+ } else if (amt == 0) { // reach EOF so don't have to poll pfds[0].
+ ::close(pfds[0].fd);
+ pfds[0].fd = -1;
+ } else {
+ rpos += amt;
+ cirSize += amt;
+ }
+ }
+
+ // write to parsing process
+ if (cirSize > 0 && pfds[1].fd != -1) {
+ ssize_t amt;
+ if (rpos > wpos) {
+ amt = ::write(toFd, cirBuf + wpos, rpos - wpos);
+ } else {
+ amt = ::write(toFd, cirBuf + wpos, BUFFER_SIZE - wpos);
+ }
+ if (amt < 0) {
+ if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
+ return -errno;
+ } // otherwise just continue
+ } else {
+ wpos += amt;
+ cirSize -= amt;
+ }
+ }
+
+ // if buffer is empty and fd is closed, close write fd.
+ if (cirSize == 0 && pfds[0].fd == -1 && pfds[1].fd != -1) {
+ ::close(pfds[1].fd);
+ pfds[1].fd = -1;
+ }
+
+ // circular buffer, reset rpos and wpos
+ if (rpos >= BUFFER_SIZE) {
+ rpos = 0;
+ }
+ if (wpos >= BUFFER_SIZE) {
+ wpos = 0;
+ }
+
+ // read from parsing process
+ ssize_t amt = ::read(fromFd, buf + mCurrentWritten, BUFFER_SIZE - mCurrentWritten);
+ if (amt < 0) {
+ if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
+ return -errno;
+ } // otherwise just continue
+ } else if (amt == 0) {
+ break;
+ } else {
+ mCurrentWritten += amt;
+ }
+ }
+
+ mFinishTime = uptimeMillis();
+ return NO_ERROR;
+}
+
size_t
FdBuffer::size()
{