system: add Android Debug Bridge daemon

This commit is contained in:
Simon Piriou 2020-10-26 17:18:48 +01:00 committed by Alan Carvalho de Assis
parent efd81744d1
commit c1c488e835
9 changed files with 1224 additions and 0 deletions

158
system/adb/Kconfig Normal file
View File

@ -0,0 +1,158 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
menuconfig SYSTEM_ADBD
tristate "ADB daemon application"
default n
---help---
Enable support for adb daemon.
if SYSTEM_ADBD
config ADBD_PROGNAME
string "Program name"
default "adbd"
---help---
This is the name of the program that will be used.
config ADBD_STACKSIZE
int "Stack size"
default DEFAULT_TASK_STACKSIZE
---help---
The size of stack allocated for the adb daemon task.
config ADBD_PRIORITY
int "Task priority"
default 100
---help---
The priority of the adb daemon task.
config ADBD_AUTHENTICATION
bool "Authentication support"
default n
---help---
Enable authentication for adb daemon.
if ADBD_AUTHENTICATION
config ADBD_AUTH_PUBKEY
bool "Public key authentication"
default n
---help---
Enable hook to accept new public keys.
config ADBD_TOKEN_SIZE
int "Authentication token size"
default 20
endif # ADBD_AUTHENTICATION
if ! BOARDCTL_UNIQUEID
config ADBD_DEVICE_ID
string "Default adb device id"
default ""
endif # BOARDCTL_UNIQUEID
config ADBD_PRODUCT_NAME
string "Default adb product name"
default "adb dev"
config ADBD_PRODUCT_MODEL
string "Default adb product model"
default "adb board"
config ADBD_PRODUCT_DEVICE
string "Default adb product device"
default "NuttX device"
config ADBD_FEATURES
string "Default adb server features list"
default "cmd"
config ADBD_PAYLOAD_SIZE
int "Normal ADB frame size"
default 64
---help---
Normal frame size in bytes.
config ADBD_CNXN_PAYLOAD_SIZE
int "Connection frame size"
default 1024
---help---
Connection frame is bigger than others.
Can be between 128 to 256 bytes in most of the cases.
If authentication is enabled, frame size must bigger
to receive public key from host (around 1024 bytes).
config ADBD_FRAME_MAX
int "Frame pool size"
default 1
---help---
ADB frame pool size.
config ADBD_TCP_SERVER
bool "Network socket transport support"
depends on NET_TCP
default n
---help---
Run adb daemon on network socket.
config ADBD_TCP_SERVER_PORT
int "Network socket transport port"
depends on ADBD_TCP_SERVER
default 5555
---help---
Port used by adb daemon socket server
config ADBD_USB_SERVER
bool "USB transport support"
depends on USBADB
default n
---help---
Run adb daemon on USB bus
config ADBD_LOGCAT_SERVICE
bool "ADB logcat support"
depends on RAMLOG_SYSLOG
default n
---help---
Enable "adb logcat" feature.
config ADBD_FILE_SERVICE
bool "ADB file sync support"
default n
---help---
Enable "adb ls/push/pull" feature.
config ADBD_SHELL_SERVICE
bool "ADB shell support"
depends on NSH_CONSOLE
default n
---help---
Enable "adb shell" feature.
config ADBD_FILE_SYMLINK
bool "File service symlink support"
default n
depends on PSEUDOFS_SOFTLINKS
---help---
Enable fs symlink support.
config ADBD_BOARD_INIT
bool "Board initialization"
depends on LIB_BOARDCTL
default n
---help---
Setup board before running adb daemon.
config ADBD_NET_INIT
bool "Network initialization"
default n
depends on NET
select NETUTILS_NETINIT
---help---
This option enables/disables all network initialization in ADB server.
endif # SYSTEM_ADBD

23
system/adb/Make.defs Normal file
View File

@ -0,0 +1,23 @@
############################################################################
# system/adb/Make.defs
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
ifneq ($(CONFIG_SYSTEM_ADBD),)
CONFIGURED_APPS += $(APPDIR)/system/adb
endif

92
system/adb/Makefile Normal file
View File

@ -0,0 +1,92 @@
############################################################################
# system/adb/Makefile
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
include $(APPDIR)/Make.defs
ADB_DIR := $(APPDIR)/system/adb
CONFIG_ADBD_URL ?= "https://github.com/spiriou/microADB.git"
CONFIG_ADBD_VERSION ?= bbd1e74bd795aa2fc53eae2b76bff993d6ccaa37
ADB_UNPACKNAME := microADB
ADB_UNPACKDIR := $(ADB_DIR)/$(ADB_UNPACKNAME)
$(ADB_UNPACKDIR):
@echo "Downloading: $(ADB_UNPACKNAME)"
$(call DELDIR, "$@")
$(Q) mkdir "$@"
$(Q) cd "$@" && git init && \
git remote add origin "$(CONFIG_ADBD_URL)" && \
git fetch origin $(CONFIG_ADBD_VERSION) --depth=1 && \
git reset --hard FETCH_HEAD
# adb server app
PROGNAME := $(CONFIG_ADBD_PROGNAME)
PRIORITY := $(CONFIG_ADBD_PRIORITY)
STACKSIZE := $(CONFIG_ADBD_STACKSIZE)
MODULE := $(CONFIG_ADB_SERVER)
# Files
MAINSRC := adb_main.c
CSRCS += adb_banner.c
CSRCS += $(ADB_UNPACKNAME)/adb_client.c
CSRCS += $(ADB_UNPACKNAME)/adb_frame.c
CSRCS += $(ADB_UNPACKNAME)/hal/hal_uv.c
CSRCS += $(ADB_UNPACKNAME)/hal/hal_uv_packet.c
CFLAGS += -D__NUTTX__=1
CFLAGS += -I$(ADB_UNPACKNAME)
ifeq ($(CONFIG_ADBD_TCP_SERVER),y)
CSRCS += $(ADB_UNPACKNAME)/hal/hal_uv_client_tcp.c
endif
ifeq ($(CONFIG_ADBD_USB_SERVER),y)
CSRCS += $(ADB_UNPACKNAME)/hal/hal_uv_client_usb.c
endif
ifeq ($(CONFIG_ADBD_AUTHENTICATION),y)
CSRCS += $(ADB_UNPACKNAME)/adb_auth_key.c
endif
ifeq ($(CONFIG_ADBD_FILE_SERVICE),y)
CSRCS += $(ADB_UNPACKNAME)/file_sync_service.c
endif
ifeq ($(CONFIG_ADBD_LOGCAT_SERVICE),y)
CSRCS += logcat_service.c
endif
ifeq ($(CONFIG_ADBD_SHELL_SERVICE),y)
CSRCS += shell_service.c
CSRCS += shell_pipe.c
endif
context:: $(ADB_UNPACKDIR)
clean::
$(call DELFILE, $(OBJS))
distclean::
$(call DELDIR, $(ADB_UNPACKDIR))
include $(APPDIR)/Application.mk

117
system/adb/adb_banner.c Normal file
View File

@ -0,0 +1,117 @@
/****************************************************************************
* system/adb/adb_main.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "adb.h"
#ifdef CONFIG_BOARDCTL_UNIQUEID
#include <sys/boardctl.h>
#include <string.h>
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
int adb_fill_connect_data(char *buf, size_t bufsize)
{
size_t len;
size_t remaining = bufsize;
#ifdef CONFIG_BOARDCTL_UNIQUEID
/* Get board id */
int ret;
uint8_t board_id[CONFIG_BOARDCTL_UNIQUEID_SIZE];
memset(board_id, 0, CONFIG_BOARDCTL_UNIQUEID_SIZE);
ret = boardctl(BOARDIOC_UNIQUEID, (uintptr_t)board_id);
if (ret)
{
/* Failed to get board id */
adb_log("failed to get board id\n");
len = snprintf(buf, remaining, "device::");
}
else
{
/* FIXME only keep first 4 bytes */
len = snprintf(buf, remaining, "device:%x:", *(uint32_t *)board_id);
}
#else
len = snprintf(buf, remaining, "device:" CONFIG_ADBD_DEVICE_ID ":");
#endif
if (len >= remaining)
{
return -1;
}
#ifdef CONFIG_ADBD_PRODUCT_NAME
remaining -= len;
buf += len;
len = snprintf(buf, remaining,
"ro.product.name=" CONFIG_ADBD_PRODUCT_NAME ";");
if (len >= remaining)
{
return bufsize;
}
#endif
#ifdef CONFIG_ADBD_PRODUCT_MODEL
remaining -= len;
buf += len;
len = snprintf(buf, remaining,
"ro.product.model=" CONFIG_ADBD_PRODUCT_MODEL ";");
if (len >= remaining)
{
return bufsize;
}
#endif
#ifdef CONFIG_ADBD_PRODUCT_DEVICE
remaining -= len;
buf += len;
len = snprintf(buf, remaining,
"ro.product.device=" CONFIG_ADBD_PRODUCT_DEVICE ";");
if (len >= remaining)
{
return bufsize;
}
#endif
remaining -= len;
buf += len;
len = snprintf(buf, remaining, "features=" CONFIG_ADBD_FEATURES);
if (len >= remaining)
{
return bufsize;
}
return bufsize - remaining + len;
}

119
system/adb/adb_main.c Normal file
View File

@ -0,0 +1,119 @@
/****************************************************************************
* system/adb/adb_main.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "adb.h"
#ifdef CONFIG_ADBD_BOARD_INIT
#include <sys/boardctl.h>
#endif
#ifdef CONFIG_ADBD_NET_INIT
#include "netutils/netinit.h"
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
void adb_log_impl(FAR const char *func, int line, FAR const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "%s (%d): ", func, line);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
int main(int argc, FAR char **argv)
{
UNUSED(argc);
UNUSED(argv);
adb_context_t *ctx;
#ifdef CONFIG_ADBD_BOARD_INIT
{
boardctl(BOARDIOC_INIT, 0);
#if defined(CONFIG_ADBD_USB_SERVER) && \
defined(CONFIG_USBDEV_COMPOSITE) && \
defined (CONFIG_BOARDCTL_USBDEVCTRL)
/* Setup composite USB device */
struct boardioc_usbdev_ctrl_s ctrl;
int ret;
FAR void *handle;
/* Perform architecture-specific initialization */
ctrl.usbdev = BOARDIOC_USBDEV_COMPOSITE;
ctrl.action = BOARDIOC_USBDEV_INITIALIZE;
ctrl.instance = 0;
ctrl.config = 0;
ctrl.handle = NULL;
ret = boardctl(BOARDIOC_USBDEV_CONTROL, (uintptr_t)&ctrl);
if (ret < 0)
{
printf("boardctl(BOARDIOC_USBDEV_CONTROL) failed: %d\n", ret);
return 1;
}
/* Initialize the USB composite device device */
ctrl.usbdev = BOARDIOC_USBDEV_COMPOSITE;
ctrl.action = BOARDIOC_USBDEV_CONNECT;
ctrl.instance = 0;
ctrl.config = 0;
ctrl.handle = &handle;
ret = boardctl(BOARDIOC_USBDEV_CONTROL, (uintptr_t)&ctrl);
if (ret < 0)
{
printf("boardctl(BOARDIOC_USBDEV_CONTROL) failed: %d\n", ret);
return 1;
}
#endif /* ADBD_USB_SERVER && USBDEV_COMPOSITE && BOARDCTL_USBDEVCTRL */
}
#endif /* CONFIG_ADBD_BOARD_INIT */
#ifdef CONFIG_ADBD_NET_INIT
/* Bring up the network */
netinit_bringup();
#endif
ctx = adb_hal_create_context();
if (!ctx)
{
return -1;
}
adb_hal_run(ctx);
adb_hal_destroy_context(ctx);
return 0;
}

213
system/adb/logcat_service.c Normal file
View File

@ -0,0 +1,213 @@
/****************************************************************************
* system/adb/logcat_service_uv.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <errno.h>
#include <stdlib.h>
#include <nuttx/syslog/ramlog.h>
#include <unistd.h>
#include "adb.h"
#include "logcat_service.h"
#include "hal/hal_uv_priv.h"
/****************************************************************************
* Private types
****************************************************************************/
typedef struct alog_service_s
{
adb_service_t service;
uv_poll_t poll;
int wait_ack;
} alog_service_t;
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static void logcat_on_data_available(uv_poll_t * handle,
int status, int events);
/****************************************************************************
* Private Functions
****************************************************************************/
static int alog_on_write(adb_service_t *service, apacket *p)
{
UNUSED(p);
UNUSED(service);
return -1;
}
static void alog_on_kick(struct adb_service_s *service)
{
alog_service_t *svc = container_of(service, alog_service_t, service);
if (!svc->wait_ack)
{
int ret;
ret = uv_poll_start(&svc->poll, UV_READABLE, logcat_on_data_available);
assert(ret == 0);
}
}
static int alog_on_ack(adb_service_t *service, apacket *p)
{
UNUSED(p);
alog_service_t *svc = container_of(service, alog_service_t, service);
svc->wait_ack = 0;
alog_on_kick(service);
return 0;
}
static void close_cb(uv_handle_t *handle)
{
alog_service_t *service = container_of(handle, alog_service_t, poll);
free(service);
}
static void alog_close(struct adb_service_s *service)
{
int fd;
int ret;
alog_service_t *svc = container_of(service, alog_service_t, service);
ret = uv_fileno((uv_handle_t *)&svc->poll, &fd);
assert(ret == 0);
close(fd);
uv_close((uv_handle_t *)&svc->poll, close_cb);
}
static const adb_service_ops_t logcat_ops =
{
.on_write_frame = alog_on_write,
.on_ack_frame = alog_on_ack,
.on_kick = alog_on_kick,
.close = alog_close
};
static void logcat_on_data_available(uv_poll_t * handle,
int status, int events)
{
int ret;
int fd;
apacket_uv_t *ap;
alog_service_t *service = container_of(handle, alog_service_t, poll);
adb_client_uv_t *client = (adb_client_uv_t *)handle->data;
ap = adb_uv_packet_allocate(client, 0);
if (ap == NULL)
{
uv_poll_stop(handle);
return;
}
if (status)
{
adb_log("status error %d\n", status);
/* Fatal error, stop service */
goto exit_stop_service;
}
assert(uv_fileno((uv_handle_t *)handle, &fd) == 0);
ret = read(fd, ap->p.data, CONFIG_ADBD_PAYLOAD_SIZE);
if (ret < 0)
{
adb_log("frame read failed %d %d\n", ret, errno);
if (errno == EAGAIN)
{
/* TODO this should never happen */
goto exit_release_packet;
}
/* Fatal error, stop service */
goto exit_stop_service;
}
if (ret == 0)
{
goto exit_release_packet;
}
service->wait_ack = 1;
uv_poll_stop(handle);
ap->p.write_len = ret;
ap->p.msg.arg0 = service->service.id;
ap->p.msg.arg1 = service->service.peer_id;
adb_send_data_frame(&client->client, &ap->p);
return;
exit_release_packet:
adb_hal_apacket_release(&client->client, &ap->p);
return;
exit_stop_service:
adb_service_close(&client->client, &service->service, &ap->p);
}
/****************************************************************************
* Public Functions
****************************************************************************/
adb_service_t * logcat_service(adb_client_t *client, const char *params)
{
int ret;
alog_service_t *service =
(alog_service_t *)malloc(sizeof(alog_service_t));
if (service == NULL)
{
return NULL;
}
service->service.ops = &logcat_ops;
service->wait_ack = 0;
/* TODO parse params string to extract logcat parameters */
ret = open(CONFIG_SYSLOG_DEVPATH, O_RDONLY | O_CLOEXEC);
if (ret < 0)
{
adb_log("failed to open %s (%d)\n", CONFIG_SYSLOG_DEVPATH, errno);
free(service);
return NULL;
}
uv_handle_t *handle = adb_uv_get_client_handle(client);
ret = uv_poll_init(handle->loop, &service->poll, ret);
assert(ret == 0);
service->poll.data = client;
alog_on_kick(&service->service);
return &service->service;
}

237
system/adb/shell_pipe.c Normal file
View File

@ -0,0 +1,237 @@
/****************************************************************************
* system/adb/shell_pipe.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <uv.h>
#include <unistd.h>
#include "adb.h"
#include "shell_pipe.h"
#include "hal/hal_uv_priv.h"
#include <nshlib/nshlib.h>
/****************************************************************************
* Private Functions
****************************************************************************/
static void shell_on_data_available(uv_poll_t * handle,
int status, int events)
{
int ret;
apacket_uv_t *ap;
shell_pipe_t *pipe = container_of(handle, shell_pipe_t, handle);
adb_client_t *client = (adb_client_t *)pipe->handle.data;
if (status)
{
adb_log("status error %d\n", status);
/* FIXME missing logic here */
pipe->on_data_cb(pipe, NULL);
return;
}
ap = adb_uv_packet_allocate((adb_client_uv_t *)client, 0);
if (ap == NULL)
{
/* frame allocation failed. Try again later */
uv_poll_stop(&pipe->handle);
return;
}
int nread = 0;
do
{
ret = read(handle->io_watcher.fd, &ap->p.data[nread], 1);
if (ret == 0)
{
/* EOF */
break;
}
if (ret < 0)
{
/* Revisit. EAGAIN should not happen but it happens a lot */
if (errno == EAGAIN)
{
if (nread <= 0)
{
adb_hal_apacket_release(
(adb_client_t *)pipe->handle.data, &ap->p);
return;
}
break;
}
/* Release packet and forward error */
adb_hal_apacket_release((adb_client_t *)pipe->handle.data, &ap->p);
pipe->on_data_cb(pipe, NULL);
return;
}
/* FIXME CR LF conversion */
if (ap->p.data[nread++] == '\n')
{
ap->p.data[nread++] = '\r';
}
}
while (nread < CONFIG_ADBD_PAYLOAD_SIZE - 1);
ap->p.msg.data_length = nread;
pipe->on_data_cb(pipe, &ap->p);
}
static void shell_pipe_close_callback(uv_handle_t *handle)
{
shell_pipe_t *pipe = container_of(handle, shell_pipe_t, handle);
/* Notify caller pipe is closed */
pipe->close_cb(pipe);
}
/****************************************************************************
* Public Functions
****************************************************************************/
int shell_pipe_setup(adb_client_t *client, shell_pipe_t *apipe)
{
apipe->handle.data = client;
return 0;
}
void shell_pipe_destroy(shell_pipe_t *pipe, void (*close_cb)(shell_pipe_t *))
{
pipe->close_cb = close_cb;
close(pipe->write_fd);
uv_close((uv_handle_t *)&pipe->handle, shell_pipe_close_callback);
}
int shell_pipe_write(shell_pipe_t *pipe, const void *buf, size_t count)
{
/* TODO revisit */
return write(pipe->write_fd, buf, count);
}
int shell_pipe_start(shell_pipe_t *pipe,
void (*on_data_cb)(shell_pipe_t *, apacket *))
{
pipe->on_data_cb = on_data_cb;
return uv_poll_start(&pipe->handle, UV_READABLE, shell_on_data_available);
}
int shell_pipe_exec(char * const argv[], shell_pipe_t *apipe,
void (*on_data_cb)(shell_pipe_t *, apacket *))
{
int ret;
int in_fds[2];
int out_fds[2];
adb_client_uv_t *client = (adb_client_uv_t *)apipe->handle.data;
/* Create pipe for stdin */
ret = pipe(in_fds);
assert(ret == 0);
ret = pipe(out_fds);
assert(ret == 0);
/* TODO check return code */
apipe->write_fd = in_fds[1];
/* Setup stdout (read: adb, write: child) */
ret = dup2(out_fds[1], 1);
assert(ret == 0);
ret = close(out_fds[1]);
assert(ret == 0);
ret = fcntl(out_fds[0], F_GETFD);
assert(ret >= 0);
ret = fcntl(out_fds[0], F_SETFD, ret | FD_CLOEXEC);
assert(ret == 0);
ret = fcntl(out_fds[0], F_GETFL);
assert(ret >= 0);
ret = fcntl(out_fds[0], F_SETFL, ret | O_NONBLOCK);
assert(ret >= 0);
/* Setup stdin */
ret = dup2(in_fds[0], 0);
assert(ret == 0);
ret = close(in_fds[0]);
assert(ret == 0);
ret = fcntl(in_fds[1], F_GETFD);
assert(ret >= 0);
ret = fcntl(in_fds[1], F_SETFD, ret | FD_CLOEXEC);
assert(ret == 0);
ret = fcntl(in_fds[1], F_GETFL);
assert(ret >= 0);
ret = fcntl(in_fds[1], F_SETFL, ret | O_NONBLOCK);
assert(ret == 0);
ret = uv_poll_init(
adb_uv_get_client_handle(client)->loop,
&apipe->handle, out_fds[0]);
/* TODO check return code */
assert(ret == 0);
/* Create shell process */
ret = task_create("ADB shell", CONFIG_SYSTEM_NSH_PRIORITY,
CONFIG_SYSTEM_NSH_STACKSIZE, nsh_consolemain,
argv);
/* Close stdin and stdout */
dup2(2, 0);
dup2(2, 1);
/* TODO check return code */
assert(ret >= 0);
/* Start listening shell process stdout */
ret = shell_pipe_start(apipe, on_data_cb);
/* TODO check return code */
assert(ret == 0);
return 0;
}

56
system/adb/shell_pipe.h Normal file
View File

@ -0,0 +1,56 @@
/****************************************************************************
* system/adb/shell_pipe.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <uv.h>
#include "adb.h"
/****************************************************************************
* Private types
****************************************************************************/
struct shell_pipe_s
{
uv_poll_t handle;
int write_fd;
void (*close_cb)(struct shell_pipe_s *);
void (*on_data_cb)(struct shell_pipe_s *, struct apacket_s *);
};
typedef struct shell_pipe_s shell_pipe_t;
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
int shell_pipe_setup(adb_client_t *client, shell_pipe_t *pipe);
int shell_pipe_start(shell_pipe_t *pipe,
void (*on_data_cb)(shell_pipe_t *, apacket *));
void shell_pipe_destroy(shell_pipe_t *pipe,
void (*close_cb)(shell_pipe_t *));
int shell_pipe_write(shell_pipe_t *pipe, const void *buf, size_t count);
int shell_pipe_exec(char * const argv[], shell_pipe_t *pipe,
void (*on_data_cb)(shell_pipe_t *, apacket *));
int shell_exec_builtin(const char *appname, FAR char *const *argv,
shell_pipe_t *apipe);

209
system/adb/shell_service.c Normal file
View File

@ -0,0 +1,209 @@
/****************************************************************************
* system/adb/shell_service.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdlib.h>
#include "adb.h"
#include "shell_service.h"
#include "shell_pipe.h"
/****************************************************************************
* Private types
****************************************************************************/
typedef struct ash_service_s
{
adb_service_t service;
shell_pipe_t pipe;
adb_client_t *client;
} ash_service_t;
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static void exec_on_data_available(shell_pipe_t * pipe, apacket * p);
static int shell_ack(adb_service_t *service, apacket *p);
static int shell_write(adb_service_t *service, apacket *p);
static void shell_close(struct adb_service_s *service);
static void shell_kick(adb_service_t *service);
/****************************************************************************
* Private Functions
****************************************************************************/
static void exec_on_data_available(shell_pipe_t * pipe, apacket * p)
{
ash_service_t *service = container_of(pipe, ash_service_t, pipe);
if (p->msg.data_length <= 0)
{
/* Got EOF */
adb_service_close(service->client, &service->service, p);
return;
}
p->write_len = p->msg.data_length;
p->msg.arg0 = service->service.id;
p->msg.arg1 = service->service.peer_id;
adb_send_data_frame(service->client, p);
}
static int shell_write(adb_service_t *service, apacket *p)
{
int ret;
ash_service_t *svc = container_of(service, ash_service_t, service);
UNUSED(svc);
if (p->msg.data_length <= 0)
{
return -1;
}
ret = shell_pipe_write(&svc->pipe, p->data, p->msg.data_length);
if (ret < 0)
{
/* Shell process terminated, close service */
return -1;
}
assert(ret == p->msg.data_length);
return 0;
}
static int shell_ack(adb_service_t *service, apacket *p)
{
UNUSED(service);
UNUSED(p);
return 0;
}
static void shell_kick(adb_service_t *service)
{
int ret;
ash_service_t *svc = container_of(service, ash_service_t, service);
ret = shell_pipe_start(&svc->pipe, exec_on_data_available);
/* TODO handle return code */
assert(ret == 0);
}
static void shell_on_close(shell_pipe_t *pipe)
{
ash_service_t *svc = container_of(pipe, ash_service_t, pipe);
free(svc);
}
static void shell_close(adb_service_t *service)
{
ash_service_t *svc = container_of(service, ash_service_t, service);
/* FIXME missing logic here if shell process is still running */
shell_pipe_destroy(&svc->pipe, shell_on_close);
}
static const adb_service_ops_t shell_ops =
{
.on_write_frame = shell_write,
.on_ack_frame = shell_ack,
.on_kick = shell_kick,
.close = shell_close
};
/****************************************************************************
* Public Functions
****************************************************************************/
adb_service_t * shell_service(adb_client_t *client, const char *params)
{
UNUSED(params);
UNUSED(client);
int ret;
char **argv;
const char *target;
ash_service_t *service =
(ash_service_t *)malloc(sizeof(ash_service_t));
if (service == NULL)
{
return NULL;
}
service->client = client;
service->service.ops = &shell_ops;
ret = shell_pipe_setup(client, &service->pipe);
/* TODO check return code */
assert(ret == 0);
/* Check parameters after "shell:" */
target = &params[6];
if (target[0] != 0)
{
/* Build argv: <nsh -c "command">
* argv[0] => "-c"
* argv[1] => command
* argv[2] => NULL
*
* malloc content:
* - x3 argv pointers
* - 3 characters: "-c\0"
* - space for command string
*/
argv = malloc(sizeof(char *) * 3 + 3 + (strlen(target)+1));
argv[0] = (char *)&argv[3];
argv[1] = &((char *)&argv[3])[3];
argv[2] = NULL;
strcpy(argv[0], "-c");
strcpy(argv[1], target);
}
else
{
argv = NULL;
}
ret = shell_pipe_exec(argv, &service->pipe,
exec_on_data_available);
/* TODO check return code */
assert(ret == 0);
free(argv);
return &service->service;
}