Yahan Zhou | 4105059 | 2016-07-28 16:31:59 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 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 | |
Yilong Li | 4666908 | 2020-01-14 16:22:57 -0800 | [diff] [blame] | 17 | #include "ProcessPipe.h" |
Yahan Zhou | e8cf63d | 2016-09-22 12:33:50 -0700 | [diff] [blame] | 18 | #include "renderControl_enc.h" |
Roman Kiryanov | 5fb783e | 2020-04-28 13:22:29 -0700 | [diff] [blame] | 19 | |
| 20 | #define ALLOW_DEPRECATED_QEMU_PIPE_HEADERS |
| 21 | #include <qemu_pipe.h> |
Yahan Zhou | e8cf63d | 2016-09-22 12:33:50 -0700 | [diff] [blame] | 22 | |
Luca Stefani | 1cb647a | 2019-03-07 21:58:17 +0100 | [diff] [blame] | 23 | #if PLATFORM_SDK_VERSION < 26 |
Logan Chien | d7bf00d | 2018-09-21 06:30:09 +0000 | [diff] [blame] | 24 | #include <cutils/log.h> |
Luca Stefani | 1cb647a | 2019-03-07 21:58:17 +0100 | [diff] [blame] | 25 | #else |
| 26 | #include <log/log.h> |
| 27 | #endif |
Yahan Zhou | 4105059 | 2016-07-28 16:31:59 -0700 | [diff] [blame] | 28 | #include <pthread.h> |
Lingfeng Yang | e38d15c | 2018-09-24 16:24:01 -0700 | [diff] [blame] | 29 | #include <errno.h> |
Yahan Zhou | 4105059 | 2016-07-28 16:31:59 -0700 | [diff] [blame] | 30 | |
David Reveman | 5e2e842 | 2019-05-02 15:48:15 -0400 | [diff] [blame] | 31 | #ifdef __Fuchsia__ |
Yilong Li | b373b39 | 2019-10-17 15:30:14 -0700 | [diff] [blame] | 32 | #include <fuchsia/hardware/goldfish/cpp/fidl.h> |
David Reveman | 5e2e842 | 2019-05-02 15:48:15 -0400 | [diff] [blame] | 33 | #include <lib/zx/vmo.h> |
John Bauman | 8153a44 | 2019-10-16 15:41:17 -0700 | [diff] [blame] | 34 | |
| 35 | #include "services/service_connector.h" |
| 36 | |
David Reveman | 8bc3255 | 2019-06-28 10:32:41 -0400 | [diff] [blame] | 37 | static QEMU_PIPE_HANDLE sProcDevice = 0; |
Lingfeng Yang | 9c26ebf | 2019-12-30 09:14:49 -0800 | [diff] [blame] | 38 | #else // __Fuchsia__ |
| 39 | |
| 40 | #include "VirtioGpuPipeStream.h" |
| 41 | static VirtioGpuPipeStream* sVirtioGpuPipeStream = 0; |
| 42 | |
| 43 | #endif // !__Fuchsia__ |
David Reveman | 5e2e842 | 2019-05-02 15:48:15 -0400 | [diff] [blame] | 44 | |
Lingfeng Yang | e38d15c | 2018-09-24 16:24:01 -0700 | [diff] [blame] | 45 | static QEMU_PIPE_HANDLE sProcPipe = 0; |
Yahan Zhou | 4105059 | 2016-07-28 16:31:59 -0700 | [diff] [blame] | 46 | static pthread_once_t sProcPipeOnce = PTHREAD_ONCE_INIT; |
| 47 | // sProcUID is a unique ID per process assigned by the host. |
| 48 | // It is different from getpid(). |
| 49 | static uint64_t sProcUID = 0; |
Lingfeng Yang | 9c26ebf | 2019-12-30 09:14:49 -0800 | [diff] [blame] | 50 | static volatile HostConnectionType sConnType = HOST_CONNECTION_VIRTIO_GPU_PIPE; |
Yahan Zhou | 4105059 | 2016-07-28 16:31:59 -0700 | [diff] [blame] | 51 | |
Yahan Zhou | e8cf63d | 2016-09-22 12:33:50 -0700 | [diff] [blame] | 52 | // processPipeInitOnce is used to generate a process unique ID (puid). |
Yahan Zhou | 4105059 | 2016-07-28 16:31:59 -0700 | [diff] [blame] | 53 | // processPipeInitOnce will only be called at most once per process. |
| 54 | // Use it with pthread_once for thread safety. |
| 55 | // The host associates resources with process unique ID (puid) for memory cleanup. |
| 56 | // It will fallback to the default path if the host does not support it. |
| 57 | // Processes are identified by acquiring a per-process 64bit unique ID from the |
| 58 | // host. |
David Reveman | 5e2e842 | 2019-05-02 15:48:15 -0400 | [diff] [blame] | 59 | #ifdef __Fuchsia__ |
| 60 | static void processPipeInitOnce() { |
John Bauman | 8153a44 | 2019-10-16 15:41:17 -0700 | [diff] [blame] | 61 | zx::channel channel(GetConnectToServiceFunction()(QEMU_PIPE_PATH)); |
| 62 | if (!channel) { |
| 63 | ALOGE("%s: failed to open " QEMU_PIPE_PATH, |
| 64 | __FUNCTION__); |
David Reveman | 5e2e842 | 2019-05-02 15:48:15 -0400 | [diff] [blame] | 65 | return; |
| 66 | } |
| 67 | |
Yilong Li | b373b39 | 2019-10-17 15:30:14 -0700 | [diff] [blame] | 68 | fuchsia::hardware::goldfish::PipeDeviceSyncPtr device; |
David Reveman | 5e2e842 | 2019-05-02 15:48:15 -0400 | [diff] [blame] | 69 | device.Bind(std::move(channel)); |
| 70 | |
Yilong Li | b373b39 | 2019-10-17 15:30:14 -0700 | [diff] [blame] | 71 | fuchsia::hardware::goldfish::PipeSyncPtr pipe; |
David Reveman | 8bc3255 | 2019-06-28 10:32:41 -0400 | [diff] [blame] | 72 | device->OpenPipe(pipe.NewRequest()); |
| 73 | |
John Bauman | 8153a44 | 2019-10-16 15:41:17 -0700 | [diff] [blame] | 74 | zx_status_t status, status2 = ZX_OK; |
David Reveman | 5e2e842 | 2019-05-02 15:48:15 -0400 | [diff] [blame] | 75 | zx::vmo vmo; |
David Reveman | 8bc3255 | 2019-06-28 10:32:41 -0400 | [diff] [blame] | 76 | status = pipe->GetBuffer(&status2, &vmo); |
David Reveman | 5e2e842 | 2019-05-02 15:48:15 -0400 | [diff] [blame] | 77 | if (status != ZX_OK || status2 != ZX_OK) { |
| 78 | ALOGE("%s: failed to get buffer: %d:%d", __FUNCTION__, status, status2); |
| 79 | return; |
| 80 | } |
| 81 | |
| 82 | size_t len = strlen("pipe:GLProcessPipe"); |
| 83 | status = vmo.write("pipe:GLProcessPipe", 0, len + 1); |
| 84 | if (status != ZX_OK) { |
| 85 | ALOGE("%s: failed write pipe name", __FUNCTION__); |
| 86 | return; |
| 87 | } |
| 88 | uint64_t actual; |
David Reveman | 8bc3255 | 2019-06-28 10:32:41 -0400 | [diff] [blame] | 89 | status = pipe->Write(len + 1, 0, &status2, &actual); |
David Reveman | 5e2e842 | 2019-05-02 15:48:15 -0400 | [diff] [blame] | 90 | if (status != ZX_OK || status2 != ZX_OK) { |
| 91 | ALOGD("%s: connecting to pipe service failed: %d:%d", __FUNCTION__, |
| 92 | status, status2); |
| 93 | return; |
| 94 | } |
| 95 | |
David Reveman | 8bc3255 | 2019-06-28 10:32:41 -0400 | [diff] [blame] | 96 | // Send a confirmation int to the host and get per-process unique ID back |
David Reveman | 5e2e842 | 2019-05-02 15:48:15 -0400 | [diff] [blame] | 97 | int32_t confirmInt = 100; |
| 98 | status = vmo.write(&confirmInt, 0, sizeof(confirmInt)); |
| 99 | if (status != ZX_OK) { |
| 100 | ALOGE("%s: failed write confirm int", __FUNCTION__); |
| 101 | return; |
| 102 | } |
David Reveman | 8bc3255 | 2019-06-28 10:32:41 -0400 | [diff] [blame] | 103 | status = pipe->Call(sizeof(confirmInt), 0, sizeof(sProcUID), 0, &status2, &actual); |
David Reveman | 5e2e842 | 2019-05-02 15:48:15 -0400 | [diff] [blame] | 104 | if (status != ZX_OK || status2 != ZX_OK) { |
David Reveman | 8bc3255 | 2019-06-28 10:32:41 -0400 | [diff] [blame] | 105 | ALOGD("%s: failed to get per-process ID: %d:%d", __FUNCTION__, |
David Reveman | 5e2e842 | 2019-05-02 15:48:15 -0400 | [diff] [blame] | 106 | status, status2); |
| 107 | return; |
| 108 | } |
| 109 | status = vmo.read(&sProcUID, 0, sizeof(sProcUID)); |
| 110 | if (status != ZX_OK) { |
| 111 | ALOGE("%s: failed read per-process ID: %d", __FUNCTION__, status); |
| 112 | return; |
| 113 | } |
David Reveman | 8bc3255 | 2019-06-28 10:32:41 -0400 | [diff] [blame] | 114 | sProcDevice = device.Unbind().TakeChannel().release(); |
| 115 | sProcPipe = pipe.Unbind().TakeChannel().release(); |
David Reveman | 5e2e842 | 2019-05-02 15:48:15 -0400 | [diff] [blame] | 116 | } |
Lingfeng Yang | 9c26ebf | 2019-12-30 09:14:49 -0800 | [diff] [blame] | 117 | #else // __Fuchsia__ |
| 118 | |
| 119 | static void sQemuPipeInit() { |
Yahan Zhou | 4105059 | 2016-07-28 16:31:59 -0700 | [diff] [blame] | 120 | sProcPipe = qemu_pipe_open("GLProcessPipe"); |
Lingfeng Yang | e38d15c | 2018-09-24 16:24:01 -0700 | [diff] [blame] | 121 | if (!qemu_pipe_valid(sProcPipe)) { |
Yahan Zhou | 4105059 | 2016-07-28 16:31:59 -0700 | [diff] [blame] | 122 | sProcPipe = 0; |
| 123 | ALOGW("Process pipe failed"); |
| 124 | return; |
| 125 | } |
| 126 | // Send a confirmation int to the host |
| 127 | int32_t confirmInt = 100; |
| 128 | ssize_t stat = 0; |
| 129 | do { |
Lingfeng Yang | e38d15c | 2018-09-24 16:24:01 -0700 | [diff] [blame] | 130 | stat = |
| 131 | qemu_pipe_write(sProcPipe, (const char*)&confirmInt, |
Yahan Zhou | 4105059 | 2016-07-28 16:31:59 -0700 | [diff] [blame] | 132 | sizeof(confirmInt)); |
| 133 | } while (stat < 0 && errno == EINTR); |
| 134 | |
| 135 | if (stat != sizeof(confirmInt)) { // failed |
Lingfeng Yang | e38d15c | 2018-09-24 16:24:01 -0700 | [diff] [blame] | 136 | qemu_pipe_close(sProcPipe); |
Yahan Zhou | 4105059 | 2016-07-28 16:31:59 -0700 | [diff] [blame] | 137 | sProcPipe = 0; |
| 138 | ALOGW("Process pipe failed"); |
| 139 | return; |
| 140 | } |
| 141 | |
| 142 | // Ask the host for per-process unique ID |
| 143 | do { |
Lingfeng Yang | e38d15c | 2018-09-24 16:24:01 -0700 | [diff] [blame] | 144 | stat = |
| 145 | qemu_pipe_read(sProcPipe, (char*)&sProcUID, |
| 146 | sizeof(sProcUID)); |
Lingfeng Yang | d0b2a8a | 2019-08-07 00:59:55 +0000 | [diff] [blame] | 147 | } while (stat < 0 && (errno == EINTR || errno == EAGAIN)); |
Yahan Zhou | 4105059 | 2016-07-28 16:31:59 -0700 | [diff] [blame] | 148 | |
| 149 | if (stat != sizeof(sProcUID)) { |
Lingfeng Yang | e38d15c | 2018-09-24 16:24:01 -0700 | [diff] [blame] | 150 | qemu_pipe_close(sProcPipe); |
Yahan Zhou | 4105059 | 2016-07-28 16:31:59 -0700 | [diff] [blame] | 151 | sProcPipe = 0; |
| 152 | sProcUID = 0; |
| 153 | ALOGW("Process pipe failed"); |
| 154 | return; |
| 155 | } |
| 156 | } |
| 157 | |
Lingfeng Yang | 9c26ebf | 2019-12-30 09:14:49 -0800 | [diff] [blame] | 158 | static void processPipeInitOnce() { |
Lingfeng Yang | fe14fdb | 2020-01-02 10:22:09 -0800 | [diff] [blame] | 159 | #if defined(HOST_BUILD) || !defined(GOLDFISH_VULKAN) |
Lingfeng Yang | 9c26ebf | 2019-12-30 09:14:49 -0800 | [diff] [blame] | 160 | sQemuPipeInit(); |
| 161 | #else // HOST_BUILD |
| 162 | switch (sConnType) { |
| 163 | // TODO: Move those over too |
| 164 | case HOST_CONNECTION_QEMU_PIPE: |
| 165 | case HOST_CONNECTION_ADDRESS_SPACE: |
| 166 | case HOST_CONNECTION_TCP: |
| 167 | case HOST_CONNECTION_VIRTIO_GPU: |
| 168 | sQemuPipeInit(); |
| 169 | break; |
| 170 | case HOST_CONNECTION_VIRTIO_GPU_PIPE: { |
| 171 | sVirtioGpuPipeStream = new VirtioGpuPipeStream(4096); |
| 172 | sProcUID = sVirtioGpuPipeStream->initProcessPipe(); |
| 173 | break; |
| 174 | } |
| 175 | } |
| 176 | #endif // !HOST_BUILD |
| 177 | } |
| 178 | #endif // !__Fuchsia__ |
| 179 | |
| 180 | bool processPipeInit(HostConnectionType connType, renderControl_encoder_context_t *rcEnc) { |
| 181 | sConnType = connType; |
Yahan Zhou | 4105059 | 2016-07-28 16:31:59 -0700 | [diff] [blame] | 182 | pthread_once(&sProcPipeOnce, processPipeInitOnce); |
Yilong Li | 4666908 | 2020-01-14 16:22:57 -0800 | [diff] [blame] | 183 | bool pipeHandleInvalid = !sProcPipe; |
| 184 | #ifndef __Fuchsia__ |
| 185 | pipeHandleInvalid = pipeHandleInvalid && !sVirtioGpuPipeStream; |
| 186 | #endif // !__Fuchsia__ |
| 187 | if (pipeHandleInvalid) return false; |
Yahan Zhou | e8cf63d | 2016-09-22 12:33:50 -0700 | [diff] [blame] | 188 | rcEnc->rcSetPuid(rcEnc, sProcUID); |
| 189 | return true; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 190 | } |