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