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
19 #include <errno.h>
20 #include <log/log.h>
21 #include <pthread.h>
22 #include <qemu_pipe_bp.h>
23
24 #include "HostConnection.h"
25
26 #ifndef __Fuchsia__
27
28 #include "VirtioGpuPipeStream.h"
29 static VirtioGpuPipeStream* sVirtioGpuPipeStream = 0;
30 static int sStreamHandle = -1;
31
32 #endif // !__Fuchsia__
33
34 static QEMU_PIPE_HANDLE sProcPipe = 0;
35 // sProcUID is a unique ID per process assigned by the host.
36 // It is different from getpid().
37 static uint64_t sProcUID = 0;
38 static HostConnectionType sConnType = HOST_CONNECTION_VIRTIO_GPU_PIPE;
39
40 static uint32_t* sSeqnoPtr = 0;
41
42 // Meant to be called only once per process.
initSeqno(void)43 static void initSeqno(void) {
44 // So why do we reinitialize here? It's for testing purposes only;
45 // we have a unit test that exercise the case where this sequence
46 // number is reset as a result of guest process kill.
47 if (sSeqnoPtr) delete sSeqnoPtr;
48 sSeqnoPtr = new uint32_t;
49 *sSeqnoPtr = 0;
50 }
51
52 namespace {
53
54 static std::mutex sNeedInitMutex;
55 static bool sNeedInit = true;
56
57 } // namespace
58
59 #ifndef __Fuchsia__
60
sQemuPipeInit()61 static void sQemuPipeInit() {
62 sProcPipe = qemu_pipe_open("GLProcessPipe");
63 if (!qemu_pipe_valid(sProcPipe)) {
64 sProcPipe = 0;
65 ALOGW("Process pipe failed");
66 return;
67 }
68 // Send a confirmation int to the host
69 int32_t confirmInt = 100;
70 if (qemu_pipe_write_fully(sProcPipe, &confirmInt, sizeof(confirmInt))) { // failed
71 qemu_pipe_close(sProcPipe);
72 sProcPipe = 0;
73 ALOGW("Process pipe failed");
74 return;
75 }
76
77 // Ask the host for per-process unique ID
78 if (qemu_pipe_read_fully(sProcPipe, &sProcUID, sizeof(sProcUID))) {
79 qemu_pipe_close(sProcPipe);
80 sProcPipe = 0;
81 sProcUID = 0;
82 ALOGW("Process pipe failed");
83 return;
84 }
85 }
86
87 #endif // !__Fuchsia__
88
processPipeDoInit(uint32_t noRenderControlEnc)89 static void processPipeDoInit(uint32_t noRenderControlEnc) {
90 initSeqno();
91
92 // No need to setup auxiliary pipe stream in this case
93 if (noRenderControlEnc) return;
94
95 #if defined(__Fuchsia__)
96 // Note: sProcUID is not initialized.
97 ALOGE("Fuchsia: requires noRenderControlEnc");
98 abort();
99 #else
100 switch (sConnType) {
101 // TODO: Move those over too
102 case HOST_CONNECTION_QEMU_PIPE:
103 case HOST_CONNECTION_ADDRESS_SPACE:
104 sQemuPipeInit();
105 break;
106 case HOST_CONNECTION_VIRTIO_GPU_PIPE:
107 case HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE: {
108 sVirtioGpuPipeStream = new VirtioGpuPipeStream(4096, sStreamHandle);
109 sProcUID = sVirtioGpuPipeStream->initProcessPipe();
110 break;
111 }
112 }
113 #endif
114 }
115
processPipeInit(int streamHandle,HostConnectionType connType,uint32_t noRenderControlEnc)116 bool processPipeInit(int streamHandle, HostConnectionType connType, uint32_t noRenderControlEnc) {
117 sConnType = connType;
118 #ifndef __Fuchsia__
119 sStreamHandle = streamHandle;
120 #endif // !__Fuchsia
121
122 {
123 std::lock_guard<std::mutex> lock(sNeedInitMutex);
124
125 if (sNeedInit) {
126 sNeedInit = false;
127 processPipeDoInit(noRenderControlEnc);
128
129 if (noRenderControlEnc) {
130 return true;
131 }
132
133 #ifndef __Fuchsia__
134 if (!sProcPipe && !sVirtioGpuPipeStream) {
135 return false;
136 }
137 #endif
138 }
139 }
140
141 return true;
142 }
143
getPuid()144 uint64_t getPuid() {
145 return sProcUID;
146 }
147
processPipeRestart()148 void processPipeRestart() {
149 std::lock_guard<std::mutex> lock(sNeedInitMutex);
150
151 ALOGW("%s: restarting process pipe\n", __func__);
152 bool isPipe = false;
153
154 switch (sConnType) {
155 // TODO: Move those over too
156 case HOST_CONNECTION_QEMU_PIPE:
157 case HOST_CONNECTION_ADDRESS_SPACE:
158 isPipe = true;
159 break;
160 case HOST_CONNECTION_VIRTIO_GPU_PIPE:
161 case HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE: {
162 isPipe = false;
163 break;
164 }
165 }
166
167 sProcUID = 0;
168
169 if (isPipe) {
170 if (qemu_pipe_valid(sProcPipe)) {
171 qemu_pipe_close(sProcPipe);
172 sProcPipe = 0;
173 }
174 } else {
175 #ifndef __Fuchsia__
176 if (sVirtioGpuPipeStream) {
177 delete sVirtioGpuPipeStream;
178 sVirtioGpuPipeStream = nullptr;
179 }
180 #endif
181 }
182
183 if (sConnType == HOST_CONNECTION_VIRTIO_GPU_PIPE ||
184 sConnType == HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE) {
185 VirtGpuDevice::resetInstance();
186 }
187
188 sNeedInit = true;
189 }
190
refreshHostConnection()191 void refreshHostConnection() {
192 #if GFXSTREAM_ENABLE_GUEST_GLES
193 HostConnection* hostConn = HostConnection::get();
194 ExtendedRCEncoderContext* rcEnc = hostConn->rcEncoder();
195 rcEnc->rcSetPuid(rcEnc, sProcUID);
196 #endif
197 }
198
getSeqnoPtrForProcess()199 uint32_t* getSeqnoPtrForProcess() {
200 // It's assumed process pipe state has already been initialized.
201 return sSeqnoPtr;
202 }
203