1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "host-common/HostGoldfishPipe.h"
16
17 #include "aemu/base/containers/Lookup.h"
18 #include "aemu/base/Result.h"
19 #include "android/crashreport/crash-handler.h"
20 #include "host-common/android_pipe_device.h"
21 #include "host-common/AndroidPipe.h"
22 #include "host-common/crash-handler.h"
23 #include "host-common/testing/TestVmLock.h"
24 #include "host-common/VmLock.h"
25
26 #include <algorithm>
27 #include <unordered_map>
28 #include <unordered_set>
29 #include <vector>
30
31 #include <errno.h>
32 #include <stdint.h>
33 #include <string.h>
34
35 #ifdef _MSC_VER
36 #ifdef ERROR
37 #undef ERROR
38 #endif
39 #endif
40
41 #define HOST_PIPE_DEBUG 0
42
43 #if HOST_PIPE_DEBUG
44
45 #define HOST_PIPE_DLOG(fmt,...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);
46
47 #else
48
49 #define HOST_PIPE_DLOG(fmt,...)
50
51 #endif
52
53 using android::base::Result;
54 using android::base::Ok;
55 using android::base::Err;
56
57 namespace android {
58
59 const AndroidPipeHwFuncs HostGoldfishPipeDevice::HostHwPipe::vtbl = {
60 &closeFromHostCallback,
61 &signalWakeCallback,
62 &getPipeIdCallback,
63 };
64
HostHwPipe(int fd)65 HostGoldfishPipeDevice::HostHwPipe::HostHwPipe(int fd) : vtblPtr(&vtbl), mFd(fd) {}
66
~HostHwPipe()67 HostGoldfishPipeDevice::HostHwPipe::~HostHwPipe() {}
68
69 std::unique_ptr<HostGoldfishPipeDevice::HostHwPipe>
create(int fd)70 HostGoldfishPipeDevice::HostHwPipe::create(int fd) {
71 return std::make_unique<HostHwPipe>(fd);
72 }
73
HostGoldfishPipeDevice()74 HostGoldfishPipeDevice::HostGoldfishPipeDevice() {}
75
~HostGoldfishPipeDevice()76 HostGoldfishPipeDevice::~HostGoldfishPipeDevice() {
77 clearLocked(); // no lock required in dctor
78 }
79
getErrno() const80 int HostGoldfishPipeDevice::getErrno() const {
81 ScopedVmLock lock;
82 return mErrno;
83 }
84
85 // Also opens.
connect(const char * name)86 int HostGoldfishPipeDevice::connect(const char* name) {
87 const auto handshake = std::string("pipe:") + name;
88
89 ScopedVmLock lock;
90 const int hwPipeFd = ++mFdGenerator;
91 std::unique_ptr<HostHwPipe> hwPipe = HostHwPipe::create(hwPipeFd);
92
93 InternalPipe* hostPipe = static_cast<InternalPipe*>(
94 android_pipe_guest_open(hwPipe.get(), nullptr));
95 if (!hostPipe) {
96 mErrno = ENOENT;
97 return kNoFd;
98 }
99
100 const ssize_t len = static_cast<ssize_t>(handshake.size()) + 1;
101 const ssize_t ret = writeInternal(&hostPipe, handshake.c_str(), len);
102
103 if (ret == len) {
104 HostHwPipe* hwPipeWeak = associatePipes(std::move(hwPipe), hostPipe);
105 if (hwPipeWeak) {
106 HOST_PIPE_DLOG("New pipe: service: for '%s', hwpipe: %p hostpipe: %p",
107 name, hwPipeWeak, hostPipe);
108
109 return hwPipeWeak->getFd();
110 } else {
111 mErrno = ENOENT;
112 return kNoFd;
113 }
114 } else {
115 LOG(ERROR) << "Could not connect to goldfish pipe name: " << name;
116 android_pipe_guest_close(hostPipe, PIPE_CLOSE_GRACEFUL);
117 mErrno = EIO;
118 return kNoFd;
119 }
120 }
121
close(const int fd)122 void HostGoldfishPipeDevice::close(const int fd) {
123 HOST_PIPE_DLOG("Close fd=%d", fd);
124
125 ScopedVmLock lock;
126 if (!eraseFdInfo(fd)) {
127 LOG(INFO) << "Could not close pipe, ENOENT.";
128 mErrno = ENOENT;
129 }
130 }
131
132 // Read/write/poll but for a particular pipe.
read(const int fd,void * buffer,size_t len)133 ssize_t HostGoldfishPipeDevice::read(const int fd, void* buffer, size_t len) {
134 ScopedVmLock lock;
135
136 FdInfo* fdInfo = lookupFdInfo(fd);
137 if (!fdInfo) {
138 LOG(ERROR) << "fd=" << fd << " is not a valid pipe fd";
139 mErrno = EINVAL;
140 return PIPE_ERROR_INVAL;
141 }
142
143 AndroidPipeBuffer buf = { static_cast<uint8_t*>(buffer), len };
144 ssize_t res = android_pipe_guest_recv(fdInfo->hostPipe, &buf, 1);
145 setErrno(res);
146 return res;
147 }
148
read(int fd,size_t maxLength)149 HostGoldfishPipeDevice::ReadResult HostGoldfishPipeDevice::read(int fd, size_t maxLength) {
150 std::vector<uint8_t> resultBuffer(maxLength);
151 ssize_t read_size = read(fd, resultBuffer.data(), maxLength);
152
153 if (read_size < 0) {
154 return Err(mErrno);
155 } else {
156 if (read_size < maxLength) {
157 resultBuffer.resize(read_size);
158 }
159 return Ok(resultBuffer);
160 }
161 }
162
write(const int fd,const void * buffer,size_t len)163 ssize_t HostGoldfishPipeDevice::write(const int fd, const void* buffer, size_t len) {
164 ScopedVmLock lock;
165
166 FdInfo* fdInfo = lookupFdInfo(fd);
167 if (!fdInfo) {
168 LOG(ERROR) << "fd=" << fd << " is not a valid pipe fd";
169 mErrno = EINVAL;
170 return PIPE_ERROR_INVAL;
171 }
172
173 return writeInternal(&fdInfo->hostPipe, buffer, len);
174 }
175
176 HostGoldfishPipeDevice::WriteResult
write(const int fd,const std::vector<uint8_t> & data)177 HostGoldfishPipeDevice::write(const int fd, const std::vector<uint8_t>& data) {
178 ssize_t res = write(fd, data.data(), data.size());
179
180 if (res < 0) {
181 return Err(mErrno);
182 } else {
183 return Ok(res);
184 }
185 }
186
poll(const int fd) const187 unsigned HostGoldfishPipeDevice::poll(const int fd) const {
188 ScopedVmLock lock;
189
190 const FdInfo* fdInfo = lookupFdInfo(fd);
191 if (!fdInfo) {
192 LOG(ERROR) << "fd=" << fd << " is not a valid pipe fd";
193 return 0;
194 }
195
196 return android_pipe_guest_poll(fdInfo->hostPipe);
197 }
198
setWakeCallback(const int fd,std::function<void (int)> callback)199 void HostGoldfishPipeDevice::setWakeCallback(const int fd,
200 std::function<void(int)> callback) {
201 ScopedVmLock lock;
202
203 FdInfo* fdInfo = lookupFdInfo(fd);
204 if (fdInfo) {
205 fdInfo->wakeCallback = std::move(callback);
206 }
207 }
208
getHostPipe(const int fd) const209 void* HostGoldfishPipeDevice::getHostPipe(const int fd) const {
210 ScopedVmLock lock;
211
212 const FdInfo* fdInfo = lookupFdInfo(fd);
213 return fdInfo ? fdInfo->hostPipe : nullptr;
214 }
215
saveSnapshot(base::Stream * stream)216 void HostGoldfishPipeDevice::saveSnapshot(base::Stream* stream) {
217 HOST_PIPE_DLOG("Saving snapshot");
218
219 auto cStream = reinterpret_cast<::Stream*>(stream);
220
221 ScopedVmLock lock;
222
223 android_pipe_guest_pre_save(cStream);
224 stream_put_be32(cStream, mFdInfo.size());
225 for (const auto& kv : mFdInfo) {
226 HOST_PIPE_DLOG("save pipe: fd=%d hwPipe=%p hostPipe=%p",
227 kv.first, kv.second.hwPipe.get(), kv.second.hostPipe);
228 stream_put_be32(cStream, kv.first);
229 android_pipe_guest_save(kv.second.hostPipe, cStream);
230 }
231 android_pipe_guest_post_save(cStream);
232 }
233
loadSnapshot(base::Stream * stream)234 void HostGoldfishPipeDevice::loadSnapshot(base::Stream* stream) {
235 auto cStream = reinterpret_cast<::Stream*>(stream);
236
237 ScopedVmLock lock;
238 clearLocked();
239
240 android_pipe_guest_pre_load(cStream);
241 const uint32_t pipeCount = stream_get_be32(cStream);
242
243 for (uint32_t i = 0; i < pipeCount; ++i) {
244 const int fd = stream_get_be32(cStream);
245 mFdGenerator = std::max(mFdGenerator, fd);
246
247 std::unique_ptr<HostHwPipe> hwPipe = HostHwPipe::create(fd);
248
249 HOST_PIPE_DLOG("attempt to load a host pipe");
250
251 char forceClose = 0;
252 InternalPipe* hostPipe = static_cast<InternalPipe*>(
253 android_pipe_guest_load(cStream, hwPipe.get(), &forceClose));
254
255 if (!forceClose) {
256 HostHwPipe* hwPipePtr = associatePipes(std::move(hwPipe), hostPipe);
257 HOST_PIPE_DLOG("Successfully loaded host pipe %p for hw pipe %p",
258 hostPipe, hwPipePtr);
259 } else {
260 HOST_PIPE_DLOG("Failed to load host pipe for hw pipe %p", hwpipe);
261 LOG(ERROR) << "Could not load goldfish pipe";
262 mErrno = EIO;
263 return;
264 }
265 }
266
267 android_pipe_guest_post_load(cStream);
268 }
269
saveSnapshot(base::Stream * stream,const int fd)270 void HostGoldfishPipeDevice::saveSnapshot(base::Stream* stream, const int fd) {
271 HOST_PIPE_DLOG("Saving snapshot for fd=%d", fd);
272
273 ScopedVmLock lock;
274 FdInfo* fdInfo = lookupFdInfo(fd);
275 if (!fdInfo) {
276 crashhandler_die_format("%s:%d fd=%d is a valid pipe fd",
277 __func__, __LINE__, fd);
278 }
279
280 auto cStream = reinterpret_cast<::Stream*>(stream);
281
282 android_pipe_guest_pre_save(cStream);
283
284 stream_put_be32(cStream, 1);
285 stream_put_be32(cStream, fd);
286 android_pipe_guest_save(fdInfo->hostPipe, cStream);
287 android_pipe_guest_post_save(cStream);
288 }
289
loadSnapshotSinglePipe(base::Stream * stream)290 int HostGoldfishPipeDevice::loadSnapshotSinglePipe(base::Stream* stream) {
291 HOST_PIPE_DLOG("Loading snapshot for a single pipe");
292
293 auto cStream = reinterpret_cast<::Stream*>(stream);
294
295 ScopedVmLock lock;
296
297 android_pipe_guest_pre_load(cStream);
298 uint32_t pipeCount = stream_get_be32(cStream);
299
300 if (pipeCount != 1) {
301 LOG(ERROR) << "Invalid pipe count from stream";
302 mErrno = EIO;
303 return kNoFd;
304 }
305
306 const int fd = stream_get_be32(cStream);
307 eraseFdInfo(fd);
308
309 HOST_PIPE_DLOG("attempt to load a host pipe");
310
311 std::unique_ptr<HostHwPipe> hwPipe = HostHwPipe::create(fd);
312
313 char forceClose = 0;
314 InternalPipe* hostPipe = static_cast<InternalPipe*>(
315 android_pipe_guest_load(cStream, hwPipe.get(), &forceClose));
316 if (!forceClose) {
317 associatePipes(std::move(hwPipe), hostPipe);
318 HOST_PIPE_DLOG("Successfully loaded host pipe %p for fd=%d", hostPipe, fd);
319 } else {
320 HOST_PIPE_DLOG("Failed to load host pipe for hw pipe %p", hwPipeFromStream);
321 LOG(ERROR) << "Could not load goldfish pipe";
322 mErrno = EIO;
323 }
324
325 android_pipe_guest_post_load(cStream);
326
327 return fd;
328 }
329
clear()330 void HostGoldfishPipeDevice::clear() {
331 ScopedVmLock lock;
332 clearLocked();
333 }
334
initialize()335 void HostGoldfishPipeDevice::initialize() {
336 if (mInitialized) return;
337 AndroidPipe::Service::resetAll();
338 AndroidPipe::initThreading(android::HostVmLock::getInstance());
339 mInitialized = true;
340 }
341
342 // locked
clearLocked()343 void HostGoldfishPipeDevice::clearLocked() {
344 while (true) {
345 const auto i = mFdInfo.begin();
346 if (i == mFdInfo.end()) {
347 break;
348 } else {
349 eraseFdInfo(i->first);
350 }
351 }
352 }
353
354 // locked
lookupFdInfo(int fd)355 HostGoldfishPipeDevice::FdInfo* HostGoldfishPipeDevice::lookupFdInfo(int fd) {
356 const auto i = mFdInfo.find(fd);
357 return (i == mFdInfo.end()) ? nullptr : &i->second;
358 }
359
360 // locked
lookupFdInfo(int fd) const361 const HostGoldfishPipeDevice::FdInfo* HostGoldfishPipeDevice::lookupFdInfo(int fd) const {
362 const auto i = mFdInfo.find(fd);
363 return (i == mFdInfo.end()) ? nullptr : &i->second;
364 }
365
366 // locked
367 HostGoldfishPipeDevice::HostHwPipe*
associatePipes(std::unique_ptr<HostGoldfishPipeDevice::HostHwPipe> hwPipe,HostGoldfishPipeDevice::InternalPipe * hostPipe)368 HostGoldfishPipeDevice::associatePipes(std::unique_ptr<HostGoldfishPipeDevice::HostHwPipe> hwPipe,
369 HostGoldfishPipeDevice::InternalPipe* hostPipe) {
370 HostHwPipe* hwPipePtr = hwPipe.get();
371 const int hwPipeFd = hwPipePtr->getFd();
372
373 mPipeToHwPipe[hostPipe] = hwPipePtr;
374
375 FdInfo info;
376 info.hwPipe = std::move(hwPipe);
377 info.hostPipe = hostPipe;
378
379 if (!mFdInfo.insert({hwPipeFd, std::move(info)}).second) {
380 crashhandler_die_format("%s:%d hwPipeFd=%d already exists",
381 __func__, __LINE__, hwPipeFd);
382 }
383
384 return hwPipePtr;
385 }
386
387 // locked
eraseFdInfo(const int fd)388 bool HostGoldfishPipeDevice::eraseFdInfo(const int fd) {
389 const auto i = mFdInfo.find(fd);
390 if (i == mFdInfo.end()) {
391 return false;
392 }
393
394 if (mPipeToHwPipe.erase(i->second.hostPipe) == 0) {
395 crashhandler_die_format("%s:%d hostPipe=%p does not exit while fd=%d exists",
396 __func__, __LINE__, i->second.hostPipe, fd);
397 }
398
399 android_pipe_guest_close(i->second.hostPipe, PIPE_CLOSE_GRACEFUL);
400 mFdInfo.erase(i);
401
402 return true;
403 }
404
writeInternal(InternalPipe ** ppipe,const void * buffer,size_t len)405 ssize_t HostGoldfishPipeDevice::writeInternal(InternalPipe** ppipe,
406 const void* buffer,
407 size_t len) {
408 AndroidPipeBuffer buf = {(uint8_t*)buffer, len};
409 ssize_t res = android_pipe_guest_send((void**)ppipe, &buf, 1);
410 setErrno(res);
411 return res;
412 }
413
setErrno(ssize_t res)414 void HostGoldfishPipeDevice::setErrno(ssize_t res) {
415 if (res >= 0) return;
416 switch (res) {
417 case PIPE_ERROR_INVAL:
418 mErrno = EINVAL;
419 break;
420 case PIPE_ERROR_AGAIN:
421 mErrno = EAGAIN;
422 break;
423 case PIPE_ERROR_NOMEM:
424 mErrno = ENOMEM;
425 break;
426 case PIPE_ERROR_IO:
427 mErrno = EIO;
428 break;
429 }
430 }
431
signalWake(const int fd,const int wakes)432 void HostGoldfishPipeDevice::signalWake(const int fd, const int wakes) {
433 ScopedVmLock lock;
434 const FdInfo* fdInfo = lookupFdInfo(fd);
435 if (fdInfo) {
436 fdInfo->wakeCallback(wakes);
437 }
438 }
439
sDevice()440 static HostGoldfishPipeDevice* sDevice() {
441 static HostGoldfishPipeDevice* d = new HostGoldfishPipeDevice;
442 return d;
443 }
444
445 // static
get()446 HostGoldfishPipeDevice* HostGoldfishPipeDevice::get() {
447 auto res = sDevice();
448 // Must be separate from construction
449 // as some initialization routines require
450 // the instance to be constructed.
451 res->initialize();
452 return res;
453 }
454
455 // Callbacks for AndroidPipeHwFuncs.
456 // static
closeFromHostCallback(void * hwPipeRaw)457 void HostGoldfishPipeDevice::closeFromHostCallback(void* hwPipeRaw) {
458 const int fd = static_cast<const HostHwPipe*>(hwPipeRaw)->getFd();
459
460 // PIPE_WAKE_CLOSED gets translated to closeFromHostCallback.
461 // To simplify detecting a close-from-host, signal a wake callback so that
462 // the event can be detected.
463 HostGoldfishPipeDevice::get()->signalWake(fd, PIPE_WAKE_CLOSED);
464 HostGoldfishPipeDevice::get()->close(fd);
465 }
466
467 // static
signalWakeCallback(void * hwPipeRaw,unsigned wakes)468 void HostGoldfishPipeDevice::signalWakeCallback(void* hwPipeRaw, unsigned wakes) {
469 const int fd = static_cast<const HostHwPipe*>(hwPipeRaw)->getFd();
470 HostGoldfishPipeDevice::get()->signalWake(fd, wakes);
471 }
472
473 // static
getPipeIdCallback(void * hwPipeRaw)474 int HostGoldfishPipeDevice::getPipeIdCallback(void* hwPipeRaw) {
475 return static_cast<const HostHwPipe*>(hwPipeRaw)->getFd();
476 }
477
478 } // namespace android
479