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:
Doug Zongker 2012-03-19 15:52:03 -07:00
parent 45fdb3899d
commit 48704798ea
9 changed files with 40 additions and 1171 deletions

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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));

View file

@ -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