1 /*
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 #define DEBUG false
17 #include "Log.h"
18
19 #include "FdBuffer.h"
20
21 #include <log/log.h>
22 #include <utils/SystemClock.h>
23
24 #include <fcntl.h>
25 #include <poll.h>
26 #include <unistd.h>
27 #include <wait.h>
28
29 namespace android {
30 namespace os {
31 namespace incidentd {
32
33 const ssize_t BUFFER_SIZE = 16 * 1024; // 16 KB
34 const ssize_t MAX_BUFFER_COUNT = 6144; // 96 MB max
35
FdBuffer()36 FdBuffer::FdBuffer()
37 :mBuffer(new EncodedBuffer(BUFFER_SIZE)),
38 mStartTime(-1),
39 mFinishTime(-1),
40 mTimedOut(false),
41 mTruncated(false) {
42 }
43
~FdBuffer()44 FdBuffer::~FdBuffer() {
45 }
46
read(int fd,int64_t timeout)47 status_t FdBuffer::read(int fd, int64_t timeout) {
48 struct pollfd pfds = {.fd = fd, .events = POLLIN};
49 mStartTime = uptimeMillis();
50
51 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
52
53 while (true) {
54 if (mBuffer->size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
55 mTruncated = true;
56 VLOG("Truncating data");
57 break;
58 }
59 if (mBuffer->writeBuffer() == NULL) {
60 VLOG("No memory");
61 return NO_MEMORY;
62 }
63
64 int64_t remainingTime = (mStartTime + timeout) - uptimeMillis();
65 if (remainingTime <= 0) {
66 VLOG("timed out due to long read");
67 mTimedOut = true;
68 break;
69 }
70
71 int count = TEMP_FAILURE_RETRY(poll(&pfds, 1, remainingTime));
72 if (count == 0) {
73 VLOG("timed out due to block calling poll");
74 mTimedOut = true;
75 break;
76 } else if (count < 0) {
77 VLOG("poll failed: %s", strerror(errno));
78 return -errno;
79 } else {
80 if ((pfds.revents & POLLERR) != 0) {
81 VLOG("return event has error %s", strerror(errno));
82 return errno != 0 ? -errno : UNKNOWN_ERROR;
83 } else {
84 ssize_t amt = TEMP_FAILURE_RETRY(
85 ::read(fd, mBuffer->writeBuffer(), mBuffer->currentToWrite()));
86 if (amt < 0) {
87 if (errno == EAGAIN || errno == EWOULDBLOCK) {
88 continue;
89 } else {
90 VLOG("Fail to read %d: %s", fd, strerror(errno));
91 return -errno;
92 }
93 } else if (amt == 0) {
94 VLOG("Reached EOF of fd=%d", fd);
95 break;
96 }
97 mBuffer->wp()->move(amt);
98 }
99 }
100 }
101 mFinishTime = uptimeMillis();
102 return NO_ERROR;
103 }
104
readFully(int fd)105 status_t FdBuffer::readFully(int fd) {
106 mStartTime = uptimeMillis();
107
108 while (true) {
109 if (mBuffer->size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
110 // Don't let it get too big.
111 mTruncated = true;
112 VLOG("Truncating data");
113 break;
114 }
115 if (mBuffer->writeBuffer() == NULL) {
116 VLOG("No memory");
117 return NO_MEMORY;
118 }
119
120 ssize_t amt =
121 TEMP_FAILURE_RETRY(::read(fd, mBuffer->writeBuffer(), mBuffer->currentToWrite()));
122 if (amt < 0) {
123 VLOG("Fail to read %d: %s", fd, strerror(errno));
124 return -errno;
125 } else if (amt == 0) {
126 VLOG("Done reading %zu bytes", mBuffer->size());
127 // We're done.
128 break;
129 }
130 mBuffer->wp()->move(amt);
131 }
132
133 mFinishTime = uptimeMillis();
134 return NO_ERROR;
135 }
136
readProcessedDataInStream(int fd,unique_fd toFd,unique_fd fromFd,int64_t timeoutMs,const bool isSysfs)137 status_t FdBuffer::readProcessedDataInStream(int fd, unique_fd toFd, unique_fd fromFd,
138 int64_t timeoutMs, const bool isSysfs) {
139 struct pollfd pfds[] = {
140 {.fd = fd, .events = POLLIN},
141 {.fd = toFd.get(), .events = POLLOUT},
142 {.fd = fromFd.get(), .events = POLLIN},
143 };
144
145 mStartTime = uptimeMillis();
146
147 // mark all fds non blocking
148 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
149 fcntl(toFd.get(), F_SETFL, fcntl(toFd.get(), F_GETFL, 0) | O_NONBLOCK);
150 fcntl(fromFd.get(), F_SETFL, fcntl(fromFd.get(), F_GETFL, 0) | O_NONBLOCK);
151
152 // A circular buffer holds data read from fd and writes to parsing process
153 uint8_t cirBuf[BUFFER_SIZE];
154 size_t cirSize = 0;
155 int rpos = 0, wpos = 0;
156
157 // This is the buffer used to store processed data
158 while (true) {
159 if (mBuffer->size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
160 VLOG("Truncating data");
161 mTruncated = true;
162 break;
163 }
164 if (mBuffer->writeBuffer() == NULL) {
165 VLOG("No memory");
166 return NO_MEMORY;
167 }
168
169 int64_t remainingTime = (mStartTime + timeoutMs) - uptimeMillis();
170 if (remainingTime <= 0) {
171 VLOG("timed out due to long read");
172 mTimedOut = true;
173 break;
174 }
175
176 // wait for any pfds to be ready to perform IO
177 int count = TEMP_FAILURE_RETRY(poll(pfds, 3, remainingTime));
178 if (count == 0) {
179 VLOG("timed out due to block calling poll");
180 mTimedOut = true;
181 break;
182 } else if (count < 0) {
183 VLOG("Fail to poll: %s", strerror(errno));
184 return -errno;
185 }
186
187 // make sure no errors occur on any fds
188 for (int i = 0; i < 3; ++i) {
189 if ((pfds[i].revents & POLLERR) != 0) {
190 if (i == 0 && isSysfs) {
191 VLOG("fd %d is sysfs, ignore its POLLERR return value", fd);
192 continue;
193 }
194 VLOG("fd[%d]=%d returns error events: %s", i, fd, strerror(errno));
195 return errno != 0 ? -errno : UNKNOWN_ERROR;
196 }
197 }
198
199 // read from fd
200 if (cirSize != BUFFER_SIZE && pfds[0].fd != -1) {
201 ssize_t amt;
202 if (rpos >= wpos) {
203 amt = TEMP_FAILURE_RETRY(::read(fd, cirBuf + rpos, BUFFER_SIZE - rpos));
204 } else {
205 amt = TEMP_FAILURE_RETRY(::read(fd, cirBuf + rpos, wpos - rpos));
206 }
207 if (amt < 0) {
208 if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
209 VLOG("Fail to read fd %d: %s", fd, strerror(errno));
210 return -errno;
211 } // otherwise just continue
212 } else if (amt == 0) {
213 VLOG("Reached EOF of input file %d", fd);
214 pfds[0].fd = -1; // reach EOF so don't have to poll pfds[0].
215 } else {
216 rpos += amt;
217 cirSize += amt;
218 }
219 }
220
221 // write to parsing process
222 if (cirSize > 0 && pfds[1].fd != -1) {
223 ssize_t amt;
224 if (rpos > wpos) {
225 amt = TEMP_FAILURE_RETRY(::write(toFd.get(), cirBuf + wpos, rpos - wpos));
226 } else {
227 amt = TEMP_FAILURE_RETRY(::write(toFd.get(), cirBuf + wpos, BUFFER_SIZE - wpos));
228 }
229 if (amt < 0) {
230 if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
231 VLOG("Fail to write toFd %d: %s", toFd.get(), strerror(errno));
232 return -errno;
233 } // otherwise just continue
234 } else {
235 wpos += amt;
236 cirSize -= amt;
237 }
238 }
239
240 // if buffer is empty and fd is closed, close write fd.
241 if (cirSize == 0 && pfds[0].fd == -1 && pfds[1].fd != -1) {
242 VLOG("Close write pipe %d", toFd.get());
243 toFd.reset();
244 pfds[1].fd = -1;
245 }
246
247 // circular buffer, reset rpos and wpos
248 if (rpos >= BUFFER_SIZE) {
249 rpos = 0;
250 }
251 if (wpos >= BUFFER_SIZE) {
252 wpos = 0;
253 }
254
255 // read from parsing process
256 ssize_t amt = TEMP_FAILURE_RETRY(
257 ::read(fromFd.get(), mBuffer->writeBuffer(), mBuffer->currentToWrite()));
258 if (amt < 0) {
259 if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
260 VLOG("Fail to read fromFd %d: %s", fromFd.get(), strerror(errno));
261 return -errno;
262 } // otherwise just continue
263 } else if (amt == 0) {
264 VLOG("Reached EOF of fromFd %d", fromFd.get());
265 break;
266 } else {
267 mBuffer->wp()->move(amt);
268 }
269 }
270
271 mFinishTime = uptimeMillis();
272 return NO_ERROR;
273 }
274
write(uint8_t const * buf,size_t size)275 status_t FdBuffer::write(uint8_t const* buf, size_t size) {
276 return mBuffer->writeRaw(buf, size);
277 }
278
write(const sp<ProtoReader> & reader)279 status_t FdBuffer::write(const sp<ProtoReader>& reader) {
280 return mBuffer->writeRaw(reader);
281 }
282
write(const sp<ProtoReader> & reader,size_t size)283 status_t FdBuffer::write(const sp<ProtoReader>& reader, size_t size) {
284 return mBuffer->writeRaw(reader, size);
285 }
286
size() const287 size_t FdBuffer::size() const {
288 return mBuffer->size();
289 }
290
data() const291 sp<EncodedBuffer> FdBuffer::data() const {
292 return mBuffer;
293 }
294
295 } // namespace incidentd
296 } // namespace os
297 } // namespace android
298