Merge "adb: fix subprocess exit handling, oom adjust fixes, extra debugging."
This commit is contained in:
commit
bab2c6a883
26
adb/adb.c
26
adb/adb.c
|
@ -36,6 +36,9 @@
|
|||
#include "usb_vendors.h"
|
||||
#endif
|
||||
|
||||
#if ADB_TRACE
|
||||
ADB_MUTEX_DEFINE( D_lock );
|
||||
#endif
|
||||
|
||||
int HOST = 0;
|
||||
|
||||
|
@ -90,6 +93,7 @@ void adb_trace_init(void)
|
|||
{ "sysdeps", TRACE_SYSDEPS },
|
||||
{ "transport", TRACE_TRANSPORT },
|
||||
{ "jdwp", TRACE_JDWP },
|
||||
{ "services", TRACE_SERVICES },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
|
@ -591,14 +595,6 @@ nomem:
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_FORKEXEC
|
||||
static void sigchld_handler(int n)
|
||||
{
|
||||
int status;
|
||||
while(waitpid(-1, &status, WNOHANG) > 0) ;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WIN32_PROC
|
||||
static BOOL WINAPI ctrlc_handler(DWORD type)
|
||||
{
|
||||
|
@ -641,6 +637,7 @@ void start_logging(void)
|
|||
|
||||
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) {
|
||||
|
@ -648,6 +645,7 @@ void start_logging(void)
|
|||
}
|
||||
dup2(fd, 1);
|
||||
dup2(fd, 2);
|
||||
adb_close(fd);
|
||||
fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
|
||||
#endif
|
||||
}
|
||||
|
@ -807,9 +805,10 @@ int launch_server(int server_port)
|
|||
// 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", errno);
|
||||
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') {
|
||||
|
@ -848,7 +847,7 @@ int adb_main(int is_daemon, int server_port)
|
|||
#ifdef HAVE_WIN32_PROC
|
||||
SetConsoleCtrlHandler( ctrlc_handler, TRUE );
|
||||
#elif defined(HAVE_FORKEXEC)
|
||||
signal(SIGCHLD, sigchld_handler);
|
||||
// No SIGCHLD. Let the service subproc handle its children.
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
|
@ -957,7 +956,9 @@ int adb_main(int is_daemon, int server_port)
|
|||
// listen on default port
|
||||
local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
|
||||
}
|
||||
D("adb_main(): pre init_jdwp()\n");
|
||||
init_jdwp();
|
||||
D("adb_main(): post init_jdwp()\n");
|
||||
#endif
|
||||
|
||||
if (is_daemon)
|
||||
|
@ -971,6 +972,7 @@ int adb_main(int is_daemon, int server_port)
|
|||
#endif
|
||||
start_logging();
|
||||
}
|
||||
D("Event loop starting\n");
|
||||
|
||||
fdevent_loop();
|
||||
|
||||
|
@ -1269,8 +1271,9 @@ int recovery_mode = 0;
|
|||
int main(int argc, char **argv)
|
||||
{
|
||||
#if ADB_HOST
|
||||
adb_trace_init();
|
||||
adb_sysdeps_init();
|
||||
adb_trace_init();
|
||||
D("Handling commandline()\n");
|
||||
return adb_commandline(argc - 1, argv + 1);
|
||||
#else
|
||||
if((argc > 1) && (!strcmp(argv[1],"recovery"))) {
|
||||
|
@ -1279,6 +1282,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
start_device_log();
|
||||
D("Handling main()\n");
|
||||
return adb_main(0, DEFAULT_ADB_PORT);
|
||||
#endif
|
||||
}
|
||||
|
|
47
adb/adb.h
47
adb/adb.h
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include <limits.h>
|
||||
|
||||
#include "transport.h" /* readx(), writex() */
|
||||
|
||||
#define MAX_PAYLOAD 4096
|
||||
|
||||
#define A_SYNC 0x434e5953
|
||||
|
@ -315,13 +317,6 @@ void put_apacket(apacket *p);
|
|||
int check_header(apacket *p);
|
||||
int check_data(apacket *p);
|
||||
|
||||
/* convenience wrappers around read/write that will retry on
|
||||
** EINTR and/or short read/write. Returns 0 on success, -1
|
||||
** on error or EOF.
|
||||
*/
|
||||
int readx(int fd, void *ptr, size_t len);
|
||||
int writex(int fd, const void *ptr, size_t len);
|
||||
|
||||
/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
|
||||
|
||||
#define ADB_TRACE 1
|
||||
|
@ -331,33 +326,56 @@ int writex(int fd, const void *ptr, size_t len);
|
|||
* the adb_trace_init() function implemented in adb.c
|
||||
*/
|
||||
typedef enum {
|
||||
TRACE_ADB = 0,
|
||||
TRACE_ADB = 0, /* 0x001 */
|
||||
TRACE_SOCKETS,
|
||||
TRACE_PACKETS,
|
||||
TRACE_TRANSPORT,
|
||||
TRACE_RWX,
|
||||
TRACE_RWX, /* 0x010 */
|
||||
TRACE_USB,
|
||||
TRACE_SYNC,
|
||||
TRACE_SYSDEPS,
|
||||
TRACE_JDWP,
|
||||
TRACE_JDWP, /* 0x100 */
|
||||
TRACE_SERVICES,
|
||||
} AdbTrace;
|
||||
|
||||
#if ADB_TRACE
|
||||
|
||||
int adb_trace_mask;
|
||||
|
||||
extern int adb_trace_mask;
|
||||
extern unsigned char adb_trace_output_count;
|
||||
void adb_trace_init(void);
|
||||
|
||||
# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
|
||||
|
||||
/* you must define TRACE_TAG before using this macro */
|
||||
#define D(...) \
|
||||
# define D(...) \
|
||||
do { \
|
||||
if (ADB_TRACING) \
|
||||
if (ADB_TRACING) { \
|
||||
int save_errno = errno; \
|
||||
adb_mutex_lock(&D_lock); \
|
||||
fprintf(stderr, "%s::%s():", \
|
||||
__FILE__, __FUNCTION__); \
|
||||
errno = save_errno; \
|
||||
fprintf(stderr, __VA_ARGS__ ); \
|
||||
fflush(stderr); \
|
||||
adb_mutex_unlock(&D_lock); \
|
||||
errno = save_errno; \
|
||||
} \
|
||||
} while (0)
|
||||
# define DR(...) \
|
||||
do { \
|
||||
if (ADB_TRACING) { \
|
||||
int save_errno = errno; \
|
||||
adb_mutex_lock(&D_lock); \
|
||||
errno = save_errno; \
|
||||
fprintf(stderr, __VA_ARGS__ ); \
|
||||
fflush(stderr); \
|
||||
adb_mutex_unlock(&D_lock); \
|
||||
errno = save_errno; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
# define D(...) ((void)0)
|
||||
# define DR(...) ((void)0)
|
||||
# define ADB_TRACING 0
|
||||
#endif
|
||||
|
||||
|
@ -413,6 +431,7 @@ int connection_state(atransport *t);
|
|||
#define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */
|
||||
|
||||
extern int HOST;
|
||||
extern int SHELL_EXIT_NOTIFY_FD;
|
||||
|
||||
#define CHUNK_SIZE (64*1024)
|
||||
|
||||
|
|
|
@ -202,6 +202,7 @@ int _adb_connect(const char *service)
|
|||
return -1;
|
||||
}
|
||||
|
||||
D("_adb_connect: return fd %d\n", fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
@ -210,6 +211,7 @@ int adb_connect(const char *service)
|
|||
// first query the adb server's version
|
||||
int fd = _adb_connect("host:version");
|
||||
|
||||
D("adb_connect: service %s\n", service);
|
||||
if(fd == -2) {
|
||||
fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
|
||||
__adb_server_port);
|
||||
|
@ -266,6 +268,7 @@ int adb_connect(const char *service)
|
|||
if(fd == -2) {
|
||||
fprintf(stderr,"** daemon still not running");
|
||||
}
|
||||
D("adb_connect: return fd %d\n", fd);
|
||||
|
||||
return fd;
|
||||
error:
|
||||
|
|
|
@ -37,12 +37,6 @@
|
|||
#include "adb_client.h"
|
||||
#include "file_sync_service.h"
|
||||
|
||||
enum {
|
||||
IGNORE_DATA,
|
||||
WIPE_DATA,
|
||||
FLASH_DATA
|
||||
};
|
||||
|
||||
static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
|
||||
|
||||
void get_my_path(char *s, size_t maxLen);
|
||||
|
@ -138,11 +132,6 @@ void help()
|
|||
" adb help - show this help message\n"
|
||||
" adb version - show version num\n"
|
||||
"\n"
|
||||
"DATAOPTS:\n"
|
||||
" (no option) - don't touch the data partition\n"
|
||||
" -w - wipe the data partition\n"
|
||||
" -d - flash the data partition\n"
|
||||
"\n"
|
||||
"scripting:\n"
|
||||
" adb wait-for-device - block until device is online\n"
|
||||
" adb start-server - ensure that there is a server running\n"
|
||||
|
@ -218,7 +207,9 @@ static void read_and_dump(int fd)
|
|||
int len;
|
||||
|
||||
while(fd >= 0) {
|
||||
D("read_and_dump(): pre adb_read(fd=%d)\n", fd);
|
||||
len = adb_read(fd, buf, 4096);
|
||||
D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len);
|
||||
if(len == 0) {
|
||||
break;
|
||||
}
|
||||
|
@ -246,7 +237,9 @@ static void *stdin_read_thread(void *x)
|
|||
|
||||
for(;;) {
|
||||
/* fdi is really the client's stdin, so use read, not adb_read here */
|
||||
D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
|
||||
r = unix_read(fdi, buf, 1024);
|
||||
D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
|
||||
if(r == 0) break;
|
||||
if(r < 0) {
|
||||
if(errno == EINTR) continue;
|
||||
|
@ -853,6 +846,7 @@ top:
|
|||
}
|
||||
|
||||
if(argc < 2) {
|
||||
D("starting interactive shell\n");
|
||||
r = interactive_shell();
|
||||
if (h) {
|
||||
printf("\x1b[0m");
|
||||
|
@ -877,9 +871,12 @@ top:
|
|||
}
|
||||
|
||||
for(;;) {
|
||||
D("interactive shell loop. buff=%s\n", buf);
|
||||
fd = adb_connect(buf);
|
||||
if(fd >= 0) {
|
||||
D("about to read_and_dump(fd=%d)\n", fd);
|
||||
read_and_dump(fd);
|
||||
D("read_and_dump() done.\n");
|
||||
adb_close(fd);
|
||||
r = 0;
|
||||
} else {
|
||||
|
@ -896,6 +893,7 @@ top:
|
|||
printf("\x1b[0m");
|
||||
fflush(stdout);
|
||||
}
|
||||
D("interactive shell loop. return r=%d\n", r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
|
241
adb/fdevent.c
241
adb/fdevent.c
|
@ -15,6 +15,8 @@
|
|||
** limitations under the License.
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -27,10 +29,20 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#include "fdevent.h"
|
||||
#include "transport.h"
|
||||
#include "sysdeps.h"
|
||||
|
||||
#define TRACE(x...) fprintf(stderr,x)
|
||||
|
||||
#define DEBUG 0
|
||||
/* !!! Do not enable DEBUG for the adb that will run as the server:
|
||||
** both stdout and stderr are used to communicate between the client
|
||||
** and server. Any extra output will cause failures.
|
||||
*/
|
||||
#define DEBUG 0 /* non-0 will break adb server */
|
||||
|
||||
// This socket is used when a subproc shell service exists.
|
||||
// It wakes up the fdevent_loop() and cause the correct handling
|
||||
// of the shell's pseudo-tty master. I.e. force close it.
|
||||
int SHELL_EXIT_NOTIFY_FD = -1;
|
||||
|
||||
static void fatal(const char *fn, const char *fmt, ...)
|
||||
{
|
||||
|
@ -45,15 +57,28 @@ static void fatal(const char *fn, const char *fmt, ...)
|
|||
#define FATAL(x...) fatal(__FUNCTION__, x)
|
||||
|
||||
#if DEBUG
|
||||
#define D(...) \
|
||||
do { \
|
||||
adb_mutex_lock(&D_lock); \
|
||||
int save_errno = errno; \
|
||||
fprintf(stderr, "%s::%s():", __FILE__, __FUNCTION__); \
|
||||
errno = save_errno; \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
adb_mutex_unlock(&D_lock); \
|
||||
errno = save_errno; \
|
||||
} while(0)
|
||||
static void dump_fde(fdevent *fde, const char *info)
|
||||
{
|
||||
adb_mutex_lock(&D_lock);
|
||||
fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
|
||||
fde->state & FDE_READ ? 'R' : ' ',
|
||||
fde->state & FDE_WRITE ? 'W' : ' ',
|
||||
fde->state & FDE_ERROR ? 'E' : ' ',
|
||||
info);
|
||||
adb_mutex_unlock(&D_lock);
|
||||
}
|
||||
#else
|
||||
#define D(...) ((void)0)
|
||||
#define dump_fde(fde, info) do { } while(0)
|
||||
#endif
|
||||
|
||||
|
@ -67,6 +92,7 @@ static void dump_fde(fdevent *fde, const char *info)
|
|||
static void fdevent_plist_enqueue(fdevent *node);
|
||||
static void fdevent_plist_remove(fdevent *node);
|
||||
static fdevent *fdevent_plist_dequeue(void);
|
||||
static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata);
|
||||
|
||||
static fdevent list_pending = {
|
||||
.next = &list_pending,
|
||||
|
@ -270,9 +296,72 @@ static void fdevent_update(fdevent *fde, unsigned events)
|
|||
FD_CLR(fde->fd, &error_fds);
|
||||
}
|
||||
|
||||
fde->state = (fde->state & FDE_STATEMASK) | events;
|
||||
fde->state = (fde->state & FDE_STATEMASK) | events;
|
||||
}
|
||||
|
||||
/* Looks at fd_table[] for bad FDs and sets bit in fds.
|
||||
** Returns the number of bad FDs.
|
||||
*/
|
||||
static int fdevent_fd_check(fd_set *fds)
|
||||
{
|
||||
int i, n = 0;
|
||||
fdevent *fde;
|
||||
|
||||
for(i = 0; i < select_n; i++) {
|
||||
fde = fd_table[i];
|
||||
if(fde == 0) continue;
|
||||
if(fcntl(i, F_GETFL, NULL) < 0) {
|
||||
FD_SET(i, fds);
|
||||
n++;
|
||||
// fde->state |= FDE_DONT_CLOSE;
|
||||
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
static inline void dump_all_fds(const char *extra_msg) {}
|
||||
#else
|
||||
static void dump_all_fds(const char *extra_msg)
|
||||
{
|
||||
int i;
|
||||
fdevent *fde;
|
||||
// per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank
|
||||
char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff;
|
||||
size_t max_chars = FD_SETSIZE * 6 + 1;
|
||||
int printed_out;
|
||||
#define SAFE_SPRINTF(...) \
|
||||
do { \
|
||||
printed_out = snprintf(pb, max_chars, __VA_ARGS__); \
|
||||
if (printed_out <= 0) { \
|
||||
D("... snprintf failed.\n"); \
|
||||
return; \
|
||||
} \
|
||||
if (max_chars < (unsigned int)printed_out) { \
|
||||
D("... snprintf out of space.\n"); \
|
||||
return; \
|
||||
} \
|
||||
pb += printed_out; \
|
||||
max_chars -= printed_out; \
|
||||
} while(0)
|
||||
|
||||
for(i = 0; i < select_n; i++) {
|
||||
fde = fd_table[i];
|
||||
SAFE_SPRINTF("%d", i);
|
||||
if(fde == 0) {
|
||||
SAFE_SPRINTF("? ");
|
||||
continue;
|
||||
}
|
||||
if(fcntl(i, F_GETFL, NULL) < 0) {
|
||||
SAFE_SPRINTF("b");
|
||||
}
|
||||
SAFE_SPRINTF(" ");
|
||||
}
|
||||
D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void fdevent_process()
|
||||
{
|
||||
int i, n;
|
||||
|
@ -284,28 +373,49 @@ static void fdevent_process()
|
|||
memcpy(&wfd, &write_fds, sizeof(fd_set));
|
||||
memcpy(&efd, &error_fds, sizeof(fd_set));
|
||||
|
||||
n = select(select_n, &rfd, &wfd, &efd, 0);
|
||||
dump_all_fds("pre select()");
|
||||
|
||||
n = select(select_n, &rfd, &wfd, &efd, NULL);
|
||||
int saved_errno = errno;
|
||||
D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0);
|
||||
|
||||
dump_all_fds("post select()");
|
||||
|
||||
if(n < 0) {
|
||||
if(errno == EINTR) return;
|
||||
perror("select");
|
||||
return;
|
||||
switch(saved_errno) {
|
||||
case EINTR: return;
|
||||
case EBADF:
|
||||
// Can't trust the FD sets after an error.
|
||||
FD_ZERO(&wfd);
|
||||
FD_ZERO(&efd);
|
||||
FD_ZERO(&rfd);
|
||||
break;
|
||||
default:
|
||||
D("Unexpected select() error=%d\n", saved_errno);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(n <= 0) {
|
||||
// We fake a read, as the rest of the code assumes
|
||||
// that errors will be detected at that point.
|
||||
n = fdevent_fd_check(&rfd);
|
||||
}
|
||||
|
||||
for(i = 0; (i < select_n) && (n > 0); i++) {
|
||||
events = 0;
|
||||
if(FD_ISSET(i, &rfd)) events |= FDE_READ;
|
||||
if(FD_ISSET(i, &wfd)) events |= FDE_WRITE;
|
||||
if(FD_ISSET(i, &efd)) events |= FDE_ERROR;
|
||||
if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; }
|
||||
if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; }
|
||||
if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; }
|
||||
|
||||
if(events) {
|
||||
n--;
|
||||
|
||||
fde = fd_table[i];
|
||||
if(fde == 0) FATAL("missing fde for fd %d\n", i);
|
||||
if(fde == 0)
|
||||
FATAL("missing fde for fd %d\n", i);
|
||||
|
||||
fde->events |= events;
|
||||
|
||||
D("got events fde->fd=%d events=%04x, state=%04x\n",
|
||||
fde->fd, fde->events, fde->state);
|
||||
if(fde->state & FDE_PENDING) continue;
|
||||
fde->state |= FDE_PENDING;
|
||||
fdevent_plist_enqueue(fde);
|
||||
|
@ -350,14 +460,14 @@ static void fdevent_unregister(fdevent *fde)
|
|||
}
|
||||
|
||||
if(fd_table[fde->fd] != fde) {
|
||||
FATAL("fd_table out of sync");
|
||||
FATAL("fd_table out of sync [%d]\n", fde->fd);
|
||||
}
|
||||
|
||||
fd_table[fde->fd] = 0;
|
||||
|
||||
if(!(fde->state & FDE_DONT_CLOSE)) {
|
||||
dump_fde(fde, "close");
|
||||
close(fde->fd);
|
||||
adb_close(fde->fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -394,6 +504,74 @@ static fdevent *fdevent_plist_dequeue(void)
|
|||
return node;
|
||||
}
|
||||
|
||||
static void fdevent_call_fdfunc(fdevent* fde)
|
||||
{
|
||||
unsigned events = fde->events;
|
||||
fde->events = 0;
|
||||
if(!(fde->state & FDE_PENDING)) return;
|
||||
fde->state &= (~FDE_PENDING);
|
||||
dump_fde(fde, "callback");
|
||||
fde->func(fde->fd, events, fde->arg);
|
||||
}
|
||||
|
||||
static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata)
|
||||
{
|
||||
|
||||
D("subproc handling on fd=%d ev=%04x\n", fd, ev);
|
||||
|
||||
// Hook oneself back into the fde's suitable for select() on read.
|
||||
if((fd < 0) || (fd >= fd_table_max)) {
|
||||
FATAL("fd %d out of range for fd_table \n", fd);
|
||||
}
|
||||
fdevent *fde = fd_table[fd];
|
||||
fdevent_add(fde, FDE_READ);
|
||||
|
||||
if(ev & FDE_READ){
|
||||
int subproc_fd;
|
||||
|
||||
if(readx(fd, &subproc_fd, sizeof(subproc_fd))) {
|
||||
FATAL("Failed to read the subproc's fd from fd=%d\n", fd);
|
||||
}
|
||||
if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) {
|
||||
D("subproc_fd %d out of range 0, fd_table_max=%d\n",
|
||||
subproc_fd, fd_table_max);
|
||||
return;
|
||||
}
|
||||
fdevent *subproc_fde = fd_table[subproc_fd];
|
||||
if(!subproc_fde) {
|
||||
D("subproc_fd %d cleared from fd_table\n", subproc_fd);
|
||||
return;
|
||||
}
|
||||
if(subproc_fde->fd != subproc_fd) {
|
||||
// Already reallocated?
|
||||
D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd);
|
||||
return;
|
||||
}
|
||||
|
||||
subproc_fde->force_eof = 1;
|
||||
|
||||
int rcount = 0;
|
||||
ioctl(subproc_fd, TIOCINQ, &rcount);
|
||||
D("subproc with fd=%d has rcount=%d err=%d\n",
|
||||
subproc_fd, rcount, errno);
|
||||
|
||||
if(rcount) {
|
||||
// If there is data left, it will show up in the select().
|
||||
// This works because there is no other thread reading that
|
||||
// data when in this fd_func().
|
||||
return;
|
||||
}
|
||||
|
||||
D("subproc_fde.state=%04x\n", subproc_fde->state);
|
||||
subproc_fde->events |= FDE_READ;
|
||||
if(subproc_fde->state & FDE_PENDING) {
|
||||
return;
|
||||
}
|
||||
subproc_fde->state |= FDE_PENDING;
|
||||
fdevent_call_fdfunc(subproc_fde);
|
||||
}
|
||||
}
|
||||
|
||||
fdevent *fdevent_create(int fd, fd_func func, void *arg)
|
||||
{
|
||||
fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
|
||||
|
@ -412,11 +590,12 @@ void fdevent_destroy(fdevent *fde)
|
|||
fdevent_remove(fde);
|
||||
}
|
||||
|
||||
void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
|
||||
void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
|
||||
{
|
||||
memset(fde, 0, sizeof(fdevent));
|
||||
fde->state = FDE_ACTIVE;
|
||||
fde->fd = fd;
|
||||
fde->force_eof = 0;
|
||||
fde->func = func;
|
||||
fde->arg = arg;
|
||||
|
||||
|
@ -437,7 +616,7 @@ void fdevent_remove(fdevent *fde)
|
|||
|
||||
if(fde->state & FDE_ACTIVE) {
|
||||
fdevent_disconnect(fde);
|
||||
dump_fde(fde, "disconnect");
|
||||
dump_fde(fde, "disconnect");
|
||||
fdevent_unregister(fde);
|
||||
}
|
||||
|
||||
|
@ -484,23 +663,33 @@ void fdevent_del(fdevent *fde, unsigned events)
|
|||
fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
|
||||
}
|
||||
|
||||
void fdevent_subproc_setup()
|
||||
{
|
||||
int s[2];
|
||||
|
||||
if(adb_socketpair(s)) {
|
||||
FATAL("cannot create shell-exit socket-pair\n");
|
||||
}
|
||||
SHELL_EXIT_NOTIFY_FD = s[0];
|
||||
fdevent *fde;
|
||||
fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
|
||||
if(!fde)
|
||||
FATAL("cannot create fdevent for shell-exit handler\n");
|
||||
fdevent_add(fde, FDE_READ);
|
||||
}
|
||||
|
||||
void fdevent_loop()
|
||||
{
|
||||
fdevent *fde;
|
||||
fdevent_subproc_setup();
|
||||
|
||||
for(;;) {
|
||||
#if DEBUG
|
||||
fprintf(stderr,"--- ---- waiting for events\n");
|
||||
#endif
|
||||
D("--- ---- waiting for events\n");
|
||||
|
||||
fdevent_process();
|
||||
|
||||
while((fde = fdevent_plist_dequeue())) {
|
||||
unsigned events = fde->events;
|
||||
fde->events = 0;
|
||||
fde->state &= (~FDE_PENDING);
|
||||
dump_fde(fde, "callback");
|
||||
fde->func(fde->fd, events, fde->arg);
|
||||
fdevent_call_fdfunc(fde);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,8 @@ struct fdevent
|
|||
fdevent *prev;
|
||||
|
||||
int fd;
|
||||
int force_eof;
|
||||
|
||||
unsigned short state;
|
||||
unsigned short events;
|
||||
|
||||
|
|
|
@ -641,8 +641,9 @@ static int local_build_list(copyinfo **filelist,
|
|||
} else {
|
||||
ci = mkcopyinfo(lpath, rpath, name, 0);
|
||||
if(lstat(ci->src, &st)) {
|
||||
closedir(d);
|
||||
fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
|
||||
closedir(d);
|
||||
|
||||
return -1;
|
||||
}
|
||||
if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
|
||||
|
|
|
@ -193,9 +193,11 @@ static int handle_send_file(int s, char *path, mode_t mode, char *buffer)
|
|||
if(fd < 0)
|
||||
continue;
|
||||
if(writex(fd, buffer, len)) {
|
||||
int saved_errno = errno;
|
||||
adb_close(fd);
|
||||
adb_unlink(path);
|
||||
fd = -1;
|
||||
errno = saved_errno;
|
||||
if(fail_errno(s)) return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
/* the list of mutexes used by addb */
|
||||
/* the list of mutexes used by adb */
|
||||
/* #ifndef __MUTEX_LIST_H
|
||||
* Do not use an include-guard. This file is included once to declare the locks
|
||||
* and once in win32 to actually do the runtime initialization.
|
||||
*/
|
||||
#ifndef ADB_MUTEX
|
||||
#error ADB_MUTEX not defined when including this file
|
||||
#endif
|
||||
|
||||
ADB_MUTEX(dns_lock)
|
||||
ADB_MUTEX(socket_list_lock)
|
||||
ADB_MUTEX(transport_lock)
|
||||
|
@ -11,4 +14,13 @@ ADB_MUTEX(local_transports_lock)
|
|||
#endif
|
||||
ADB_MUTEX(usb_lock)
|
||||
|
||||
// Sadly logging to /data/adb/adb-... is not thread safe.
|
||||
// After modifying adb.h::D() to count invocations:
|
||||
// DEBUG(jpa):0:Handling main()
|
||||
// DEBUG(jpa):1:[ usb_init - starting thread ]
|
||||
// (Oopsies, no :2:, and matching message is also gone.)
|
||||
// DEBUG(jpa):3:[ usb_thread - opening device ]
|
||||
// DEBUG(jpa):4:jdwp control socket started (10)
|
||||
ADB_MUTEX(D_lock)
|
||||
|
||||
#undef ADB_MUTEX
|
||||
|
|
116
adb/services.c
116
adb/services.c
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "sysdeps.h"
|
||||
|
||||
#define TRACE_TAG TRACE_ADB
|
||||
#define TRACE_TAG TRACE_SERVICES
|
||||
#include "adb.h"
|
||||
#include "file_sync_service.h"
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
|||
# ifndef HAVE_WINSOCK
|
||||
# include <netinet/in.h>
|
||||
# include <netdb.h>
|
||||
# include <sys/ioctl.h>
|
||||
# endif
|
||||
#else
|
||||
# include <cutils/android_reboot.h>
|
||||
|
@ -267,15 +268,16 @@ static int create_service_thread(void (*func)(int, void *), void *cookie)
|
|||
return s[0];
|
||||
}
|
||||
|
||||
static int create_subprocess(const char *cmd, const char *arg0, const char *arg1)
|
||||
#if !ADB_HOST
|
||||
static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
|
||||
{
|
||||
#ifdef HAVE_WIN32_PROC
|
||||
fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
|
||||
return -1;
|
||||
D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
|
||||
fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
|
||||
return -1;
|
||||
#else /* !HAVE_WIN32_PROC */
|
||||
char *devname;
|
||||
int ptm;
|
||||
pid_t pid;
|
||||
|
||||
ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
|
||||
if(ptm < 0){
|
||||
|
@ -287,22 +289,27 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1
|
|||
if(grantpt(ptm) || unlockpt(ptm) ||
|
||||
((devname = (char*) ptsname(ptm)) == 0)){
|
||||
printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
|
||||
adb_close(ptm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if(pid < 0) {
|
||||
*pid = fork();
|
||||
if(*pid < 0) {
|
||||
printf("- fork failed: %s -\n", strerror(errno));
|
||||
adb_close(ptm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pid == 0){
|
||||
if(*pid == 0){
|
||||
int pts;
|
||||
|
||||
setsid();
|
||||
|
||||
pts = unix_open(devname, O_RDWR);
|
||||
if(pts < 0) exit(-1);
|
||||
if(pts < 0) {
|
||||
fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
dup2(pts, 0);
|
||||
dup2(pts, 1);
|
||||
|
@ -311,15 +318,9 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1
|
|||
adb_close(pts);
|
||||
adb_close(ptm);
|
||||
|
||||
execl(cmd, cmd, arg0, arg1, NULL);
|
||||
fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
|
||||
cmd, strerror(errno), errno);
|
||||
exit(-1);
|
||||
} else {
|
||||
#if !ADB_HOST
|
||||
// set child's OOM adjustment to zero
|
||||
// set OOM adjustment to zero
|
||||
char text[64];
|
||||
snprintf(text, sizeof text, "/proc/%d/oom_adj", pid);
|
||||
snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
|
||||
int fd = adb_open(text, O_WRONLY);
|
||||
if (fd >= 0) {
|
||||
adb_write(fd, "0", 1);
|
||||
|
@ -327,11 +328,20 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1
|
|||
} else {
|
||||
D("adb: unable to open %s\n", text);
|
||||
}
|
||||
#endif
|
||||
execl(cmd, cmd, arg0, arg1, NULL);
|
||||
fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
|
||||
cmd, strerror(errno), errno);
|
||||
exit(-1);
|
||||
} else {
|
||||
// Don't set child's OOM adjustment to zero.
|
||||
// Let the child do it itself, as sometimes the parent starts
|
||||
// running before the child has a /proc/pid/oom_adj.
|
||||
// """adb: unable to open /proc/644/oom_adj""" seen in some logs.
|
||||
return ptm;
|
||||
}
|
||||
#endif /* !HAVE_WIN32_PROC */
|
||||
}
|
||||
#endif /* !ABD_HOST */
|
||||
|
||||
#if ADB_HOST
|
||||
#define SHELL_COMMAND "/bin/sh"
|
||||
|
@ -339,6 +349,70 @@ static int create_subprocess(const char *cmd, const char *arg0, const char *arg1
|
|||
#define SHELL_COMMAND "/system/bin/sh"
|
||||
#endif
|
||||
|
||||
#if !ADB_HOST
|
||||
static void subproc_waiter_service(int fd, void *cookie)
|
||||
{
|
||||
pid_t pid = (pid_t)cookie;
|
||||
|
||||
D("entered. fd=%d of pid=%d\n", fd, pid);
|
||||
for (;;) {
|
||||
int status;
|
||||
pid_t p = waitpid(pid, &status, 0);
|
||||
if (p == pid) {
|
||||
D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
|
||||
if (WIFSIGNALED(status)) {
|
||||
D("*** Killed by signal %d\n", WTERMSIG(status));
|
||||
break;
|
||||
} else if (!WIFEXITED(status)) {
|
||||
D("*** Didn't exit!!. status %d\n", status);
|
||||
break;
|
||||
} else if (WEXITSTATUS(status) >= 0) {
|
||||
D("*** Exit code %d\n", WEXITSTATUS(status));
|
||||
break;
|
||||
}
|
||||
}
|
||||
usleep(100000); // poll every 0.1 sec
|
||||
}
|
||||
D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
|
||||
if (SHELL_EXIT_NOTIFY_FD >=0) {
|
||||
int res;
|
||||
res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
|
||||
D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
|
||||
SHELL_EXIT_NOTIFY_FD, pid, res, errno);
|
||||
}
|
||||
}
|
||||
|
||||
static int create_subproc_thread(const char *name)
|
||||
{
|
||||
stinfo *sti;
|
||||
adb_thread_t t;
|
||||
int ret_fd;
|
||||
pid_t pid;
|
||||
if(name) {
|
||||
ret_fd = create_subprocess(SHELL_COMMAND, "-c", name, &pid);
|
||||
} else {
|
||||
ret_fd = create_subprocess(SHELL_COMMAND, "-", 0, &pid);
|
||||
}
|
||||
D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
|
||||
|
||||
sti = malloc(sizeof(stinfo));
|
||||
if(sti == 0) fatal("cannot allocate stinfo");
|
||||
sti->func = subproc_waiter_service;
|
||||
sti->cookie = (void*)pid;
|
||||
sti->fd = ret_fd;
|
||||
|
||||
if(adb_thread_create( &t, service_bootstrap_func, sti)){
|
||||
free(sti);
|
||||
adb_close(ret_fd);
|
||||
printf("cannot create service thread\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
|
||||
return ret_fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
int service_to_fd(const char *name)
|
||||
{
|
||||
int ret = -1;
|
||||
|
@ -389,14 +463,12 @@ int service_to_fd(const char *name)
|
|||
ret = create_jdwp_connection_fd(atoi(name+5));
|
||||
} else if (!strncmp(name, "log:", 4)) {
|
||||
ret = create_service_thread(log_service, get_log_file_path(name + 4));
|
||||
#endif
|
||||
} else if(!HOST && !strncmp(name, "shell:", 6)) {
|
||||
if(name[6]) {
|
||||
ret = create_subprocess(SHELL_COMMAND, "-c", name + 6);
|
||||
ret = create_subproc_thread(name + 6);
|
||||
} else {
|
||||
ret = create_subprocess(SHELL_COMMAND, "-", 0);
|
||||
ret = create_subproc_thread(0);
|
||||
}
|
||||
#if !ADB_HOST
|
||||
} else if(!strncmp(name, "sync:", 5)) {
|
||||
ret = create_service_thread(file_sync_service, NULL);
|
||||
} else if(!strncmp(name, "remount:", 8)) {
|
||||
|
|
|
@ -199,6 +199,7 @@ static void local_socket_close(asocket *s)
|
|||
static void local_socket_destroy(asocket *s)
|
||||
{
|
||||
apacket *p, *n;
|
||||
D("LS(%d): destroying fde.fd=%d\n", s->id, s->fde.fd);
|
||||
|
||||
/* IMPORTANT: the remove closes the fd
|
||||
** that belongs to this socket
|
||||
|
@ -218,7 +219,10 @@ static void local_socket_destroy(asocket *s)
|
|||
|
||||
static void local_socket_close_locked(asocket *s)
|
||||
{
|
||||
D("entered. LS(%d) fd=%d\n", s->id, s->fd);
|
||||
if(s->peer) {
|
||||
D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n",
|
||||
s->id, s->peer->id, s->peer->fd);
|
||||
s->peer->peer = 0;
|
||||
// tweak to avoid deadlock
|
||||
if (s->peer->close == local_socket_close)
|
||||
|
@ -243,6 +247,7 @@ static void local_socket_close_locked(asocket *s)
|
|||
s->closing = 1;
|
||||
fdevent_del(&s->fde, FDE_READ);
|
||||
remove_socket(s);
|
||||
D("LS(%d): put on socket_closing_list fd=%d\n", s->id, s->fd);
|
||||
insert_local_socket(s, &local_socket_closing_list);
|
||||
}
|
||||
|
||||
|
@ -250,6 +255,8 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s)
|
|||
{
|
||||
asocket *s = _s;
|
||||
|
||||
D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev);
|
||||
|
||||
/* put the FDE_WRITE processing before the FDE_READ
|
||||
** in order to simplify the code.
|
||||
*/
|
||||
|
@ -308,6 +315,7 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s)
|
|||
|
||||
while(avail > 0) {
|
||||
r = adb_read(fd, x, avail);
|
||||
D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%d\n", s->id, s->fd, r, r<0?errno:0, avail);
|
||||
if(r > 0) {
|
||||
avail -= r;
|
||||
x += r;
|
||||
|
@ -322,13 +330,15 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s)
|
|||
is_eof = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n",
|
||||
s->id, s->fd, r, is_eof, s->fde.force_eof);
|
||||
if((avail == MAX_PAYLOAD) || (s->peer == 0)) {
|
||||
put_apacket(p);
|
||||
} else {
|
||||
p->len = MAX_PAYLOAD - avail;
|
||||
|
||||
r = s->peer->enqueue(s->peer, p);
|
||||
D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r);
|
||||
|
||||
if(r < 0) {
|
||||
/* error return means they closed us as a side-effect
|
||||
|
@ -351,7 +361,7 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s)
|
|||
}
|
||||
}
|
||||
|
||||
if(is_eof) {
|
||||
if(s->fde.force_eof || is_eof) {
|
||||
s->close(s);
|
||||
}
|
||||
}
|
||||
|
@ -362,6 +372,8 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s)
|
|||
** bytes of readable data.
|
||||
*/
|
||||
// s->close(s);
|
||||
D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -370,11 +382,11 @@ asocket *create_local_socket(int fd)
|
|||
{
|
||||
asocket *s = calloc(1, sizeof(asocket));
|
||||
if (s == NULL) fatal("cannot allocate socket");
|
||||
install_local_socket(s);
|
||||
s->fd = fd;
|
||||
s->enqueue = local_socket_enqueue;
|
||||
s->ready = local_socket_ready;
|
||||
s->close = local_socket_close;
|
||||
install_local_socket(s);
|
||||
|
||||
fdevent_install(&s->fde, fd, local_socket_event_func, s);
|
||||
/* fdevent_add(&s->fde, FDE_ERROR); */
|
||||
|
@ -400,7 +412,7 @@ asocket *create_local_service_socket(const char *name)
|
|||
if(fd < 0) return 0;
|
||||
|
||||
s = create_local_socket(fd);
|
||||
D("LS(%d): bound to '%s'\n", s->id, name);
|
||||
D("LS(%d): bound to '%s' via %d\n", s->id, name, fd);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -430,7 +442,8 @@ typedef struct aremotesocket {
|
|||
|
||||
static int remote_socket_enqueue(asocket *s, apacket *p)
|
||||
{
|
||||
D("Calling remote_socket_enqueue\n");
|
||||
D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n",
|
||||
s->id, s->fd, s->peer->fd);
|
||||
p->msg.command = A_WRTE;
|
||||
p->msg.arg0 = s->peer->id;
|
||||
p->msg.arg1 = s->id;
|
||||
|
@ -441,7 +454,8 @@ static int remote_socket_enqueue(asocket *s, apacket *p)
|
|||
|
||||
static void remote_socket_ready(asocket *s)
|
||||
{
|
||||
D("Calling remote_socket_ready\n");
|
||||
D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d\n",
|
||||
s->id, s->fd, s->peer->fd);
|
||||
apacket *p = get_apacket();
|
||||
p->msg.command = A_OKAY;
|
||||
p->msg.arg0 = s->peer->id;
|
||||
|
@ -451,12 +465,15 @@ static void remote_socket_ready(asocket *s)
|
|||
|
||||
static void remote_socket_close(asocket *s)
|
||||
{
|
||||
D("Calling remote_socket_close\n");
|
||||
D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n",
|
||||
s->id, s->fd, s->peer?s->peer->fd:-1);
|
||||
apacket *p = get_apacket();
|
||||
p->msg.command = A_CLSE;
|
||||
if(s->peer) {
|
||||
p->msg.arg0 = s->peer->id;
|
||||
s->peer->peer = 0;
|
||||
D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n",
|
||||
s->id, s->peer->id, s->peer->fd);
|
||||
s->peer->close(s->peer);
|
||||
}
|
||||
p->msg.arg1 = s->id;
|
||||
|
@ -501,7 +518,7 @@ asocket *create_remote_socket(unsigned id, atransport *t)
|
|||
|
||||
void connect_to_remote(asocket *s, const char *destination)
|
||||
{
|
||||
D("Connect_to_remote call \n");
|
||||
D("Connect_to_remote call RS(%d) fd=%d\n", s->id, s->fd);
|
||||
apacket *p = get_apacket();
|
||||
int len = strlen(destination) + 1;
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ typedef CRITICAL_SECTION adb_mutex_t;
|
|||
#define ADB_MUTEX_DEFINE(x) adb_mutex_t x
|
||||
|
||||
/* declare all mutexes */
|
||||
/* For win32, adb_sysdeps_init() will do the mutex runtime initialization. */
|
||||
#define ADB_MUTEX(x) extern adb_mutex_t x;
|
||||
#include "mutex_list.h"
|
||||
|
||||
|
@ -195,6 +196,8 @@ struct fdevent {
|
|||
fdevent *prev;
|
||||
|
||||
int fd;
|
||||
int force_eof;
|
||||
|
||||
unsigned short state;
|
||||
unsigned short events;
|
||||
|
||||
|
@ -274,13 +277,14 @@ static __inline__ int adb_is_absolute_host_path( const char* path )
|
|||
#define OS_PATH_SEPARATOR_STR "/"
|
||||
|
||||
typedef pthread_mutex_t adb_mutex_t;
|
||||
|
||||
#define ADB_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
|
||||
#define adb_mutex_init pthread_mutex_init
|
||||
#define adb_mutex_lock pthread_mutex_lock
|
||||
#define adb_mutex_unlock pthread_mutex_unlock
|
||||
#define adb_mutex_destroy pthread_mutex_destroy
|
||||
|
||||
#define ADB_MUTEX_DEFINE(m) static adb_mutex_t m = PTHREAD_MUTEX_INITIALIZER
|
||||
#define ADB_MUTEX_DEFINE(m) adb_mutex_t m = PTHREAD_MUTEX_INITIALIZER
|
||||
|
||||
#define adb_cond_t pthread_cond_t
|
||||
#define adb_cond_init pthread_cond_init
|
||||
|
@ -289,6 +293,10 @@ typedef pthread_mutex_t adb_mutex_t;
|
|||
#define adb_cond_signal pthread_cond_signal
|
||||
#define adb_cond_destroy pthread_cond_destroy
|
||||
|
||||
/* declare all mutexes */
|
||||
#define ADB_MUTEX(x) extern adb_mutex_t x;
|
||||
#include "mutex_list.h"
|
||||
|
||||
static __inline__ void close_on_exec(int fd)
|
||||
{
|
||||
fcntl( fd, F_SETFD, FD_CLOEXEC );
|
||||
|
|
|
@ -35,24 +35,30 @@ static atransport transport_list = {
|
|||
ADB_MUTEX_DEFINE( transport_lock );
|
||||
|
||||
#if ADB_TRACE
|
||||
#define MAX_DUMP_HEX_LEN 16
|
||||
static void dump_hex( const unsigned char* ptr, size_t len )
|
||||
{
|
||||
int nn, len2 = len;
|
||||
// Build a string instead of logging each character.
|
||||
// MAX chars in 2 digit hex, one space, MAX chars, one '\0'.
|
||||
char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer;
|
||||
|
||||
if (len2 > 16) len2 = 16;
|
||||
if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN;
|
||||
|
||||
for (nn = 0; nn < len2; nn++)
|
||||
D("%02x", ptr[nn]);
|
||||
D(" ");
|
||||
for (nn = 0; nn < len2; nn++) {
|
||||
sprintf(pb, "%02x", ptr[nn]);
|
||||
pb += 2;
|
||||
}
|
||||
sprintf(pb++, " ");
|
||||
|
||||
for (nn = 0; nn < len2; nn++) {
|
||||
int c = ptr[nn];
|
||||
if (c < 32 || c > 127)
|
||||
c = '.';
|
||||
D("%c", c);
|
||||
*pb++ = c;
|
||||
}
|
||||
D("\n");
|
||||
fflush(stdout);
|
||||
*pb++ = '\0';
|
||||
DR("%s\n", buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -192,6 +198,7 @@ write_packet(int fd, const char* name, apacket** ppacket)
|
|||
static void transport_socket_events(int fd, unsigned events, void *_t)
|
||||
{
|
||||
atransport *t = _t;
|
||||
D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events);
|
||||
if(events & FDE_READ){
|
||||
apacket *p = 0;
|
||||
if(read_packet(fd, t->serial, &p)){
|
||||
|
@ -221,8 +228,10 @@ void send_packet(apacket *p, atransport *t)
|
|||
print_packet("send", p);
|
||||
|
||||
if (t == NULL) {
|
||||
fatal_errno("Transport is null");
|
||||
D("Transport is null \n");
|
||||
// Zap errno because print_packet() and other stuff have errno effect.
|
||||
errno = 0;
|
||||
fatal_errno("Transport is null");
|
||||
}
|
||||
|
||||
if(write_packet(t->transport_socket, t->serial, &p)){
|
||||
|
@ -1069,4 +1078,3 @@ int check_data(apacket *p)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
#ifndef __TRANSPORT_H
|
||||
#define __TRANSPORT_H
|
||||
|
||||
/* convenience wrappers around read/write that will retry on
|
||||
** EINTR and/or short read/write. Returns 0 on success, -1
|
||||
** on error or EOF.
|
||||
*/
|
||||
int readx(int fd, void *ptr, size_t len);
|
||||
int writex(int fd, const void *ptr, size_t len);
|
||||
#endif /* __TRANSPORT_H */
|
|
@ -45,7 +45,7 @@
|
|||
/* usb scan debugging is waaaay too verbose */
|
||||
#define DBGX(x...)
|
||||
|
||||
static adb_mutex_t usb_lock = ADB_MUTEX_INITIALIZER;
|
||||
ADB_MUTEX_DEFINE( usb_lock );
|
||||
|
||||
struct usb_handle
|
||||
{
|
||||
|
@ -369,6 +369,7 @@ static int usb_bulk_read(usb_handle *h, void *data, int len)
|
|||
h->reaper_thread = pthread_self();
|
||||
adb_mutex_unlock(&h->lock);
|
||||
res = ioctl(h->desc, USBDEVFS_REAPURB, &out);
|
||||
int saved_errno = errno;
|
||||
adb_mutex_lock(&h->lock);
|
||||
h->reaper_thread = 0;
|
||||
if(h->dead) {
|
||||
|
@ -376,7 +377,7 @@ static int usb_bulk_read(usb_handle *h, void *data, int len)
|
|||
break;
|
||||
}
|
||||
if(res < 0) {
|
||||
if(errno == EINTR) {
|
||||
if(saved_errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
D("[ reap urb - error ]\n");
|
||||
|
@ -685,4 +686,3 @@ void usb_init()
|
|||
fatal_errno("cannot create input thread");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -83,14 +83,14 @@ int usb_write(usb_handle *h, const void *data, int len)
|
|||
{
|
||||
int n;
|
||||
|
||||
D("[ write %d ]\n", len);
|
||||
D("about to write (fd=%d, len=%d)\n", h->fd, len);
|
||||
n = adb_write(h->fd, data, len);
|
||||
if(n != len) {
|
||||
D("ERROR: n = %d, errno = %d (%s)\n",
|
||||
n, errno, strerror(errno));
|
||||
D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
|
||||
h->fd, n, errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
D("[ done ]\n");
|
||||
D("[ done fd=%d ]\n", h->fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -98,13 +98,14 @@ int usb_read(usb_handle *h, void *data, int len)
|
|||
{
|
||||
int n;
|
||||
|
||||
D("[ read %d ]\n", len);
|
||||
D("about to read (fd=%d, len=%d)\n", h->fd, len);
|
||||
n = adb_read(h->fd, data, len);
|
||||
if(n != len) {
|
||||
D("ERROR: n = %d, errno = %d (%s)\n",
|
||||
n, errno, strerror(errno));
|
||||
D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
|
||||
h->fd, n, errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
D("[ done fd=%d ]\n", h->fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,4 +22,4 @@ extern unsigned vendorIdCount;
|
|||
|
||||
void usb_vendors_init(void);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -246,10 +246,10 @@ usb_handle* do_usb_open(const wchar_t* interface_name) {
|
|||
}
|
||||
|
||||
// Something went wrong.
|
||||
errno = GetLastError();
|
||||
int saved_errno = GetLastError();
|
||||
usb_cleanup_handle(ret);
|
||||
free(ret);
|
||||
SetLastError(errno);
|
||||
SetLastError(saved_errno);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ int usb_write(usb_handle* handle, const void* data, int len) {
|
|||
(unsigned long)len,
|
||||
&written,
|
||||
time_out);
|
||||
errno = GetLastError();
|
||||
int saved_errno = GetLastError();
|
||||
|
||||
if (ret) {
|
||||
// Make sure that we've written what we were asked to write
|
||||
|
@ -285,9 +285,10 @@ int usb_write(usb_handle* handle, const void* data, int len) {
|
|||
}
|
||||
} else {
|
||||
// assume ERROR_INVALID_HANDLE indicates we are disconnected
|
||||
if (errno == ERROR_INVALID_HANDLE)
|
||||
if (saved_errno == ERROR_INVALID_HANDLE)
|
||||
usb_kick(handle);
|
||||
}
|
||||
errno = saved_errno;
|
||||
} else {
|
||||
D("usb_write NULL handle\n");
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
|
@ -313,20 +314,21 @@ int usb_read(usb_handle *handle, void* data, int len) {
|
|||
(unsigned long)xfer,
|
||||
&read,
|
||||
time_out);
|
||||
errno = GetLastError();
|
||||
D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, errno);
|
||||
int saved_errno = GetLastError();
|
||||
D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, saved_errno);
|
||||
if (ret) {
|
||||
data += read;
|
||||
len -= read;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
} else if (errno != ERROR_SEM_TIMEOUT) {
|
||||
} else if (saved_errno != ERROR_SEM_TIMEOUT) {
|
||||
// assume ERROR_INVALID_HANDLE indicates we are disconnected
|
||||
if (errno == ERROR_INVALID_HANDLE)
|
||||
if (saved_errno == ERROR_INVALID_HANDLE)
|
||||
usb_kick(handle);
|
||||
break;
|
||||
}
|
||||
errno = saved_errno;
|
||||
}
|
||||
} else {
|
||||
D("usb_read NULL handle\n");
|
||||
|
|
Loading…
Reference in New Issue