1 /*
2 * Copyright (C) 2011 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 "HostConnection.h"
17
18 #include "GoldfishAddressSpaceStream.h"
19 #include "GrallocGoldfish.h"
20 #include "GrallocMinigbm.h"
21 #include "VirtioGpuAddressSpaceStream.h"
22 #include "aemu/base/AndroidHealthMonitor.h"
23 #include "aemu/base/AndroidHealthMonitorConsumerBasic.h"
24 #include "aemu/base/threads/AndroidThread.h"
25
26 #if defined(__ANDROID__)
27 #include "ANativeWindowAndroid.h"
28 #include "android-base/properties.h"
29 #endif
30
31 #include "aemu/base/Process.h"
32
33 using gfxstream::guest::CreateHealthMonitor;
34 using gfxstream::guest::HealthMonitor;
35 using gfxstream::guest::HealthMonitorConsumerBasic;
36 using gfxstream::guest::IOStream;
37 using gfxstream::GoldfishGralloc;
38 using gfxstream::MinigbmGralloc;
39
40 #include "VkEncoder.h"
41 #include "AddressSpaceStream.h"
42
43 using gfxstream::vk::VkEncoder;
44
45 #include <unistd.h>
46
47 #include "ProcessPipe.h"
48 #include "QemuPipeStream.h"
49 #include "ThreadInfo.h"
50
51 using gfxstream::guest::getCurrentThreadId;
52
53 #include "VirtGpu.h"
54 #include "VirtioGpuPipeStream.h"
55 #include "virtgpu_drm.h"
56
57 #if defined(__linux__) || defined(__ANDROID__)
58 #include <fstream>
59 #include <string>
60 #include <unistd.h>
61
62 static const size_t kPageSize = getpagesize();
63 #else
64 constexpr size_t kPageSize = PAGE_SIZE;
65 #endif
66
67 #undef LOG_TAG
68 #define LOG_TAG "HostConnection"
69 #include <cutils/log.h>
70
71 #define STREAM_BUFFER_SIZE (4*1024*1024)
72 #define STREAM_PORT_NUM 22468
73
74 constexpr const auto kEglProp = "ro.hardware.egl";
75
getGlobalHealthMonitor()76 HealthMonitor<>* getGlobalHealthMonitor() {
77 // Initialize HealthMonitor
78 // Rather than inject as a construct arg, we keep it as a static variable in the .cpp
79 // to avoid setting up dependencies in other repos (external/qemu)
80 static HealthMonitorConsumerBasic sHealthMonitorConsumerBasic;
81 static std::unique_ptr<HealthMonitor<>> sHealthMonitor = CreateHealthMonitor(sHealthMonitorConsumerBasic);
82 return sHealthMonitor.get();
83 }
84
getConnectionTypeFromProperty(enum VirtGpuCapset capset)85 static HostConnectionType getConnectionTypeFromProperty(enum VirtGpuCapset capset) {
86 #if defined(__Fuchsia__) || defined(LINUX_GUEST_BUILD)
87 return HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE;
88 #else
89 std::string transport;
90
91 #if defined(__ANDROID__)
92 transport = android::base::GetProperty("ro.boot.hardware.gltransport", "");
93 #else
94 const char* transport_envvar = getenv("GFXSTREAM_TRANSPORT");
95 if (transport_envvar != nullptr) {
96 transport = std::string(transport_envvar);
97 }
98 #endif
99
100 if (transport.empty()) {
101 #if defined(__ANDROID__)
102 return HOST_CONNECTION_QEMU_PIPE;
103 #else
104 return HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE;
105 #endif
106 }
107
108 if (transport == "asg") {
109 return HOST_CONNECTION_ADDRESS_SPACE;
110 }
111 if (transport == "pipe") {
112 return HOST_CONNECTION_QEMU_PIPE;
113 }
114
115 if (transport == "virtio-gpu-asg" || transport == "virtio-gpu-pipe") {
116 std::string egl;
117 #if defined(__ANDROID__)
118 egl = android::base::GetProperty(kEglProp, "");
119 #endif
120 // ANGLE doesn't work well without ASG, particularly if HostComposer uses a pipe
121 // transport and VK uses ASG.
122 if (capset == kCapsetGfxStreamVulkan || egl == "angle") {
123 return HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE;
124 } else {
125 return HOST_CONNECTION_VIRTIO_GPU_PIPE;
126 }
127 }
128
129 return HOST_CONNECTION_QEMU_PIPE;
130 #endif
131 }
132
getGrallocTypeFromProperty()133 static GrallocType getGrallocTypeFromProperty() {
134 std::string value;
135
136 #if defined(__ANDROID__)
137 value = android::base::GetProperty("ro.hardware.gralloc", "");
138 #endif
139
140 if (value.empty()) {
141 return GRALLOC_TYPE_RANCHU;
142 }
143 if (value == "minigbm") {
144 return GRALLOC_TYPE_MINIGBM;
145 }
146 if (value == "ranchu") {
147 return GRALLOC_TYPE_RANCHU;
148 }
149 return GRALLOC_TYPE_RANCHU;
150 }
151
152 #if defined(__ANDROID__)
153 static GoldfishGralloc m_goldfishGralloc;
154 #endif
155
HostConnection()156 HostConnection::HostConnection()
157 : exitUncleanly(false),
158 m_hostExtensions(),
159 m_noHostError(true),
160 m_rendernodeFd(-1) { }
161
~HostConnection()162 HostConnection::~HostConnection()
163 {
164 // round-trip to ensure that queued commands have been processed
165 // before process pipe closure is detected.
166 #if GFXSTREAM_GUEST_USE_GLES
167 if (m_rcEnc && !exitUncleanly) {
168 (void)m_rcEnc->rcGetRendererVersion(m_rcEnc.get());
169 }
170 #endif
171
172 if (m_grallocType == GRALLOC_TYPE_MINIGBM) {
173 delete m_grallocHelper;
174 }
175
176 if (m_vkEnc) {
177 m_vkEnc->decRef();
178 }
179
180 if (m_stream) {
181 m_stream->decRef();
182 }
183 }
184
185
186 // static
connect(enum VirtGpuCapset capset)187 std::unique_ptr<HostConnection> HostConnection::connect(enum VirtGpuCapset capset) {
188 const enum HostConnectionType connType = getConnectionTypeFromProperty(capset);
189 uint32_t noRenderControlEnc = 0;
190
191 // Use "new" to access a non-public constructor.
192 auto con = std::unique_ptr<HostConnection>(new HostConnection);
193 con->m_connectionType = connType;
194
195 switch (connType) {
196 case HOST_CONNECTION_ADDRESS_SPACE: {
197 #if defined(__ANDROID__) || defined(__Fuchsia__)
198 auto stream = createGoldfishAddressSpaceStream(STREAM_BUFFER_SIZE, getGlobalHealthMonitor());
199 if (!stream) {
200 ALOGE("Failed to create AddressSpaceStream for host connection\n");
201 return nullptr;
202 }
203 con->m_stream = stream;
204 #else
205 ALOGE("Fatal: HOST_CONNECTION_ADDRESS_SPACE not supported on this host.");
206 abort();
207 #endif
208 con->m_grallocType = GRALLOC_TYPE_RANCHU;
209 #if defined(__ANDROID__)
210 con->m_grallocHelper = &m_goldfishGralloc;
211 #endif
212 break;
213 }
214 #if !defined(__Fuchsia__)
215 case HOST_CONNECTION_QEMU_PIPE: {
216 auto stream = new QemuPipeStream(STREAM_BUFFER_SIZE);
217 if (!stream) {
218 ALOGE("Failed to create QemuPipeStream for host connection\n");
219 return nullptr;
220 }
221 if (stream->connect() < 0) {
222 ALOGE("Failed to connect to host (QemuPipeStream)\n");
223 return nullptr;
224 }
225 con->m_grallocType = GRALLOC_TYPE_RANCHU;
226 con->m_stream = stream;
227 #if defined(__ANDROID__)
228 con->m_grallocHelper = &m_goldfishGralloc;
229 #endif
230 break;
231 }
232 #endif
233 case HOST_CONNECTION_VIRTIO_GPU_PIPE: {
234 auto stream = new VirtioGpuPipeStream(STREAM_BUFFER_SIZE);
235 if (!stream) {
236 ALOGE("Failed to create VirtioGpu for host connection\n");
237 return nullptr;
238 }
239 if (stream->connect() < 0) {
240 ALOGE("Failed to connect to host (VirtioGpu)\n");
241 return nullptr;
242 }
243 con->m_grallocType = getGrallocTypeFromProperty();
244 auto rendernodeFd = stream->getRendernodeFd();
245 con->m_stream = stream;
246 con->m_rendernodeFd = rendernodeFd;
247 #if defined(__ANDROID__)
248 switch (con->m_grallocType) {
249 case GRALLOC_TYPE_RANCHU:
250 con->m_grallocHelper = &m_goldfishGralloc;
251 break;
252 case GRALLOC_TYPE_MINIGBM: {
253 MinigbmGralloc* m = new MinigbmGralloc;
254 m->setFd(rendernodeFd);
255 con->m_grallocHelper = m;
256 break;
257 }
258 default:
259 ALOGE("Fatal: Unknown gralloc type 0x%x\n", con->m_grallocType);
260 abort();
261 }
262 #endif
263 break;
264 }
265 case HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE: {
266 // Use kCapsetGfxStreamVulkan for now, Ranchu HWC needs to be modified to pass in
267 // right capset.
268 auto device = VirtGpuDevice::getInstance(kCapsetGfxStreamVulkan);
269 auto deviceHandle = device->getDeviceHandle();
270 auto stream =
271 createVirtioGpuAddressSpaceStream(kCapsetGfxStreamVulkan, getGlobalHealthMonitor());
272 if (!stream) {
273 ALOGE("Failed to create virtgpu AddressSpaceStream\n");
274 return nullptr;
275 }
276 con->m_grallocType = getGrallocTypeFromProperty();
277 con->m_stream = stream;
278 con->m_rendernodeFd = deviceHandle;
279 #if defined(__ANDROID__)
280 switch (con->m_grallocType) {
281 case GRALLOC_TYPE_RANCHU:
282 con->m_grallocHelper = &m_goldfishGralloc;
283 break;
284 case GRALLOC_TYPE_MINIGBM: {
285 MinigbmGralloc* m = new gfxstream::MinigbmGralloc;
286 m->setFd(deviceHandle);
287 con->m_grallocHelper = m;
288 break;
289 }
290 default:
291 ALOGE("Fatal: Unknown gralloc type 0x%x\n", con->m_grallocType);
292 abort();
293 }
294 #endif
295 break;
296 }
297 default:
298 break;
299 }
300
301 #if defined(__ANDROID__)
302 con->m_anwHelper = new gfxstream::ANativeWindowHelperAndroid();
303 #else
304 // Host builds are expected to set an ANW helper for testing.
305 #endif
306 con->m_syncHelper.reset(gfxstream::createPlatformSyncHelper());
307
308 // send zero 'clientFlags' to the host.
309 unsigned int *pClientFlags =
310 (unsigned int *)con->m_stream->allocBuffer(sizeof(unsigned int));
311 *pClientFlags = 0;
312 con->m_stream->commitBuffer(sizeof(unsigned int));
313
314 if (capset == kCapsetGfxStreamMagma) {
315 noRenderControlEnc = 1;
316 } else if (capset == kCapsetGfxStreamVulkan) {
317 VirtGpuDevice* instance = VirtGpuDevice::getInstance(kCapsetGfxStreamVulkan);
318 auto caps = instance->getCaps();
319 noRenderControlEnc = caps.vulkanCapset.noRenderControlEnc;
320 }
321
322 auto fd = (connType == HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE) ? con->m_rendernodeFd : -1;
323 processPipeInit(fd, connType, noRenderControlEnc);
324 return con;
325 }
326
get()327 HostConnection* HostConnection::get() { return getWithThreadInfo(getEGLThreadInfo(), kCapsetNone); }
328
getOrCreate(enum VirtGpuCapset capset)329 HostConnection* HostConnection::getOrCreate(enum VirtGpuCapset capset) {
330 return getWithThreadInfo(getEGLThreadInfo(), capset);
331 }
332
getWithThreadInfo(EGLThreadInfo * tinfo,enum VirtGpuCapset capset)333 HostConnection* HostConnection::getWithThreadInfo(EGLThreadInfo* tinfo, enum VirtGpuCapset capset) {
334 // Get thread info
335 if (!tinfo) {
336 return NULL;
337 }
338
339 if (tinfo->hostConn == NULL) {
340 tinfo->hostConn = HostConnection::createUnique(capset);
341 }
342
343 return tinfo->hostConn.get();
344 }
345
exit()346 void HostConnection::exit() {
347 EGLThreadInfo *tinfo = getEGLThreadInfo();
348 if (!tinfo) {
349 return;
350 }
351
352 tinfo->hostConn.reset();
353 }
354
exitUnclean()355 void HostConnection::exitUnclean() {
356 EGLThreadInfo *tinfo = getEGLThreadInfo();
357 if (!tinfo) {
358 return;
359 }
360
361 tinfo->hostConn->exitUncleanly = true;
362 tinfo->hostConn.reset();
363 }
364
365 // static
createUnique(enum VirtGpuCapset capset)366 std::unique_ptr<HostConnection> HostConnection::createUnique(enum VirtGpuCapset capset) {
367 return connect(capset);
368 }
369
vkEncoder()370 VkEncoder* HostConnection::vkEncoder() {
371 if (!m_vkEnc) {
372 m_vkEnc = new VkEncoder(m_stream, getGlobalHealthMonitor());
373 }
374 return m_vkEnc;
375 }
376