blob: 527d7eef3a96e548a3278eb72d1cb6059a3bfe5f [file] [log] [blame]
Joe Onorato1754d742016-11-21 17:51:35 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "incidentd"
18
19#include "FdBuffer.h"
20
21#include <cutils/log.h>
22#include <utils/SystemClock.h>
23
24#include <fcntl.h>
25#include <poll.h>
26#include <unistd.h>
27
28const ssize_t BUFFER_SIZE = 16 * 1024;
29const ssize_t MAX_BUFFER_COUNT = 256; // 4 MB max
30
31
32FdBuffer::FdBuffer()
33 :mBuffers(),
34 mStartTime(-1),
35 mFinishTime(-1),
36 mCurrentWritten(-1),
37 mTimedOut(false),
38 mTruncated(false)
39{
40}
41
42FdBuffer::~FdBuffer()
43{
44 const int N = mBuffers.size();
45 for (int i=0; i<N; i++) {
46 uint8_t* buf = mBuffers[i];
47 free(buf);
48 }
49}
50
51status_t
52FdBuffer::read(int fd, int64_t timeout)
53{
54 struct pollfd pfds = {
55 .fd = fd,
56 .events = POLLIN
57 };
58 mStartTime = uptimeMillis();
59
60 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
61
62 uint8_t* buf = NULL;
63 while (true) {
64 if (mCurrentWritten >= BUFFER_SIZE || mCurrentWritten < 0) {
65 if (mBuffers.size() == MAX_BUFFER_COUNT) {
66 mTruncated = true;
67 break;
68 }
69 buf = (uint8_t*)malloc(BUFFER_SIZE);
70 if (buf == NULL) {
71 return NO_MEMORY;
72 }
73 mBuffers.push_back(buf);
74 mCurrentWritten = 0;
75 }
76
77 int64_t remainingTime = (mStartTime + timeout) - uptimeMillis();
78 if (remainingTime <= 0) {
79 mTimedOut = true;
80 break;
81 }
82
83 int count = poll(&pfds, 1, remainingTime);
84 if (count == 0) {
85 mTimedOut = true;
86 break;
87 } else if (count < 0) {
88 return -errno;
89 } else {
90 if ((pfds.revents & POLLERR) != 0) {
91 return errno != 0 ? -errno : UNKNOWN_ERROR;
92 } else {
93 ssize_t amt = ::read(fd, buf + mCurrentWritten, BUFFER_SIZE - mCurrentWritten);
94 if (amt < 0) {
95 if (errno == EAGAIN || errno == EWOULDBLOCK) {
96 continue;
97 } else {
98 return -errno;
99 }
100 } else if (amt == 0) {
101 break;
102 }
103 mCurrentWritten += amt;
104 }
105 }
106 }
107
108 mFinishTime = uptimeMillis();
109 return NO_ERROR;
110}
111
112size_t
113FdBuffer::size()
114{
115 return ((mBuffers.size() - 1) * BUFFER_SIZE) + mCurrentWritten;
116}
117
118status_t
119FdBuffer::write(ReportRequestSet* reporter)
120{
121 const int N = mBuffers.size() - 1;
122 for (int i=0; i<N; i++) {
123 reporter->write(mBuffers[i], BUFFER_SIZE);
124 }
125 reporter->write(mBuffers[N], mCurrentWritten);
126 return NO_ERROR;
127}
128
129