run minadbd as shell user, remove unused code
Make minadbd drop its root privileges after initializing. We need to make the /tmp directory writable by the shell group so that it can drop the sideloaded file there.
This commit is contained in:
parent
45fdb3899d
commit
48704798ea
9 changed files with 40 additions and 1171 deletions
|
@ -15,6 +15,9 @@ on init
|
|||
mkdir /cache
|
||||
mount /tmp /tmp tmpfs
|
||||
|
||||
chown root shell /tmp
|
||||
chmod 0775 /tmp
|
||||
|
||||
write /sys/class/android_usb/android0/enable 0
|
||||
write /sys/class/android_usb/android0/idVendor 18D1
|
||||
write /sys/class/android_usb/android0/idProduct D001
|
||||
|
|
|
@ -4,16 +4,19 @@ the following changes:
|
|||
adb.c
|
||||
- much support for host mode and non-linux OS's stripped out; this
|
||||
version only runs as adbd on the device.
|
||||
- does not setuid/setgid itself (always stays root)
|
||||
- always setuid/setgid's itself to the shell user
|
||||
- only uses USB transport
|
||||
- references to JDWP removed
|
||||
- main() removed
|
||||
- all ADB_HOST and win32 code removed
|
||||
- removed listeners, logging code, background server (for host)
|
||||
|
||||
adb.h
|
||||
- minor changes to match adb.c changes
|
||||
|
||||
sockets.c
|
||||
- references to JDWP removed
|
||||
- ADB_HOST code removed
|
||||
|
||||
services.c
|
||||
- all services except echo_service (which is commented out) removed
|
||||
|
@ -25,3 +28,12 @@ services.c
|
|||
Android.mk
|
||||
- only builds in adbd mode; builds as static library instead of a
|
||||
standalone executable.
|
||||
|
||||
sysdeps.h
|
||||
- changes adb_creat() to use O_NOFOLLOW
|
||||
|
||||
transport.c
|
||||
- removed ADB_HOST code
|
||||
|
||||
transport_usb.c
|
||||
- removed ADB_HOST code
|
||||
|
|
757
minadbd/adb.c
757
minadbd/adb.c
|
@ -28,13 +28,9 @@
|
|||
#include "sysdeps.h"
|
||||
#include "adb.h"
|
||||
|
||||
#if !ADB_HOST
|
||||
#include <private/android_filesystem_config.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/prctl.h>
|
||||
#else
|
||||
#include "usb_vendors.h"
|
||||
#endif
|
||||
|
||||
#if ADB_TRACE
|
||||
ADB_MUTEX_DEFINE( D_lock );
|
||||
|
@ -228,29 +224,6 @@ static void send_connect(atransport *t)
|
|||
HOST ? "host" : adb_device_banner);
|
||||
cp->msg.data_length = strlen((char*) cp->data) + 1;
|
||||
send_packet(cp, t);
|
||||
#if ADB_HOST
|
||||
/* XXX why sleep here? */
|
||||
// allow the device some time to respond to the connect message
|
||||
adb_sleep_ms(1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
static char *connection_state_name(atransport *t)
|
||||
{
|
||||
if (t == NULL) {
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
switch(t->connection_state) {
|
||||
case CS_BOOTLOADER:
|
||||
return "bootloader";
|
||||
case CS_DEVICE:
|
||||
return "device";
|
||||
case CS_OFFLINE:
|
||||
return "offline";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void parse_banner(char *banner, atransport *t)
|
||||
|
@ -400,448 +373,11 @@ void handle_packet(apacket *p, atransport *t)
|
|||
put_apacket(p);
|
||||
}
|
||||
|
||||
alistener listener_list = {
|
||||
.next = &listener_list,
|
||||
.prev = &listener_list,
|
||||
};
|
||||
|
||||
static void ss_listener_event_func(int _fd, unsigned ev, void *_l)
|
||||
{
|
||||
asocket *s;
|
||||
|
||||
if(ev & FDE_READ) {
|
||||
struct sockaddr addr;
|
||||
socklen_t alen;
|
||||
int fd;
|
||||
|
||||
alen = sizeof(addr);
|
||||
fd = adb_socket_accept(_fd, &addr, &alen);
|
||||
if(fd < 0) return;
|
||||
|
||||
adb_socket_setbufsize(fd, CHUNK_SIZE);
|
||||
|
||||
s = create_local_socket(fd);
|
||||
if(s) {
|
||||
connect_to_smartsocket(s);
|
||||
return;
|
||||
}
|
||||
|
||||
adb_close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void listener_event_func(int _fd, unsigned ev, void *_l)
|
||||
{
|
||||
alistener *l = _l;
|
||||
asocket *s;
|
||||
|
||||
if(ev & FDE_READ) {
|
||||
struct sockaddr addr;
|
||||
socklen_t alen;
|
||||
int fd;
|
||||
|
||||
alen = sizeof(addr);
|
||||
fd = adb_socket_accept(_fd, &addr, &alen);
|
||||
if(fd < 0) return;
|
||||
|
||||
s = create_local_socket(fd);
|
||||
if(s) {
|
||||
s->transport = l->transport;
|
||||
connect_to_remote(s, l->connect_to);
|
||||
return;
|
||||
}
|
||||
|
||||
adb_close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void free_listener(alistener* l)
|
||||
{
|
||||
if (l->next) {
|
||||
l->next->prev = l->prev;
|
||||
l->prev->next = l->next;
|
||||
l->next = l->prev = l;
|
||||
}
|
||||
|
||||
// closes the corresponding fd
|
||||
fdevent_remove(&l->fde);
|
||||
|
||||
if (l->local_name)
|
||||
free((char*)l->local_name);
|
||||
|
||||
if (l->connect_to)
|
||||
free((char*)l->connect_to);
|
||||
|
||||
if (l->transport) {
|
||||
remove_transport_disconnect(l->transport, &l->disconnect);
|
||||
}
|
||||
free(l);
|
||||
}
|
||||
|
||||
static void listener_disconnect(void* _l, atransport* t)
|
||||
{
|
||||
alistener* l = _l;
|
||||
|
||||
free_listener(l);
|
||||
}
|
||||
|
||||
int local_name_to_fd(const char *name)
|
||||
{
|
||||
int port;
|
||||
|
||||
if(!strncmp("tcp:", name, 4)){
|
||||
int ret;
|
||||
port = atoi(name + 4);
|
||||
ret = socket_loopback_server(port, SOCK_STREAM);
|
||||
return ret;
|
||||
}
|
||||
#ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */
|
||||
// It's non-sensical to support the "reserved" space on the adb host side
|
||||
if(!strncmp(name, "local:", 6)) {
|
||||
return socket_local_server(name + 6,
|
||||
ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
|
||||
} else if(!strncmp(name, "localabstract:", 14)) {
|
||||
return socket_local_server(name + 14,
|
||||
ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
|
||||
} else if(!strncmp(name, "localfilesystem:", 16)) {
|
||||
return socket_local_server(name + 16,
|
||||
ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
|
||||
}
|
||||
|
||||
#endif
|
||||
printf("unknown local portname '%s'\n", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int remove_listener(const char *local_name, const char *connect_to, atransport* transport)
|
||||
{
|
||||
alistener *l;
|
||||
|
||||
for (l = listener_list.next; l != &listener_list; l = l->next) {
|
||||
if (!strcmp(local_name, l->local_name) &&
|
||||
!strcmp(connect_to, l->connect_to) &&
|
||||
l->transport && l->transport == transport) {
|
||||
|
||||
listener_disconnect(l, transport);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int install_listener(const char *local_name, const char *connect_to, atransport* transport)
|
||||
{
|
||||
alistener *l;
|
||||
|
||||
//printf("install_listener('%s','%s')\n", local_name, connect_to);
|
||||
|
||||
for(l = listener_list.next; l != &listener_list; l = l->next){
|
||||
if(strcmp(local_name, l->local_name) == 0) {
|
||||
char *cto;
|
||||
|
||||
/* can't repurpose a smartsocket */
|
||||
if(l->connect_to[0] == '*') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cto = strdup(connect_to);
|
||||
if(cto == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
//printf("rebinding '%s' to '%s'\n", local_name, connect_to);
|
||||
free((void*) l->connect_to);
|
||||
l->connect_to = cto;
|
||||
if (l->transport != transport) {
|
||||
remove_transport_disconnect(l->transport, &l->disconnect);
|
||||
l->transport = transport;
|
||||
add_transport_disconnect(l->transport, &l->disconnect);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
|
||||
if((l->local_name = strdup(local_name)) == 0) goto nomem;
|
||||
if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
|
||||
|
||||
|
||||
l->fd = local_name_to_fd(local_name);
|
||||
if(l->fd < 0) {
|
||||
free((void*) l->local_name);
|
||||
free((void*) l->connect_to);
|
||||
free(l);
|
||||
printf("cannot bind '%s'\n", local_name);
|
||||
return -2;
|
||||
}
|
||||
|
||||
close_on_exec(l->fd);
|
||||
if(!strcmp(l->connect_to, "*smartsocket*")) {
|
||||
fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
|
||||
} else {
|
||||
fdevent_install(&l->fde, l->fd, listener_event_func, l);
|
||||
}
|
||||
fdevent_set(&l->fde, FDE_READ);
|
||||
|
||||
l->next = &listener_list;
|
||||
l->prev = listener_list.prev;
|
||||
l->next->prev = l;
|
||||
l->prev->next = l;
|
||||
l->transport = transport;
|
||||
|
||||
if (transport) {
|
||||
l->disconnect.opaque = l;
|
||||
l->disconnect.func = listener_disconnect;
|
||||
add_transport_disconnect(transport, &l->disconnect);
|
||||
}
|
||||
return 0;
|
||||
|
||||
nomem:
|
||||
fatal("cannot allocate listener");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_WIN32_PROC
|
||||
static BOOL WINAPI ctrlc_handler(DWORD type)
|
||||
{
|
||||
exit(STATUS_CONTROL_C_EXIT);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void adb_cleanup(void)
|
||||
{
|
||||
usb_cleanup();
|
||||
}
|
||||
|
||||
void start_logging(void)
|
||||
{
|
||||
#ifdef HAVE_WIN32_PROC
|
||||
char temp[ MAX_PATH ];
|
||||
FILE* fnul;
|
||||
FILE* flog;
|
||||
|
||||
GetTempPath( sizeof(temp) - 8, temp );
|
||||
strcat( temp, "adb.log" );
|
||||
|
||||
/* Win32 specific redirections */
|
||||
fnul = fopen( "NUL", "rt" );
|
||||
if (fnul != NULL)
|
||||
stdin[0] = fnul[0];
|
||||
|
||||
flog = fopen( temp, "at" );
|
||||
if (flog == NULL)
|
||||
flog = fnul;
|
||||
|
||||
setvbuf( flog, NULL, _IONBF, 0 );
|
||||
|
||||
stdout[0] = flog[0];
|
||||
stderr[0] = flog[0];
|
||||
fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
|
||||
#else
|
||||
int fd;
|
||||
|
||||
fd = unix_open("/dev/null", O_RDONLY);
|
||||
dup2(fd, 0);
|
||||
adb_close(fd);
|
||||
|
||||
fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
|
||||
if(fd < 0) {
|
||||
fd = unix_open("/dev/null", O_WRONLY);
|
||||
}
|
||||
dup2(fd, 1);
|
||||
dup2(fd, 2);
|
||||
adb_close(fd);
|
||||
fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !ADB_HOST
|
||||
void start_device_log(void)
|
||||
{
|
||||
int fd;
|
||||
char path[PATH_MAX];
|
||||
struct tm now;
|
||||
time_t t;
|
||||
char value[PROPERTY_VALUE_MAX];
|
||||
|
||||
// read the trace mask from persistent property persist.adb.trace_mask
|
||||
// give up if the property is not set or cannot be parsed
|
||||
property_get("persist.adb.trace_mask", value, "");
|
||||
if (sscanf(value, "%x", &adb_trace_mask) != 1)
|
||||
return;
|
||||
|
||||
adb_mkdir("/data/adb", 0775);
|
||||
tzset();
|
||||
time(&t);
|
||||
localtime_r(&t, &now);
|
||||
strftime(path, sizeof(path),
|
||||
"/data/adb/adb-%Y-%m-%d-%H-%M-%S.txt",
|
||||
&now);
|
||||
fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
// redirect stdout and stderr to the log file
|
||||
dup2(fd, 1);
|
||||
dup2(fd, 2);
|
||||
fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
|
||||
adb_close(fd);
|
||||
|
||||
fd = unix_open("/dev/null", O_RDONLY);
|
||||
dup2(fd, 0);
|
||||
adb_close(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ADB_HOST
|
||||
int launch_server(int server_port)
|
||||
{
|
||||
#ifdef HAVE_WIN32_PROC
|
||||
/* we need to start the server in the background */
|
||||
/* we create a PIPE that will be used to wait for the server's "OK" */
|
||||
/* message since the pipe handles must be inheritable, we use a */
|
||||
/* security attribute */
|
||||
HANDLE pipe_read, pipe_write;
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
STARTUPINFO startup;
|
||||
PROCESS_INFORMATION pinfo;
|
||||
char program_path[ MAX_PATH ];
|
||||
int ret;
|
||||
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.lpSecurityDescriptor = NULL;
|
||||
sa.bInheritHandle = TRUE;
|
||||
|
||||
/* create pipe, and ensure its read handle isn't inheritable */
|
||||
ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
|
||||
if (!ret) {
|
||||
fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
|
||||
return -1;
|
||||
}
|
||||
|
||||
SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
|
||||
|
||||
ZeroMemory( &startup, sizeof(startup) );
|
||||
startup.cb = sizeof(startup);
|
||||
startup.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
|
||||
startup.hStdOutput = pipe_write;
|
||||
startup.hStdError = GetStdHandle( STD_ERROR_HANDLE );
|
||||
startup.dwFlags = STARTF_USESTDHANDLES;
|
||||
|
||||
ZeroMemory( &pinfo, sizeof(pinfo) );
|
||||
|
||||
/* get path of current program */
|
||||
GetModuleFileName( NULL, program_path, sizeof(program_path) );
|
||||
|
||||
ret = CreateProcess(
|
||||
program_path, /* program path */
|
||||
"adb fork-server server",
|
||||
/* the fork-server argument will set the
|
||||
debug = 2 in the child */
|
||||
NULL, /* process handle is not inheritable */
|
||||
NULL, /* thread handle is not inheritable */
|
||||
TRUE, /* yes, inherit some handles */
|
||||
DETACHED_PROCESS, /* the new process doesn't have a console */
|
||||
NULL, /* use parent's environment block */
|
||||
NULL, /* use parent's starting directory */
|
||||
&startup, /* startup info, i.e. std handles */
|
||||
&pinfo );
|
||||
|
||||
CloseHandle( pipe_write );
|
||||
|
||||
if (!ret) {
|
||||
fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
|
||||
CloseHandle( pipe_read );
|
||||
return -1;
|
||||
}
|
||||
|
||||
CloseHandle( pinfo.hProcess );
|
||||
CloseHandle( pinfo.hThread );
|
||||
|
||||
/* wait for the "OK\n" message */
|
||||
{
|
||||
char temp[3];
|
||||
DWORD count;
|
||||
|
||||
ret = ReadFile( pipe_read, temp, 3, &count, NULL );
|
||||
CloseHandle( pipe_read );
|
||||
if ( !ret ) {
|
||||
fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
|
||||
return -1;
|
||||
}
|
||||
if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
|
||||
fprintf(stderr, "ADB server didn't ACK\n" );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_FORKEXEC)
|
||||
char path[PATH_MAX];
|
||||
int fd[2];
|
||||
|
||||
// set up a pipe so the child can tell us when it is ready.
|
||||
// fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
|
||||
if (pipe(fd)) {
|
||||
fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
|
||||
return -1;
|
||||
}
|
||||
get_my_path(path, PATH_MAX);
|
||||
pid_t pid = fork();
|
||||
if(pid < 0) return -1;
|
||||
|
||||
if (pid == 0) {
|
||||
// child side of the fork
|
||||
|
||||
// redirect stderr to the pipe
|
||||
// we use stderr instead of stdout due to stdout's buffering behavior.
|
||||
adb_close(fd[0]);
|
||||
dup2(fd[1], STDERR_FILENO);
|
||||
adb_close(fd[1]);
|
||||
|
||||
// child process
|
||||
int result = execl(path, "adb", "fork-server", "server", NULL);
|
||||
// this should not return
|
||||
fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
|
||||
} else {
|
||||
// parent side of the fork
|
||||
|
||||
char temp[3];
|
||||
|
||||
temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
|
||||
// wait for the "OK\n" message
|
||||
adb_close(fd[1]);
|
||||
int ret = adb_read(fd[0], temp, 3);
|
||||
int saved_errno = errno;
|
||||
adb_close(fd[0]);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno);
|
||||
return -1;
|
||||
}
|
||||
if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
|
||||
fprintf(stderr, "ADB server didn't ACK\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
setsid();
|
||||
}
|
||||
#else
|
||||
#error "cannot implement background server start on this platform"
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Constructs a local name of form tcp:port.
|
||||
* target_str points to the target string, it's content will be overwritten.
|
||||
* target_size is the capacity of the target string.
|
||||
* server_port is the port number to use for the local name.
|
||||
*/
|
||||
void build_local_name(char* target_str, size_t target_size, int server_port)
|
||||
{
|
||||
snprintf(target_str, target_size, "tcp:%d", server_port);
|
||||
}
|
||||
|
||||
int adb_main()
|
||||
{
|
||||
atexit(adb_cleanup);
|
||||
|
@ -858,6 +394,16 @@ int adb_main()
|
|||
usb_init();
|
||||
}
|
||||
|
||||
if (setgid(AID_SHELL) != 0) {
|
||||
fprintf(stderr, "failed to setgid to shell\n");
|
||||
exit(1);
|
||||
}
|
||||
if (setuid(AID_SHELL) != 0) {
|
||||
fprintf(stderr, "failed to setuid to shell\n");
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "userid is %d\n", getuid());
|
||||
|
||||
D("Event loop starting\n");
|
||||
|
||||
fdevent_loop();
|
||||
|
@ -866,286 +412,3 @@ int adb_main()
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if ADB_HOST
|
||||
void connect_device(char* host, char* buffer, int buffer_size)
|
||||
{
|
||||
int port, fd;
|
||||
char* portstr = strchr(host, ':');
|
||||
char hostbuf[100];
|
||||
char serial[100];
|
||||
|
||||
strncpy(hostbuf, host, sizeof(hostbuf) - 1);
|
||||
if (portstr) {
|
||||
if (portstr - host >= sizeof(hostbuf)) {
|
||||
snprintf(buffer, buffer_size, "bad host name %s", host);
|
||||
return;
|
||||
}
|
||||
// zero terminate the host at the point we found the colon
|
||||
hostbuf[portstr - host] = 0;
|
||||
if (sscanf(portstr + 1, "%d", &port) == 0) {
|
||||
snprintf(buffer, buffer_size, "bad port number %s", portstr);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
|
||||
}
|
||||
|
||||
snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
|
||||
if (find_transport(serial)) {
|
||||
snprintf(buffer, buffer_size, "already connected to %s", serial);
|
||||
return;
|
||||
}
|
||||
|
||||
fd = socket_network_client(hostbuf, port, SOCK_STREAM);
|
||||
if (fd < 0) {
|
||||
snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
|
||||
return;
|
||||
}
|
||||
|
||||
D("client: connected on remote on fd %d\n", fd);
|
||||
close_on_exec(fd);
|
||||
disable_tcp_nagle(fd);
|
||||
register_socket_transport(fd, serial, port, 0);
|
||||
snprintf(buffer, buffer_size, "connected to %s", serial);
|
||||
}
|
||||
|
||||
void connect_emulator(char* port_spec, char* buffer, int buffer_size)
|
||||
{
|
||||
char* port_separator = strchr(port_spec, ',');
|
||||
if (!port_separator) {
|
||||
snprintf(buffer, buffer_size,
|
||||
"unable to parse '%s' as <console port>,<adb port>",
|
||||
port_spec);
|
||||
return;
|
||||
}
|
||||
|
||||
// Zero-terminate console port and make port_separator point to 2nd port.
|
||||
*port_separator++ = 0;
|
||||
int console_port = strtol(port_spec, NULL, 0);
|
||||
int adb_port = strtol(port_separator, NULL, 0);
|
||||
if (!(console_port > 0 && adb_port > 0)) {
|
||||
*(port_separator - 1) = ',';
|
||||
snprintf(buffer, buffer_size,
|
||||
"Invalid port numbers: Expected positive numbers, got '%s'",
|
||||
port_spec);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the emulator is already known.
|
||||
* Note: There's a small but harmless race condition here: An emulator not
|
||||
* present just yet could be registered by another invocation right
|
||||
* after doing this check here. However, local_connect protects
|
||||
* against double-registration too. From here, a better error message
|
||||
* can be produced. In the case of the race condition, the very specific
|
||||
* error message won't be shown, but the data doesn't get corrupted. */
|
||||
atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
|
||||
if (known_emulator != NULL) {
|
||||
snprintf(buffer, buffer_size,
|
||||
"Emulator on port %d already registered.", adb_port);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if more emulators can be registered. Similar unproblematic
|
||||
* race condition as above. */
|
||||
int candidate_slot = get_available_local_transport_index();
|
||||
if (candidate_slot < 0) {
|
||||
snprintf(buffer, buffer_size, "Cannot accept more emulators.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Preconditions met, try to connect to the emulator. */
|
||||
if (!local_connect_arbitrary_ports(console_port, adb_port)) {
|
||||
snprintf(buffer, buffer_size,
|
||||
"Connected to emulator on ports %d,%d", console_port, adb_port);
|
||||
} else {
|
||||
snprintf(buffer, buffer_size,
|
||||
"Could not connect to emulator on ports %d,%d",
|
||||
console_port, adb_port);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
|
||||
{
|
||||
atransport *transport = NULL;
|
||||
char buf[4096];
|
||||
|
||||
if(!strcmp(service, "kill")) {
|
||||
fprintf(stderr,"adb server killed by remote request\n");
|
||||
fflush(stdout);
|
||||
adb_write(reply_fd, "OKAY", 4);
|
||||
usb_cleanup();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#if ADB_HOST
|
||||
// "transport:" is used for switching transport with a specified serial number
|
||||
// "transport-usb:" is used for switching transport to the only USB transport
|
||||
// "transport-local:" is used for switching transport to the only local transport
|
||||
// "transport-any:" is used for switching transport to the only transport
|
||||
if (!strncmp(service, "transport", strlen("transport"))) {
|
||||
char* error_string = "unknown failure";
|
||||
transport_type type = kTransportAny;
|
||||
|
||||
if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
|
||||
type = kTransportUsb;
|
||||
} else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
|
||||
type = kTransportLocal;
|
||||
} else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
|
||||
type = kTransportAny;
|
||||
} else if (!strncmp(service, "transport:", strlen("transport:"))) {
|
||||
service += strlen("transport:");
|
||||
serial = service;
|
||||
}
|
||||
|
||||
transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
|
||||
|
||||
if (transport) {
|
||||
s->transport = transport;
|
||||
adb_write(reply_fd, "OKAY", 4);
|
||||
} else {
|
||||
sendfailmsg(reply_fd, error_string);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// return a list of all connected devices
|
||||
if (!strcmp(service, "devices")) {
|
||||
char buffer[4096];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
D("Getting device list \n");
|
||||
list_transports(buffer, sizeof(buffer));
|
||||
snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
|
||||
D("Wrote device list \n");
|
||||
writex(reply_fd, buf, strlen(buf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// add a new TCP transport, device or emulator
|
||||
if (!strncmp(service, "connect:", 8)) {
|
||||
char buffer[4096];
|
||||
char* host = service + 8;
|
||||
if (!strncmp(host, "emu:", 4)) {
|
||||
connect_emulator(host + 4, buffer, sizeof(buffer));
|
||||
} else {
|
||||
connect_device(host, buffer, sizeof(buffer));
|
||||
}
|
||||
// Send response for emulator and device
|
||||
snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
|
||||
writex(reply_fd, buf, strlen(buf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// remove TCP transport
|
||||
if (!strncmp(service, "disconnect:", 11)) {
|
||||
char buffer[4096];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
char* serial = service + 11;
|
||||
if (serial[0] == 0) {
|
||||
// disconnect from all TCP devices
|
||||
unregister_all_tcp_transports();
|
||||
} else {
|
||||
char hostbuf[100];
|
||||
// assume port 5555 if no port is specified
|
||||
if (!strchr(serial, ':')) {
|
||||
snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial);
|
||||
serial = hostbuf;
|
||||
}
|
||||
atransport *t = find_transport(serial);
|
||||
|
||||
if (t) {
|
||||
unregister_transport(t);
|
||||
} else {
|
||||
snprintf(buffer, sizeof(buffer), "No such device %s", serial);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
|
||||
writex(reply_fd, buf, strlen(buf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// returns our value for ADB_SERVER_VERSION
|
||||
if (!strcmp(service, "version")) {
|
||||
char version[12];
|
||||
snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
|
||||
snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
|
||||
writex(reply_fd, buf, strlen(buf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
|
||||
char *out = "unknown";
|
||||
transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
|
||||
if (transport && transport->serial) {
|
||||
out = transport->serial;
|
||||
}
|
||||
snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
|
||||
writex(reply_fd, buf, strlen(buf));
|
||||
return 0;
|
||||
}
|
||||
// indicates a new emulator instance has started
|
||||
if (!strncmp(service,"emulator:",9)) {
|
||||
int port = atoi(service+9);
|
||||
local_connect(port);
|
||||
/* we don't even need to send a reply */
|
||||
return 0;
|
||||
}
|
||||
#endif // ADB_HOST
|
||||
|
||||
if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) {
|
||||
char *local, *remote, *err;
|
||||
int r;
|
||||
atransport *transport;
|
||||
|
||||
int createForward = strncmp(service,"kill",4);
|
||||
|
||||
local = service + (createForward ? 8 : 12);
|
||||
remote = strchr(local,';');
|
||||
if(remote == 0) {
|
||||
sendfailmsg(reply_fd, "malformed forward spec");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*remote++ = 0;
|
||||
if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
|
||||
sendfailmsg(reply_fd, "malformed forward spec");
|
||||
return 0;
|
||||
}
|
||||
|
||||
transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
|
||||
if (!transport) {
|
||||
sendfailmsg(reply_fd, err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (createForward) {
|
||||
r = install_listener(local, remote, transport);
|
||||
} else {
|
||||
r = remove_listener(local, remote, transport);
|
||||
}
|
||||
if(r == 0) {
|
||||
/* 1st OKAY is connect, 2nd OKAY is status */
|
||||
writex(reply_fd, "OKAYOKAY", 8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (createForward) {
|
||||
sendfailmsg(reply_fd, (r == -1) ? "cannot rebind smartsocket" : "cannot bind socket");
|
||||
} else {
|
||||
sendfailmsg(reply_fd, "cannot remove listener");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!strncmp(service,"get-state",strlen("get-state"))) {
|
||||
transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
|
||||
char *state = connection_state_name(transport);
|
||||
snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state);
|
||||
writex(reply_fd, buf, strlen(buf));
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
typedef struct amessage amessage;
|
||||
typedef struct apacket apacket;
|
||||
typedef struct asocket asocket;
|
||||
typedef struct alistener alistener;
|
||||
typedef struct aservice aservice;
|
||||
typedef struct atransport atransport;
|
||||
typedef struct adisconnect adisconnect;
|
||||
|
@ -134,7 +133,7 @@ struct asocket {
|
|||
/* the adisconnect structure is used to record a callback that
|
||||
** will be called whenever a transport is disconnected (e.g. by the user)
|
||||
** this should be used to cleanup objects that depend on the
|
||||
** transport (e.g. remote sockets, listeners, etc...)
|
||||
** transport (e.g. remote sockets, etc...)
|
||||
*/
|
||||
struct adisconnect
|
||||
{
|
||||
|
@ -194,30 +193,6 @@ struct atransport
|
|||
};
|
||||
|
||||
|
||||
/* A listener is an entity which binds to a local port
|
||||
** and, upon receiving a connection on that port, creates
|
||||
** an asocket to connect the new local connection to a
|
||||
** specific remote service.
|
||||
**
|
||||
** TODO: some listeners read from the new connection to
|
||||
** determine what exact service to connect to on the far
|
||||
** side.
|
||||
*/
|
||||
struct alistener
|
||||
{
|
||||
alistener *next;
|
||||
alistener *prev;
|
||||
|
||||
fdevent fde;
|
||||
int fd;
|
||||
|
||||
const char *local_name;
|
||||
const char *connect_to;
|
||||
atransport *transport;
|
||||
adisconnect disconnect;
|
||||
};
|
||||
|
||||
|
||||
void print_packet(const char *label, apacket *p);
|
||||
|
||||
asocket *find_local_socket(unsigned id);
|
||||
|
|
|
@ -53,6 +53,7 @@ static void sideload_service(int s, void *cookie)
|
|||
|
||||
fd = adb_creat(ADB_SIDELOAD_FILENAME, 0644);
|
||||
if(fd < 0) {
|
||||
fprintf(stderr, "failed to create %s\n", ADB_SIDELOAD_FILENAME);
|
||||
adb_close(s);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -413,22 +413,6 @@ asocket *create_local_service_socket(const char *name)
|
|||
return s;
|
||||
}
|
||||
|
||||
#if ADB_HOST
|
||||
static asocket *create_host_service_socket(const char *name, const char* serial)
|
||||
{
|
||||
asocket *s;
|
||||
|
||||
s = host_service_to_socket(name, serial);
|
||||
|
||||
if (s != NULL) {
|
||||
D("LS(%d) bound to '%s'\n", s->id, name);
|
||||
return s;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
#endif /* ADB_HOST */
|
||||
|
||||
/* a Remote socket is used to send/receive data to/from a given transport object
|
||||
** it needs to be closed when the transport is forcibly destroyed by the user
|
||||
*/
|
||||
|
@ -612,11 +596,6 @@ char *skip_host_serial(char *service) {
|
|||
static int smart_socket_enqueue(asocket *s, apacket *p)
|
||||
{
|
||||
unsigned len;
|
||||
#if ADB_HOST
|
||||
char *service = NULL;
|
||||
char* serial = NULL;
|
||||
transport_type ttype = kTransportAny;
|
||||
#endif
|
||||
|
||||
D("SS(%d): enqueue %d\n", s->id, p->len);
|
||||
|
||||
|
@ -658,84 +637,6 @@ static int smart_socket_enqueue(asocket *s, apacket *p)
|
|||
|
||||
D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4));
|
||||
|
||||
#if ADB_HOST
|
||||
service = (char *)p->data + 4;
|
||||
if(!strncmp(service, "host-serial:", strlen("host-serial:"))) {
|
||||
char* serial_end;
|
||||
service += strlen("host-serial:");
|
||||
|
||||
// serial number should follow "host:" and could be a host:port string.
|
||||
serial_end = skip_host_serial(service);
|
||||
if (serial_end) {
|
||||
*serial_end = 0; // terminate string
|
||||
serial = service;
|
||||
service = serial_end + 1;
|
||||
}
|
||||
} else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {
|
||||
ttype = kTransportUsb;
|
||||
service += strlen("host-usb:");
|
||||
} else if (!strncmp(service, "host-local:", strlen("host-local:"))) {
|
||||
ttype = kTransportLocal;
|
||||
service += strlen("host-local:");
|
||||
} else if (!strncmp(service, "host:", strlen("host:"))) {
|
||||
ttype = kTransportAny;
|
||||
service += strlen("host:");
|
||||
} else {
|
||||
service = NULL;
|
||||
}
|
||||
|
||||
if (service) {
|
||||
asocket *s2;
|
||||
|
||||
/* some requests are handled immediately -- in that
|
||||
** case the handle_host_request() routine has sent
|
||||
** the OKAY or FAIL message and all we have to do
|
||||
** is clean up.
|
||||
*/
|
||||
if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) {
|
||||
/* XXX fail message? */
|
||||
D( "SS(%d): handled host service '%s'\n", s->id, service );
|
||||
goto fail;
|
||||
}
|
||||
if (!strncmp(service, "transport", strlen("transport"))) {
|
||||
D( "SS(%d): okay transport\n", s->id );
|
||||
p->len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* try to find a local service with this name.
|
||||
** if no such service exists, we'll fail out
|
||||
** and tear down here.
|
||||
*/
|
||||
s2 = create_host_service_socket(service, serial);
|
||||
if(s2 == 0) {
|
||||
D( "SS(%d): couldn't create host service '%s'\n", s->id, service );
|
||||
sendfailmsg(s->peer->fd, "unknown host service");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* we've connected to a local host service,
|
||||
** so we make our peer back into a regular
|
||||
** local socket and bind it to the new local
|
||||
** service socket, acknowledge the successful
|
||||
** connection, and close this smart socket now
|
||||
** that its work is done.
|
||||
*/
|
||||
adb_write(s->peer->fd, "OKAY", 4);
|
||||
|
||||
s->peer->ready = local_socket_ready;
|
||||
s->peer->close = local_socket_close;
|
||||
s->peer->peer = s2;
|
||||
s2->peer = s->peer;
|
||||
s->peer = 0;
|
||||
D( "SS(%d): okay\n", s->id );
|
||||
s->close(s);
|
||||
|
||||
/* initial state is "ready" */
|
||||
s2->ready(s2);
|
||||
return 0;
|
||||
}
|
||||
#else /* !ADB_HOST */
|
||||
if (s->transport == NULL) {
|
||||
char* error_string = "unknown failure";
|
||||
s->transport = acquire_one_transport (CS_ANY,
|
||||
|
@ -746,7 +647,6 @@ static int smart_socket_enqueue(asocket *s, apacket *p)
|
|||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) {
|
||||
/* if there's no remote we fail the connection
|
||||
|
|
|
@ -324,6 +324,18 @@ static __inline__ int adb_open_mode( const char* pathname, int options, int
|
|||
return open( pathname, options, mode );
|
||||
}
|
||||
|
||||
static __inline__ int adb_creat(const char* path, int mode)
|
||||
{
|
||||
int fd = open(path, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW, mode);
|
||||
|
||||
if ( fd < 0 )
|
||||
return -1;
|
||||
|
||||
close_on_exec(fd);
|
||||
return fd;
|
||||
}
|
||||
#undef creat
|
||||
#define creat ___xxx_creat
|
||||
|
||||
static __inline__ int adb_open( const char* pathname, int options )
|
||||
{
|
||||
|
@ -380,19 +392,6 @@ static __inline__ int adb_unlink(const char* path)
|
|||
#undef unlink
|
||||
#define unlink ___xxx_unlink
|
||||
|
||||
static __inline__ int adb_creat(const char* path, int mode)
|
||||
{
|
||||
int fd = creat(path, mode);
|
||||
|
||||
if ( fd < 0 )
|
||||
return -1;
|
||||
|
||||
close_on_exec(fd);
|
||||
return fd;
|
||||
}
|
||||
#undef creat
|
||||
#define creat ___xxx_creat
|
||||
|
||||
static __inline__ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen)
|
||||
{
|
||||
int fd;
|
||||
|
|
|
@ -363,154 +363,10 @@ static int transport_registration_send = -1;
|
|||
static int transport_registration_recv = -1;
|
||||
static fdevent transport_registration_fde;
|
||||
|
||||
|
||||
#if ADB_HOST
|
||||
static int list_transports_msg(char* buffer, size_t bufferlen)
|
||||
{
|
||||
char head[5];
|
||||
int len;
|
||||
|
||||
len = list_transports(buffer+4, bufferlen-4);
|
||||
snprintf(head, sizeof(head), "%04x", len);
|
||||
memcpy(buffer, head, 4);
|
||||
len += 4;
|
||||
return len;
|
||||
}
|
||||
|
||||
/* this adds support required by the 'track-devices' service.
|
||||
* this is used to send the content of "list_transport" to any
|
||||
* number of client connections that want it through a single
|
||||
* live TCP connection
|
||||
*/
|
||||
typedef struct device_tracker device_tracker;
|
||||
struct device_tracker {
|
||||
asocket socket;
|
||||
int update_needed;
|
||||
device_tracker* next;
|
||||
};
|
||||
|
||||
/* linked list of all device trackers */
|
||||
static device_tracker* device_tracker_list;
|
||||
|
||||
static void
|
||||
device_tracker_remove( device_tracker* tracker )
|
||||
{
|
||||
device_tracker** pnode = &device_tracker_list;
|
||||
device_tracker* node = *pnode;
|
||||
|
||||
adb_mutex_lock( &transport_lock );
|
||||
while (node) {
|
||||
if (node == tracker) {
|
||||
*pnode = node->next;
|
||||
break;
|
||||
}
|
||||
pnode = &node->next;
|
||||
node = *pnode;
|
||||
}
|
||||
adb_mutex_unlock( &transport_lock );
|
||||
}
|
||||
|
||||
static void
|
||||
device_tracker_close( asocket* socket )
|
||||
{
|
||||
device_tracker* tracker = (device_tracker*) socket;
|
||||
asocket* peer = socket->peer;
|
||||
|
||||
D( "device tracker %p removed\n", tracker);
|
||||
if (peer) {
|
||||
peer->peer = NULL;
|
||||
peer->close(peer);
|
||||
}
|
||||
device_tracker_remove(tracker);
|
||||
free(tracker);
|
||||
}
|
||||
|
||||
static int
|
||||
device_tracker_enqueue( asocket* socket, apacket* p )
|
||||
{
|
||||
/* you can't read from a device tracker, close immediately */
|
||||
put_apacket(p);
|
||||
device_tracker_close(socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
device_tracker_send( device_tracker* tracker,
|
||||
const char* buffer,
|
||||
int len )
|
||||
{
|
||||
apacket* p = get_apacket();
|
||||
asocket* peer = tracker->socket.peer;
|
||||
|
||||
memcpy(p->data, buffer, len);
|
||||
p->len = len;
|
||||
return peer->enqueue( peer, p );
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
device_tracker_ready( asocket* socket )
|
||||
{
|
||||
device_tracker* tracker = (device_tracker*) socket;
|
||||
|
||||
/* we want to send the device list when the tracker connects
|
||||
* for the first time, even if no update occured */
|
||||
if (tracker->update_needed > 0) {
|
||||
char buffer[1024];
|
||||
int len;
|
||||
|
||||
tracker->update_needed = 0;
|
||||
|
||||
len = list_transports_msg(buffer, sizeof(buffer));
|
||||
device_tracker_send(tracker, buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
asocket*
|
||||
create_device_tracker(void)
|
||||
{
|
||||
device_tracker* tracker = calloc(1,sizeof(*tracker));
|
||||
|
||||
if(tracker == 0) fatal("cannot allocate device tracker");
|
||||
|
||||
D( "device tracker %p created\n", tracker);
|
||||
|
||||
tracker->socket.enqueue = device_tracker_enqueue;
|
||||
tracker->socket.ready = device_tracker_ready;
|
||||
tracker->socket.close = device_tracker_close;
|
||||
tracker->update_needed = 1;
|
||||
|
||||
tracker->next = device_tracker_list;
|
||||
device_tracker_list = tracker;
|
||||
|
||||
return &tracker->socket;
|
||||
}
|
||||
|
||||
|
||||
/* call this function each time the transport list has changed */
|
||||
void update_transports(void)
|
||||
{
|
||||
char buffer[1024];
|
||||
int len;
|
||||
device_tracker* tracker;
|
||||
|
||||
len = list_transports_msg(buffer, sizeof(buffer));
|
||||
|
||||
tracker = device_tracker_list;
|
||||
while (tracker != NULL) {
|
||||
device_tracker* next = tracker->next;
|
||||
/* note: this may destroy the tracker if the connection is closed */
|
||||
device_tracker_send(tracker, buffer, len);
|
||||
tracker = next;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void update_transports(void)
|
||||
{
|
||||
// nothing to do on the device side
|
||||
}
|
||||
#endif // ADB_HOST
|
||||
|
||||
typedef struct tmsg tmsg;
|
||||
struct tmsg
|
||||
|
@ -822,64 +678,6 @@ retry:
|
|||
return result;
|
||||
}
|
||||
|
||||
#if ADB_HOST
|
||||
static const char *statename(atransport *t)
|
||||
{
|
||||
switch(t->connection_state){
|
||||
case CS_OFFLINE: return "offline";
|
||||
case CS_BOOTLOADER: return "bootloader";
|
||||
case CS_DEVICE: return "device";
|
||||
case CS_HOST: return "host";
|
||||
case CS_RECOVERY: return "recovery";
|
||||
case CS_SIDELOAD: return "sideload";
|
||||
case CS_NOPERM: return "no permissions";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
int list_transports(char *buf, size_t bufsize)
|
||||
{
|
||||
char* p = buf;
|
||||
char* end = buf + bufsize;
|
||||
int len;
|
||||
atransport *t;
|
||||
|
||||
/* XXX OVERRUN PROBLEMS XXX */
|
||||
adb_mutex_lock(&transport_lock);
|
||||
for(t = transport_list.next; t != &transport_list; t = t->next) {
|
||||
const char* serial = t->serial;
|
||||
if (!serial || !serial[0])
|
||||
serial = "????????????";
|
||||
len = snprintf(p, end - p, "%s\t%s\n", serial, statename(t));
|
||||
|
||||
if (p + len >= end) {
|
||||
/* discard last line if buffer is too short */
|
||||
break;
|
||||
}
|
||||
p += len;
|
||||
}
|
||||
p[0] = 0;
|
||||
adb_mutex_unlock(&transport_lock);
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
|
||||
/* hack for osx */
|
||||
void close_usb_devices()
|
||||
{
|
||||
atransport *t;
|
||||
|
||||
adb_mutex_lock(&transport_lock);
|
||||
for(t = transport_list.next; t != &transport_list; t = t->next) {
|
||||
if ( !t->kicked ) {
|
||||
t->kicked = 1;
|
||||
t->kick(t);
|
||||
}
|
||||
}
|
||||
adb_mutex_unlock(&transport_lock);
|
||||
}
|
||||
#endif // ADB_HOST
|
||||
|
||||
void register_socket_transport(int s, const char *serial, int port, int local)
|
||||
{
|
||||
atransport *t = calloc(1, sizeof(atransport));
|
||||
|
@ -901,61 +699,6 @@ void register_socket_transport(int s, const char *serial, int port, int local)
|
|||
register_transport(t);
|
||||
}
|
||||
|
||||
#if ADB_HOST
|
||||
atransport *find_transport(const char *serial)
|
||||
{
|
||||
atransport *t;
|
||||
|
||||
adb_mutex_lock(&transport_lock);
|
||||
for(t = transport_list.next; t != &transport_list; t = t->next) {
|
||||
if (t->serial && !strcmp(serial, t->serial)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
adb_mutex_unlock(&transport_lock);
|
||||
|
||||
if (t != &transport_list)
|
||||
return t;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void unregister_transport(atransport *t)
|
||||
{
|
||||
adb_mutex_lock(&transport_lock);
|
||||
t->next->prev = t->prev;
|
||||
t->prev->next = t->next;
|
||||
adb_mutex_unlock(&transport_lock);
|
||||
|
||||
kick_transport(t);
|
||||
transport_unref(t);
|
||||
}
|
||||
|
||||
// unregisters all non-emulator TCP transports
|
||||
void unregister_all_tcp_transports()
|
||||
{
|
||||
atransport *t, *next;
|
||||
adb_mutex_lock(&transport_lock);
|
||||
for (t = transport_list.next; t != &transport_list; t = next) {
|
||||
next = t->next;
|
||||
if (t->type == kTransportLocal && t->adb_port == 0) {
|
||||
t->next->prev = t->prev;
|
||||
t->prev->next = next;
|
||||
// we cannot call kick_transport when holding transport_lock
|
||||
if (!t->kicked)
|
||||
{
|
||||
t->kicked = 1;
|
||||
t->kick(t);
|
||||
}
|
||||
transport_unref_locked(t);
|
||||
}
|
||||
}
|
||||
|
||||
adb_mutex_unlock(&transport_lock);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable)
|
||||
{
|
||||
atransport *t = calloc(1, sizeof(atransport));
|
||||
|
|
|
@ -23,10 +23,6 @@
|
|||
#define TRACE_TAG TRACE_TRANSPORT
|
||||
#include "adb.h"
|
||||
|
||||
#if ADB_HOST
|
||||
#include "usb_vendors.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BIG_ENDIAN
|
||||
#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
|
||||
static inline void fix_endians(apacket *p)
|
||||
|
@ -121,28 +117,5 @@ void init_usb_transport(atransport *t, usb_handle *h, int state)
|
|||
t->type = kTransportUsb;
|
||||
t->usb = h;
|
||||
|
||||
#if ADB_HOST
|
||||
HOST = 1;
|
||||
#else
|
||||
HOST = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ADB_HOST
|
||||
int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < vendorIdCount; i++) {
|
||||
if (vid == vendorIds[i]) {
|
||||
if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS &&
|
||||
usb_protocol == ADB_PROTOCOL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue