diff options
| -rw-r--r-- | adb/adb.h | 8 | ||||
| -rw-r--r-- | adb/backup_service.c | 62 | ||||
| -rw-r--r-- | adb/commandline.c | 12 | ||||
| -rw-r--r-- | adb/services.c | 6 | ||||
| -rw-r--r-- | adb/sockets.c | 19 | ||||
| -rw-r--r-- | rootdir/init.rc | 43 |
6 files changed, 107 insertions, 43 deletions
@@ -35,7 +35,7 @@ #define ADB_VERSION_MAJOR 1 // Used for help/version information #define ADB_VERSION_MINOR 0 // Used for help/version information -#define ADB_SERVER_VERSION 27 // Increment this when we want to force users to start a new adb server +#define ADB_SERVER_VERSION 29 // Increment this when we want to force users to start a new adb server typedef struct amessage amessage; typedef struct apacket apacket; @@ -86,12 +86,6 @@ struct asocket { */ int closing; - /* flag: kick the transport when the socket is closed. - ** This is needed to handle commands that cause the - ** remote daemon to terminate, like "adb root" - */ - int kick_on_close; - /* the asocket we are connected to */ diff --git a/adb/backup_service.c b/adb/backup_service.c index 2e6e7546..669ff862 100644 --- a/adb/backup_service.c +++ b/adb/backup_service.c @@ -22,6 +22,31 @@ #define TRACE_TAG TRACE_ADB #include "adb.h" +typedef struct { + pid_t pid; + int fd; +} backup_harvest_params; + +// socketpair but do *not* mark as close_on_exec +static int backup_socketpair(int sv[2]) { + int rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv ); + if (rc < 0) + return -1; + + return 0; +} + +// harvest the child process then close the read end of the socketpair +static void* backup_child_waiter(void* args) { + int status; + backup_harvest_params* params = (backup_harvest_params*) args; + + waitpid(params->pid, &status, 0); + adb_close(params->fd); + free(params); + return NULL; +} + /* returns the data socket passing the backup data here for forwarding */ int backup_service(BackupOperation op, char* args) { pid_t pid; @@ -42,12 +67,15 @@ int backup_service(BackupOperation op, char* args) { // set up the pipe from the subprocess to here // parent will read s[0]; child will write s[1] - if (adb_socketpair(s)) { + if (backup_socketpair(s)) { D("can't create backup/restore socketpair\n"); fprintf(stderr, "unable to create backup/restore socketpair\n"); return -1; } + D("Backup/restore socket pair: (send=%d, receive=%d)\n", s[1], s[0]); + close_on_exec(s[0]); // only the side we hold on to + // spin off the child process to run the backup command pid = fork(); if (pid < 0) { @@ -61,12 +89,14 @@ int backup_service(BackupOperation op, char* args) { // Great, we're off and running. if (pid == 0) { + // child -- actually run the backup here char* p; int argc; + char portnum[16]; char** bu_args; - // child -- actually run the backup here - argc = 2; // room for the basic 'bu' argv[0] and '[operation]' argv[1] + // fixed args: [0] is 'bu', [1] is the port number, [2] is the 'operation' string + argc = 3; for (p = (char*)args; p && *p; ) { argc++; while (*p && *p != ':') p++; @@ -74,9 +104,13 @@ int backup_service(BackupOperation op, char* args) { } bu_args = (char**) alloca(argc*sizeof(char*) + 1); - bu_args[0] = "bu"; - bu_args[1] = operation; - argc = 2; // run through again to build the argv array + + // run through again to build the argv array + argc = 0; + bu_args[argc++] = "bu"; + snprintf(portnum, sizeof(portnum), "%d", s[1]); + bu_args[argc++] = portnum; + bu_args[argc++] = operation; for (p = (char*)args; p && *p; ) { bu_args[argc++] = p; while (*p && *p != ':') p++; @@ -90,7 +124,6 @@ int backup_service(BackupOperation op, char* args) { // Close the half of the socket that we don't care about, route 'bu's console // to the output socket, and off we go adb_close(s[0]); - dup2(s[1], socketnum); // off we go execvp("/system/bin/bu", (char * const *)bu_args); @@ -98,8 +131,23 @@ int backup_service(BackupOperation op, char* args) { fprintf(stderr, "Unable to exec 'bu', bailing\n"); exit(-1); } else { + adb_thread_t t; + backup_harvest_params* params; + // parent, i.e. adbd -- close the sending half of the socket + D("fork() returned pid %d\n", pid); adb_close(s[1]); + + // spin a thread to harvest the child process + params = (backup_harvest_params*) malloc(sizeof(backup_harvest_params)); + params->pid = pid; + params->fd = s[0]; + if (adb_thread_create(&t, backup_child_waiter, params)) { + adb_close(s[0]); + free(params); + D("Unable to create child harvester\n"); + return -1; + } } // we'll be reading from s[0] as the data is sent by the child process diff --git a/adb/commandline.c b/adb/commandline.c index 2dc86f27..28bae98e 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -239,18 +239,23 @@ static void read_and_dump(int fd) } static void copy_to_file(int inFd, int outFd) { - char buf[4096]; + const size_t BUFSIZE = 32 * 1024; + char* buf = (char*) malloc(BUFSIZE); int len; long total = 0; D("copy_to_file(%d -> %d)\n", inFd, outFd); for (;;) { - len = adb_read(inFd, buf, sizeof(buf)); + len = adb_read(inFd, buf, BUFSIZE); if (len == 0) { + D("copy_to_file() : read 0 bytes; exiting\n"); break; } if (len < 0) { - if (errno == EINTR) continue; + if (errno == EINTR) { + D("copy_to_file() : EINTR, retrying\n"); + continue; + } D("copy_to_file() : error %d\n", errno); break; } @@ -258,6 +263,7 @@ static void copy_to_file(int inFd, int outFd) { total += len; } D("copy_to_file() finished after %lu bytes\n", total); + free(buf); } static void *stdin_read_thread(void *x) diff --git a/adb/services.c b/adb/services.c index 6bbd6f88..6940be80 100644 --- a/adb/services.c +++ b/adb/services.c @@ -125,14 +125,12 @@ void restart_root_service(int fd, void *cookie) return; } - property_set("service.adb.root", "1"); snprintf(buf, sizeof(buf), "restarting adbd as root\n"); writex(fd, buf, strlen(buf)); adb_close(fd); - // quit, and init will restart us as root - sleep(1); - exit(1); + // This will cause a property trigger in init.rc to restart us + property_set("service.adb.root", "1"); } } diff --git a/adb/sockets.c b/adb/sockets.c index 72192936..df223b13 100644 --- a/adb/sockets.c +++ b/adb/sockets.c @@ -190,14 +190,6 @@ static void local_socket_ready(asocket *s) static void local_socket_close(asocket *s) { -#if ADB_HOST - /* to special case commands that cause the remote daemon to terminate */ - if (s->kick_on_close && s->transport) { - kick_transport(s->transport); - /* delay to work around a race condition */ - adb_sleep_ms(1000); - } -#endif adb_mutex_lock(&socket_list_lock); local_socket_close_locked(s); adb_mutex_unlock(&socket_list_lock); @@ -288,6 +280,7 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s) if(errno == EAGAIN) return; if(errno == EINTR) continue; } + D(" closing after write because r=%d and errno is %d\n", r, errno); s->close(s); return; } @@ -303,6 +296,7 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s) ** we can now destroy it. */ if (s->closing) { + D(" closing because 'closing' is set after write\n"); s->close(s); return; } @@ -372,6 +366,7 @@ static void local_socket_event_func(int fd, unsigned ev, void *_s) } /* Don't allow a forced eof if data is still there */ if((s->fde.force_eof && !r) || is_eof) { + D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof); s->close(s); } } @@ -532,14 +527,6 @@ void connect_to_remote(asocket *s, const char *destination) apacket *p = get_apacket(); int len = strlen(destination) + 1; -#if ADB_HOST - /* special case commands that cause the remote daemon to terminate */ - if (!strcmp(destination, "root:")) { - D("connect_to_remote setting kick_on_close for %s\n", destination); - s->kick_on_close = 1; - } -#endif - if(len > (MAX_PAYLOAD-1)) { fatal("destination oversized"); } diff --git a/rootdir/init.rc b/rootdir/init.rc index a2c6bebe..c1fd0778 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -186,6 +186,9 @@ on post-fs-data # Set indication (checked by vold) that we have finished this action #setprop vold.post_fs_data_done 1 + chown system system /sys/class/android_usb/android0/f_mass_storage/lun/file + chmod 0660 /sys/class/android_usb/android0/f_mass_storage/lun/file + on boot # basic network init ifup lo @@ -325,6 +328,28 @@ on property:vold.decrypt=trigger_shutdown_framework class_reset late_start class_reset main +# USB accessory configuration +on property:sys.usb.config=accessory + write /sys/class/android_usb/android0/enable 0 + write /sys/class/android_usb/android0/idVendor 18d1 + write /sys/class/android_usb/android0/idProduct 2d00 + write /sys/class/android_usb/android0/functions $sys.usb.config + write /sys/class/android_usb/android0/enable 1 + setprop sys.usb.state $sys.usb.config + +# USB accessory configuration, with adb +on property:sys.usb.config=accessory,adb + write /sys/class/android_usb/android0/enable 0 + write /sys/class/android_usb/android0/idVendor 18d1 + write /sys/class/android_usb/android0/idProduct 2d01 + write /sys/class/android_usb/android0/functions $sys.usb.config + write /sys/class/android_usb/android0/enable 1 + start adbd + setprop sys.usb.state $sys.usb.config + +on property:persist.sys.usb.config=* + setprop sys.usb.config $persist.sys.usb.config + ## Daemon processes to be run by init. ## service ueventd /sbin/ueventd @@ -341,7 +366,7 @@ service console /system/bin/sh on property:ro.debuggable=1 start console -# adbd is controlled by the persist.service.adb.enable system property +# adbd is controlled via property triggers in init.<platform>.usb.rc service adbd /sbin/adbd class core disabled @@ -350,11 +375,17 @@ service adbd /sbin/adbd on property:ro.kernel.qemu=1 start adbd -on property:persist.service.adb.enable=1 - start adbd - -on property:persist.service.adb.enable=0 - stop adbd +# This property trigger has added to imitiate the previous behavior of "adb root". +# The adb gadget driver used to reset the USB bus when the adbd daemon exited, +# and the host side adb relied on this behavior to force it to reconnect with the +# new adbd instance after init relaunches it. So now we force the USB bus to reset +# here when adbd sets the service.adb.root property to 1. We also restart adbd here +# rather than waiting for init to notice its death and restarting it so the timing +# of USB resetting and adb restarting more closely matches the previous behavior. +on property:service.adb.root=1 + write /sys/class/android_usb/android0/enable 0 + restart adbd + write /sys/class/android_usb/android0/enable 1 service servicemanager /system/bin/servicemanager class core |
