1 /*
2 * Copyright (C) 2011 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 #include "QemuPipeStream.h"
17 #include <qemu_pipe_bp.h>
18
19 #if PLATFORM_SDK_VERSION < 26
20 #include <cutils/log.h>
21 #else
22 #include <log/log.h>
23 #endif
24 #include <errno.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <string.h>
29
30 static const size_t kReadSize = 512 * 1024;
31 static const size_t kWriteOffset = kReadSize;
32
QemuPipeStream(size_t bufSize)33 QemuPipeStream::QemuPipeStream(size_t bufSize) :
34 IOStream(bufSize),
35 m_sock((QEMU_PIPE_HANDLE)(-1)),
36 m_bufsize(bufSize),
37 m_buf(NULL),
38 m_read(0),
39 m_readLeft(0)
40 {
41 }
42
QemuPipeStream(QEMU_PIPE_HANDLE sock,size_t bufSize)43 QemuPipeStream::QemuPipeStream(QEMU_PIPE_HANDLE sock, size_t bufSize) :
44 IOStream(bufSize),
45 m_sock(sock),
46 m_bufsize(bufSize),
47 m_buf(NULL),
48 m_read(0),
49 m_readLeft(0)
50 {
51 }
52
~QemuPipeStream()53 QemuPipeStream::~QemuPipeStream()
54 {
55 if (valid()) {
56 flush();
57 qemu_pipe_close(m_sock);
58 }
59 if (m_buf != NULL) {
60 free(m_buf);
61 }
62 }
63
64
connect(void)65 int QemuPipeStream::connect(void)
66 {
67 m_sock = qemu_pipe_open("opengles");
68 if (!valid()) {
69 ALOGE("%s: failed to connect to opengles pipe", __FUNCTION__);
70 qemu_pipe_print_error(m_sock);
71 return -1;
72 }
73 return 0;
74 }
75
allocBuffer(size_t minSize)76 void *QemuPipeStream::allocBuffer(size_t minSize)
77 {
78 // Add dedicated read buffer space at the front of the buffer.
79 minSize += kReadSize;
80
81 size_t allocSize = (m_bufsize < minSize ? minSize : m_bufsize);
82 if (!m_buf) {
83 m_buf = (unsigned char *)malloc(allocSize);
84 }
85 else if (m_bufsize < allocSize) {
86 unsigned char *p = (unsigned char *)realloc(m_buf, allocSize);
87 if (p != NULL) {
88 m_buf = p;
89 m_bufsize = allocSize;
90 } else {
91 ERR("realloc (%zu) failed\n", allocSize);
92 free(m_buf);
93 m_buf = NULL;
94 m_bufsize = 0;
95 }
96 }
97
98 return m_buf + kWriteOffset;
99 };
100
commitBuffer(size_t size)101 int QemuPipeStream::commitBuffer(size_t size)
102 {
103 if (size == 0) return 0;
104 return writeFully(m_buf + kWriteOffset, size);
105 }
106
writeFully(const void * buf,size_t len)107 int QemuPipeStream::writeFully(const void *buf, size_t len)
108 {
109 return qemu_pipe_write_fully(m_sock, buf, len);
110 }
111
getSocket() const112 QEMU_PIPE_HANDLE QemuPipeStream::getSocket() const {
113 return m_sock;
114 }
115
readFully(void * buf,size_t len)116 const unsigned char *QemuPipeStream::readFully(void *buf, size_t len)
117 {
118 return commitBufferAndReadFully(0, buf, len);
119 }
120
commitBufferAndReadFully(size_t writeSize,void * userReadBufPtr,size_t totalReadSize)121 const unsigned char *QemuPipeStream::commitBufferAndReadFully(size_t writeSize, void *userReadBufPtr, size_t totalReadSize) {
122
123 unsigned char* userReadBuf = static_cast<unsigned char*>(userReadBufPtr);
124
125 if (!valid()) return NULL;
126
127 if (!userReadBuf) {
128 if (totalReadSize > 0) {
129 ALOGE("QemuPipeStream::commitBufferAndReadFully failed, userReadBuf=NULL, totalReadSize %zu, lethal"
130 " error, exiting.", totalReadSize);
131 abort();
132 }
133 if (!writeSize) {
134 return NULL;
135 }
136 }
137
138 // Advance buffered read if not yet consumed.
139 size_t remaining = totalReadSize;
140 size_t bufferedReadSize = m_readLeft < remaining ? m_readLeft : remaining;
141 if (bufferedReadSize) {
142 memcpy(userReadBuf, m_buf + (m_read - m_readLeft), bufferedReadSize);
143 remaining -= bufferedReadSize;
144 m_readLeft -= bufferedReadSize;
145 }
146
147 // Early out if nothing left to do.
148 if (!writeSize && !remaining) {
149 return userReadBuf;
150 }
151
152 writeFully(m_buf + kWriteOffset, writeSize);
153
154 // Now done writing. Early out if no reading left to do.
155 if (!remaining) {
156 return userReadBuf;
157 }
158
159 // Read up to kReadSize bytes if all buffered read has been consumed.
160 size_t maxRead = m_readLeft ? 0 : kReadSize;
161
162 ssize_t actual = 0;
163
164 if (maxRead) {
165 actual = qemu_pipe_read(m_sock, m_buf, maxRead);
166 // Updated buffered read size.
167 if (actual > 0) {
168 m_read = m_readLeft = actual;
169 }
170
171 if (actual == 0) {
172 ALOGD("%s: end of pipe", __FUNCTION__);
173 return NULL;
174 }
175 }
176
177 // Consume buffered read and read more if necessary.
178 while (remaining) {
179 bufferedReadSize = m_readLeft < remaining ? m_readLeft : remaining;
180 if (bufferedReadSize) {
181 memcpy(userReadBuf + (totalReadSize - remaining),
182 m_buf + (m_read - m_readLeft),
183 bufferedReadSize);
184 remaining -= bufferedReadSize;
185 m_readLeft -= bufferedReadSize;
186 continue;
187 }
188
189 actual = qemu_pipe_read(m_sock, m_buf, kReadSize);
190
191 if (actual == 0) {
192 ALOGD("%s: Failed reading from pipe: %d", __FUNCTION__, errno);
193 return NULL;
194 }
195
196 if (actual > 0) {
197 m_read = m_readLeft = actual;
198 continue;
199 }
200
201 if (!qemu_pipe_try_again(actual)) {
202 ALOGD("%s: Error reading from pipe: %d", __FUNCTION__, errno);
203 return NULL;
204 }
205 }
206
207 return userReadBuf;
208 }
209
read(void * buf,size_t * inout_len)210 const unsigned char *QemuPipeStream::read( void *buf, size_t *inout_len)
211 {
212 //DBG(">> QemuPipeStream::read %d\n", *inout_len);
213 if (!valid()) return NULL;
214 if (!buf) {
215 ERR("QemuPipeStream::read failed, buf=NULL");
216 return NULL; // do not allow NULL buf in that implementation
217 }
218
219 int n = recv(buf, *inout_len);
220
221 if (n > 0) {
222 *inout_len = n;
223 return (const unsigned char *)buf;
224 }
225
226 //DBG("<< QemuPipeStream::read %d\n", *inout_len);
227 return NULL;
228 }
229
recv(void * buf,size_t len)230 int QemuPipeStream::recv(void *buf, size_t len)
231 {
232 if (!valid()) return int(ERR_INVALID_SOCKET);
233 char* p = (char *)buf;
234 int ret = 0;
235 while(len > 0) {
236 int res = qemu_pipe_read(m_sock, p, len);
237 if (res > 0) {
238 p += res;
239 ret += res;
240 len -= res;
241 continue;
242 }
243 if (res == 0) { /* EOF */
244 break;
245 }
246 if (qemu_pipe_try_again(res)) {
247 continue;
248 }
249
250 /* A real error */
251 if (ret == 0)
252 ret = -1;
253 break;
254 }
255 return ret;
256 }
257