• 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 <lib/zx/channel.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <zircon/process.h>
26 
27 #include <utility>
28 
29 #include "services/service_connector.h"
30 
31 #define GET_STATUS_SAFE(result, member) \
32     ((result).ok() ? ((result).Unwrap()->member) : ZX_OK)
33 
34 constexpr size_t kReadSize = 512 * 1024;
35 constexpr size_t kWriteOffset = kReadSize;
36 
QemuPipeStream(size_t bufSize)37 QemuPipeStream::QemuPipeStream(size_t bufSize) :
38     IOStream(bufSize),
39     m_sock(-1),
40     m_bufsize(bufSize),
41     m_buf(nullptr),
42     m_read(0),
43     m_readLeft(0)
44 {
45 }
46 
QemuPipeStream(QEMU_PIPE_HANDLE sock,size_t bufSize)47 QemuPipeStream::QemuPipeStream(QEMU_PIPE_HANDLE sock, size_t bufSize) :
48     IOStream(bufSize),
49     m_sock(sock),
50     m_bufsize(bufSize),
51     m_buf(nullptr),
52     m_read(0),
53     m_readLeft(0)
54 {
55 }
56 
~QemuPipeStream()57 QemuPipeStream::~QemuPipeStream()
58 {
59     if (m_device) {
60         flush();
61     }
62     if (m_buf) {
63         zx_status_t status = zx_vmar_unmap(zx_vmar_root_self(),
64                                            reinterpret_cast<zx_vaddr_t>(m_buf),
65                                            m_bufsize);
66         if (status != ZX_OK) {
67             ALOGE("zx_vmar_unmap failed: %d\n", status);
68             abort();
69         }
70     }
71 }
72 
connect(void)73 int QemuPipeStream::connect(void)
74 {
75     fidl::ClientEnd<fuchsia_hardware_goldfish::PipeDevice> channel{
76         zx::channel(GetConnectToServiceFunction()(QEMU_PIPE_PATH))};
77     if (!channel) {
78         ALOGE("%s: failed to get service handle for " QEMU_PIPE_PATH,
79               __FUNCTION__);
80         return -1;
81     }
82 
83     m_device = std::make_unique<
84         fidl::WireSyncClient<fuchsia_hardware_goldfish::PipeDevice>>(
85         std::move(channel));
86 
87     auto pipe_ends =
88         fidl::CreateEndpoints<::fuchsia_hardware_goldfish::Pipe>();
89     if (!pipe_ends.is_ok()) {
90         ALOGE("zx::channel::create failed: %d", pipe_ends.status_value());
91         return ZX_HANDLE_INVALID;
92     }
93     m_device->OpenPipe(std::move(pipe_ends->server));
94     m_pipe =
95         std::make_unique<fidl::WireSyncClient<fuchsia_hardware_goldfish::Pipe>>(
96             std::move(pipe_ends->client));
97 
98     zx::event event;
99     zx_status_t status = zx::event::create(0, &event);
100     if (status != ZX_OK) {
101         ALOGE("%s: failed to create event: %d", __FUNCTION__, status);
102         return -1;
103     }
104     zx::event event_copy;
105     status = event.duplicate(ZX_RIGHT_SAME_RIGHTS, &event_copy);
106     if (status != ZX_OK) {
107         ALOGE("%s: failed to duplicate event: %d", __FUNCTION__, status);
108         return -1;
109     }
110 
111     {
112         auto result = m_pipe->SetEvent(std::move(event_copy));
113         if (!result.ok()) {
114             ALOGE("%s: failed to set event: %d:%d", __FUNCTION__,
115                   result.status());
116             return -1;
117         }
118     }
119 
120     if (!allocBuffer(m_bufsize)) {
121         ALOGE("%s: failed allocate initial buffer", __FUNCTION__);
122         return -1;
123     }
124 
125     size_t len = strlen("pipe:opengles");
126     status = m_vmo.write("pipe:opengles", 0, len + 1);
127     if (status != ZX_OK) {
128         ALOGE("%s: failed write pipe name", __FUNCTION__);
129         return -1;
130     }
131 
132     {
133         auto result = m_pipe->Write(len + 1, 0);
134         if (!result.ok() || result.Unwrap()->res != ZX_OK) {
135             ALOGD("%s: connecting to pipe service failed: %d:%d", __FUNCTION__,
136                   result.status(), GET_STATUS_SAFE(result, res));
137             return -1;
138         }
139     }
140 
141     m_event = std::move(event);
142     return 0;
143 }
144 
allocBuffer(size_t minSize)145 void *QemuPipeStream::allocBuffer(size_t minSize)
146 {
147     // Add dedicated read buffer space at the front of buffer.
148     minSize += kReadSize;
149 
150     zx_status_t status;
151     if (m_buf) {
152         if (minSize <= m_bufsize) {
153             return m_buf + kWriteOffset;
154         }
155         status = zx_vmar_unmap(zx_vmar_root_self(),
156                                reinterpret_cast<zx_vaddr_t>(m_buf),
157                                m_bufsize);
158         if (status != ZX_OK) {
159           ALOGE("zx_vmar_unmap failed: %d\n", status);
160           abort();
161         }
162         m_buf = nullptr;
163     }
164 
165     size_t allocSize = m_bufsize < minSize ? minSize : m_bufsize;
166 
167     {
168         auto result = m_pipe->SetBufferSize(allocSize);
169         if (!result.ok() || result.Unwrap()->res != ZX_OK) {
170             ALOGE("%s: failed to get buffer: %d:%d", __FUNCTION__,
171                   result.status(), GET_STATUS_SAFE(result, res));
172             return nullptr;
173         }
174     }
175 
176     zx::vmo vmo;
177     {
178         auto result = m_pipe->GetBuffer();
179         if (!result.ok() || result.Unwrap()->res != ZX_OK) {
180             ALOGE("%s: failed to get buffer: %d:%d", __FUNCTION__,
181                   result.status(), GET_STATUS_SAFE(result, res));
182             return nullptr;
183         }
184         vmo = std::move(result.Unwrap()->vmo);
185     }
186 
187     zx_vaddr_t mapped_addr;
188     status =
189         zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
190                     vmo.get(), 0, allocSize, &mapped_addr);
191     if (status != ZX_OK) {
192         ALOGE("%s: failed to map buffer: %d", __FUNCTION__, status);
193         return nullptr;
194     }
195 
196     m_buf = reinterpret_cast<unsigned char*>(mapped_addr);
197     m_bufsize = allocSize;
198     m_vmo = std::move(vmo);
199     return m_buf + kWriteOffset;
200 }
201 
commitBuffer(size_t size)202 int QemuPipeStream::commitBuffer(size_t size)
203 {
204     if (size == 0) return 0;
205 
206     auto result = m_pipe->DoCall(size, kWriteOffset, 0, 0);
207     if (!result.ok() || result.Unwrap()->res != ZX_OK) {
208         ALOGD("%s: Pipe call failed: %d:%d", __FUNCTION__, result.status(),
209               GET_STATUS_SAFE(result, res));
210         return -1;
211     }
212 
213     return 0;
214 }
215 
writeFully(const void * buf,size_t len)216 int QemuPipeStream::writeFully(const void *buf, size_t len)
217 {
218     ALOGE("%s: unsupported", __FUNCTION__);
219     abort();
220     return -1;
221 }
222 
getSocket() const223 QEMU_PIPE_HANDLE QemuPipeStream::getSocket() const {
224     return m_sock;
225 }
226 
readFully(void * buf,size_t len)227 const unsigned char *QemuPipeStream::readFully(void *buf, size_t len)
228 {
229     return commitBufferAndReadFully(0, buf, len);
230 }
231 
commitBufferAndReadFully(size_t size,void * buf,size_t len)232 const unsigned char *QemuPipeStream::commitBufferAndReadFully(size_t size, void *buf, size_t len)
233 {
234     if (!m_device)
235         return nullptr;
236 
237     if (!buf) {
238         if (len > 0) {
239             ALOGE("QemuPipeStream::commitBufferAndReadFully failed, buf=NULL, len %zu, lethal"
240                     " error, exiting.", len);
241             abort();
242         }
243         if (!size) {
244             return nullptr;
245         }
246     }
247 
248     // Advance buffered read if not yet consumed.
249     size_t remaining = len;
250     size_t readSize = m_readLeft < remaining ? m_readLeft : remaining;
251     if (readSize) {
252         memcpy(static_cast<char*>(buf), m_buf + (m_read - m_readLeft), readSize);
253         remaining -= readSize;
254         m_readLeft -= readSize;
255     }
256 
257     // Early out if nothing left to do.
258     if (!size && !remaining) {
259         return static_cast<const unsigned char *>(buf);
260     }
261 
262     // Read up to kReadSize bytes if all buffered read has been consumed.
263     size_t maxRead = (m_readLeft || !remaining) ? 0 : kReadSize;
264 
265     auto result = m_pipe->DoCall(size, kWriteOffset, maxRead, 0);
266     if (!result.ok()) {
267         ALOGD("%s: Pipe call failed: %d", __FUNCTION__, result.status());
268         return nullptr;
269     }
270 
271     // Updated buffered read size.
272     if (result.Unwrap()->actual) {
273         m_read = m_readLeft = result.Unwrap()->actual;
274     }
275 
276     // Consume buffered read and read more if neccessary.
277     while (remaining) {
278         readSize = m_readLeft < remaining ? m_readLeft : remaining;
279         if (readSize) {
280             memcpy(static_cast<char*>(buf) + (len - remaining),
281                    m_buf + (m_read - m_readLeft),
282                    readSize);
283             remaining -= readSize;
284             m_readLeft -= readSize;
285             continue;
286         }
287 
288         auto result = m_pipe->Read(kReadSize, 0);
289         if (!result.ok()) {
290             ALOGD("%s: Failed reading from pipe: %d:%d", __FUNCTION__,
291                   result.status());
292             return nullptr;
293         }
294 
295         if (result.Unwrap()->actual) {
296             m_read = m_readLeft = result.Unwrap()->actual;
297             continue;
298         }
299         if (result.Unwrap()->res != ZX_ERR_SHOULD_WAIT) {
300             ALOGD("%s: Error reading from pipe: %d", __FUNCTION__,
301                   result.Unwrap()->res);
302             return nullptr;
303         }
304 
305         zx_signals_t observed = ZX_SIGNAL_NONE;
306         zx_status_t status = m_event.wait_one(
307             fuchsia_hardware_goldfish::wire::kSignalReadable |
308                 fuchsia_hardware_goldfish::wire::kSignalHangup,
309             zx::time::infinite(), &observed);
310         if (status != ZX_OK) {
311             ALOGD("%s: wait_one failed: %d", __FUNCTION__, status);
312             return nullptr;
313         }
314         if (observed & fuchsia_hardware_goldfish::wire::kSignalHangup) {
315             ALOGD("%s: Remote end hungup", __FUNCTION__);
316             return nullptr;
317         }
318     }
319 
320     return static_cast<const unsigned char *>(buf);
321 }
322 
read(void * buf,size_t * inout_len)323 const unsigned char *QemuPipeStream::read(void *buf, size_t *inout_len)
324 {
325     ALOGE("%s: unsupported", __FUNCTION__);
326     abort();
327     return nullptr;
328 }
329 
recv(void * buf,size_t len)330 int QemuPipeStream::recv(void *buf, size_t len)
331 {
332     ALOGE("%s: unsupported", __FUNCTION__);
333     abort();
334     return -1;
335 }
336