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