Home | History | Annotate | Download | only in OpenglSystemCommon
      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