blob: 40c1a8394260c6d7c8705cfdb78f39eebeef5eec [file] [log] [blame]
// Copyright 2016 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android/emulation/AndroidPipe.h"
#include "android/base/async/Looper.h"
#include "android/base/async/ThreadLooper.h"
#include "android/base/Log.h"
#include "android/base/memory/LazyInstance.h"
#include "android/base/Optional.h"
#include "android/base/synchronization/Lock.h"
#include "android/base/threads/ThreadStore.h"
#include "android/emulation/android_pipe_device.h"
#include "android/emulation/android_pipe_host.h"
#include "android/emulation/DeviceContextRunner.h"
#include "android/emulation/VmLock.h"
#include <memory>
#include <string>
#include <vector>
#include <unordered_map>
#define DEBUG 0
#if DEBUG >= 1
#include <stdio.h>
#define D(...) fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n")
#else
#define D(...) (void)0
#endif
#if DEBUG >= 2
#define DD(...) fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n")
#else
#define DD(...) (void)0
#endif
#define E(...) fprintf(stderr, "ERROR:" __VA_ARGS__), fprintf(stderr, "\n")
static const AndroidPipeHwFuncs* sPipeHwFuncs = nullptr;
using namespace android::base;
using AndroidPipe = android::AndroidPipe;
using BaseStream = android::base::Stream;
using CStream = ::Stream;
using OptionalString = android::base::Optional<std::string>;
using Service = android::AndroidPipe::Service;
using ServiceList = std::vector<std::unique_ptr<Service>>;
using VmLock = android::VmLock;
static BaseStream* asBaseStream(CStream* stream) {
return reinterpret_cast<BaseStream*>(stream);
}
// Use CHECK_VM_STATE_LOCK() to panic in debug builds if the current thread
// doesn't hold the VM state lock.
#if (DEBUG > 0) || !defined(NDEBUG)
#define CHECK_VM_STATE_LOCK() CHECK(VmLock::get()->isLockedBySelf())
#else
#define CHECK_VM_STATE_LOCK() (void)0
#endif
namespace android {
namespace {
// Write an optional string |str| to |stream|. |str| can be null. Use
// readOptionalString() to read it back later.
static void writeOptionalString(BaseStream* stream, const char* str) {
if (str) {
stream->putByte(1);
stream->putString(str);
} else {
stream->putByte(0);
}
}
// Read an optional string from |stream|. If the result is not constructed
// (i.e. equals to false), this means the original |str| parameter was null.
static OptionalString readOptionalString(BaseStream* stream) {
if (stream->getByte()) {
return OptionalString(std::move(stream->getString()));
}
return OptionalString();
}
// forward
Service* findServiceByName(const char* name);
// Implementation of a special AndroidPipe class used to model the state
// of a pipe connection before the service name has been written to the
// file descriptor by the guest. The most important method is onGuestSend()
// which will detect when this happens.
class ConnectorPipe : public AndroidPipe {
public:
ConnectorPipe(void* hwPipe, Service* service)
: AndroidPipe(hwPipe, service) {
DD("%s: Creating new ConnectorPipe hwpipe=%p", __FUNCTION__, mHwPipe);
}
virtual void onGuestClose() override {
// nothing to do here
DD("%s: closing ConnectorPipe hwpipe=%p prematurily!", __FUNCTION__,
mHwPipe);
}
virtual unsigned onGuestPoll() const override {
// A connector always want to receive data.
DD("%s: polling hwpipe=%p", __FUNCTION__, mHwPipe);
return PIPE_POLL_OUT;
}
virtual int onGuestRecv(AndroidPipeBuffer* buffers,
int numBuffers) override {
// This pipe never wants to write to the guest, so getting there
// is an error since PIPE_WAKE_IN is never signaled.
DD("%s: trying to receive data from hwpipe=%p", __FUNCTION__, mHwPipe);
return PIPE_ERROR_IO;
}
// TECHNICAL NOTE: This function reads data from the guest until it
// finds a zero-terminated C-string. After that it parses it to find
// a registered service corresponding to one of the allowed formats
// (see below). In case of success, this creates a new AndroidPipe
// instance and calls AndroidPipeHwFuncs::resetPipe() to associate it with
// the current hardware-side |mHwPipe|, then *deletes* the current
// instance! In case of error (e.g. invalid service name, or error during
// initialization), PIPE_ERROR_INVAL will be returned, otherwise, the
// number of bytes accepted from the guest is returned.
virtual int onGuestSend(const AndroidPipeBuffer* buffers,
int numBuffers) override {
int result = 0;
size_t avail = kBufferSize - mPos;
bool foundZero = false;
for (; !foundZero && avail > 0 && numBuffers > 0;
buffers++, numBuffers--) {
const uint8_t* data = buffers[0].data;
size_t count = std::min(avail, buffers[0].size);
// Read up to |count| bytes, stopping after the first zero.
size_t n = 0;
while (n < count) {
uint8_t byte = data[n++];
mBuffer[mPos++] = (char) byte;
if (!byte) {
foundZero = true;
break;
}
}
result += static_cast<int>(n);
avail -= n;
}
DD("%s: receiving %d connection bytes from hwpipe=%p", __FUNCTION__,
result, mHwPipe);
if (!foundZero) {
if (avail == 0) {
DD("%s: service name buffer full, force-closing connection",
__FUNCTION__);
return PIPE_ERROR_IO;
}
// Still waiting for terminating zero.
DD("%s: still waiting for terminating zero!", __FUNCTION__);
return result;
}
// Acceptable formats for the connection string are:
//
// pipe:<name>
// pipe:<name>:<arguments>
//
char* pipeName;
char* pipeArgs;
D("%s: connector: '%s'", __FUNCTION__, mBuffer);
if (memcmp(mBuffer, "pipe:", 5) != 0) {
// Nope, we don't handle these for now.
D("%s: Unknown pipe connection: '%s'", __FUNCTION__, mBuffer);
return PIPE_ERROR_INVAL;
}
pipeName = mBuffer + 5;
pipeArgs = strchr(pipeName, ':');
Service* svc = nullptr;
// As a special case, if the service name is as:
// qemud:<name>
// qemud:<name>:args
//
// First look for a registered pipe service named "qemud:<name>"
// and if not found, fallback to "qemud" only.
//
// This is useful to support qemud services that are now served
// by a dedicated (and faster) pipe service, e.g. 'qemud:adb'
// as currently implemented by QEMU2 (and soon by QEMU1).
static const char kQemudPrefix[] = "qemud:";
const size_t kQemudPrefixSize = sizeof(kQemudPrefix) - 1U;
if (!::strncmp(pipeName, kQemudPrefix, kQemudPrefixSize)) {
assert(pipeArgs == pipeName + kQemudPrefixSize - 1);
char* pipeArgs2 = strchr(pipeArgs + 1, ':');
if (pipeArgs2) {
*pipeArgs2 = '\0';
}
svc = findServiceByName(pipeName);
if (svc) {
pipeArgs = pipeArgs2;
} else if (pipeArgs2) {
// Restore colon.
*pipeArgs2 = ':';
}
}
if (pipeArgs) {
*pipeArgs++ = '\0';
if (!pipeArgs) {
pipeArgs = NULL;
}
}
if (!svc) {
svc = findServiceByName(pipeName);
}
if (!svc) {
D("%s: Unknown server with name %s!", __FUNCTION__, pipeName);
return PIPE_ERROR_INVAL;
}
AndroidPipe* newPipe = svc->create(mHwPipe, pipeArgs);
if (!newPipe) {
D("%s: Initialization failed for %s pipe!", __FUNCTION__, pipeName);
return PIPE_ERROR_INVAL;
}
// Swap your host-side pipe instance with this one weird trick!
D("%s: starting new pipe %p (swapping %p) for service %s",
__FUNCTION__,
newPipe,
mHwPipe,
pipeName);
sPipeHwFuncs->resetPipe(mHwPipe, newPipe);
delete this;
return result;
}
virtual void onGuestWantWakeOn(int wakeFlags) override {
// nothing to do here
DD("%s: signaling wakeFlags=%d for hwpipe=%p", __FUNCTION__, wakeFlags,
mHwPipe);
}
virtual void onSave(BaseStream* stream) override {
DD("%s: saving connector state for hwpipe=%p", __FUNCTION__, mHwPipe);
stream->putBe32(mPos);
stream->write(mBuffer, mPos);
}
bool onLoad(BaseStream* stream) {
DD("%s: loading connector state for hwpipe=%p", __FUNCTION__, mHwPipe);
int32_t len = stream->getBe32();
if (len < 0 || len > kBufferSize) {
D("%s: invalid length %d (expected 0 <= len <= %d)", __FUNCTION__,
static_cast<int>(len), kBufferSize);
return false;
}
mPos = (int)len;
int ret = (int)stream->read(mBuffer, mPos);
DD("%s: read %d bytes (%d expected)", __FUNCTION__, ret, mPos);
return (ret == mPos);
}
private:
static constexpr int kBufferSize = 128;
char mBuffer[kBufferSize];
int mPos = 0;
};
// Associated AndroidPipe::Service class for ConnectorPipe instances.
class ConnectorService : public Service {
public:
ConnectorService() : Service("<connector>") {}
virtual AndroidPipe* create(void* hwPipe, const char* args) override {
return new ConnectorPipe(hwPipe, this);
}
virtual bool canLoad() const override { return true; }
virtual AndroidPipe* load(void* hwPipe,
const char* args,
BaseStream* stream) override {
ConnectorPipe* pipe = new ConnectorPipe(hwPipe, this);
if (!pipe->onLoad(stream)) {
delete pipe;
return nullptr;
}
return pipe;
}
};
// A helper class used to send signalWake() and closeFromHost() commands to
// the device thread, depending on the threading mode setup by the emulation
// engine.
struct PipeWakeCommand {
void* hwPipe;
int wakeFlags;
};
class PipeWaker final : public DeviceContextRunner<PipeWakeCommand> {
public:
void signalWake(void* hwPipe, int wakeFlags) {
queueDeviceOperation({ hwPipe, wakeFlags });
}
void closeFromHost(void* hwPipe) {
signalWake(hwPipe, PIPE_WAKE_CLOSED);
}
private:
virtual void performDeviceOperation(const PipeWakeCommand& wake_cmd) {
void* hwPipe = wake_cmd.hwPipe;
int flags = wake_cmd.wakeFlags;
if (flags & PIPE_WAKE_CLOSED) {
sPipeHwFuncs->closeFromHost(hwPipe);
} else {
sPipeHwFuncs->signalWake(hwPipe, flags);
}
}
};
struct Globals {
ServiceList services;
ConnectorService connectorService;
PipeWaker pipeWaker;
Service* findServiceByName(const char* name) const {
for (const auto& service : services) {
if (service->name() == name) {
return service.get();
}
}
return nullptr;
}
Service* loadServiceByName(BaseStream* stream) {
OptionalString serviceName = readOptionalString(stream);
if (!serviceName) {
DD("%s: no name (assuming connector state)", __FUNCTION__);
return &connectorService;
}
DD("%s: found [%s]", __FUNCTION__, serviceName->c_str());
return this->findServiceByName(serviceName->c_str());
}
};
android::base::LazyInstance<Globals> sGlobals = LAZY_INSTANCE_INIT;
Service* findServiceByName(const char* name) {
return sGlobals->findServiceByName(name);
}
AndroidPipe* loadPipeFromStreamCommon(BaseStream* stream,
void* hwPipe,
Service* service,
char* pForceClose) {
*pForceClose = 0;
OptionalString args = readOptionalString(stream);
AndroidPipe* pipe = nullptr;
if (service->canLoad()) {
DD("%s: loading state for [%s] hwpipe=%p", __FUNCTION__,
service->name().c_str(), hwPipe);
pipe = service->load(hwPipe, args ? args->c_str() : nullptr, stream);
} else {
DD("%s: force-closing hwpipe=%p", __FUNCTION__, hwPipe);
*pForceClose = 1;
}
return pipe;
}
} // namespace
// static
void AndroidPipe::initThreading(VmLock* vmLock) {
sGlobals->pipeWaker.init(vmLock);
}
AndroidPipe::~AndroidPipe() {
DD("%s: for hwpipe=%p (host %p '%s')", __FUNCTION__, mHwPipe, this,
mService->name().c_str());
}
// static
void AndroidPipe::Service::add(Service* service) {
DD("Adding new pipe service '%s' this=%p", service->name().c_str(),
service);
std::unique_ptr<Service> svc(service);
sGlobals->services.push_back(std::move(svc));
}
// static
void AndroidPipe::Service::resetAll() {
DD("Resetting all pipe services");
sGlobals->services.clear();
}
void AndroidPipe::signalWake(int wakeFlags) {
sGlobals->pipeWaker.signalWake(mHwPipe, wakeFlags);
}
void AndroidPipe::closeFromHost() {
sGlobals->pipeWaker.closeFromHost(mHwPipe);
}
// static
void AndroidPipe::saveToStream(BaseStream* stream) {
// First, write service name.
if (mService == &sGlobals->connectorService) {
// A connector pipe
stream->putByte(0);
} else {
// A regular service pipe.
stream->putByte(1);
stream->putString(mService->name());
}
writeOptionalString(stream, mArgs.c_str());
// Save pipe-specific state now.
onSave(stream);
}
// static
AndroidPipe* AndroidPipe::loadFromStream(BaseStream* stream,
void* hwPipe,
char* pForceClose) {
Service* service = sGlobals->loadServiceByName(stream);
if (!service) {
return nullptr;
}
return loadPipeFromStreamCommon(stream, hwPipe, service, pForceClose);
}
// static
AndroidPipe* AndroidPipe::loadFromStreamLegacy(BaseStream* stream,
void* hwPipe,
uint64_t* pChannel,
unsigned char* pWakes,
unsigned char* pClosed,
char* pForceClose) {
Service* service = sGlobals->loadServiceByName(stream);
if (!service) {
return nullptr;
}
*pChannel = stream->getBe64();
*pWakes = stream->getByte();
*pClosed = stream->getByte();
return loadPipeFromStreamCommon(stream, hwPipe, service, pForceClose);
}
} // namespace android
// API for the virtual device.
const AndroidPipeHwFuncs* android_pipe_set_hw_funcs(
const AndroidPipeHwFuncs* hwFuncs) {
const AndroidPipeHwFuncs* result = sPipeHwFuncs;
sPipeHwFuncs = hwFuncs;
return result;
}
void android_pipe_reset_services() {
AndroidPipe::Service::resetAll();
}
void* android_pipe_guest_open(void* hwpipe) {
CHECK_VM_STATE_LOCK();
DD("%s: Creating new connector pipe for hwpipe=%p", __FUNCTION__, hwpipe);
return android::sGlobals->connectorService.create(hwpipe, nullptr);
}
void android_pipe_guest_close(void* internalPipe) {
CHECK_VM_STATE_LOCK();
auto pipe = static_cast<android::AndroidPipe*>(internalPipe);
if (pipe) {
D("%s: host=%p [%s]", __FUNCTION__, pipe, pipe->name());
pipe->onGuestClose();
}
}
void android_pipe_guest_save(void* internalPipe, CStream* stream) {
CHECK_VM_STATE_LOCK();
auto pipe = static_cast<android::AndroidPipe*>(internalPipe);
DD("%s: host=%p [%s]", __FUNCTION__, pipe, pipe->name());
pipe->saveToStream(asBaseStream(stream));
}
void* android_pipe_guest_load(CStream* stream,
void* hwPipe,
char* pForceClose) {
CHECK_VM_STATE_LOCK();
DD("%s: hwpipe=%p", __FUNCTION__, hwPipe);
return AndroidPipe::loadFromStream(asBaseStream(stream), hwPipe,
pForceClose);
}
void* android_pipe_guest_load_legacy(CStream* stream,
void* hwPipe,
uint64_t* pChannel,
unsigned char* pWakes,
unsigned char* pClosed,
char* pForceClose) {
CHECK_VM_STATE_LOCK();
DD("%s: hwpipe=%p", __FUNCTION__, hwPipe);
return android::AndroidPipe::loadFromStreamLegacy(asBaseStream(stream),
hwPipe, pChannel, pWakes,
pClosed, pForceClose);
}
unsigned android_pipe_guest_poll(void* internalPipe) {
CHECK_VM_STATE_LOCK();
auto pipe = static_cast<AndroidPipe*>(internalPipe);
DD("%s: host=%p [%s]", __FUNCTION__, pipe, pipe->name());
return pipe->onGuestPoll();
}
int android_pipe_guest_recv(void* internalPipe,
AndroidPipeBuffer* buffers,
int numBuffers) {
CHECK_VM_STATE_LOCK();
auto pipe = static_cast<AndroidPipe*>(internalPipe);
return pipe->onGuestRecv(buffers, numBuffers);
}
int android_pipe_guest_send(void* internalPipe,
const AndroidPipeBuffer* buffers,
int numBuffers) {
CHECK_VM_STATE_LOCK();
auto pipe = static_cast<AndroidPipe*>(internalPipe);
return pipe->onGuestSend(buffers, numBuffers);
}
void android_pipe_guest_wake_on(void* internalPipe, unsigned wakes) {
CHECK_VM_STATE_LOCK();
auto pipe = static_cast<AndroidPipe*>(internalPipe);
pipe->onGuestWantWakeOn(wakes);
}
// API implemented by the virtual device.
void android_pipe_host_close(void* hwpipe) {
auto pipe = static_cast<android::AndroidPipe*>(hwpipe);
D("%s: host=%p [%s]", __FUNCTION__, pipe, pipe->name());
android::sGlobals->pipeWaker.closeFromHost(pipe);
}
void android_pipe_host_signal_wake(void* hwpipe, unsigned flags) {
android::sGlobals->pipeWaker.signalWake(hwpipe, flags);
}