aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--adb/adb.h8
-rw-r--r--adb/backup_service.c62
-rw-r--r--adb/commandline.c12
-rw-r--r--adb/services.c6
-rw-r--r--adb/sockets.c19
-rw-r--r--rootdir/init.rc43
6 files changed, 107 insertions, 43 deletions
diff --git a/adb/adb.h b/adb/adb.h
index ac5bc8bd..ac31f11c 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -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