system/adb: Replace NuttX special shell service with microADB builtin one

since the new libuv porting support uv_proccess_t now

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
This commit is contained in:
Xiang Xiao 2022-01-23 16:04:06 +08:00 committed by Petro Karashchenko
parent 77382e7209
commit 29374c96c3
5 changed files with 26 additions and 537 deletions

View File

@ -136,19 +136,36 @@ config ADBD_FILE_SERVICE
---help---
Enable "adb ls/push/pull" feature.
config ADBD_FILE_SYMLINK
bool "File service symlink support"
default n
depends on ADBD_FILE_SERVICE
depends on PSEUDOFS_SOFTLINKS
---help---
Enable fs symlink support.
config ADBD_SHELL_SERVICE
bool "ADB shell support"
depends on NSH_CONSOLE
depends on SYSTEM_NSH
select LIBC_EXECFUNCS
select PSEUDOTERM
default n
---help---
Enable "adb shell" feature.
config ADBD_FILE_SYMLINK
bool "File service symlink support"
default n
depends on PSEUDOFS_SOFTLINKS
config ADBD_SHELL_SERVICE_CMD
string "ADB shell command"
depends on ADBD_SHELL_SERVICE
default "sh"
---help---
Enable fs symlink support.
The shell command name.
config ADBD_SHELL_SERVICE_PATH
string "ADB shell path"
depends on ADBD_SHELL_SERVICE
default "/bin/sh"
---help---
The path to the shell executable.
config ADBD_BOARD_INIT
bool "Board initialization"

View File

@ -76,8 +76,7 @@ CSRCS += logcat_service.c
endif
ifeq ($(CONFIG_ADBD_SHELL_SERVICE),y)
CSRCS += shell_service.c
CSRCS += shell_pipe.c
CSRCS += $(ADB_UNPACKNAME)/hal/shell_service_uv.c
endif
context:: $(ADB_UNPACKDIR)

View File

@ -1,259 +0,0 @@
/****************************************************************************
* apps/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);
/* Close stdout pipe */
close(pipe->write_fd);
/* 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);
if (uv_fileno((const uv_handle_t *)&pipe->handle, &pipe->write_fd))
{
pipe->write_fd = -1;
}
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 */
if ((ret = pipe(in_fds)))
{
adb_log("failed to open in pipe %d\n", errno);
goto exit_fail;
}
if ((ret = pipe(out_fds)))
{
adb_log("failed to open out pipe %d\n", errno);
goto exit_close_pipe_in;
}
apipe->write_fd = in_fds[1];
/* Setup stdout (read: adb, write: child) */
ret = dup2(out_fds[1], 1);
assert(ret == 1);
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,
argv ? nsh_system : 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;
exit_close_pipe_in:
close(in_fds[0]);
close(in_fds[1]);
exit_fail:
return ret;
}

View File

@ -1,56 +0,0 @@
/****************************************************************************
* apps/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);

View File

@ -1,212 +0,0 @@
/****************************************************************************
* apps/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);
free(argv);
if (ret)
{
adb_log("failed to setup shell pipe %d\n", ret);
free(service);
return NULL;
}
return &service->service;
}