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
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
130