• 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 "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