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