• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (C) 2019 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 
18 #include <cutils/log.h>
19 #include <errno.h>
20 #include <fuchsia/hardware/goldfish/pipe/c/fidl.h>
21 #include <lib/fdio/fdio.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <zircon/process.h>
27 
28 #include <utility>
29 
QemuPipeStream(size_t bufSize)30 QemuPipeStream::QemuPipeStream(size_t bufSize) :
31     IOStream(bufSize),
32     m_sock(-1),
33     m_bufsize(bufSize),
34     m_buf(nullptr)
35 {
36 }
37 
QemuPipeStream(QEMU_PIPE_HANDLE sock,size_t bufSize)38 QemuPipeStream::QemuPipeStream(QEMU_PIPE_HANDLE sock, size_t bufSize) :
39     IOStream(bufSize),
40     m_sock(sock),
41     m_bufsize(bufSize),
42     m_buf(nullptr)
43 {
44 }
45 
~QemuPipeStream()46 QemuPipeStream::~QemuPipeStream()
47 {
48     if (m_channel.is_valid()) {
49         flush();
50     }
51     if (m_buf) {
52         zx_status_t status = zx_vmar_unmap(zx_vmar_root_self(),
53                                            reinterpret_cast<zx_vaddr_t>(m_buf),
54                                            m_bufsize);
55         if (status != ZX_OK) {
56             ALOGE("zx_vmar_unmap failed: %d\n", status);
57             abort();
58         }
59     }
60 }
61 
connect(void)62 int QemuPipeStream::connect(void)
63 {
64     int fd = TEMP_FAILURE_RETRY(open(QEMU_PIPE_PATH, O_RDWR));
65     if (fd < 0) {
66         ALOGE("%s: failed to open " QEMU_PIPE_PATH ": %s",
67               __FUNCTION__, strerror(errno));
68         return -1;
69     }
70 
71     zx::channel channel;
72     zx_status_t status = fdio_get_service_handle(
73         fd, channel.reset_and_get_address());
74     if (status != ZX_OK) {
75         ALOGE("%s: failed to get service handle for " QEMU_PIPE_PATH ": %d",
76               __FUNCTION__, status);
77         close(fd);
78         return -1;
79     }
80 
81     zx::event event;
82     status = zx::event::create(0, &event);
83     if (status != ZX_OK) {
84         ALOGE("%s: failed to create event: %d", __FUNCTION__, status);
85         return -1;
86     }
87     zx::event event_copy;
88     status = event.duplicate(ZX_RIGHT_SAME_RIGHTS, &event_copy);
89     if (status != ZX_OK) {
90         ALOGE("%s: failed to duplicate event: %d", __FUNCTION__, status);
91         return -1;
92     }
93 
94     status = fuchsia_hardware_goldfish_pipe_DeviceSetEvent(
95         channel.get(), event_copy.release());
96     if (status != ZX_OK) {
97         ALOGE("%s: failed to set event: %d:%d", __FUNCTION__, status);
98         return -1;
99     }
100 
101     zx_status_t status2 = ZX_OK;
102     zx::vmo vmo;
103     status = fuchsia_hardware_goldfish_pipe_DeviceGetBuffer(
104         channel.get(), &status2, vmo.reset_and_get_address());
105     if (status != ZX_OK || status2 != ZX_OK) {
106         ALOGE("%s: failed to get buffer: %d:%d", __FUNCTION__, status, status2);
107         return -1;
108     }
109 
110     size_t len = strlen("pipe:opengles");
111     status = vmo.write("pipe:opengles", 0, len + 1);
112     if (status != ZX_OK) {
113         ALOGE("%s: failed write pipe name", __FUNCTION__);
114         return -1;
115     }
116 
117     uint64_t actual;
118     status = fuchsia_hardware_goldfish_pipe_DeviceWrite(
119         channel.get(), len + 1, 0, &status2, &actual);
120     if (status != ZX_OK || status2 != ZX_OK) {
121         ALOGD("%s: connecting to pipe service failed: %d:%d", __FUNCTION__,
122               status, status2);
123         return -1;
124     }
125 
126     m_channel = std::move(channel);
127     m_event = std::move(event);
128     m_vmo = std::move(vmo);
129     return 0;
130 }
131 
allocBuffer(size_t minSize)132 void *QemuPipeStream::allocBuffer(size_t minSize)
133 {
134     zx_status_t status;
135     if (m_buf) {
136         if (minSize <= m_bufsize) {
137             return m_buf;
138         }
139         status = zx_vmar_unmap(zx_vmar_root_self(),
140                                reinterpret_cast<zx_vaddr_t>(m_buf),
141                                m_bufsize);
142         if (status != ZX_OK) {
143           ALOGE("zx_vmar_unmap failed: %d\n", status);
144           abort();
145         }
146         m_buf = nullptr;
147     }
148 
149     size_t allocSize = m_bufsize < minSize ? minSize : m_bufsize;
150 
151     zx_status_t status2 = ZX_OK;
152     status = fuchsia_hardware_goldfish_pipe_DeviceSetBufferSize(
153         m_channel.get(), allocSize, &status2);
154     if (status != ZX_OK || status2 != ZX_OK) {
155         ALOGE("%s: failed to get buffer: %d:%d", __FUNCTION__, status, status2);
156         return nullptr;
157     }
158 
159     zx::vmo vmo;
160     status = fuchsia_hardware_goldfish_pipe_DeviceGetBuffer(
161         m_channel.get(), &status2, vmo.reset_and_get_address());
162     if (status != ZX_OK || status2 != ZX_OK) {
163         ALOGE("%s: failed to get buffer: %d:%d", __FUNCTION__, status, status2);
164         return nullptr;
165     }
166 
167     zx_vaddr_t mapped_addr;
168     status = zx_vmar_map(zx_vmar_root_self(),
169                          ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
170                          0, vmo.get(), 0, allocSize, &mapped_addr);
171     if (status != ZX_OK) {
172         ALOGE("%s: failed to map buffer: %d:%d", __FUNCTION__, status);
173         return nullptr;
174     }
175 
176     m_buf = reinterpret_cast<unsigned char*>(mapped_addr);
177     m_bufsize = allocSize;
178     m_vmo = std::move(vmo);
179     return m_buf;
180 }
181 
commitBuffer(size_t size)182 int QemuPipeStream::commitBuffer(size_t size)
183 {
184     if (size == 0) return 0;
185 
186     size_t remaining = size;
187     while (remaining) {
188         zx_status_t status2 = ZX_OK;
189         uint64_t actual = 0;
190         zx_status_t status = fuchsia_hardware_goldfish_pipe_DeviceWrite(
191             m_channel.get(), remaining, size - remaining, &status2, &actual);
192         if (status != ZX_OK) {
193             ALOGD("%s: Failed writing to pipe: %d", __FUNCTION__, status);
194             return -1;
195         }
196         if (actual) {
197             remaining -= actual;
198             continue;
199         }
200         if (status2 != ZX_ERR_SHOULD_WAIT) {
201             ALOGD("%s: Error writing to pipe: %d", __FUNCTION__, status2);
202             return -1;
203         }
204         zx_signals_t observed = ZX_SIGNAL_NONE;
205         status = m_event.wait_one(
206             fuchsia_hardware_goldfish_pipe_SIGNAL_WRITABLE |
207             fuchsia_hardware_goldfish_pipe_SIGNAL_HANGUP,
208             zx::time::infinite(), &observed);
209         if (status != ZX_OK) {
210             ALOGD("%s: wait_one failed: %d", __FUNCTION__, status);
211             return -1;
212         }
213         if (observed & fuchsia_hardware_goldfish_pipe_SIGNAL_HANGUP) {
214             ALOGD("%s: Remote end hungup", __FUNCTION__);
215             return -1;
216         }
217     }
218 
219     return 0;
220 }
221 
writeFully(const void * buf,size_t len)222 int QemuPipeStream::writeFully(const void *buf, size_t len)
223 {
224     ALOGE("%s: unsupported", __FUNCTION__);
225     abort();
226     return -1;
227 }
228 
getSocket() const229 QEMU_PIPE_HANDLE QemuPipeStream::getSocket() const {
230     return m_sock;
231 }
232 
readFully(void * buf,size_t len)233 const unsigned char *QemuPipeStream::readFully(void *buf, size_t len)
234 {
235     if (!m_channel.is_valid()) return nullptr;
236 
237     if (!buf) {
238         if (len > 0) {
239             ALOGE("QemuPipeStream::readFully failed, buf=NULL, len %zu, lethal"
240                     " error, exiting.", len);
241             abort();
242         }
243         return nullptr;
244     }
245 
246     size_t remaining = len;
247     while (remaining) {
248         size_t readSize = m_bufsize < remaining ? m_bufsize : remaining;
249         zx_status_t status2 = ZX_OK;
250         uint64_t actual = 0;
251         zx_status_t status = fuchsia_hardware_goldfish_pipe_DeviceRead(
252             m_channel.get(), readSize, 0, &status2, &actual);
253         if (status != ZX_OK) {
254             ALOGD("%s: Failed reading from pipe: %d", __FUNCTION__, status);
255             return nullptr;
256         }
257         if (actual) {
258             m_vmo.read(static_cast<char *>(buf) + (len - remaining), 0, actual);
259             remaining -= actual;
260             continue;
261         }
262         if (status2 != ZX_ERR_SHOULD_WAIT) {
263             ALOGD("%s: Error reading from pipe: %d", __FUNCTION__, status2);
264             return nullptr;
265         }
266         zx_signals_t observed = ZX_SIGNAL_NONE;
267         status = m_event.wait_one(
268             fuchsia_hardware_goldfish_pipe_SIGNAL_READABLE |
269             fuchsia_hardware_goldfish_pipe_SIGNAL_HANGUP,
270             zx::time::infinite(), &observed);
271         if (status != ZX_OK) {
272             ALOGD("%s: wait_one failed: %d", __FUNCTION__, status);
273             return nullptr;
274         }
275         if (observed & fuchsia_hardware_goldfish_pipe_SIGNAL_HANGUP) {
276             ALOGD("%s: Remote end hungup", __FUNCTION__);
277             return nullptr;
278         }
279     }
280 
281     return static_cast<const unsigned char *>(buf);
282 }
283 
read(void * buf,size_t * inout_len)284 const unsigned char *QemuPipeStream::read(void *buf, size_t *inout_len)
285 {
286     ALOGE("%s: unsupported", __FUNCTION__);
287     abort();
288     return nullptr;
289 }
290 
recv(void * buf,size_t len)291 int QemuPipeStream::recv(void *buf, size_t len)
292 {
293     ALOGE("%s: unsupported", __FUNCTION__);
294     abort();
295     return -1;
296 }
297