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