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 30 QemuPipeStream::QemuPipeStream(size_t bufSize) : 31 IOStream(bufSize), 32 m_sock(-1), 33 m_bufsize(bufSize), 34 m_buf(nullptr) 35 { 36 } 37 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 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 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 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 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 222 int QemuPipeStream::writeFully(const void *buf, size_t len) 223 { 224 ALOGE("%s: unsupported", __FUNCTION__); 225 abort(); 226 return -1; 227 } 228 229 QEMU_PIPE_HANDLE QemuPipeStream::getSocket() const { 230 return m_sock; 231 } 232 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 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 291 int QemuPipeStream::recv(void *buf, size_t len) 292 { 293 ALOGE("%s: unsupported", __FUNCTION__); 294 abort(); 295 return -1; 296 } 297