blob: 3fbfe51ce35f0798962fd3f81fc15de9d4fc07e7 [file] [log] [blame] [edit]
/*
* ARM Android emulator adb backend
*
* Copyright (c) 2014 Linaro Limited
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* Handle connections to the qemud:adb pipe from Android guests and route
* traffic over this pipe to the host adb server connecting to the qemu
* process on a tcp socket.
*/
#include <glib.h>
#include <stdio.h>
#include <unistd.h>
#include "qemu-common.h"
#include "qemu/config-file.h"
#include "qemu/main-loop.h"
#include "qapi/error.h"
#include "qemu/module.h"
#include "qemu/sockets.h"
#include "hw/misc/android_pipe.h"
//#define DEBUG_ADB
#ifdef DEBUG_ADB
#define DPRINTF(fmt, ...) \
do { fprintf(stderr, "adb: " fmt , ## __VA_ARGS__); } while (0)
#else
#define DPRINTF(fmt, ...) do {} while(0)
#endif
#define PIPE_QUEUE_LEN 16
#define HANDSHAKE_MAXLEN 128
#define ADB_BUFFER_LEN 4096
#define ADB_SERVER_PORT 5037
/* 'accept' request from adbd */
static const char _accept_req[] = "accept";
/* 'start' request from adbd */
static const char _start_req[] = "start";
/* handshake reply to adbd */
static const char _ok_resp[] = "ok";
static const char _ko_resp[] = "ko";
static bool pipe_backend_initialized = false;
enum adb_connect_state {
ADB_CONNECTION_STATE_UNCONNECTED = 0,
ADB_CONNECTION_STATE_ACCEPT,
ADB_CONNECTION_STATE_CONNECTED,
};
typedef struct {
void* hwpipe;
enum adb_connect_state state;
GIOChannel *chan; /* I/O channel to adb server */
unsigned flags;
/* TODO: Make sure access to thes buffers is
* synchronized through the io accessor
* functions in QEMU or some other
* mechanism. */
char out_buffer[ADB_BUFFER_LEN];
char *out_next;
unsigned out_cnt;
} adb_pipe;
/*
* This structure keeps track of the adb-server connection state (that
* is HOST adb-server <-> QEMU connections). We only expect to see one
* active connection at a time as data is multiplexed over the pipe.
*/
typedef struct {
GIOChannel *listen_chan; /* listener/connect socket */
GIOChannel *chan; /* actual comms socket */
/* these cache the read/write state for when wakeon is called */
gboolean data_in; /* have we seen data? */
gboolean data_out; /* can we output data? */
adb_pipe *adb_pipes[PIPE_QUEUE_LEN];
adb_pipe *connected_pipe;
} adb_backend_state;
static adb_backend_state adb_state;
static void adb_reply(adb_pipe *apipe, const char *reply);
/****************************************************************************
* ADB Server Interface
*/
static QemuOpts* adb_server_config(void) {
QemuOpts *socket_opts;
socket_opts = qemu_opts_create(&socket_optslist, NULL, 0,
&error_abort);
if (!qemu_opt_get(socket_opts, "host")) {
qemu_opt_set(socket_opts, "host", "localhost");
}
if (!qemu_opt_get(socket_opts, "port")) {
qemu_opt_set_number(socket_opts, "port", ADB_SERVER_PORT);
}
return socket_opts;
}
static void adb_server_notify(int adb_port) {
Error *local_err = NULL;
QemuOpts *socket_opts = adb_server_config();
int sock = inet_connect_opts(socket_opts, &local_err, NULL, NULL);
size_t len;
gchar *message,*handshake;
if (sock >= 0) {
socket_set_nodelay(sock);
}
/* Failed to establish connection */
if (sock < 0) {
fprintf(stderr,"%s: Failed to establish connection to ADB server\n",
__func__);
return;
}
message = g_strdup_printf("host:emulator:%d", adb_port);
handshake = g_strdup_printf("%04x%s", (int) strlen(message), message);
len = strlen(handshake);
if (send_all(sock, handshake, len) != len) {
fprintf(stderr,"%s: error sending string:%s\n", __func__, handshake);
}
closesocket(sock);
g_free(message);
g_free(handshake);
return;
}
/* TODO: Needs a common implementation with the likes of qemu-char.c */
static GIOChannel *io_channel_from_socket(int fd)
{
GIOChannel *chan;
if (fd == -1) {
return NULL;
}
#ifdef _WIN32
chan = g_io_channel_win32_new_socket(fd);
#else
chan = g_io_channel_unix_new(fd);
#endif
g_io_channel_set_encoding(chan, NULL, NULL);
g_io_channel_set_buffered(chan, FALSE);
return chan;
}
static gboolean tcp_adb_accept(GIOChannel *channel, GIOCondition cond,
void *opaque);
/* Close a connection to the server.
**
** We need to ensure we clean-up any connection state and re-enable
** the watch on the listen socket so new connections can be created.
*/
static void tcp_adb_server_close(adb_backend_state *bs)
{
g_assert(bs->chan);
g_assert(bs->listen_chan);
/* clean-up connected pipes */
if (bs->connected_pipe) {
DPRINTF("%s: closing connected pipe\n", __func__);
android_pipe_close(bs->connected_pipe->hwpipe);
bs->connected_pipe->chan = NULL;
bs->connected_pipe = NULL;
}
/* wait for new connections */
g_io_add_watch(bs->listen_chan, G_IO_IN, tcp_adb_accept, bs);
/* finally close down this socket */
g_io_channel_shutdown(bs->chan, FALSE, NULL);
g_io_channel_unref(bs->chan);
bs->chan = NULL;
}
/*
* This handles state changes on the server socket. We don't directly
* start receiving or sending data here but we do need to ensure that
* the pipe guest wakes up so it can start reading data.
*
* This is a one-shot wake up - the watch needs re-adding whenever
* things go quite so we'll wake up again when needed.
*/
static gboolean tcp_adb_server_data(GIOChannel *channel, GIOCondition cond,
void *opaque)
{
adb_backend_state *bs = (adb_backend_state *) opaque;
if (cond & G_IO_IN) {
bs->data_in = TRUE;
if (bs->connected_pipe && bs->connected_pipe->flags & PIPE_WAKE_READ) {
DPRINTF("%s: waking up pipe for incomming data\n", __func__);
android_pipe_wake(bs->connected_pipe->hwpipe, PIPE_WAKE_READ);
}
}
if (cond & G_IO_OUT) {
bs->data_out = TRUE;
if (bs->connected_pipe && bs->connected_pipe->flags & PIPE_WAKE_WRITE) {
DPRINTF("%s: waking up pipe for now able to write\n", __func__);
android_pipe_wake(bs->connected_pipe->hwpipe, PIPE_WAKE_WRITE);
}
}
if ((cond & G_IO_ERR) ||
(cond & G_IO_HUP)) {
DPRINTF("%s: error %d - closing server connectio\n", __func__, cond);
tcp_adb_server_close(bs);
}
/* Done, we must re-add watch next time we are waiting for data */
return FALSE;
}
static gboolean tcp_adb_connect(adb_backend_state *bs, int fd)
{
if (bs->chan) {
DPRINTF("%s: existing connection %p, fail connect!\n",
__func__, bs->chan);
return FALSE;
} else {
DPRINTF("%s: in-coming connection on %d\n", __func__, fd);
qemu_set_nonblock(fd);
bs->chan = io_channel_from_socket(fd);
g_io_add_watch(bs->chan, G_IO_IN|G_IO_ERR|G_IO_HUP, tcp_adb_server_data, bs);
/* If we don't have a pipe to use for the tcp backend, then find one in
* the accept state. Note, this can happen, for example, if the previous
* connected pipe was closed for some reason. Also note that this becomes
* sort of random which pipe we select, but there doesn't seem to be any
* clearly defined semantics about the ordering here. A proper fifo may
* be a better data structure for this.
*/
if (!bs->connected_pipe) {
int i;
for (i = 0; i < PIPE_QUEUE_LEN; i++) {
if (bs->adb_pipes[i] &&
bs->adb_pipes[i]->state == ADB_CONNECTION_STATE_ACCEPT) {
bs->connected_pipe = bs->adb_pipes[i];
}
}
}
/* Tell the adbd that the adb server has conected and that we're ready to
* receive the start package */
if (bs->connected_pipe) {
DPRINTF("Incoming TCP connection on already accepted pipe, connect\n");
adb_pipe *apipe = bs->connected_pipe;
apipe->chan = bs->chan;
if (apipe->out_next) {
fprintf(stderr, "Pending reply on non-connected pipe, error\n");
abort();
}
adb_reply(apipe, _ok_resp);
}
return TRUE;
}
}
/* Accept incoming connections. If the connect succeeds and we create
* a connection we return FALSE to take the listen socket out of the
* polling loop. We need to re-add the watch if/when the connection
* dies so another connection can be created.
*/
static gboolean tcp_adb_accept(GIOChannel *channel, GIOCondition cond,
void *opaque)
{
adb_backend_state *bs = opaque;
struct sockaddr_in saddr;
struct sockaddr *addr;
socklen_t len;
int fd;
for(;;) {
len = sizeof(saddr);
addr = (struct sockaddr *)&saddr;
fd = qemu_accept(g_io_channel_unix_get_fd(bs->listen_chan), addr, &len);
if (fd < 0 && errno != EINTR) {
DPRINTF("%s: failed to accept %d/%d\n", __func__, fd, errno);
return FALSE;
} else if (fd >= 0) {
break;
}
}
if (tcp_adb_connect(bs, fd)) {
return FALSE;
} else {
return TRUE;
}
}
static bool adb_server_listen_incoming(int port)
{
adb_backend_state *bs = &adb_state;
char *host_port;
Error *err = NULL;
int fd;
host_port = g_strdup_printf("127.0.0.1:%d", port);
fd = inet_listen(host_port, NULL, 0, SOCK_STREAM, 0, &err);
if (fd < 0) {
return false;
}
bs->listen_chan = io_channel_from_socket(fd);
g_io_add_watch(bs->listen_chan, G_IO_IN, tcp_adb_accept, bs);
return true;
}
/****************************************************************************
* Android Pipe adbd Interface
*/
static void* adb_pipe_init(void *hwpipe,void *opaque, const char *args)
{
adb_pipe *apipe;
int i;
DPRINTF("%s: hwpipe=%p\n", __FUNCTION__, hwpipe);
apipe = g_malloc0(sizeof(adb_pipe));
apipe->hwpipe = hwpipe;
apipe->state = ADB_CONNECTION_STATE_UNCONNECTED;
apipe->out_next = NULL;
apipe->out_cnt = 0;
apipe->flags = 0;
for (i = 0; i < PIPE_QUEUE_LEN; i++) {
if (adb_state.adb_pipes[i] == NULL) {
adb_state.adb_pipes[i] = apipe;
break;
}
}
if (i == PIPE_QUEUE_LEN) {
DPRINTF("Could not handle more open adb pipes\n");
g_free(apipe);
return NULL;
}
return apipe;
}
static void adb_pipe_close(void *opaque )
{
adb_pipe *apipe = opaque;
int i;
DPRINTF("%s: hwpipe=%p\n", __FUNCTION__, apipe->hwpipe);
if (adb_state.connected_pipe == apipe) {
tcp_adb_server_close(&adb_state);
adb_state.connected_pipe = NULL;
}
for (i = 0; i < PIPE_QUEUE_LEN; i++) {
if (adb_state.adb_pipes[i] == apipe) {
adb_state.adb_pipes[i] = NULL;
break;
}
}
g_free(apipe);
}
static int pipe_send_data(adb_pipe *apipe, char *data, unsigned len,
const AndroidPipeBuffer *buffers, int cnt)
{
int avail = len;
int chunk;
while (cnt > 0 && avail > 0) {
if (avail < buffers[0].size) {
chunk = avail;
} else {
chunk = buffers[0].size;
}
memcpy(data, buffers[0].data, chunk);
data += chunk;
avail -= chunk;
buffers++;
cnt--;
}
return len - avail;
}
static bool match_request(const char *request, int len, const char *match)
{
return len == strlen(match) && !strncmp(request, match, strlen(match));
}
static const char *handle_request(adb_pipe *apipe, const char *request, int len)
{
adb_backend_state *bs = &adb_state;
if (match_request(request, len, _accept_req)) {
if (apipe->state != ADB_CONNECTION_STATE_UNCONNECTED) {
return _ko_resp;
}
apipe->state = ADB_CONNECTION_STATE_ACCEPT;
/* If we don't have any connected adb_pipe to the tcp backend yet,
* elect ourselves. If the tcp connection is ready as well, go ahead
* and thell adbd to carry on.
*/
if (!bs->connected_pipe) {
bs->connected_pipe = apipe;
if (bs->chan) {
g_assert(!bs->connected_pipe->chan);
bs->connected_pipe->chan = bs->chan;
DPRINTF("Already have tcp connection, reply 'ok' to 'accept'\n");
return _ok_resp;
}
}
DPRINTF("no tcp connection, wait for it\n");
return NULL; /* wait until adb server connects */
} else if (match_request(request, len, _start_req)) {
if (apipe->state != ADB_CONNECTION_STATE_ACCEPT) {
DPRINTF("adbd requested 'start' when we are not ready, error\n");
android_pipe_close(apipe->hwpipe);
return NULL;
}
if (!bs->chan) {
DPRINTF("adbd requested 'start' but tcp connection not yet connected, error\n");
bs->connected_pipe->chan = NULL;
android_pipe_close(apipe->hwpipe);
return NULL;
}
apipe->state = ADB_CONNECTION_STATE_CONNECTED;
return NULL; /* start proxying data */
} else {
/* unrecognized command */
return _ko_resp;
}
}
static void adb_reply(adb_pipe *apipe, const char *reply)
{
strcpy(apipe->out_buffer, reply);
apipe->out_cnt = strlen(reply);
apipe->out_next = &apipe->out_buffer[0];
}
static int adb_pipe_proxy_send(adb_pipe *apipe, const AndroidPipeBuffer *buffers,
int cnt)
{
gsize total_copied = 0;
adb_backend_state *bs = &adb_state;
g_assert(apipe->chan);
DPRINTF("%s: %p/%d\n", __func__, buffers, cnt);
do {
GError *error = NULL;
gchar *bptr = (gchar *) buffers[0].data;
gsize bsize = buffers[0].size;
gsize copied = 0;
GIOStatus status = g_io_channel_write_chars(
apipe->chan, bptr, bsize, &copied, &error);
total_copied += copied;
/* If we have already copied some data lets signal that and
* let it come back to here.
*/
if (total_copied > 0 &&
((status == G_IO_STATUS_EOF || status == G_IO_STATUS_AGAIN))) {
bs->data_out = FALSE;
return total_copied;
}
/* Can't write and more data.... */
if (status == G_IO_STATUS_AGAIN) {
DPRINTF("%s: out of data, setting up watch\n", __func__);
g_io_add_watch(apipe->chan, G_IO_IN|G_IO_ERR|G_IO_HUP,
tcp_adb_server_data, bs);
bs->data_out = FALSE;
return PIPE_ERROR_AGAIN;
}
if (status == G_IO_STATUS_EOF) {
bs->data_out = FALSE;
tcp_adb_server_close(bs);
return 0;
}
if (status != G_IO_STATUS_NORMAL) {
DPRINTF("%s: went wrong (%d)\n", __func__, status);
bs->data_out = FALSE;
tcp_adb_server_close(bs);
return PIPE_ERROR_IO;
}
if (copied < bsize) {
g_assert(total_copied > 0);
bs->data_out = FALSE;
break;
}
buffers++;
} while (--cnt);
return total_copied;
}
static int adb_pipe_send(void *opaque, const AndroidPipeBuffer* buffers,
int cnt)
{
adb_pipe *apipe = opaque;
int ret = 0;
char request[HANDSHAKE_MAXLEN + 1];
const char *reply;
if (apipe->state != ADB_CONNECTION_STATE_CONNECTED) {
if (apipe->out_next) {
/* Existing reply in progress, not ready */
DPRINTF("%s: unconnected pipe, reply in progress\n", __func__);
return PIPE_ERROR_AGAIN;
}
ret = pipe_send_data(apipe, request, sizeof(request), buffers, cnt);
reply = handle_request(apipe, request, ret);
if (reply) {
adb_reply(apipe, reply);
android_pipe_wake(adb_state.connected_pipe->hwpipe, PIPE_WAKE_READ);
}
} else {
ret = adb_pipe_proxy_send(apipe, buffers, cnt);
if (ret == 0) {
return PIPE_ERROR_AGAIN;
}
}
return ret;
}
static int pipe_recv_data(adb_pipe *apipe, const char *data, unsigned len,
AndroidPipeBuffer *buffers, int cnt)
{
int remain = len;
int chunk;
while (remain > 0 && cnt > 0) {
if (remain > buffers[0].size) {
chunk = buffers[0].size;
} else {
chunk = remain;
}
memcpy(buffers[0].data, data, chunk);
data += chunk;
remain -= chunk;
buffers++;
cnt--;
}
return len - remain;
}
static int adb_pipe_proxy_recv(adb_pipe *apipe, AndroidPipeBuffer *buffers,
int cnt)
{
gsize total_copied = 0;
adb_backend_state *bs = &adb_state;
g_assert(apipe->chan);
g_assert(bs->chan == apipe->chan);
DPRINTF("%s: hwpipe=%p (buffers %p/%d)\n", __func__, apipe->hwpipe, buffers, cnt);
do {
GError *error = NULL;
gchar *bptr = (gchar *) buffers[0].data;
gsize bsize = buffers[0].size;
gsize copied = 0;
GIOStatus status = g_io_channel_read_chars(
apipe->chan, bptr, bsize, &copied, &error);
DPRINTF("%s: read %zd bytes into %p[%zd] -> %d\n", __func__,
copied, bptr, bsize, status);
total_copied += copied;
/* If we have already copied some data lets signal that and
* let it come back to here */
if (total_copied > 0 &&
((status == G_IO_STATUS_EOF || status == G_IO_STATUS_AGAIN))) {
bs->data_in = FALSE;
return total_copied;
}
/* no data to read.... */
if (status == G_IO_STATUS_AGAIN) {
DPRINTF("%s: out of data, setting up watch\n", __func__);
g_io_add_watch(apipe->chan, G_IO_IN|G_IO_ERR|G_IO_HUP,
tcp_adb_server_data, bs);
bs->data_in = FALSE;
return PIPE_ERROR_AGAIN;
}
if (status == G_IO_STATUS_EOF) {
bs->data_in = FALSE;
tcp_adb_server_close(bs);
return 0;
}
if (status != G_IO_STATUS_NORMAL) {
DPRINTF("%s: went wrong (%d)\n", __func__, status);
bs->data_in = FALSE;
tcp_adb_server_close(bs);
return PIPE_ERROR_IO;
}
if (copied < bsize) {
g_assert(total_copied > 0);
bs->data_in = FALSE;
break;
}
buffers++;
cnt--;
} while (cnt);
return total_copied;
}
static int adb_pipe_recv(void *opaque, AndroidPipeBuffer *buffers,
int cnt)
{
adb_pipe *apipe = opaque;
adb_backend_state *bs = &adb_state;
int ret = 0;
if (apipe->state == ADB_CONNECTION_STATE_CONNECTED) {
if (bs->data_in) {
ret = adb_pipe_proxy_recv(apipe, buffers, cnt);
return ret;
} else {
return PIPE_ERROR_AGAIN;
}
}
assert(cnt > 0);
if (!apipe->out_next) {
return PIPE_ERROR_AGAIN;
}
assert((apipe->out_next - apipe->out_buffer)
+ apipe->out_cnt < ADB_BUFFER_LEN);
ret = pipe_recv_data(apipe, apipe->out_next, apipe->out_cnt, buffers, cnt);
apipe->out_cnt -= ret;
if (ret == apipe->out_cnt) {
apipe->out_next = NULL;
} else {
apipe->out_next += ret;
}
return ret;
}
static unsigned adb_pipe_poll(void *opaque)
{
adb_pipe *apipe = opaque;
adb_backend_state *bs = &adb_state;
unsigned flags = 0;
if (apipe->state != ADB_CONNECTION_STATE_CONNECTED) {
if (apipe->out_next) {
flags |= PIPE_POLL_IN;
} else {
flags |= PIPE_POLL_OUT;
}
} else {
if (bs->data_in) {
flags |= PIPE_POLL_IN;
}
/* We can always forward data to the socket as far as we know */
flags |= PIPE_POLL_OUT;
}
return flags;
}
static void adb_pipe_wake_on(void *opaque, int flags)
{
adb_pipe *apipe = opaque;
DPRINTF("%s: setting flags 0x%x->0x%x\n", __func__, apipe->flags, flags);
apipe->flags |= flags;
if (flags & PIPE_WAKE_READ && adb_state.data_in) {
android_pipe_wake(apipe->hwpipe, PIPE_WAKE_READ);
}
if (flags & PIPE_WAKE_WRITE && adb_state.data_out) {
android_pipe_wake(apipe->hwpipe, PIPE_WAKE_WRITE);
}
}
static const AndroidPipeFuncs adb_pipe_funcs = {
adb_pipe_init,
adb_pipe_close,
adb_pipe_send,
adb_pipe_recv,
adb_pipe_poll,
adb_pipe_wake_on,
};
/* Initialize and try to listen on the specified port;
* return true on success or false if the port was in use.
* Note that there's no way to undo this, so the board must
* set up the console port first and the adb port second.
*/
bool adb_server_init(int port)
{
if (!pipe_backend_initialized) {
adb_state.chan = NULL;
adb_state.listen_chan = NULL;
adb_state.data_in = FALSE;
adb_state.connected_pipe = NULL;
android_pipe_add_type("qemud:adb", NULL, &adb_pipe_funcs);
pipe_backend_initialized = true;
}
if (!adb_server_listen_incoming(port)) {
return false;
}
adb_server_notify(port);
return true;
}