merge from master
diff --git a/adb/adb.c b/adb/adb.c
index e8d2c8f..283ebce 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -832,6 +832,7 @@
{
#if !ADB_HOST
int secure = 0;
+ int port;
char value[PROPERTY_VALUE_MAX];
#endif
@@ -850,7 +851,7 @@
HOST = 1;
usb_vendors_init();
usb_init();
- local_init();
+ local_init(ADB_LOCAL_TRANSPORT_PORT);
if(install_listener("tcp:5037", "*smartsocket*", NULL)) {
exit(1);
@@ -918,14 +919,19 @@
}
/* for the device, start the usb transport if the
- ** android usb device exists, otherwise start the
- ** network transport.
+ ** android usb device exists and "service.adb.tcp"
+ ** is not set, otherwise start the network transport.
*/
- if(access("/dev/android_adb", F_OK) == 0 ||
- access("/dev/android", F_OK) == 0) {
+ property_get("service.adb.tcp.port", value, "0");
+ if (sscanf(value, "%d", &port) == 1 && port > 0) {
+ // listen on TCP port specified by service.adb.tcp.port property
+ local_init(port);
+ } else if (access("/dev/android_adb", F_OK) == 0) {
+ // listen on USB
usb_init();
} else {
- local_init();
+ // listen on default port
+ local_init(ADB_LOCAL_TRANSPORT_PORT);
}
init_jdwp();
#endif
@@ -1006,6 +1012,43 @@
return 0;
}
+ // add a new TCP transport
+ if (!strncmp(service, "connect:", 8)) {
+ char buffer[4096];
+ int port, fd;
+ char* host = service + 8;
+ char* portstr = strchr(host, ':');
+
+ if (!portstr) {
+ snprintf(buffer, sizeof(buffer), "unable to parse %s as <host>:<port>\n", host);
+ goto done;
+ }
+ // zero terminate host by overwriting the ':'
+ *portstr++ = 0;
+ if (sscanf(portstr, "%d", &port) == 0) {
+ snprintf(buffer, sizeof(buffer), "bad port number %s\n", portstr);
+ goto done;
+ }
+
+ fd = socket_network_client(host, port, SOCK_STREAM);
+ if (fd < 0) {
+ snprintf(buffer, sizeof(buffer), "unable to connect to %s:%d\n", host, port);
+ goto done;
+ }
+
+ D("client: connected on remote on fd %d\n", fd);
+ close_on_exec(fd);
+ disable_tcp_nagle(fd);
+ snprintf(buf, sizeof buf, "%s:%d", host, port);
+ register_socket_transport(fd, buf, port, 0);
+ snprintf(buffer, sizeof(buffer), "connected to %s:%d\n", host, port);
+
+done:
+ 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];
diff --git a/adb/adb.h b/adb/adb.h
index 8d57bf2..713666f 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -33,7 +33,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 22 // Increment this when we want to force users to start a new adb server
+#define ADB_SERVER_VERSION 25 // Increment this when we want to force users to start a new adb server
typedef struct amessage amessage;
typedef struct apacket apacket;
@@ -262,15 +262,18 @@
void kick_transport( atransport* t );
/* initialize a transport object's func pointers and state */
-int init_socket_transport(atransport *t, int s, int port);
-void init_usb_transport(atransport *t, usb_handle *usb);
+int init_socket_transport(atransport *t, int s, int port, int local);
+void init_usb_transport(atransport *t, usb_handle *usb, int state);
/* for MacOS X cleanup */
void close_usb_devices();
/* cause new transports to be init'd and added to the list */
-void register_socket_transport(int s, const char *serial, int port);
-void register_usb_transport(usb_handle *h, const char *serial);
+void register_socket_transport(int s, const char *serial, int port, int local);
+void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable);
+
+/* this should only be used for transports with connection_state == CS_NOPERM */
+void unregister_usb_transport(usb_handle *usb);
int service_to_fd(const char *name);
#if ADB_HOST
@@ -357,7 +360,7 @@
#define ADB_PROTOCOL 0x1
-void local_init();
+void local_init(int port);
int local_connect(int port);
/* usb host/client interface */
@@ -384,7 +387,7 @@
#define CS_DEVICE 2
#define CS_HOST 3
#define CS_RECOVERY 4
-#define CS_ERROR 5
+#define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */
extern int HOST;
diff --git a/adb/commandline.c b/adb/commandline.c
index 5414e5e..411bb82 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -96,7 +96,8 @@
" -e - directs command to the only running emulator.\n"
" returns an error if more than one emulator is running.\n"
" -s <serial number> - directs command to the USB device or emulator with\n"
- " the given serial number\n"
+ " the given serial number. Overrides ANDROID_SERIAL\n"
+ " envivornment variable.\n"
" -p <product name or path> - simple product name like 'sooner', or\n"
" a relative/absolute path to a product\n"
" out directory like 'out/target/product/sooner'.\n"
@@ -104,6 +105,7 @@
" environment variable is used, which must\n"
" be an absolute path.\n"
" devices - list all connected devices\n"
+ " connect <host>:<port> - connect to a device via TCP/IP"
"\n"
"device commands:\n"
" adb push <local> <remote> - copy file/dir to device\n"
@@ -148,7 +150,9 @@
" adb status-window - continuously print device status for a specified device\n"
" adb remount - remounts the /system partition on the device read-write\n"
" adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
- " adb root - restarts adb with root permissions\n"
+ " adb root - restarts the adbd daemon with root permissions\n"
+ " adb usb - restarts the adbd daemon listening on USB"
+ " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port"
"\n"
"networking:\n"
" adb ppp <tty> [parameters] - Run PPP over USB.\n"
@@ -767,6 +771,8 @@
}
// TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
+ serial = getenv("ANDROID_SERIAL");
+
/* modifiers and flags */
while(argc > 0) {
if(!strcmp(argv[0],"nodaemon")) {
@@ -847,6 +853,22 @@
}
}
+ if(!strcmp(argv[0], "connect")) {
+ char *tmp;
+ if (argc != 2) {
+ fprintf(stderr, "Usage: adb connect <host>:<port>\n");
+ return 1;
+ }
+ snprintf(buf, sizeof buf, "host:%s:%s", argv[0], argv[1]);
+ tmp = adb_query(buf);
+ if(tmp) {
+ printf("%s\n", tmp);
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
if (!strcmp(argv[0], "emu")) {
return adb_send_emulator_command(argc, argv);
}
@@ -905,35 +927,15 @@
return 0;
}
- if(!strcmp(argv[0], "remount")) {
- int fd = adb_connect("remount:");
- if(fd >= 0) {
- read_and_dump(fd);
- adb_close(fd);
- return 0;
- }
- fprintf(stderr,"error: %s\n", adb_error());
- return 1;
- }
-
- if(!strcmp(argv[0], "reboot")) {
- int fd;
+ if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
+ || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
+ || !strcmp(argv[0], "root")) {
+ char command[100];
if (argc > 1)
- snprintf(buf, sizeof(buf), "reboot:%s", argv[1]);
+ snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
else
- snprintf(buf, sizeof(buf), "reboot:");
- fd = adb_connect(buf);
- if(fd >= 0) {
- read_and_dump(fd);
- adb_close(fd);
- return 0;
- }
- fprintf(stderr,"error: %s\n", adb_error());
- return 1;
- }
-
- if(!strcmp(argv[0], "root")) {
- int fd = adb_connect("root:");
+ snprintf(command, sizeof(command), "%s:", argv[0]);
+ int fd = adb_connect(command);
if(fd >= 0) {
read_and_dump(fd);
adb_close(fd);
diff --git a/adb/get_my_path_darwin.c b/adb/get_my_path_darwin.c
index 00dfee4..6125cb4 100644
--- a/adb/get_my_path_darwin.c
+++ b/adb/get_my_path_darwin.c
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <utils/executablepath.h>
#import <Carbon/Carbon.h>
#include <unistd.h>
diff --git a/adb/services.c b/adb/services.c
index 517da55..2864ac9 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -120,6 +120,7 @@
if (strcmp(value, "1") != 0) {
snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");
writex(fd, buf, strlen(buf));
+ adb_close(fd);
return;
}
@@ -134,13 +135,52 @@
}
}
-void reboot_service(int fd, char *arg)
+void restart_tcp_service(int fd, void *cookie)
+{
+ char buf[100];
+ char value[PROPERTY_VALUE_MAX];
+ int port = (int)cookie;
+
+ if (port <= 0) {
+ snprintf(buf, sizeof(buf), "invalid port\n");
+ writex(fd, buf, strlen(buf));
+ adb_close(fd);
+ return;
+ }
+
+ snprintf(value, sizeof(value), "%d", port);
+ property_set("service.adb.tcp.port", value);
+ snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
+ writex(fd, buf, strlen(buf));
+ adb_close(fd);
+
+ // quit, and init will restart us in TCP mode
+ sleep(1);
+ exit(1);
+}
+
+void restart_usb_service(int fd, void *cookie)
+{
+ char buf[100];
+
+ property_set("service.adb.tcp.port", "0");
+ snprintf(buf, sizeof(buf), "restarting in USB mode\n");
+ writex(fd, buf, strlen(buf));
+ adb_close(fd);
+
+ // quit, and init will restart us in USB mode
+ sleep(1);
+ exit(1);
+}
+
+void reboot_service(int fd, void *arg)
{
char buf[100];
int ret;
sync();
- ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, arg);
+ ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+ LINUX_REBOOT_CMD_RESTART2, (char *)arg);
if (ret < 0) {
snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
writex(fd, buf, strlen(buf));
@@ -415,12 +455,20 @@
} else if(!strncmp(name, "remount:", 8)) {
ret = create_service_thread(remount_service, NULL);
} else if(!strncmp(name, "reboot:", 7)) {
- char* arg = name + 7;
+ const char* arg = name + 7;
if (*name == 0)
arg = NULL;
- ret = create_service_thread(reboot_service, arg);
+ ret = create_service_thread(reboot_service, (void *)arg);
} else if(!strncmp(name, "root:", 5)) {
ret = create_service_thread(restart_root_service, NULL);
+ } else if(!strncmp(name, "tcpip:", 6)) {
+ int port;
+ if (sscanf(name + 6, "%d", &port) == 0) {
+ port = 0;
+ }
+ ret = create_service_thread(restart_tcp_service, (void *)port);
+ } else if(!strncmp(name, "usb:", 4)) {
+ ret = create_service_thread(restart_usb_service, NULL);
#endif
#if 0
} else if(!strncmp(name, "echo:", 5)){
diff --git a/adb/transport.c b/adb/transport.c
index c76f1a5..617dabf 100644
--- a/adb/transport.c
+++ b/adb/transport.c
@@ -584,18 +584,37 @@
return;
}
+ /* don't create transport threads for inaccessible devices */
+ if (t->connection_state != CS_NOPERM) {
/* initial references are the two threads */
- t->ref_count = 2;
+ t->ref_count = 2;
- if(adb_socketpair(s)) {
- fatal_errno("cannot open transport socketpair");
+ if(adb_socketpair(s)) {
+ fatal_errno("cannot open transport socketpair");
+ }
+
+ D("transport: %p (%d,%d) starting\n", t, s[0], s[1]);
+
+ t->transport_socket = s[0];
+ t->fd = s[1];
+
+ D("transport: %p install %d\n", t, t->transport_socket );
+ fdevent_install(&(t->transport_fde),
+ t->transport_socket,
+ transport_socket_events,
+ t);
+
+ fdevent_set(&(t->transport_fde), FDE_READ);
+
+ if(adb_thread_create(&input_thread_ptr, input_thread, t)){
+ fatal_errno("cannot create input thread");
+ }
+
+ if(adb_thread_create(&output_thread_ptr, output_thread, t)){
+ fatal_errno("cannot create output thread");
+ }
}
- D("transport: %p (%d,%d) starting\n", t, s[0], s[1]);
-
- t->transport_socket = s[0];
- t->fd = s[1];
-
/* put us on the master device list */
adb_mutex_lock(&transport_lock);
t->next = &transport_list;
@@ -604,22 +623,6 @@
t->prev->next = t;
adb_mutex_unlock(&transport_lock);
- D("transport: %p install %d\n", t, t->transport_socket );
- fdevent_install(&(t->transport_fde),
- t->transport_socket,
- transport_socket_events,
- t);
-
- fdevent_set(&(t->transport_fde), FDE_READ);
-
- if(adb_thread_create(&input_thread_ptr, input_thread, t)){
- fatal_errno("cannot create input thread");
- }
-
- if(adb_thread_create(&output_thread_ptr, output_thread, t)){
- fatal_errno("cannot create output thread");
- }
-
t->disconnects.next = t->disconnects.prev = &t->disconnects;
update_transports();
@@ -717,6 +720,12 @@
adb_mutex_lock(&transport_lock);
for (t = transport_list.next; t != &transport_list; t = t->next) {
+ if (t->connection_state == CS_NOPERM) {
+ if (error_out)
+ *error_out = "insufficient permissions for device";
+ continue;
+ }
+
/* check for matching serial number */
if (serial) {
if (t->serial && !strcmp(serial, t->serial)) {
@@ -763,7 +772,6 @@
*error_out = "device offline";
result = NULL;
}
-
/* check for required connection state */
if (result && state != CS_ANY && result->connection_state != state) {
if (error_out)
@@ -793,6 +801,7 @@
case CS_DEVICE: return "device";
case CS_HOST: return "host";
case CS_RECOVERY: return "recovery";
+ case CS_NOPERM: return "no permissions";
default: return "unknown";
}
}
@@ -807,9 +816,10 @@
/* XXX OVERRUN PROBLEMS XXX */
adb_mutex_lock(&transport_lock);
for(t = transport_list.next; t != &transport_list; t = t->next) {
- len = snprintf(p, end - p, "%s\t%s\n",
- t->serial ? t->serial : "",
- statename(t));
+ 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 */
@@ -839,11 +849,11 @@
}
#endif // ADB_HOST
-void register_socket_transport(int s, const char *serial, int port)
+void register_socket_transport(int s, const char *serial, int port, int local)
{
atransport *t = calloc(1, sizeof(atransport));
D("transport: %p init'ing for socket %d, on port %d\n", t, s, port);
- if ( init_socket_transport(t, s, port) < 0 ) {
+ if ( init_socket_transport(t, s, port, local) < 0 ) {
adb_close(s);
free(t);
return;
@@ -854,18 +864,32 @@
register_transport(t);
}
-void register_usb_transport(usb_handle *usb, const char *serial)
+void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable)
{
atransport *t = calloc(1, sizeof(atransport));
D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
serial ? serial : "");
- init_usb_transport(t, usb);
+ init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
if(serial) {
t->serial = strdup(serial);
}
register_transport(t);
}
+/* this should only be used for transports with connection_state == CS_NOPERM */
+void unregister_usb_transport(usb_handle *usb)
+{
+ atransport *t;
+ adb_mutex_lock(&transport_lock);
+ for(t = transport_list.next; t != &transport_list; t = t->next) {
+ if (t->usb == usb && t->connection_state == CS_NOPERM) {
+ t->next->prev = t->prev;
+ t->prev->next = t->next;
+ break;
+ }
+ }
+ adb_mutex_unlock(&transport_lock);
+}
#undef TRACE_TAG
#define TRACE_TAG TRACE_RWX
diff --git a/adb/transport_local.c b/adb/transport_local.c
index be01f29..c528d1f 100644
--- a/adb/transport_local.c
+++ b/adb/transport_local.c
@@ -122,7 +122,7 @@
close_on_exec(fd);
disable_tcp_nagle(fd);
snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, port - 1);
- register_socket_transport(fd, buf, port);
+ register_socket_transport(fd, buf, port, 1);
return 0;
}
return -1;
@@ -147,17 +147,18 @@
return 0;
}
-static void *server_socket_thread(void *x)
+static void *server_socket_thread(void * arg)
{
int serverfd, fd;
struct sockaddr addr;
socklen_t alen;
+ int port = (int)arg;
D("transport: server_socket_thread() starting\n");
serverfd = -1;
for(;;) {
if(serverfd == -1) {
- serverfd = socket_inaddr_any_server(ADB_LOCAL_TRANSPORT_PORT, SOCK_STREAM);
+ serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
if(serverfd < 0) {
D("server: cannot bind socket yet\n");
adb_sleep_ms(1000);
@@ -167,20 +168,20 @@
}
alen = sizeof(addr);
- D("server: trying to get new connection from %d\n", ADB_LOCAL_TRANSPORT_PORT);
+ D("server: trying to get new connection from %d\n", port);
fd = adb_socket_accept(serverfd, &addr, &alen);
if(fd >= 0) {
D("server: new connection on fd %d\n", fd);
close_on_exec(fd);
disable_tcp_nagle(fd);
- register_socket_transport(fd,"host",ADB_LOCAL_TRANSPORT_PORT);
+ register_socket_transport(fd, "host", port, 1);
}
}
D("transport: server_socket_thread() exiting\n");
return 0;
}
-void local_init(void)
+void local_init(int port)
{
adb_thread_t thr;
void* (*func)(void *);
@@ -193,7 +194,7 @@
D("transport: local %s init\n", HOST ? "client" : "server");
- if(adb_thread_create(&thr, func, 0)) {
+ if(adb_thread_create(&thr, func, (void *)port)) {
fatal_errno("cannot create local socket %s thread",
HOST ? "client" : "server");
}
@@ -225,7 +226,7 @@
adb_close(t->fd);
}
-int init_socket_transport(atransport *t, int s, int port)
+int init_socket_transport(atransport *t, int s, int port, int local)
{
int fail = 0;
@@ -239,7 +240,7 @@
t->type = kTransportLocal;
#if ADB_HOST
- if (HOST) {
+ if (HOST && local) {
adb_mutex_lock( &local_transports_lock );
{
int index = (port - ADB_LOCAL_TRANSPORT_PORT)/2;
diff --git a/adb/transport_usb.c b/adb/transport_usb.c
index 3737c5c..2584163 100644
--- a/adb/transport_usb.c
+++ b/adb/transport_usb.c
@@ -110,7 +110,7 @@
usb_kick(t->usb);
}
-void init_usb_transport(atransport *t, usb_handle *h)
+void init_usb_transport(atransport *t, usb_handle *h, int state)
{
D("transport: usb\n");
t->close = remote_close;
@@ -118,7 +118,7 @@
t->read_from_remote = remote_read;
t->write_to_remote = remote_write;
t->sync_token = 1;
- t->connection_state = CS_OFFLINE;
+ t->connection_state = state;
t->type = kTransportUsb;
t->usb = h;
diff --git a/adb/usb_linux.c b/adb/usb_linux.c
index 537122d..863af1d 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.c
@@ -57,6 +57,7 @@
unsigned char ep_out;
unsigned zero_mask;
+ unsigned writeable;
struct usbdevfs_urb urb_in;
struct usbdevfs_urb urb_out;
@@ -115,7 +116,7 @@
}
static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out,
- int ifc, const char *serial, unsigned zero_mask);
+ int ifc, int serial_index, unsigned zero_mask);
static inline int badname(const char *name)
{
@@ -125,19 +126,18 @@
return 0;
}
-static int find_usb_device(const char *base,
- void (*register_device_callback) (const char *, unsigned char, unsigned char, int, const char *, unsigned))
+static void find_usb_device(const char *base,
+ void (*register_device_callback)
+ (const char *, unsigned char, unsigned char, int, int, unsigned))
{
char busname[32], devname[32];
unsigned char local_ep_in, local_ep_out;
DIR *busdir , *devdir ;
struct dirent *de;
int fd ;
- int found_device = 0;
- char serial[256];
busdir = opendir(base);
- if(busdir == 0) return 0;
+ if(busdir == 0) return;
while((de = readdir(busdir)) != 0) {
if(badname(de->d_name)) continue;
@@ -168,7 +168,7 @@
}
// DBGX("[ scanning %s ]\n", devname);
- if((fd = unix_open(devname, O_RDWR)) < 0) {
+ if((fd = unix_open(devname, O_RDONLY)) < 0) {
continue;
}
@@ -263,67 +263,13 @@
local_ep_out = ep1->bEndpointAddress;
}
- // read the device's serial number
- serial[0] = 0;
- memset(serial, 0, sizeof(serial));
- if (device->iSerialNumber) {
- struct usbdevfs_ctrltransfer ctrl;
- __u16 buffer[128];
- __u16 languages[128];
- int i, result;
- int languageCount = 0;
-
- memset(languages, 0, sizeof(languages));
- memset(&ctrl, 0, sizeof(ctrl));
-
- // read list of supported languages
- ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
- ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
- ctrl.wValue = (USB_DT_STRING << 8) | 0;
- ctrl.wIndex = 0;
- ctrl.wLength = sizeof(languages);
- ctrl.data = languages;
-
- result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
- if (result > 0)
- languageCount = (result - 2) / 2;
-
- for (i = 1; i <= languageCount; i++) {
- memset(buffer, 0, sizeof(buffer));
- memset(&ctrl, 0, sizeof(ctrl));
-
- ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
- ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
- ctrl.wValue = (USB_DT_STRING << 8) | device->iSerialNumber;
- ctrl.wIndex = languages[i];
- ctrl.wLength = sizeof(buffer);
- ctrl.data = buffer;
-
- result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
- if (result > 0) {
- int i;
- // skip first word, and copy the rest to the serial string, changing shorts to bytes.
- result /= 2;
- for (i = 1; i < result; i++)
- serial[i - 1] = buffer[i];
- serial[i - 1] = 0;
- break;
- }
- }
- }
-
register_device_callback(devname, local_ep_in, local_ep_out,
- interface->bInterfaceNumber, serial, zero_mask);
+ interface->bInterfaceNumber, device->iSerialNumber, zero_mask);
- found_device = 1;
break;
} else {
// seek next interface descriptor
- if (i < interfaces - 1) {
- while (bufptr[1] != USB_DT_INTERFACE) {
- bufptr += bufptr[0];
- }
- }
+ bufptr += (USB_DT_ENDPOINT_SIZE * interface->bNumEndpoints);
}
} // end of for
@@ -332,8 +278,6 @@
closedir(devdir);
} //end of busdir while
closedir(busdir);
-
- return found_device;
}
void usb_cleanup()
@@ -537,26 +481,30 @@
if(h->dead == 0) {
h->dead = 1;
- /* HACK ALERT!
- ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB).
- ** This is a workaround for that problem.
- */
- if (h->reaper_thread) {
- pthread_kill(h->reaper_thread, SIGALRM);
- }
+ if (h->writeable) {
+ /* HACK ALERT!
+ ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB).
+ ** This is a workaround for that problem.
+ */
+ if (h->reaper_thread) {
+ pthread_kill(h->reaper_thread, SIGALRM);
+ }
- /* cancel any pending transactions
- ** these will quietly fail if the txns are not active,
- ** but this ensures that a reader blocked on REAPURB
- ** will get unblocked
- */
- ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in);
- ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out);
- h->urb_in.status = -ENODEV;
- h->urb_out.status = -ENODEV;
- h->urb_in_busy = 0;
- h->urb_out_busy = 0;
- adb_cond_broadcast(&h->notify);
+ /* cancel any pending transactions
+ ** these will quietly fail if the txns are not active,
+ ** but this ensures that a reader blocked on REAPURB
+ ** will get unblocked
+ */
+ ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in);
+ ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out);
+ h->urb_in.status = -ENODEV;
+ h->urb_out.status = -ENODEV;
+ h->urb_in_busy = 0;
+ h->urb_out_busy = 0;
+ adb_cond_broadcast(&h->notify);
+ } else {
+ unregister_usb_transport(h);
+ }
}
adb_mutex_unlock(&h->lock);
}
@@ -580,11 +528,11 @@
static void register_device(const char *dev_name,
unsigned char ep_in, unsigned char ep_out,
- int interface,
- const char *serial, unsigned zero_mask)
+ int interface, int serial_index, unsigned zero_mask)
{
usb_handle* usb = 0;
int n = 0;
+ char serial[256];
/* Since Linux will not reassign the device ID (and dev_name)
** as long as the device is open, we can add to the list here
@@ -610,6 +558,7 @@
usb->ep_in = ep_in;
usb->ep_out = ep_out;
usb->zero_mask = zero_mask;
+ usb->writeable = 1;
adb_cond_init(&usb->notify, 0);
adb_mutex_init(&usb->lock, 0);
@@ -618,10 +567,66 @@
usb->reaper_thread = 0;
usb->desc = unix_open(usb->fname, O_RDWR);
- if(usb->desc < 0) goto fail;
- D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
- n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
- if(n != 0) goto fail;
+ if(usb->desc < 0) {
+ /* if we fail, see if have read-only access */
+ usb->desc = unix_open(usb->fname, O_RDONLY);
+ if(usb->desc < 0) goto fail;
+ usb->writeable = 0;
+ D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
+ } else {
+ D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
+ n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
+ if(n != 0) goto fail;
+ }
+
+ /* read the device's serial number */
+ serial[0] = 0;
+ memset(serial, 0, sizeof(serial));
+ if (serial_index) {
+ struct usbdevfs_ctrltransfer ctrl;
+ __u16 buffer[128];
+ __u16 languages[128];
+ int i, result;
+ int languageCount = 0;
+
+ memset(languages, 0, sizeof(languages));
+ memset(&ctrl, 0, sizeof(ctrl));
+
+ // read list of supported languages
+ ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
+ ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
+ ctrl.wValue = (USB_DT_STRING << 8) | 0;
+ ctrl.wIndex = 0;
+ ctrl.wLength = sizeof(languages);
+ ctrl.data = languages;
+
+ result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
+ if (result > 0)
+ languageCount = (result - 2) / 2;
+
+ for (i = 1; i <= languageCount; i++) {
+ memset(buffer, 0, sizeof(buffer));
+ memset(&ctrl, 0, sizeof(ctrl));
+
+ ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
+ ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
+ ctrl.wValue = (USB_DT_STRING << 8) | serial_index;
+ ctrl.wIndex = languages[i];
+ ctrl.wLength = sizeof(buffer);
+ ctrl.data = buffer;
+
+ result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
+ if (result > 0) {
+ int i;
+ // skip first word, and copy the rest to the serial string, changing shorts to bytes.
+ result /= 2;
+ for (i = 1; i < result; i++)
+ serial[i - 1] = buffer[i];
+ serial[i - 1] = 0;
+ break;
+ }
+ }
+ }
/* add to the end of the active handles */
adb_mutex_lock(&usb_lock);
@@ -631,7 +636,7 @@
usb->next->prev = usb;
adb_mutex_unlock(&usb_lock);
- register_usb_transport(usb, serial);
+ register_usb_transport(usb, serial, usb->writeable);
return;
fail:
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c
index 530bd04..0a21c6f 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.c
@@ -72,7 +72,7 @@
usb->fd = fd;
D("[ usb_thread - registering device ]\n");
- register_usb_transport(usb, 0);
+ register_usb_transport(usb, 0, 1);
}
// never gets here
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index 4892c38..00d02da 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -194,30 +194,54 @@
kr = (*dev)->GetDeviceProduct(dev, &product);
kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
- if (serialIndex > 0) {
- IOUSBDevRequest req;
- UInt16 buffer[256];
+ if (serialIndex > 0) {
+ IOUSBDevRequest req;
+ UInt16 buffer[256];
+ UInt16 languages[128];
- req.bmRequestType =
- USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
- req.bRequest = kUSBRqGetDescriptor;
- req.wValue = (kUSBStringDesc << 8) | serialIndex;
- req.wIndex = 0;
- req.pData = buffer;
- req.wLength = sizeof(buffer);
- kr = (*dev)->DeviceRequest(dev, &req);
+ memset(languages, 0, sizeof(languages));
- if (kr == kIOReturnSuccess && req.wLenDone > 0) {
- int i, count;
+ req.bmRequestType =
+ USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+ req.bRequest = kUSBRqGetDescriptor;
+ req.wValue = (kUSBStringDesc << 8) | 0;
+ req.wIndex = 0;
+ req.pData = languages;
+ req.wLength = sizeof(languages);
+ kr = (*dev)->DeviceRequest(dev, &req);
- // skip first word, and copy the rest to the serial string,
- // changing shorts to bytes.
- count = (req.wLenDone - 1) / 2;
- for (i = 0; i < count; i++)
- serial[i] = buffer[i + 1];
- serial[i] = 0;
- }
- }
+ if (kr == kIOReturnSuccess && req.wLenDone > 0) {
+
+ int langCount = (req.wLenDone - 2) / 2, lang;
+
+ for (lang = 1; lang <= langCount; lang++) {
+
+ memset(buffer, 0, sizeof(buffer));
+ memset(&req, 0, sizeof(req));
+
+ req.bmRequestType =
+ USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+ req.bRequest = kUSBRqGetDescriptor;
+ req.wValue = (kUSBStringDesc << 8) | serialIndex;
+ req.wIndex = languages[lang];
+ req.pData = buffer;
+ req.wLength = sizeof(buffer);
+ kr = (*dev)->DeviceRequest(dev, &req);
+
+ if (kr == kIOReturnSuccess && req.wLenDone > 0) {
+ int i, count;
+
+ // skip first word, and copy the rest to the serial string,
+ // changing shorts to bytes.
+ count = (req.wLenDone - 1) / 2;
+ for (i = 0; i < count; i++)
+ serial[i] = buffer[i + 1];
+ serial[i] = 0;
+ break;
+ }
+ }
+ }
+ }
(*dev)->Release(dev);
DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product,
@@ -232,7 +256,7 @@
}
DBG("AndroidDeviceAdded calling register_usb_transport\n");
- register_usb_transport(handle, (serial[0] ? serial : NULL));
+ register_usb_transport(handle, (serial[0] ? serial : NULL), 1);
// Register for an interest notification of this device being removed.
// Pass the reference to our private data as the refCon for the
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index 0951f67..38c4cf4 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -488,7 +488,7 @@
true)) {
// Lets make sure that we don't duplicate this device
if (register_new_device(handle)) {
- register_usb_transport(handle, serial_number);
+ register_usb_transport(handle, serial_number, 1);
} else {
D("register_new_device failed for %s\n", interf_name);
usb_cleanup_handle(handle);
diff --git a/fastboot/util_osx.c b/fastboot/util_osx.c
index 068241c..b43e316 100644
--- a/fastboot/util_osx.c
+++ b/fastboot/util_osx.c
@@ -26,7 +26,6 @@
* SUCH DAMAGE.
*/
-#include <utils/executablepath.h>
#import <Carbon/Carbon.h>
#include <unistd.h>
diff --git a/include/arch/freebsd-x86/AndroidConfig.h b/include/arch/freebsd-x86/AndroidConfig.h
new file mode 100644
index 0000000..cc118f4
--- /dev/null
+++ b/include/arch/freebsd-x86/AndroidConfig.h
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+/*
+ * Android config -- "FreeBSD". Used for desktop x86 FreeBSD.
+ */
+#ifndef _ANDROID_CONFIG_H
+#define _ANDROID_CONFIG_H
+
+/*
+ * make sure we are building for FreeBSD
+ */
+#ifndef OS_FREEBSD
+#define OS_FREEBSD
+#endif
+/*
+ * ===========================================================================
+ * !!! IMPORTANT !!!
+ * ===========================================================================
+ *
+ * This file is included by ALL C/C++ source files. Don't put anything in
+ * here unless you are absolutely certain it can't go anywhere else.
+ *
+ * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//"
+ * comments.
+ */
+
+/*
+ * Threading model. Choose one:
+ *
+ * HAVE_PTHREADS - use the pthreads library.
+ * HAVE_WIN32_THREADS - use Win32 thread primitives.
+ * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
+ */
+#define HAVE_PTHREADS
+
+/*
+ * Do we have the futex syscall?
+ */
+/* #define HAVE_FUTEX */
+
+/*
+ * Process creation model. Choose one:
+ *
+ * HAVE_FORKEXEC - use fork() and exec()
+ * HAVE_WIN32_PROC - use CreateProcess()
+ */
+#define HAVE_FORKEXEC
+
+/*
+ * Process out-of-memory adjustment. Set if running on Linux,
+ * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
+ * badness adjustment.
+ */
+/* #define HAVE_OOM_ADJ */
+
+/*
+ * IPC model. Choose one:
+ *
+ * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
+ * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
+ * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
+ * HAVE_ANDROID_IPC - use Android versions (?, mmap).
+ */
+#define HAVE_SYSV_IPC
+
+/*
+ * Memory-mapping model. Choose one:
+ *
+ * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
+ * HAVE_WIN32_FILEMAP - use Win32 filemaps
+ */
+#define HAVE_POSIX_FILEMAP
+
+/*
+ * Define this if you have <termio.h>
+ */
+/* #define HAVE_TERMIO_H */
+
+/*
+ * Define this if you build against MSVCRT.DLL
+ */
+/* #define HAVE_MS_C_RUNTIME */
+
+/*
+ * Define this if you have sys/uio.h
+ */
+#define HAVE_SYS_UIO_H
+
+/*
+ * Define this if your platforms implements symbolic links
+ * in its filesystems
+ */
+#define HAVE_SYMLINKS
+
+/*
+ * Define this if we have localtime_r().
+ */
+#define HAVE_LOCALTIME_R
+
+/*
+ * Define this if we have gethostbyname_r().
+ */
+/* #define HAVE_GETHOSTBYNAME_R */
+
+/*
+ * Define this if we have ioctl().
+ */
+#define HAVE_IOCTL
+
+/*
+ * Define this if we want to use WinSock.
+ */
+/* #define HAVE_WINSOCK */
+
+/*
+ * Define this if have clock_gettime() and friends
+ *
+ * Desktop Linux has this in librt, but it's broken in goobuntu, yielding
+ * mildly or wildly inaccurate results.
+ */
+#define HAVE_POSIX_CLOCKS
+
+/*
+ * Define this if we have pthread_cond_timedwait_monotonic() and
+ * clock_gettime(CLOCK_MONOTONIC).
+ */
+/* #define HAVE_TIMEDWAIT_MONOTONIC */
+
+/*
+ * Define this if we have linux style epoll()
+ */
+/* #define HAVE_EPOLL */
+
+/*
+ * Endianness of the target machine. Choose one:
+ *
+ * HAVE_ENDIAN_H -- have endian.h header we can include.
+ * HAVE_LITTLE_ENDIAN -- we are little endian.
+ * HAVE_BIG_ENDIAN -- we are big endian.
+ */
+/* #define HAVE_ENDIAN_H */
+#define HAVE_LITTLE_ENDIAN
+
+/*
+ * Define this if you have sys/endian.h
+ * NOTE: mutually exclusive with HAVE_ENDIAN_H
+ */
+#define HAVE_SYS_ENDIAN_H
+
+/*
+ * We need to choose between 32-bit and 64-bit off_t. All of our code should
+ * agree on the same size. For desktop systems, use 64-bit values,
+ * because some of our libraries (e.g. wxWidgets) expect to be built that way.
+ */
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE_SOURCE 1
+
+/*
+ * Defined if we have the backtrace() call for retrieving a stack trace.
+ * Needed for CallStack to operate; if not defined, CallStack is
+ * non-functional.
+ */
+#define HAVE_BACKTRACE 0
+
+/*
+ * Defined if we have the dladdr() call for retrieving the symbol associated
+ * with a memory address. If not defined, stack crawls will not have symbolic
+ * information.
+ */
+#define HAVE_DLADDR 1
+
+/*
+ * Defined if we have the cxxabi.h header for demangling C++ symbols. If
+ * not defined, stack crawls will be displayed with raw mangled symbols
+ */
+#define HAVE_CXXABI 0
+
+/*
+ * Defined if we have the gettid() system call.
+ */
+/* #define HAVE_GETTID */
+
+/*
+ * Defined if we have the sched_setscheduler() call
+ */
+#define HAVE_SCHED_SETSCHEDULER
+
+/*
+ * Add any extra platform-specific defines here.
+ */
+
+/*
+ * Define if we have <malloc.h> header
+ */
+#define HAVE_MALLOC_H
+
+/*
+ * Define if we have Linux-style non-filesystem Unix Domain Sockets
+ */
+
+/*
+ * What CPU architecture does this platform use?
+ */
+#define ARCH_X86
+
+
+/*
+ * Define if we have Linux's inotify in <sys/inotify.h>.
+ */
+/*#define HAVE_INOTIFY 1*/
+
+/*
+ * Define if we have madvise() in <sys/mman.h>
+ */
+#define HAVE_MADVISE 1
+
+/*
+ * Define if tm struct has tm_gmtoff field
+ */
+#define HAVE_TM_GMTOFF 1
+
+/*
+ * Define if dirent struct has d_type field
+ */
+#define HAVE_DIRENT_D_TYPE 1
+
+/*
+ * Define if libc includes Android system properties implementation.
+ */
+/* #define HAVE_LIBC_SYSTEM_PROPERTIES */
+
+/*
+ * Define if system provides a system property server (should be
+ * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
+ */
+#define HAVE_SYSTEM_PROPERTY_SERVER
+
+/*
+ * sprintf() format string for shared library naming.
+ */
+#define OS_SHARED_LIB_FORMAT_STR "lib%s.so"
+
+/*
+ * type for the third argument to mincore().
+ */
+#define MINCORE_POINTER_TYPE char *
+
+/*
+ * Do we have the sigaction flag SA_NOCLDWAIT?
+ */
+#define HAVE_SA_NOCLDWAIT
+
+/*
+ * Define if we include <sys/mount.h> for statfs()
+ */
+#define INCLUDE_SYS_MOUNT_FOR_STATFS 1
+
+/*
+ * The default path separator for the platform
+ */
+#define OS_PATH_SEPARATOR '/'
+
+/*
+ * Is the filesystem case sensitive?
+ */
+#define OS_CASE_SENSITIVE
+
+/*
+ * Define if <sys/socket.h> exists.
+ */
+#define HAVE_SYS_SOCKET_H 1
+
+/*
+ * Define if the strlcpy() function exists on the system.
+ */
+#define HAVE_STRLCPY 1
+
+/*
+ * Define if prctl() exists
+ */
+/* #define HAVE_PRCTL 1 */
+
+/*
+ * Define if writev() exists
+ */
+#define HAVE_WRITEV 1
+
+/*
+ * Define if <alloca.h> does not exist
+ * NOTE: <alloca.h> defines alloca() which
+ * on FreeBSD is defined in <stdlib.h>
+ */
+#define HAVE_NO_ALLOCA_H
+
+/*
+ * Defines CLOCK_PROCESS_CPUTIME_ID for clock_gettime()
+ * XXX: CLOCK_PROF seems to be commonly used replacement
+ */
+#ifndef CLOCK_PROCESS_CPUTIME_ID
+#define CLOCK_PROCESS_CPUTIME_ID CLOCK_PROF
+#endif
+
+#endif /*_ANDROID_CONFIG_H*/
diff --git a/include/cutils/abort_socket.h b/include/cutils/abort_socket.h
new file mode 100644
index 0000000..fbb1112
--- /dev/null
+++ b/include/cutils/abort_socket.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2009, 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.
+ */
+
+/* Helper to perform abortable blocking operations on a socket:
+ * asocket_connect()
+ * asocket_accept()
+ * asocket_read()
+ * asocket_write()
+ * These calls are similar to the regular syscalls, but can be aborted with:
+ * asocket_abort()
+ *
+ * Calling close() on a regular POSIX socket does not abort blocked syscalls on
+ * that socket in other threads.
+ *
+ * After calling asocket_abort() the socket cannot be reused.
+ *
+ * Call asocket_destory() *after* all threads have finished with the socket to
+ * finish closing the socket and free the asocket structure.
+ *
+ * The helper is implemented by setting the socket non-blocking to initiate
+ * syscalls connect(), accept(), read(), write(), then using a blocking poll()
+ * on both the primary socket and a local pipe. This makes the poll() abortable
+ * by writing a byte to the local pipe in asocket_abort().
+ *
+ * asocket_create() sets the fd to non-blocking mode. It must not be changed to
+ * blocking mode.
+ *
+ * Using asocket will triple the number of file descriptors required per
+ * socket, due to the local pipe. It may be possible to use a global pipe per
+ * process rather than per socket, but we have not been able to come up with a
+ * race-free implementation yet.
+ *
+ * All functions except asocket_init() and asocket_destroy() are thread safe.
+ */
+
+#include <stdlib.h>
+#include <sys/socket.h>
+
+#ifndef __CUTILS_ABORT_SOCKET_H__
+#define __CUTILS_ABORT_SOCKET_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct asocket {
+ int fd; /* primary socket fd */
+ int abort_fd[2]; /* pipe used to abort */
+};
+
+/* Create an asocket from fd.
+ * Sets the socket to non-blocking mode.
+ * Returns NULL on error with errno set.
+ */
+struct asocket *asocket_init(int fd);
+
+/* Blocking socket I/O with timeout.
+ * Calling asocket_abort() from another thread will cause each of these
+ * functions to immediately return with value -1 and errno ECANCELED.
+ * timeout is in ms, use -1 to indicate no timeout. On timeout -1 is returned
+ * with errno ETIMEDOUT.
+ * EINTR is handled in-call.
+ * Other semantics are identical to the regular syscalls.
+ */
+int asocket_connect(struct asocket *s, const struct sockaddr *addr,
+ socklen_t addrlen, int timeout);
+
+int asocket_accept(struct asocket *s, struct sockaddr *addr,
+ socklen_t *addrlen, int timeout);
+
+int asocket_read(struct asocket *s, void *buf, size_t count, int timeout);
+
+int asocket_write(struct asocket *s, const void *buf, size_t count,
+ int timeout);
+
+/* Abort above calls and shutdown socket.
+ * Further I/O operations on this socket will immediately fail after this call.
+ * asocket_destroy() should be used to release resources once all threads
+ * have returned from blocking calls on the socket.
+ */
+void asocket_abort(struct asocket *s);
+
+/* Close socket and free asocket structure.
+ * Must not be called until all calls on this structure have completed.
+ */
+void asocket_destroy(struct asocket *s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif //__CUTILS_ABORT_SOCKET__H__
diff --git a/init/builtins.c b/init/builtins.c
index 17df0af..43508ef 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -29,6 +29,7 @@
#include <stdlib.h>
#include <sys/mount.h>
#include <sys/resource.h>
+#include <linux/loop.h>
#include "init.h"
#include "keywords.h"
@@ -130,6 +131,18 @@
}
}
+int do_chdir(int nargs, char **args)
+{
+ chdir(args[1]);
+ return 0;
+}
+
+int do_chroot(int nargs, char **args)
+{
+ chroot(args[1]);
+ return 0;
+}
+
int do_class_start(int nargs, char **args)
{
/* Starting a class does not start services
@@ -205,7 +218,7 @@
int do_import(int nargs, char **args)
{
- return -1;
+ return parse_config_file(args[1]);
}
int do_mkdir(int nargs, char **args)
@@ -257,7 +270,7 @@
int do_mount(int nargs, char **args)
{
char tmp[64];
- char *source;
+ char *source, *target, *system;
char *options = NULL;
unsigned flags = 0;
int n, i;
@@ -275,15 +288,70 @@
options = args[n];
}
+ system = args[1];
source = args[2];
+ target = args[3];
+
if (!strncmp(source, "mtd@", 4)) {
n = mtd_name_to_number(source + 4);
- if (n >= 0) {
- sprintf(tmp, "/dev/block/mtdblock%d", n);
- source = tmp;
+ if (n < 0) {
+ return -1;
}
+
+ sprintf(tmp, "/dev/block/mtdblock%d", n);
+
+ if (mount(tmp, target, system, flags, options) < 0) {
+ return -1;
+ }
+
+ return 0;
+ } else if (!strncmp(source, "loop@", 5)) {
+ int mode, loop, fd;
+ struct loop_info info;
+
+ mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
+ fd = open(source + 5, mode);
+ if (fd < 0) {
+ return -1;
+ }
+
+ for (n = 0; ; n++) {
+ sprintf(tmp, "/dev/block/loop%d", n);
+ loop = open(tmp, mode);
+ if (loop < 0) {
+ return -1;
+ }
+
+ /* if it is a blank loop device */
+ if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
+ /* if it becomes our loop device */
+ if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
+ close(fd);
+
+ if (mount(tmp, target, system, flags, options) < 0) {
+ ioctl(loop, LOOP_CLR_FD, 0);
+ close(loop);
+ return -1;
+ }
+
+ close(loop);
+ return 0;
+ }
+ }
+
+ close(loop);
+ }
+
+ close(fd);
+ ERROR("out of loopback devices");
+ return -1;
+ } else {
+ if (mount(source, target, system, flags, options) < 0) {
+ return -1;
+ }
+
+ return 0;
}
- return mount(source, args[3], args[1], flags, options);
}
int do_setkey(int nargs, char **args)
@@ -344,6 +412,8 @@
int do_trigger(int nargs, char **args)
{
+ action_for_each_trigger(args[1], action_add_queue_tail);
+ drain_action_queue();
return 0;
}
diff --git a/init/devices.c b/init/devices.c
index ac72b34..606a074 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -288,7 +288,7 @@
chown(path, uid, gid);
}
-#ifdef LOG_UEVENTS
+#if LOG_UEVENTS
static inline suseconds_t get_usecs(void)
{
@@ -393,6 +393,9 @@
} else if(!strncmp(uevent->subsystem, "mtd", 3)) {
base = "/dev/mtd/";
mkdir(base, 0755);
+ } else if(!strncmp(uevent->subsystem, "sound", 5)) {
+ base = "/dev/snd/";
+ mkdir(base, 0755);
} else if(!strncmp(uevent->subsystem, "misc", 4) &&
!strncmp(name, "log_", 4)) {
base = "/dev/log/";
diff --git a/init/init.c b/init/init.c
old mode 100644
new mode 100755
index 0c1ad3f..adc4c9f
--- a/init/init.c
+++ b/init/init.c
@@ -65,8 +65,6 @@
static int keychords_count = 0;
static int keychords_length = 0;
-static void drain_action_queue(void);
-
static void notify_service_state(const char *name, const char *state)
{
char pname[PROP_NAME_MAX];
@@ -256,7 +254,8 @@
}
if (!dynamic_args)
- execve(svc->args[0], (char**) svc->args, (char**) ENV);
+ if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0)
+ ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
else {
char *arg_ptrs[SVC_MAXARGS+1];
int arg_idx = svc->nargs;
@@ -273,7 +272,8 @@
break;
}
arg_ptrs[arg_idx] = '\0';
- execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
+ if (execve(svc->args[0], (char**) arg_ptrs, (char**) ENV) < 0)
+ ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
}
_exit(127);
}
@@ -389,12 +389,13 @@
}
}
+ svc->flags |= SVC_RESTARTING;
+
/* Execute all onrestart commands for this service. */
list_for_each(node, &svc->onrestart.commands) {
cmd = node_to_item(node, struct command, clist);
cmd->func(cmd->nargs, cmd->args);
}
- svc->flags |= SVC_RESTARTING;
notify_service_state(svc->name, "restarting");
return 0;
}
@@ -665,7 +666,7 @@
}
}
-static void drain_action_queue(void)
+void drain_action_queue(void)
{
struct listnode *node;
struct command *cmd;
diff --git a/init/init.h b/init/init.h
index f306b7b..60c3055 100644
--- a/init/init.h
+++ b/init/init.h
@@ -165,6 +165,7 @@
void service_start(struct service *svc, const char *dynamic_args);
void property_changed(const char *name, const char *value);
+void drain_action_queue(void);
struct action *action_remove_queue_head(void);
void action_add_queue_tail(struct action *act);
void action_for_each_trigger(const char *trigger,
diff --git a/init/keywords.h b/init/keywords.h
index 6f47379..1e2b9c8 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -1,5 +1,7 @@
#ifndef KEYWORD
+int do_chroot(int nargs, char **args);
+int do_chdir(int nargs, char **args);
int do_class_start(int nargs, char **args);
int do_class_stop(int nargs, char **args);
int do_domainname(int nargs, char **args);
@@ -31,6 +33,8 @@
K_UNKNOWN,
#endif
KEYWORD(capability, OPTION, 0, 0)
+ KEYWORD(chdir, COMMAND, 1, do_chdir)
+ KEYWORD(chroot, COMMAND, 1, do_chroot)
KEYWORD(class, OPTION, 0, 0)
KEYWORD(class_start, COMMAND, 1, do_class_start)
KEYWORD(class_stop, COMMAND, 1, do_class_stop)
diff --git a/init/parser.c b/init/parser.c
index 33c1a68..0eb078d 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -128,6 +128,8 @@
switch (*s++) {
case 'c':
if (!strcmp(s, "apability")) return K_capability;
+ if (!strcmp(s, "hdir")) return K_chdir;
+ if (!strcmp(s, "hroot")) return K_chroot;
if (!strcmp(s, "lass")) return K_class;
if (!strcmp(s, "lass_start")) return K_class_start;
if (!strcmp(s, "lass_stop")) return K_class_stop;
diff --git a/init/readme.txt b/init/readme.txt
index 665090b..a185790 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -145,12 +145,18 @@
hostname <name>
Set the host name.
+chdir <directory>
+ Change working directory.
+
chmod <octal-mode> <path>
Change file access permissions.
chown <owner> <group> <path>
Change file owner and group.
+chroot <directory>
+ Change process root directory.
+
class_start <serviceclass>
Start all services of the specified class if they are
not already running.
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 18d0ee3..98e59ee 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
commonSources := \
+ abort_socket.c \
array.c \
hashmap.c \
atomic.c \
diff --git a/libcutils/abort_socket.c b/libcutils/abort_socket.c
new file mode 100644
index 0000000..6a5e5e4
--- /dev/null
+++ b/libcutils/abort_socket.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2009, 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.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+
+#include "cutils/abort_socket.h"
+
+struct asocket *asocket_init(int fd) {
+ int abort_fd[2];
+ int flags;
+ struct asocket *s;
+
+ /* set primary socket to non-blocking */
+ flags = fcntl(fd, F_GETFL);
+ if (flags == -1)
+ return NULL;
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
+ return NULL;
+
+ /* create pipe with non-blocking write, so that asocket_close() cannot
+ block */
+ if (pipe(abort_fd))
+ return NULL;
+ flags = fcntl(abort_fd[1], F_GETFL);
+ if (flags == -1)
+ return NULL;
+ if (fcntl(abort_fd[1], F_SETFL, flags | O_NONBLOCK))
+ return NULL;
+
+ s = malloc(sizeof(struct asocket));
+ if (!s)
+ return NULL;
+
+ s->fd = fd;
+ s->abort_fd[0] = abort_fd[0];
+ s->abort_fd[1] = abort_fd[1];
+
+ return s;
+}
+
+int asocket_connect(struct asocket *s, const struct sockaddr *addr,
+ socklen_t addrlen, int timeout) {
+
+ int ret;
+
+ do {
+ ret = connect(s->fd, addr, addrlen);
+ } while (ret && errno == EINTR);
+
+ if (ret && errno == EINPROGRESS) {
+ /* ready to poll() */
+ socklen_t retlen;
+ struct pollfd pfd[2];
+
+ pfd[0].fd = s->fd;
+ pfd[0].events = POLLOUT;
+ pfd[0].revents = 0;
+ pfd[1].fd = s->abort_fd[0];
+ pfd[1].events = POLLIN;
+ pfd[1].revents = 0;
+
+ do {
+ ret = poll(pfd, 2, timeout);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0)
+ return -1;
+ else if (ret == 0) {
+ /* timeout */
+ errno = ETIMEDOUT;
+ return -1;
+ }
+
+ if (pfd[1].revents) {
+ /* abort due to asocket_abort() */
+ errno = ECANCELED;
+ return -1;
+ }
+
+ if (pfd[0].revents) {
+ if (pfd[0].revents & POLLOUT) {
+ /* connect call complete, read return code */
+ retlen = sizeof(ret);
+ if (getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &ret, &retlen))
+ return -1;
+ /* got connect() return code */
+ if (ret) {
+ errno = ret;
+ }
+ } else {
+ /* some error event on this fd */
+ errno = ECONNABORTED;
+ return -1;
+ }
+ }
+ }
+
+ return ret;
+}
+
+int asocket_accept(struct asocket *s, struct sockaddr *addr,
+ socklen_t *addrlen, int timeout) {
+
+ int ret;
+ struct pollfd pfd[2];
+
+ pfd[0].fd = s->fd;
+ pfd[0].events = POLLIN;
+ pfd[0].revents = 0;
+ pfd[1].fd = s->abort_fd[0];
+ pfd[1].events = POLLIN;
+ pfd[1].revents = 0;
+
+ do {
+ ret = poll(pfd, 2, timeout);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0)
+ return -1;
+ else if (ret == 0) {
+ /* timeout */
+ errno = ETIMEDOUT;
+ return -1;
+ }
+
+ if (pfd[1].revents) {
+ /* abort due to asocket_abort() */
+ errno = ECANCELED;
+ return -1;
+ }
+
+ if (pfd[0].revents) {
+ if (pfd[0].revents & POLLIN) {
+ /* ready to accept() without blocking */
+ do {
+ ret = accept(s->fd, addr, addrlen);
+ } while (ret < 0 && errno == EINTR);
+ } else {
+ /* some error event on this fd */
+ errno = ECONNABORTED;
+ return -1;
+ }
+ }
+
+ return ret;
+}
+
+int asocket_read(struct asocket *s, void *buf, size_t count, int timeout) {
+ int ret;
+ struct pollfd pfd[2];
+
+ pfd[0].fd = s->fd;
+ pfd[0].events = POLLIN;
+ pfd[0].revents = 0;
+ pfd[1].fd = s->abort_fd[0];
+ pfd[1].events = POLLIN;
+ pfd[1].revents = 0;
+
+ do {
+ ret = poll(pfd, 2, timeout);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0)
+ return -1;
+ else if (ret == 0) {
+ /* timeout */
+ errno = ETIMEDOUT;
+ return -1;
+ }
+
+ if (pfd[1].revents) {
+ /* abort due to asocket_abort() */
+ errno = ECANCELED;
+ return -1;
+ }
+
+ if (pfd[0].revents) {
+ if (pfd[0].revents & POLLIN) {
+ /* ready to read() without blocking */
+ do {
+ ret = read(s->fd, buf, count);
+ } while (ret < 0 && errno == EINTR);
+ } else {
+ /* some error event on this fd */
+ errno = ECONNABORTED;
+ return -1;
+ }
+ }
+
+ return ret;
+}
+
+int asocket_write(struct asocket *s, const void *buf, size_t count,
+ int timeout) {
+ int ret;
+ struct pollfd pfd[2];
+
+ pfd[0].fd = s->fd;
+ pfd[0].events = POLLOUT;
+ pfd[0].revents = 0;
+ pfd[1].fd = s->abort_fd[0];
+ pfd[1].events = POLLIN;
+ pfd[1].revents = 0;
+
+ do {
+ ret = poll(pfd, 2, timeout);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0)
+ return -1;
+ else if (ret == 0) {
+ /* timeout */
+ errno = ETIMEDOUT;
+ return -1;
+ }
+
+ if (pfd[1].revents) {
+ /* abort due to asocket_abort() */
+ errno = ECANCELED;
+ return -1;
+ }
+
+ if (pfd[0].revents) {
+ if (pfd[0].revents & POLLOUT) {
+ /* ready to write() without blocking */
+ do {
+ ret = write(s->fd, buf, count);
+ } while (ret < 0 && errno == EINTR);
+ } else {
+ /* some error event on this fd */
+ errno = ECONNABORTED;
+ return -1;
+ }
+ }
+
+ return ret;
+}
+
+void asocket_abort(struct asocket *s) {
+ int ret;
+ char buf = 0;
+
+ /* Prevent further use of fd, without yet releasing the fd */
+ shutdown(s->fd, SHUT_RDWR);
+
+ /* wake up calls blocked at poll() */
+ do {
+ ret = write(s->abort_fd[1], &buf, 1);
+ } while (ret < 0 && errno == EINTR);
+}
+
+void asocket_destroy(struct asocket *s) {
+ struct asocket s_copy = *s;
+
+ /* Clients should *not* be using these fd's after calling
+ asocket_destroy(), but in case they do, set to -1 so they cannot use a
+ stale fd */
+ s->fd = -1;
+ s->abort_fd[0] = -1;
+ s->abort_fd[1] = -1;
+
+ /* Call asocket_abort() in case there are still threads blocked on this
+ socket. Clients should not rely on this behavior - it is racy because we
+ are about to close() these sockets - clients should instead make sure
+ all threads are done with the socket before calling asocket_destory().
+ */
+ asocket_abort(&s_copy);
+
+ /* enough safety checks, close and release memory */
+ close(s_copy.abort_fd[1]);
+ close(s_copy.abort_fd[0]);
+ close(s_copy.fd);
+
+ free(s);
+}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 2cf1254..080f9e3 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -23,7 +23,6 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
-#include <alloca.h>
#include <assert.h>
#include <arpa/inet.h>
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 50eb5f5..0cc85d9 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -64,12 +64,14 @@
LOCAL_MODULE:= libpixelflinger
LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES)
LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
+
ifneq ($(BUILD_TINY_ANDROID),true)
# Really this should go away entirely or at least not depend on
# libhardware, but this at least gets us built.
LOCAL_SHARED_LIBRARIES += libhardware_legacy
LOCAL_CFLAGS += -DWITH_LIB_HARDWARE
endif
+
ifeq ($(TARGET_ARCH),arm)
LOCAL_WHOLE_STATIC_LIBRARIES := libpixelflinger_armv6
endif
diff --git a/rootdir/etc/init.goldfish.sh b/rootdir/etc/init.goldfish.sh
index f1b801d..5ff0a3a 100755
--- a/rootdir/etc/init.goldfish.sh
+++ b/rootdir/etc/init.goldfish.sh
@@ -3,16 +3,20 @@
ifconfig eth0 10.0.2.15 netmask 255.255.255.0 up
route add default gw 10.0.2.2 dev eth0
-qemud=`getprop.ro.kernel.android.qemud`
-if test -z "$qemud"; then
+qemud=`getprop ro.kernel.android.qemud`
+case "$qemud" in
+ "")
radio_ril=`getprop ro.kernel.android.ril`
- if test -z "$radio_ril"; then
+ case "$radio_ril" in
+ "")
# no need for the radio interface daemon
# telephony is entirely emulated in Java
setprop ro.radio.noril yes
stop ril-daemon
- fi
-fi
+ ;;
+ esac
+ ;;
+esac
num_dns=`getprop ro.kernel.android.ndns`
case "$num_dns" in
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 2bed980..9d30518 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -38,7 +38,7 @@
# Create cgroup mount points for process groups
mkdir /dev/cpuctl
mount cgroup none /dev/cpuctl cpu
- chown sytem system /dev/cpuctl
+ chown system system /dev/cpuctl
chown system system /dev/cpuctl/tasks
chmod 0777 /dev/cpuctl/tasks
write /dev/cpuctl/cpu.shares 1024
diff --git a/toolbox/mount.c b/toolbox/mount.c
index 86047a9..472c952 100644
--- a/toolbox/mount.c
+++ b/toolbox/mount.c
@@ -138,14 +138,17 @@
if (loop) {
int file_fd, device_fd;
+ int flags;
+
+ flags = (rwflag & MS_RDONLY) ? O_RDONLY : O_RDWR;
// FIXME - only one loop mount supported at a time
- file_fd = open(dev, O_RDWR);
+ file_fd = open(dev, flags);
if (file_fd < -1) {
perror("open backing file failed");
return 1;
}
- device_fd = open(LOOP_DEVICE, O_RDWR);
+ device_fd = open(LOOP_DEVICE, flags);
if (device_fd < -1) {
perror("open loop device failed");
close(file_fd);
diff --git a/vold/blkdev.c b/vold/blkdev.c
index e10eafc..2c5681a 100644
--- a/vold/blkdev.c
+++ b/vold/blkdev.c
@@ -112,7 +112,7 @@
goto out;
}
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < NDOSPART; i++) {
struct dos_partition part;
dos_partition_dec(block + DOSPARTOFF + i * sizeof(struct dos_partition), &part);
@@ -134,7 +134,7 @@
struct dos_partition part;
int part_no = blk->minor -1;
- if (part_no < 4) {
+ if (part_no < NDOSPART) {
dos_partition_dec(block + DOSPARTOFF + part_no * sizeof(struct dos_partition), &part);
blk->part_type = part.dp_typ;
} else {
diff --git a/vold/mmc.c b/vold/mmc.c
index cbddb92..6ad97f4 100644
--- a/vold/mmc.c
+++ b/vold/mmc.c
@@ -25,6 +25,7 @@
#include "vold.h"
#include "mmc.h"
#include "media.h"
+#include "diskmbr.h" /* for NDOSPART */
#define DEBUG_BOOTSTRAP 0
@@ -157,6 +158,10 @@
sprintf(filename, "/sys%s/name", devpath);
p = read_file(filename, &sz);
+ if (!p) {
+ LOGE("Unable to read MMC name: %s", filename);
+ return -errno;
+ }
p[strlen(p) - 1] = '\0';
sprintf(tmp, "MMC_NAME=%s", p);
free(p);
@@ -233,7 +238,7 @@
*mmcblk_devname != '/'; mmcblk_devname--);
mmcblk_devname++;
- for (part_no = 0; part_no < 4; part_no++) {
+ for (part_no = 1; part_no <= NDOSPART; part_no++) {
char part_file[255];
sprintf(part_file, "/sys%s/%sp%d", devpath, mmcblk_devname, part_no);
if (!access(part_file, F_OK)) {