• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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