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
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
28 const ssize_t BUFFER_SIZE = 16 * 1024;
29 const ssize_t MAX_BUFFER_COUNT = 256; // 4 MB max
30
31
FdBuffer()32 FdBuffer::FdBuffer()
33 :mBuffers(),
34 mStartTime(-1),
35 mFinishTime(-1),
36 mCurrentWritten(-1),
37 mTimedOut(false),
38 mTruncated(false)
39 {
40 }
41
~FdBuffer()42 FdBuffer::~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
51 status_t
read(int fd,int64_t timeout)52 FdBuffer::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
112 size_t
size()113 FdBuffer::size()
114 {
115 return ((mBuffers.size() - 1) * BUFFER_SIZE) + mCurrentWritten;
116 }
117
118 status_t
write(ReportRequestSet * reporter)119 FdBuffer::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
130