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
17 #include "ProcessPipe.h"
18 #include "HostConnection.h"
19 #include "renderControl_enc.h"
20
21 #include <qemu_pipe_bp.h>
22
23 #if PLATFORM_SDK_VERSION < 26
24 #include <cutils/log.h>
25 #else
26 #include <log/log.h>
27 #endif
28 #include <pthread.h>
29 #include <errno.h>
30
31 #ifdef __Fuchsia__
32 #include <fuchsia/hardware/goldfish/llcpp/fidl.h>
33 #include <lib/zx/vmo.h>
34
35 #include "services/service_connector.h"
36
37 #define GET_STATUS_SAFE(result, member) \
38 ((result).ok() ? ((result).Unwrap()->member) : ZX_OK)
39
40 static QEMU_PIPE_HANDLE sProcDevice = 0;
41 #else // __Fuchsia__
42
43 #include "VirtioGpuPipeStream.h"
44 static VirtioGpuPipeStream* sVirtioGpuPipeStream = 0;
45
46 #endif // !__Fuchsia__
47
48 static QEMU_PIPE_HANDLE sProcPipe = 0;
49 static pthread_once_t sProcPipeOnce = PTHREAD_ONCE_INIT;
50 // sProcUID is a unique ID per process assigned by the host.
51 // It is different from getpid().
52 static uint64_t sProcUID = 0;
53 static volatile HostConnectionType sConnType = HOST_CONNECTION_VIRTIO_GPU_PIPE;
54
55 static uint32_t* sSeqnoPtr = 0;
56
57 // Meant to be called only once per process.
initSeqno()58 static void initSeqno() {
59 // So why do we reinitialize here? It's for testing purposes only;
60 // we have a unit test that exercise the case where this sequence
61 // number is reset as a result of guest process kill.
62 if (sSeqnoPtr) delete sSeqnoPtr;
63 sSeqnoPtr = new uint32_t;
64 *sSeqnoPtr = 0;
65 }
66
67 // processPipeInitOnce is used to generate a process unique ID (puid).
68 // processPipeInitOnce will only be called at most once per process.
69 // Use it with pthread_once for thread safety.
70 // The host associates resources with process unique ID (puid) for memory cleanup.
71 // It will fallback to the default path if the host does not support it.
72 // Processes are identified by acquiring a per-process 64bit unique ID from the
73 // host.
74 #ifdef __Fuchsia__
processPipeInitOnce()75 static void processPipeInitOnce() {
76 initSeqno();
77
78 fidl::ClientEnd<fuchsia_hardware_goldfish::PipeDevice> channel{
79 zx::channel(GetConnectToServiceFunction()(QEMU_PIPE_PATH))};
80 if (!channel) {
81 ALOGE("%s: failed to open " QEMU_PIPE_PATH,
82 __FUNCTION__);
83 return;
84 }
85
86 fidl::WireSyncClient<fuchsia_hardware_goldfish::PipeDevice> device(
87 std::move(channel));
88
89 auto pipe_ends =
90 fidl::CreateEndpoints<::fuchsia_hardware_goldfish::Pipe>();
91 if (!pipe_ends.is_ok()) {
92 ALOGE("%s: zx_channel_create failed: %d", __FUNCTION__, pipe_ends.status_value());
93 return;
94 }
95
96 fidl::WireSyncClient<fuchsia_hardware_goldfish::Pipe> pipe(
97 std::move(pipe_ends->client));
98 device.OpenPipe(std::move(pipe_ends->server));
99
100 zx::vmo vmo;
101 {
102 auto result = pipe.GetBuffer();
103 if (!result.ok() || result.Unwrap()->res != ZX_OK) {
104 ALOGE("%s: failed to get buffer: %d:%d", __FUNCTION__,
105 result.status(), GET_STATUS_SAFE(result, res));
106 return;
107 }
108 vmo = std::move(result.Unwrap()->vmo);
109 }
110
111 size_t len = strlen("pipe:GLProcessPipe");
112 zx_status_t status = vmo.write("pipe:GLProcessPipe", 0, len + 1);
113 if (status != ZX_OK) {
114 ALOGE("%s: failed write pipe name", __FUNCTION__);
115 return;
116 }
117
118 {
119 auto result = pipe.Write(len + 1, 0);
120 if (!result.ok() || result.Unwrap()->res != ZX_OK) {
121 ALOGD("%s: connecting to pipe service failed: %d:%d", __FUNCTION__,
122 result.status(), GET_STATUS_SAFE(result, res));
123 return;
124 }
125 }
126
127 // Send a confirmation int to the host and get per-process unique ID back
128 int32_t confirmInt = 100;
129 status = vmo.write(&confirmInt, 0, sizeof(confirmInt));
130 if (status != ZX_OK) {
131 ALOGE("%s: failed write confirm int", __FUNCTION__);
132 return;
133 }
134
135 {
136 auto result = pipe.DoCall(sizeof(confirmInt), 0, sizeof(sProcUID), 0);
137 if (!result.ok() || result.Unwrap()->res != ZX_OK) {
138 ALOGD("%s: failed to get per-process ID: %d:%d", __FUNCTION__,
139 result.status(), GET_STATUS_SAFE(result, res));
140 return;
141 }
142 }
143
144 status = vmo.read(&sProcUID, 0, sizeof(sProcUID));
145 if (status != ZX_OK) {
146 ALOGE("%s: failed read per-process ID: %d", __FUNCTION__, status);
147 return;
148 }
149 sProcDevice = device.mutable_channel()->release();
150 sProcPipe = pipe.mutable_channel()->release();
151 }
152 #else // __Fuchsia__
153
sQemuPipeInit()154 static void sQemuPipeInit() {
155 sProcPipe = qemu_pipe_open("GLProcessPipe");
156 if (!qemu_pipe_valid(sProcPipe)) {
157 sProcPipe = 0;
158 ALOGW("Process pipe failed");
159 return;
160 }
161 // Send a confirmation int to the host
162 int32_t confirmInt = 100;
163 if (qemu_pipe_write_fully(sProcPipe, &confirmInt, sizeof(confirmInt))) { // failed
164 qemu_pipe_close(sProcPipe);
165 sProcPipe = 0;
166 ALOGW("Process pipe failed");
167 return;
168 }
169
170 // Ask the host for per-process unique ID
171 if (qemu_pipe_read_fully(sProcPipe, &sProcUID, sizeof(sProcUID))) {
172 qemu_pipe_close(sProcPipe);
173 sProcPipe = 0;
174 sProcUID = 0;
175 ALOGW("Process pipe failed");
176 return;
177 }
178 }
179
processPipeInitOnce()180 static void processPipeInitOnce() {
181 initSeqno();
182
183 #if defined(HOST_BUILD) || !defined(GFXSTREAM)
184 sQemuPipeInit();
185 #else // HOST_BUILD
186 switch (sConnType) {
187 // TODO: Move those over too
188 case HOST_CONNECTION_QEMU_PIPE:
189 case HOST_CONNECTION_ADDRESS_SPACE:
190 case HOST_CONNECTION_TCP:
191 case HOST_CONNECTION_VIRTIO_GPU:
192 sQemuPipeInit();
193 break;
194 case HOST_CONNECTION_VIRTIO_GPU_PIPE:
195 case HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE: {
196 sVirtioGpuPipeStream = new VirtioGpuPipeStream(4096);
197 sProcUID = sVirtioGpuPipeStream->initProcessPipe();
198 break;
199 }
200 }
201 #endif // !HOST_BUILD
202 }
203 #endif // !__Fuchsia__
204
processPipeInit(HostConnectionType connType,renderControl_encoder_context_t * rcEnc)205 bool processPipeInit(HostConnectionType connType, renderControl_encoder_context_t *rcEnc) {
206 sConnType = connType;
207 pthread_once(&sProcPipeOnce, processPipeInitOnce);
208 bool pipeHandleInvalid = !sProcPipe;
209 #ifndef __Fuchsia__
210 pipeHandleInvalid = pipeHandleInvalid && !sVirtioGpuPipeStream;
211 #endif // !__Fuchsia__
212 if (pipeHandleInvalid) return false;
213 rcEnc->rcSetPuid(rcEnc, sProcUID);
214 return true;
215 }
216
getPuid()217 uint64_t getPuid() {
218 return sProcUID;
219 }
220
processPipeRestart()221 void processPipeRestart() {
222 ALOGW("%s: restarting process pipe\n", __func__);
223 bool isPipe = false;
224
225 switch (sConnType) {
226 // TODO: Move those over too
227 case HOST_CONNECTION_QEMU_PIPE:
228 case HOST_CONNECTION_ADDRESS_SPACE:
229 case HOST_CONNECTION_TCP:
230 case HOST_CONNECTION_VIRTIO_GPU:
231 isPipe = true;
232 break;
233 case HOST_CONNECTION_VIRTIO_GPU_PIPE:
234 case HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE: {
235 isPipe = false;
236 break;
237 }
238 }
239
240 sProcUID = 0;
241
242 #ifdef __Fuchsia__
243 zx_handle_close(sProcPipe);
244 sProcPipe = ZX_HANDLE_INVALID;
245 #else
246 if (isPipe) {
247 if (qemu_pipe_valid(sProcPipe)) {
248 qemu_pipe_close(sProcPipe);
249 sProcPipe = 0;
250 }
251 } else {
252 delete sVirtioGpuPipeStream;
253 sVirtioGpuPipeStream = nullptr;
254 }
255 #endif // __Fuchsia__
256
257 processPipeInitOnce();
258 };
259
refreshHostConnection()260 void refreshHostConnection() {
261 HostConnection* hostConn = HostConnection::get();
262 ExtendedRCEncoderContext* rcEnc = hostConn->rcEncoder();
263 rcEnc->rcSetPuid(rcEnc, sProcUID);
264 }
265
getSeqnoPtrForProcess()266 uint32_t* getSeqnoPtrForProcess() {
267 // It's assumed process pipe state has already been initialized.
268 return sSeqnoPtr;
269 }
270