blob: dca9a5717f0640c869ddec07c3885b4c5d9e061b [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.
#pragma once
#include "android/base/async/Looper.h"
#include "android/base/async/ScopedSocketWatch.h"
#include "android/base/StringView.h"
#include "android/emulation/AndroidPipe.h"
#include "android/emulation/AdbTypes.h"
#include <vector>
namespace android {
namespace emulation {
// AdbGuestPipe implements an AndroidPipe instance corresponding to the guest
// connections from the adbd daemon to the 'qemud:adb' service. Each instance
// is used to implement a single 'transport' between adbd and the host ADB
// server.
//
// The emulator implements two classes to support this: AdbGuestPipe and
// AdbHostListener and everything is linked at runtime like this:
//
// guest side | emulator | host
//
// adbd <--> /dev/qemu_pipe <--> AdbGuestPipe <--> AdbHostListener <--> ADB Server
//
// There is a little protocol between adbd and the emulator which looks like:
//
// 1) Guest opens /dev/qemu_pipe and writes 'pipe:qemud:adb:<port>\0' to
// connect to the ADB pipe service, where <port> is a decimal port
// number (5555 by default). The port number is guest-specific and
// should be ignored (it is assumed to be here for obsolete reasons).
//
// -> This ends up calling AdbGuestPipe::Service::create() to create a new
// instance.
//
// 2) Guest writes 'accept' to tell the emulator to start accepting
// connections from the ADB server.
//
// 3) Once a connection from the ADB server is established, the emulator
// should send back 'ok' (or 'ko' / closing the connection to indicate
// an error).
//
// 4) The guest will write 'start' to indicate it is ready to exchange
// data with the host ADB server (all data on the pipe should be
// proxied between the two at this point).
//
// IMPORTANT NOTE: The adbd daemon will typically create a new AdbGuestPipe
// instance just after that, but it will only 'accept'
// one at a time. For more details see qemu_socket_thread()
// in $AOSP/system/core/adb/transport_local.cpp
//
// Usage is the following:
//
// 1) Create a new AdbGuestPipe::Service instance, passing a valid
// AdbHostAgent instance to it (in practice an AdbHostListener one).
// Then call AndroidPipe::Service::add() to register it.
//
// NOTE: This must be done at emulation setup time from the QEMU main loop!
//
class AdbGuestPipe : public AndroidPipe {
public:
using StringView = ::android::base::StringView;
using ScopedSocket = ::android::base::ScopedSocket;
// AndroidPipe::Service class
class Service : public AndroidPipe::Service, public AdbGuestAgent {
public:
Service(AdbHostAgent* hostAgent)
: AndroidPipe::Service("qemud:adb"), mHostAgent(hostAgent) {}
// Create a new AdbGuestPipe instance.
virtual AndroidPipe* create(void* mHwPipe, const char* args) override;
// Can't save their state to disk.
virtual bool canLoad() const override { return false; }
// Overridden AdbGuestAgent method.
virtual void onHostConnection(ScopedSocket&& socket) override;
// Called when a new adb pipe connection is opened by
// the guest. Note that this does *not* transfer ownership of |pipe|.
// Technically, AndroidPipe instances are owned by the virtual device.
// except when onGuestClose() is called (which should destroy it).
void onPipeOpen(AdbGuestPipe* pipe);
// Called when the guest closes a pipe. This must delete the instance.
void onPipeClose(AdbGuestPipe* pipe);
// If there is no active pipe, search for an item in |mPipes| that
// is in the WaitingForHostAdbConnection state, when found record
// it as the active pipe and tell the host agent to start listening
// for host connections.
void searchForActivePipe();
private:
AdbHostAgent* mHostAgent;
AdbGuestPipe* mActivePipe = nullptr;
std::vector<AdbGuestPipe*> mPipes;
};
virtual ~AdbGuestPipe();
// Overridden AndroidPipe methods. Called from the device context.
virtual void onGuestClose() override;
virtual unsigned onGuestPoll() const override;
virtual int onGuestRecv(AndroidPipeBuffer* buffers, int count) override;
virtual int onGuestSend(const AndroidPipeBuffer* buffers,
int count) override;
virtual void onGuestWantWakeOn(int flags) override;
// Called when a host connection occurs. Transfers ownership of
// |socket| to the pipe. On success, return true, on error return
// false and closes the socket.
void onHostConnection(ScopedSocket&& socket);
private:
AdbGuestPipe(void* mHwPipe, Service* service, AdbHostAgent* hostAgent)
: AndroidPipe(mHwPipe, service), mHostAgent(hostAgent) {
setExpectedGuestCommand("accept", State::WaitingForGuestAcceptCommand);
}
// Return current service with the right type.
Service* service() const {
return static_cast<AdbGuestPipe::Service*>(mService);
}
// Each pipe instance can be in one of these states:
enum class State {
WaitingForGuestAcceptCommand,
WaitingForHostAdbConnection,
SendingAcceptReplyOk,
WaitingForGuestStartCommand,
ProxyingData,
ClosedByGuest,
ClosedByHost,
};
// Used for debugging.
static const char* toString(State);
// Called when an i/o event occurs on the host socket.
// |events| is a mask of FdWatch::kEventXXX flags.
void onHostSocketEvent(unsigned events);
// Implement onGuestRecv() and onGuestSend() while proxying the data
// between the guest and the host.
int onGuestRecvData(AndroidPipeBuffer* buffers, int count);
int onGuestSendData(const AndroidPipeBuffer* buffers, int count);
// Implement onGuestRecv() when sending a reply to the guest.
int onGuestRecvReply(AndroidPipeBuffer* buffers, int count);
// Implement onGuestSend() when receiving a command from the guest.
int onGuestSendCommand(const AndroidPipeBuffer* buffers, int count);
// Set the reply to send to the guest as |reply|, and change the state
// to |newState|.
void setReply(StringView reply, State newState);
// Set the expected |command| to wait from the guest, and change the
// state to |newState|.
void setExpectedGuestCommand(StringView command, State newState);
// Try to wait for a new host connection. Change the state according to
// whether one already occured or not.
void waitForHostConnection();
// Command/reply buffer and cursor.
char mBuffer[16]; // the command being accepted or reply being sent.
size_t mBufferSize = 0; // size of valid bytes in mBuffer.
size_t mBufferPos = 0; // number of matched command bytes on input/output.
State mState = State::WaitingForGuestAcceptCommand; // current pipe state.
android::base::ScopedSocketWatch
mHostSocket; // current host socket, if connected.
AdbHostAgent* mHostAgent = nullptr;
};
} // namespace emulation
} // namespace android