merge master to master_gl
diff --git a/adb/Android.mk b/adb/Android.mk
index c8606cf..9725478 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -53,10 +53,13 @@
 	$(USB_SRCS) \
 	shlist.c \
 	utils.c \
+	usb_vendors.c \
 
 
 ifneq ($(USE_SYSDEPS_WIN32),)
   LOCAL_SRC_FILES += sysdeps_win32.c
+else
+  LOCAL_SRC_FILES += fdevent.c
 endif
 
 LOCAL_CFLAGS += -O2 -g -DADB_HOST=1  -Wall -Wno-unused-parameter
@@ -98,6 +101,7 @@
 
 LOCAL_SRC_FILES := \
 	adb.c \
+	fdevent.c \
 	transport.c \
 	transport_local.c \
 	transport_usb.c \
diff --git a/adb/adb.c b/adb/adb.c
index 12a36f5..0b5ebac 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -29,6 +29,8 @@
 
 #if !ADB_HOST
 #include <private/android_filesystem_config.h>
+#else
+#include "usb_vendors.h"
 #endif
 
 
@@ -818,19 +820,6 @@
 #if !ADB_HOST
     int secure = 0;
     char value[PROPERTY_VALUE_MAX];
-
-    // prevent the OOM killer from killing us
-    char text[64];
-    snprintf(text, sizeof text, "/proc/%d/oom_adj", (int)getpid());
-    int fd = adb_open(text, O_WRONLY);
-    if (fd >= 0) {
-        // -17 should make us immune to OOM
-        snprintf(text, sizeof text, "%d", -17);
-        adb_write(fd, text, strlen(text));
-        adb_close(fd);
-    } else {
-       D("adb: unable to open %s\n", text);
-    }
 #endif
 
     atexit(adb_cleanup);
@@ -846,6 +835,7 @@
 
 #if ADB_HOST
     HOST = 1;
+    usb_vendors_init();
     usb_init();
     local_init();
 
@@ -929,6 +919,9 @@
     fdevent_loop();
 
     usb_cleanup();
+#if ADB_HOST
+    usb_vendors_cleanup();
+#endif
 
     return 0;
 }
diff --git a/adb/adb.h b/adb/adb.h
index aebb81a..7762e00 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -375,7 +375,9 @@
 void usb_kick(usb_handle *h);
 
 /* used for USB device detection */
+#if ADB_HOST
 int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
+#endif
 
 unsigned host_to_le32(unsigned n);
 int adb_commandline(int argc, char **argv);
diff --git a/libcutils/fdevent.c b/adb/fdevent.c
similarity index 98%
rename from libcutils/fdevent.c
rename to adb/fdevent.c
index 4cf46fa..c179b20 100644
--- a/libcutils/fdevent.c
+++ b/adb/fdevent.c
@@ -26,7 +26,7 @@
 #include <stdarg.h>
 #include <stddef.h>
 
-#include <cutils/fdevent.h>
+#include "fdevent.h"
 
 #define TRACE(x...) fprintf(stderr,x)
 
@@ -87,7 +87,7 @@
 {
         /* XXX: what's a good size for the passed in hint? */
     epoll_fd = epoll_create(256);
-    
+
     if(epoll_fd < 0) {
         perror("epoll_create() failed");
         exit(1);
@@ -105,7 +105,7 @@
     ev.events = 0;
     ev.data.ptr = fde;
 
-#if 0    
+#if 0
     if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
         perror("epoll_ctl() failed\n");
         exit(1);
@@ -116,7 +116,7 @@
 static void fdevent_disconnect(fdevent *fde)
 {
     struct epoll_event ev;
-    
+
     memset(&ev, 0, sizeof(ev));
     ev.events = 0;
     ev.data.ptr = fde;
@@ -133,9 +133,9 @@
 {
     struct epoll_event ev;
     int active;
-    
+
     active = (fde->state & FDE_EVENTMASK) != 0;
-    
+
     memset(&ev, 0, sizeof(ev));
     ev.events = 0;
     ev.data.ptr = fde;
@@ -241,7 +241,7 @@
 static void fdevent_disconnect(fdevent *fde)
 {
     int i, n;
-    
+
     FD_CLR(fde->fd, &read_fds);
     FD_CLR(fde->fd, &write_fds);
     FD_CLR(fde->fd, &error_fds);
@@ -283,9 +283,9 @@
     memcpy(&rfd, &read_fds, sizeof(fd_set));
     memcpy(&wfd, &write_fds, sizeof(fd_set));
     memcpy(&efd, &error_fds, sizeof(fd_set));
-    
+
     n = select(select_n, &rfd, &wfd, &efd, 0);
-    
+
     if(n < 0) {
         if(errno == EINTR) return;
         perror("select");
@@ -300,12 +300,12 @@
 
         if(events) {
             n--;
-            
+
             fde = fd_table[i];
             if(fde == 0) FATAL("missing fde for fd %d\n", i);
 
             fde->events |= events;
-            
+
             if(fde->state & FDE_PENDING) continue;
             fde->state |= FDE_PENDING;
             fdevent_plist_enqueue(fde);
@@ -320,7 +320,7 @@
     if(fde->fd < 0) {
         FATAL("bogus negative fd (%d)\n", fde->fd);
     }
-    
+
     if(fde->fd >= fd_table_max) {
         int oldmax = fd_table_max;
         if(fde->fd > 32000) {
@@ -383,9 +383,9 @@
 {
     fdevent *list = &list_pending;
     fdevent *node = list->next;
-    
+
     if(node == list) return 0;
-    
+
     list->next = node->next;
     list->next->prev = list;
     node->next = 0;
@@ -449,9 +449,9 @@
 void fdevent_set(fdevent *fde, unsigned events)
 {
     events &= FDE_EVENTMASK;
-    
+
     if((fde->state & FDE_EVENTMASK) == events) return;
-    
+
     if(fde->state & FDE_ACTIVE) {
         fdevent_update(fde, events);
         dump_fde(fde, "update");
@@ -487,13 +487,13 @@
 void fdevent_loop()
 {
     fdevent *fde;
-    
+
     for(;;) {
 #if DEBUG
         fprintf(stderr,"--- ---- waiting for events\n");
 #endif
         fdevent_process();
-        
+
         while((fde = fdevent_plist_dequeue())) {
             unsigned events = fde->events;
             fde->events = 0;
diff --git a/include/cutils/fdevent.h b/adb/fdevent.h
similarity index 89%
rename from include/cutils/fdevent.h
rename to adb/fdevent.h
index 7a442d4..6b7e7ec 100644
--- a/include/cutils/fdevent.h
+++ b/adb/fdevent.h
@@ -17,10 +17,13 @@
 #ifndef __FDEVENT_H
 #define __FDEVENT_H
 
+#include <stdint.h>  /* for int64_t */
+
 /* events that may be observed */
 #define FDE_READ              0x0001
 #define FDE_WRITE             0x0002
 #define FDE_ERROR             0x0004
+#define FDE_TIMEOUT           0x0008
 
 /* features that may be set (via the events set/add/del interface) */
 #define FDE_DONT_CLOSE        0x0080
@@ -30,6 +33,8 @@
 typedef void (*fd_func)(int fd, unsigned events, void *userdata);
 
 /* Allocate and initialize a new fdevent object
+ * Note: use FD_TIMER as 'fd' to create a fd-less object
+ * (used to implement timers).
 */
 fdevent *fdevent_create(int fd, fd_func func, void *arg);
 
@@ -53,6 +58,8 @@
 void fdevent_add(fdevent *fde, unsigned events);
 void fdevent_del(fdevent *fde, unsigned events);
 
+void fdevent_set_timeout(fdevent *fde, int64_t  timeout_ms);
+
 /* loop forever, handling events.
 */
 void fdevent_loop();
@@ -65,7 +72,7 @@
     int fd;
     unsigned short state;
     unsigned short events;
-    
+
     fd_func func;
     void *arg;
 };
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index 4e6d385..0ebfe73 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -165,7 +165,7 @@
 }
 
 static int sync_finish_readtime(int fd, unsigned int *timestamp,
-				unsigned int *mode, unsigned int *size)
+                                unsigned int *mode, unsigned int *size)
 {
     syncmsg msg;
 
@@ -908,12 +908,12 @@
             unsigned int timestamp, mode, size;
             if (sync_finish_readtime(fd, &timestamp, &mode, &size))
                 return 1;
-	    if (size == ci->size) {
+            if (size == ci->size) {
                 /* for links, we cannot update the atime/mtime */
                 if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
-		   (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
+                    (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
                     ci->flag = 1;
-	    }
+            }
         }
     }
 #endif
diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c
index 0de0dd5..65cb20a 100644
--- a/adb/framebuffer_service.c
+++ b/adb/framebuffer_service.c
@@ -20,7 +20,7 @@
 #include <string.h>
 #include <fcntl.h>
 
-#include <cutils/fdevent.h>
+#include "fdevent.h"
 #include "adb.h"
 
 #include <linux/fb.h>
diff --git a/adb/protocol.txt b/adb/protocol.txt
index d0f307c..398d042 100644
--- a/adb/protocol.txt
+++ b/adb/protocol.txt
@@ -23,7 +23,7 @@
 
 
 --- protocol overview and basics ---------------------------------------
- 
+
 The transport layer deals in "messages", which consist of a 24 byte
 header followed (optionally) by a payload.  The header consists of 6
 32 bit words which are sent across the wire in little endian format.
@@ -52,7 +52,7 @@
 reversed.
 
 
-
+
 --- CONNECT(version, maxdata, "system-identity-string") ----------------
 
 The CONNECT message establishes the presence of a remote system.
@@ -114,7 +114,7 @@
 not change on later READY messages sent to the same stream.
 
 
-
+
 --- WRITE(0, remote-id, "data") ----------------------------------------
 
 The WRITE message sends data to the recipient's stream identified by
@@ -172,7 +172,7 @@
 #define A_WRTE 0x45545257
 
 
-
+
 --- implementation details ---------------------------------------------
 
 The core of the bridge program will use three threads.  One thread
diff --git a/adb/services.c b/adb/services.c
index 1de55e6..0a5edcf 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -244,6 +244,18 @@
                 cmd, strerror(errno), errno);
         exit(-1);
     } else {
+#if !ADB_HOST
+        // set child's OOM adjustment to zero
+        char text[64];
+        snprintf(text, sizeof text, "/proc/%d/oom_adj", pid);
+        int fd = adb_open(text, O_WRONLY);
+        if (fd >= 0) {
+            adb_write(fd, "0", 1);
+            adb_close(fd);
+        } else {
+           D("adb: unable to open %s\n", text);
+        }
+#endif
         return ptm;
     }
 #endif /* !HAVE_WIN32_PROC */
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index e5d17a8..389fbd2 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -67,16 +67,16 @@
 
 static __inline__ int  adb_thread_create( adb_thread_t  *thread, adb_thread_func_t  func, void*  arg)
 {
-	thread->tid = _beginthread( (win_thread_func_t)func, 0, arg );
-	if (thread->tid == (unsigned)-1L) {
-		return -1;
-	}
-	return 0;
+    thread->tid = _beginthread( (win_thread_func_t)func, 0, arg );
+    if (thread->tid == (unsigned)-1L) {
+        return -1;
+    }
+    return 0;
 }
 
 static __inline__ void  close_on_exec(int  fd)
 {
-	/* nothing really */
+    /* nothing really */
 }
 
 extern void  disable_tcp_nagle(int  fd);
@@ -138,7 +138,7 @@
 
 static __inline__ int  adb_open_mode(const char* path, int options, int mode)
 {
-	return adb_open(path, options);
+    return adb_open(path, options);
 }
 
 static __inline__ int  unix_open(const char*  path, int options,...)
@@ -169,7 +169,7 @@
 extern int socket_loopback_server(int port, int type);
 extern int socket_inaddr_any_server(int port, int type);
 
-/* normally provided by <cutils/fdevent.h> */
+/* normally provided by "fdevent.h" */
 
 #define FDE_READ              0x0001
 #define FDE_WRITE             0x0002
@@ -203,7 +203,7 @@
 
 static __inline__ void  adb_sleep_ms( int  mseconds )
 {
-	Sleep( mseconds );
+    Sleep( mseconds );
 }
 
 extern int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen);
@@ -252,7 +252,7 @@
 
 #else /* !_WIN32 a.k.a. Unix */
 
-#include <cutils/fdevent.h>
+#include "fdevent.h"
 #include <cutils/sockets.h>
 #include <cutils/properties.h>
 #include <cutils/misc.h>
@@ -290,7 +290,7 @@
 
 static __inline__ void  close_on_exec(int  fd)
 {
-	fcntl( fd, F_SETFD, FD_CLOEXEC );
+    fcntl( fd, F_SETFD, FD_CLOEXEC );
 }
 
 static __inline__ int  unix_open(const char*  path, int options,...)
@@ -312,7 +312,7 @@
 
 static __inline__ int  adb_open_mode( const char*  pathname, int  options, int  mode )
 {
-	return open( pathname, options, mode );
+    return open( pathname, options, mode );
 }
 
 
@@ -368,11 +368,11 @@
 {
     int  fd = creat(path, mode);
 
-	if ( fd < 0 )
-		return -1;
+    if ( fd < 0 )
+        return -1;
 
     close_on_exec(fd);
-	return fd;
+    return fd;
 }
 #undef   creat
 #define  creat  ___xxx_creat
@@ -439,12 +439,12 @@
 
 static __inline__ void  adb_sleep_ms( int  mseconds )
 {
-	usleep( mseconds*1000 );
+    usleep( mseconds*1000 );
 }
 
 static __inline__ int  adb_mkdir(const char*  path, int mode)
 {
-	return mkdir(path, mode);
+    return mkdir(path, mode);
 }
 #undef   mkdir
 #define  mkdir  ___xxx_mkdir
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index c2a9a98..a8e3bb9 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -739,12 +739,12 @@
 {
     FH   serverfh = _fh_from_int(serverfd);
     FH   fh;
-    
+
     if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
         D( "adb_socket_accept: invalid fd %d\n", serverfd );
         return -1;
     }
-    
+
     fh = _fh_alloc( &_fh_socket_class );
     if (!fh) {
         D( "adb_socket_accept: not enough memory to allocate accepted socket descriptor\n" );
@@ -757,7 +757,7 @@
         D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError() );
         return -1;
     }
-    
+
     snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name );
     D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) );
     return  _fh_to_int(fh);
@@ -768,7 +768,7 @@
 {
     FH   fh = _fh_from_int(fd);
     int  on;
-    
+
     if ( !fh || fh->clazz != &_fh_socket_class )
         return;
 
@@ -1746,7 +1746,7 @@
 
 /**  FILE EVENT HOOKS
  **/
- 
+
 static void  _event_file_prepare( EventHook  hook )
 {
     if (hook->wanted & (FDE_READ|FDE_WRITE)) {
diff --git a/adb/transport_usb.c b/adb/transport_usb.c
index 01c4a7e..50ebff7 100644
--- a/adb/transport_usb.c
+++ b/adb/transport_usb.c
@@ -23,6 +23,10 @@
 #define  TRACE_TAG  TRACE_TRANSPORT
 #include "adb.h"
 
+#if ADB_HOST
+#include "usb_vendors.h"
+#endif
+
 /* XXX better define? */
 #ifdef __ppc__
 #define H4(x)	(((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
@@ -125,23 +129,23 @@
 #endif
 }
 
+#if ADB_HOST
 int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol)
 {
-    if (vid == VENDOR_ID_GOOGLE) {
-            /* might support adb */
-    } else if (vid == VENDOR_ID_HTC) {
-            /* might support adb */
-    } else {
-            /* not supported */
-        return 0;
-    }
+    unsigned i;
+    for (i = 0; i < vendorIdCount; i++) {
+        if (vid == vendorIds[i]) {
+            /* class:vendor (0xff) subclass:android (0x42) proto:adb (0x01) */
+            if(usb_class == 0xff) {
+                if((usb_subclass == 0x42) && (usb_protocol == 0x01)) {
+                    return 1;
+                }
+            }
 
-        /* class:vendor (0xff) subclass:android (0x42) proto:adb (0x01) */
-    if(usb_class == 0xff) {
-        if((usb_subclass == 0x42) && (usb_protocol == 0x01)) {
-            return 1;
+            return 0;
         }
     }
 
     return 0;
 }
+#endif
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index 2d4c1a9..171a9fc 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -28,20 +28,15 @@
 
 #define TRACE_TAG   TRACE_USB
 #include "adb.h"
+#include "usb_vendors.h"
 
 #define  DBG   D
 
 #define ADB_SUBCLASS           0x42
 #define ADB_PROTOCOL           0x1
 
-int vendorIds[] = {
-    VENDOR_ID_GOOGLE,
-    VENDOR_ID_HTC,
-};
-#define NUM_VENDORS             (sizeof(vendorIds)/sizeof(vendorIds[0]))
-
 static IONotificationPortRef    notificationPort = 0;
-static io_iterator_t            notificationIterators[NUM_VENDORS];
+static io_iterator_t*           notificationIterators;
 
 struct usb_handle
 {
@@ -81,7 +76,7 @@
     memset(notificationIterators, 0, sizeof(notificationIterators));
 
     //* loop through all supported vendors
-    for (i = 0; i < NUM_VENDORS; i++) {
+    for (i = 0; i < vendorIdCount; i++) {
         //* Create our matching dictionary to find the Android device's
         //* adb interface
         //* IOServiceAddMatchingNotification consumes the reference, so we do
@@ -374,7 +369,7 @@
     CFRunLoopRun();
     currentRunLoop = 0;
 
-    for (i = 0; i < NUM_VENDORS; i++) {
+    for (i = 0; i < vendorIdCount; i++) {
         IOObjectRelease(notificationIterators[i]);
     }
     IONotificationPortDestroy(notificationPort);
@@ -391,6 +386,9 @@
     {
         adb_thread_t    tid;
 
+        notificationIterators = (io_iterator_t*)malloc(
+            vendorIdCount * sizeof(io_iterator_t));
+
         adb_mutex_init(&start_lock, NULL);
         adb_cond_init(&start_cond, NULL);
 
@@ -415,6 +413,11 @@
     close_usb_devices();
     if (currentRunLoop)
         CFRunLoopStop(currentRunLoop);
+
+    if (notificationIterators != NULL) {
+        free(notificationIterators);
+        notificationIterators = NULL;
+    }
 }
 
 int usb_write(usb_handle *handle, const void *buf, int len)
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
new file mode 100644
index 0000000..f949249
--- /dev/null
+++ b/adb/usb_vendors.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 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 "usb_vendors.h"
+
+#include "sysdeps.h"
+#include <stdio.h>
+#include "adb.h"
+
+int* vendorIds = NULL;
+unsigned vendorIdCount = 0;
+
+void usb_vendors_init(void) {
+    /* for now, only put the built-in VENDOR_ID_* */
+    vendorIdCount = 2;
+    vendorIds = (int*)malloc(vendorIdCount * sizeof(int));
+    vendorIds[0] = VENDOR_ID_GOOGLE;
+    vendorIds[1] = VENDOR_ID_HTC;
+}
+
+void usb_vendors_cleanup(void) {
+    if (vendorIds != NULL) {
+        free(vendorIds);
+        vendorIds = NULL;
+        vendorIdCount = 0;
+    }
+}
diff --git a/adb/usb_vendors.h b/adb/usb_vendors.h
new file mode 100644
index 0000000..43e5f99
--- /dev/null
+++ b/adb/usb_vendors.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef __USB_VENDORS_H
+#define __USB_VENDORS_H
+
+extern int* vendorIds;
+extern unsigned  vendorIdCount;
+
+void usb_vendors_init(void);
+void usb_vendors_cleanup(void);
+
+#endif
\ No newline at end of file
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index 7ddaa0c..0951f67 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -446,7 +446,7 @@
 }
 
 void find_devices() {
-	usb_handle* handle = NULL;
+        usb_handle* handle = NULL;
   char entry_buffer[2048];
   char interf_name[2048];
   AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
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/include/cutils/native_handle.h b/include/cutils/native_handle.h
index 38ac11a..89d6b65 100644
--- a/include/cutils/native_handle.h
+++ b/include/cutils/native_handle.h
@@ -17,52 +17,57 @@
 #ifndef NATIVE_HANDLE_H_
 #define NATIVE_HANDLE_H_
 
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 typedef struct
 {
-    int version;        /* sizeof(native_handle) */
+    int version;        /* sizeof(native_handle_t) */
     int numFds;         /* number of file-descriptors at &data[0] */
     int numInts;        /* number of ints at &data[numFds] */
     int data[0];        /* numFds + numInts ints */
-} native_handle;
+} native_handle_t;
 
 
+/* keep the old definition for backward source-compatibility */
+typedef native_handle_t native_handle;
+
 /*
  * native_handle_close
  * 
- * closes the file descriptors contained in this native_handle
+ * closes the file descriptors contained in this native_handle_t
  * 
  * return 0 on success, or a negative error code on failure
  * 
  */
-int native_handle_close(const native_handle* h);
+int native_handle_close(const native_handle_t* h);
 
 
 /*
  * native_handle_create
  * 
- * creates a native_handle and initializes it. must be destroyed with
+ * creates a native_handle_t and initializes it. must be destroyed with
  * native_handle_delete().
  * 
  */
-native_handle* native_handle_create(int numFds, int numInts);
+native_handle_t* native_handle_create(int numFds, int numInts);
 
 /*
  * native_handle_delete
  * 
- * frees a native_handle allocated with native_handle_create().
- * This ONLY frees the memory allocated for the native_handle, but doesn't
+ * frees a native_handle_t allocated with native_handle_create().
+ * This ONLY frees the memory allocated for the native_handle_t, but doesn't
  * close the file descriptors; which can be achieved with native_handle_close().
  * 
  * return 0 on success, or a negative error code on failure
  * 
  */
-int native_handle_delete(native_handle* h);
+int native_handle_delete(native_handle_t* h);
 
 
-__END_DECLS
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* NATIVE_HANDLE_H_ */
diff --git a/include/cutils/tztime.h b/include/cutils/tztime.h
index 4af2ce4..cf103ca 100644
--- a/include/cutils/tztime.h
+++ b/include/cutils/tztime.h
@@ -32,6 +32,7 @@
 struct strftime_locale {
     const char *mon[12];    /* short names */
     const char *month[12];  /* long names */
+    const char *standalone_month[12];  /* long standalone names */
     const char *wday[7];    /* short names */
     const char *weekday[7]; /* long names */
     const char *X_fmt;
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index a47f2e4..a4351ac 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -49,6 +49,7 @@
 #define AID_MEDIA         1013  /* mediaserver process */
 #define AID_DHCP          1014  /* dhcp client */
 #define AID_SDCARD_RW     1015  /* external storage write access */
+#define AID_VPN           1016  /* vpn system */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
 #define AID_CACHE         2001  /* cache access */
@@ -95,6 +96,7 @@
     { "net_bt_admin", AID_NET_BT_ADMIN, },
     { "net_bt",    AID_NET_BT, },
     { "sdcard_rw", AID_SDCARD_RW, },
+    { "vpn",       AID_VPN, },
     { "inet",      AID_INET, }, 
     { "net_raw",   AID_NET_RAW, },
     { "misc",      AID_MISC, },
@@ -170,6 +172,7 @@
     { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/librank" },
     { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/procrank" },
     { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/procmem" },
+    { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/tcpdump" },
     { 00755, AID_ROOT,      AID_SHELL,     "system/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     "system/xbin/*" },
     { 00750, AID_ROOT,      AID_SHELL,     "sbin/*" },
diff --git a/include/sysutils/FrameworkClient.h b/include/sysutils/FrameworkClient.h
index 1eb112a..0ef0753 100644
--- a/include/sysutils/FrameworkClient.h
+++ b/include/sysutils/FrameworkClient.h
@@ -13,8 +13,8 @@
     FrameworkClient(int sock);
     virtual ~FrameworkClient() {}
 
-    int sendMsg(char *msg);
-    int sendMsg(char *msg, char *data);
+    int sendMsg(const char *msg);
+    int sendMsg(const char *msg, const char *data);
 };
 
 typedef android::List<FrameworkClient *> FrameworkClientCollection;
diff --git a/include/sysutils/ServiceManager.h b/include/sysutils/ServiceManager.h
new file mode 100644
index 0000000..c31dd8f
--- /dev/null
+++ b/include/sysutils/ServiceManager.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 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 _SERVICE_MANAGER_H
+#define _SERVICE_MANAGER_H
+
+class ServiceManager {
+public:
+    ServiceManager();
+    virtual ~ServiceManager() {}
+
+    int start(const char *name);
+    int stop(const char *name);
+    bool isRunning(const char *name);
+};
+
+#endif
diff --git a/include/sysutils/SocketClient.h b/include/sysutils/SocketClient.h
index cde64a5..469dd9d 100644
--- a/include/sysutils/SocketClient.h
+++ b/include/sysutils/SocketClient.h
@@ -15,8 +15,8 @@
 
     int getSocket() { return mSocket; }
 
-    int sendMsg(int code, char *msg, bool addErrno);
-    int sendMsg(char *msg);
+    int sendMsg(int code, const char *msg, bool addErrno);
+    int sendMsg(const char *msg);
 };
 
 typedef android::List<SocketClient *> SocketClientCollection;
diff --git a/include/sysutils/SocketListener.h b/include/sysutils/SocketListener.h
index 30d050d..68dcb8f 100644
--- a/include/sysutils/SocketListener.h
+++ b/include/sysutils/SocketListener.h
@@ -37,8 +37,8 @@
     int startListener();
     int stopListener();
 
-    void sendBroadcast(int code, char *msg, bool addErrno);
-    void sendBroadcast(char *msg);
+    void sendBroadcast(int code, const char *msg, bool addErrno);
+    void sendBroadcast(const char *msg);
 
 protected:
     virtual bool onDataAvailable(SocketClient *c) = 0;
diff --git a/init/builtins.c b/init/builtins.c
index bcdfee1..93ce6e8 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -127,7 +127,7 @@
 static void service_start_if_not_disabled(struct service *svc)
 {
     if (!(svc->flags & SVC_DISABLED)) {
-        service_start(svc);
+        service_start(svc, NULL);
     }
 }
 
@@ -372,7 +372,7 @@
     struct service *svc;
     svc = service_find_by_name(args[1]);
     if (svc) {
-        service_start(svc);
+        service_start(svc, NULL);
     }
     return 0;
 }
@@ -393,7 +393,7 @@
     svc = service_find_by_name(args[1]);
     if (svc) {
         service_stop(svc);
-        service_start(svc);
+        service_start(svc, NULL);
     }
     return 0;
 }
diff --git a/init/devices.c b/init/devices.c
index 8aea772..300faab 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -131,9 +131,9 @@
     { "/dev/qmi0",          0640,   AID_RADIO,      AID_RADIO,      0 },
     { "/dev/qmi1",          0640,   AID_RADIO,      AID_RADIO,      0 },
     { "/dev/qmi2",          0640,   AID_RADIO,      AID_RADIO,      0 },
-
         /* CDMA radio interface MUX */
     { "/dev/ts0710mux",     0640,   AID_RADIO,      AID_RADIO,      1 },
+    { "/dev/tun",           0640,   AID_VPN  ,      AID_VPN,        0 },
     { NULL, 0, 0, 0, 0 },
 };
 
diff --git a/init/init.c b/init/init.c
index 283608c..8c2a058 100644
--- a/init/init.c
+++ b/init/init.c
@@ -156,7 +156,7 @@
     fcntl(fd, F_SETFD, 0);
 }
 
-void service_start(struct service *svc)
+void service_start(struct service *svc, const char *dynamic_args)
 {
     struct stat s;
     pid_t pid;
@@ -192,6 +192,13 @@
         return;
     }
 
+    if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {
+        ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
+               svc->args[0]);
+        svc->flags |= SVC_DISABLED;
+        return;
+    }
+
     NOTICE("starting '%s'\n", svc->name);
 
     pid = fork();
@@ -248,8 +255,27 @@
             setuid(svc->uid);
         }
 
-        if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
-            ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
+        if (!dynamic_args) {
+            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;
+            char *tmp = strdup(dynamic_args);
+            char *next = tmp;
+            char *bword;
+
+            /* Copy the static arguments */
+            memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));
+
+            while((bword = strsep(&next, " "))) {
+                arg_ptrs[arg_idx++] = bword;
+                if (arg_idx == SVC_MAXARGS)
+                    break;
+            }
+            arg_ptrs[arg_idx] = '\0';
+            execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
         }
         _exit(127);
     }
@@ -381,7 +407,7 @@
 
     if (next_start_time <= gettime()) {
         svc->flags &= (~SVC_RESTARTING);
-        service_start(svc);
+        service_start(svc, NULL);
         return;
     }
 
@@ -407,13 +433,28 @@
 
 static void msg_start(const char *name)
 {
-    struct service *svc = service_find_by_name(name);
+    struct service *svc;
+    char *tmp = NULL;
+    char *args = NULL;
+
+    if (!strchr(name, ':'))
+        svc = service_find_by_name(name);
+    else {
+        tmp = strdup(name);
+        args = strchr(tmp, ':');
+        *args = '\0';
+        args++;
+
+        svc = service_find_by_name(tmp);
+    }
     
     if (svc) {
-        service_start(svc);
+        service_start(svc, args);
     } else {
         ERROR("no such service '%s'\n", name);
     }
+    if (tmp)
+        free(tmp);
 }
 
 static void msg_stop(const char *name)
@@ -739,7 +780,7 @@
     svc = service_find_by_keychord(id);
     if (svc) {
         INFO("starting service %s from keychord\n", svc->name);
-        service_start(svc);   
+        service_start(svc, NULL);
     } else {
         ERROR("service for keychord %d not found\n", id);
     }
diff --git a/init/init.h b/init/init.h
index b93eb50..f306b7b 100644
--- a/init/init.h
+++ b/init/init.h
@@ -116,6 +116,8 @@
 
 #define NR_SVC_SUPP_GIDS 6    /* six supplementary groups */
 
+#define SVC_MAXARGS 64
+
 struct service {
         /* list of all services */
     struct listnode slist;
@@ -160,7 +162,7 @@
 void service_for_each_flags(unsigned matchflags,
                             void (*func)(struct service *svc));
 void service_stop(struct service *svc);
-void service_start(struct service *svc);
+void service_start(struct service *svc, const char *dynamic_args);
 void property_changed(const char *name, const char *value);
 
 struct action *action_remove_queue_head(void);
diff --git a/init/parser.c b/init/parser.c
index 30fa3de..33c1a68 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -60,8 +60,6 @@
 #endif       
 }
 
-#define MAXARGS 64
-
 #define T_EOF 0
 #define T_TEXT 1
 #define T_NEWLINE 2
@@ -357,7 +355,7 @@
 static void parse_config(const char *fn, char *s)
 {
     struct parse_state state;
-    char *args[MAXARGS];
+    char *args[SVC_MAXARGS];
     int nargs;
 
     nargs = 0;
@@ -384,7 +382,7 @@
             }
             break;
         case T_TEXT:
-            if (nargs < MAXARGS) {
+            if (nargs < SVC_MAXARGS) {
                 args[nargs++] = state.text;
             }
             break;
diff --git a/libacc/FEATURES b/libacc/FEATURES
index 3e80890..1a44415 100644
--- a/libacc/FEATURES
+++ b/libacc/FEATURES
@@ -56,7 +56,7 @@
     - C Strings and C character constants are supported. Only '\n',
       '\"', '\'' and '\\' escapes are recognized.
 
-    - C Comments can be used (but no C++ comments).
+    - Both C comments ( /* */ ) and C++ comments ( // ... end-of-line ) can be used.
 
     - No error is displayed if an incorrect program is given.
 
diff --git a/libacc/MODULE_LICENSE_BSD_LIKE b/libacc/MODULE_LICENSE_BSD_LIKE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libacc/MODULE_LICENSE_BSD_LIKE
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index 50d90dd..04d45d5 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -1,4 +1,15 @@
 /*
+ * Android "Almost" C Compiler.
+ * This is a compiler for a small subset of the C language, intended for use
+ * in scripting environments where speed and memory footprint are important.
+ *
+ * This code is based upon the "unobfuscated" version of the
+ * Obfuscated Tiny C compiler, and retains the
+ * original copyright notice and license from that compiler, see below.
+ *
+ */
+
+/*
  Obfuscated Tiny C Compiler
 
  Copyright (C) 2001-2003 Fabrice Bellard
@@ -23,6 +34,7 @@
 #include <ctype.h>
 #include <dlfcn.h>
 #include <stdarg.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -31,11 +43,25 @@
 #include <unistd.h>
 #endif
 
+#if defined(__arm__)
+#define DEFAULT_ARM_CODEGEN
+#define PROVIDE_ARM_CODEGEN
+#elif defined(__i386__)
+#define DEFAULT_X86_CODEGEN
+#define PROVIDE_X86_CODEGEN
+#elif defined(__x86_64__)
+#define DEFAULT_X64_CODEGEN
+#define PROVIDE_X64_CODEGEN
+#endif
+
+
+#ifdef PROVIDE_ARM_CODEGEN
 #include "disassem.h"
+#endif
 
 namespace acc {
 
-class compiler {
+class Compiler {
     class CodeBuf {
         char* ind;
         char* pProgramBase;
@@ -63,16 +89,8 @@
             ind = pProgramBase;
         }
 
-        void o(int n) {
-            /* cannot use unsigned, so we must do a hack */
-            while (n && n != -1) {
-                *ind++ = n;
-                n = n >> 8;
-            }
-        }
-
         int o4(int n) {
-            int result = (int) ind;
+            intptr_t result = (intptr_t) ind;
             * (int*) ind = n;
             ind += 4;
             return result;
@@ -85,41 +103,16 @@
             *ind++ = n;
         }
 
-        /* output a symbol and patch all calls to it */
-        void gsym(int t) {
-            int n;
-            while (t) {
-                n = *(int *) t; /* next value */
-                *(int *) t = ((int) ind) - t - 4;
-                t = n;
-            }
-        }
-
-        /* psym is used to put an instruction with a data field which is a
-         reference to a symbol. It is in fact the same as oad ! */
-        int psym(int n, int t) {
-            return oad(n, t);
-        }
-
-        /* instruction + address */
-        int oad(int n, int t) {
-            o(n);
-            *(int *) ind = t;
-            t = (int) ind;
-            ind = ind + 4;
-            return t;
-        }
-
         inline void* getBase() {
             return (void*) pProgramBase;
         }
 
-        int getSize() {
+        intptr_t getSize() {
             return ind - pProgramBase;
         }
 
-        int getPC() {
-            return (int) ind;
+        intptr_t getPC() {
+            return (intptr_t) ind;
         }
     };
 
@@ -164,15 +157,14 @@
 
         virtual void storeEAX(int ea) = 0;
 
-        virtual void loadEAX(int ea) = 0;
-
-        virtual void postIncrementOrDecrement(int n, int op) = 0;
+        virtual void loadEAX(int ea, bool isIncDec, int op) = 0;
 
         virtual int beginFunctionCallArguments() = 0;
 
+        virtual void storeEAToArg(int l) = 0;
+
         virtual void endFunctionCallArguments(int a, int l) = 0;
 
-        virtual void storeEAToArg(int l) = 0;
 
         virtual int callForward(int symbol) = 0;
 
@@ -180,14 +172,12 @@
 
         virtual void callIndirect(int l) = 0;
 
-        virtual void adjustStackAfterCall(int l) = 0;
+        virtual void adjustStackAfterCall(int l, bool isIndirect) = 0;
 
         virtual int disassemble(FILE* out) = 0;
 
         /* output a symbol and patch all calls to it */
-        virtual void gsym(int t) {
-            pCodeBuf->gsym(t);
-        }
+        virtual void gsym(int t) = 0;
 
         virtual int finishCompile() {
 #if defined(__arm__)
@@ -206,10 +196,6 @@
         virtual int jumpOffset() = 0;
 
     protected:
-        void o(int n) {
-            pCodeBuf->o(n);
-        }
-
         /*
          * Output a byte. Handles all values, 0..ff.
          */
@@ -217,32 +203,23 @@
             pCodeBuf->ob(n);
         }
 
-        /* psym is used to put an instruction with a data field which is a
-         reference to a symbol. It is in fact the same as oad ! */
-        int psym(int n, int t) {
-            return oad(n, t);
-        }
-
-        /* instruction + address */
-        int oad(int n, int t) {
-            return pCodeBuf->oad(n,t);
-        }
-
-        int getBase() {
-            return (int) pCodeBuf->getBase();
-        }
-
-        int getPC() {
-            return pCodeBuf->getPC();
-        }
-
-        int o4(int data) {
+        intptr_t o4(int data) {
             return pCodeBuf->o4(data);
         }
+
+        intptr_t getBase() {
+            return (intptr_t) pCodeBuf->getBase();
+        }
+
+        intptr_t getPC() {
+            return pCodeBuf->getPC();
+        }
     private:
         CodeBuf* pCodeBuf;
     };
 
+#ifdef PROVIDE_ARM_CODEGEN
+
     class ARMCodeGenerator : public CodeGenerator {
     public:
         ARMCodeGenerator() {}
@@ -360,6 +337,12 @@
             case OP_MUL:
                 o4(0x0E0000091); // mul     r0,r1,r0
                 break;
+            case OP_DIV:
+                callRuntime(runtime_DIV);
+                break;
+            case OP_MOD:
+                callRuntime(runtime_MOD);
+                break;
             case OP_PLUS:
                 o4(0xE0810000);  // add     r0,r1,r0
                 break;
@@ -429,62 +412,90 @@
 
         virtual void leaEAX(int ea) {
             fprintf(stderr, "leaEAX(%d);\n", ea);
-            if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
-                error("Offset out of range: %08x", ea);
-            }
-            if (ea < 0) {
-                o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub    r0, fp, #ea
+            if (ea < LOCAL) {
+                // Local, fp relative
+                if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
+                    error("Offset out of range: %08x", ea);
+                }
+                if (ea < 0) {
+                    o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub    r0, fp, #ea
+                } else {
+                    o4(0xE28B0F00 | (0xff & (ea >> 2))); // add    r0, fp, #ea
+                }
             } else {
-                o4(0xE28B0F00 | (0xff & (ea >> 2))); // add    r0, fp, #ea
+                // Global, absolute.
+                o4(0xE59F0000); //        ldr    r0, .L1
+                o4(0xEA000000); //        b .L99
+                o4(ea);         // .L1:   .word 0
+                                // .L99:
             }
-
         }
 
         virtual void storeEAX(int ea) {
             fprintf(stderr, "storeEAX(%d);\n", ea);
-            if (ea < -4095 || ea > 4095) {
-                error("Offset out of range: %08x", ea);
-            }
-            if (ea < 0) {
-                o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
-            } else {
-                o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
+            if (ea < LOCAL) {
+                // Local, fp relative
+                if (ea < -4095 || ea > 4095) {
+                    error("Offset out of range: %08x", ea);
+                }
+                if (ea < 0) {
+                    o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea]
+                } else {
+                    o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea]
+                }
+            } else{
+                // Global, absolute
+                o4(0xE59F1000); //         ldr r1, .L1
+                o4(0xEA000000); //         b .L99
+                o4(ea);         // .L1:    .word 0
+                o4(0xE5810000); // .L99:   str r0, [r1]
             }
         }
 
-        virtual void loadEAX(int ea) {
-            fprintf(stderr, "loadEAX(%d);\n", ea);
-            if (ea < -4095 || ea > 4095) {
-                error("Offset out of range: %08x", ea);
-            }
-            if (ea < 0) {
-                o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
+        virtual void loadEAX(int ea, bool isIncDec, int op) {
+            fprintf(stderr, "loadEAX(%d, %d, %d);\n", ea, isIncDec, op);
+            if (ea < LOCAL) {
+                // Local, fp relative
+                if (ea < -4095 || ea > 4095) {
+                    error("Offset out of range: %08x", ea);
+                }
+                if (ea < 0) {
+                    o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea]
+                } else {
+                    o4(0xE59B0000 | (0xfff & ea));    // ldr r0, [fp,#ea]
+                }
             } else {
-                o4(0xE59B0000 | (0xfff & ea));    // ldr r0, [fp,#ea]
+                // Global, absolute
+                o4(0xE59F2000); //        ldr r2, .L1
+                o4(0xEA000000); //        b .L99
+                o4(ea);         // .L1:   .word ea
+                o4(0xE5920000); // .L99:  ldr r0, [r2]
             }
-        }
 
-        virtual void postIncrementOrDecrement(int ea, int op) {
-            fprintf(stderr, "postIncrementOrDecrement(%d, %d);\n", ea, op);
-            /* R0 has the original value.
-             */
-            switch (op) {
-            case OP_INCREMENT:
-                o4(0xE2801001); // add r1, r0, #1
-                break;
-            case OP_DECREMENT:
-                o4(0xE2401001); // sub r1, r0, #1
-                break;
-            default:
-                error("unknown opcode: %d", op);
-            }
-            if (ea < -4095 || ea > 4095) {
-                error("Offset out of range: %08x", ea);
-            }
-            if (ea < 0) {
-                o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
-            } else {
-                o4(0xE58B1000 | (0xfff & ea));    // str r1, [fp,#ea]
+            if (isIncDec) {
+                switch (op) {
+                case OP_INCREMENT:
+                    o4(0xE2801001); // add r1, r0, #1
+                    break;
+                case OP_DECREMENT:
+                    o4(0xE2401001); // sub r1, r0, #1
+                    break;
+                default:
+                    error("unknown opcode: %d", op);
+                }
+                if (ea < LOCAL) {
+                    // Local, fp relative
+                    // Don't need range check, was already checked above
+                    if (ea < 0) {
+                        o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea]
+                    } else {
+                        o4(0xE58B1000 | (0xfff & ea));    // str r1, [fp,#ea]
+                    }
+                } else{
+                    // Global, absolute
+                    // r2 is already set up from before.
+                    o4(0xE5821000); // str r1, [r2]
+               }
             }
         }
 
@@ -493,6 +504,14 @@
             return o4(0xE24DDF00); // Placeholder
         }
 
+        virtual void storeEAToArg(int l) {
+            fprintf(stderr, "storeEAToArg(%d);\n", l);
+            if (l < 0 || l > 4096-4) {
+                error("l out of range for stack offset: 0x%08x", l);
+            }
+            o4(0xE58D0000 + l); // str r0, [sp, #4]
+        }
+
         virtual void endFunctionCallArguments(int a, int l) {
             fprintf(stderr, "endFunctionCallArguments(0x%08x, %d);\n", a, l);
             if (l < 0 || l > 0x3FC) {
@@ -506,14 +525,6 @@
             }
         }
 
-        virtual void storeEAToArg(int l) {
-            fprintf(stderr, "storeEAToArg(%d);\n", l);
-            if (l < 0 || l > 4096-4) {
-                error("l out of range for stack offset: 0x%08x", l);
-            }
-            o4(0xE58D0000 + l); // str r0, [sp, #4]
-        }
-
         virtual int callForward(int symbol) {
             fprintf(stderr, "callForward(%d);\n", symbol);
             // Forward calls are always short (local)
@@ -538,20 +549,27 @@
 
         virtual void callIndirect(int l) {
             fprintf(stderr, "callIndirect(%d);\n", l);
-            oad(0x2494ff, l); /* call *xxx(%esp) */
+            int argCount = l >> 2;
+            int poppedArgs = argCount > 4 ? 4 : argCount;
+            int adjustedL = l - (poppedArgs << 2);
+            if (adjustedL < 0 || adjustedL > 4096-4) {
+                error("l out of range for stack offset: 0x%08x", l);
+            }
+            o4(0xE59DC000 | (0xfff & adjustedL)); // ldr    r12, [sp,#adjustedL]
+            o4(0xE12FFF3C); // blx r12
         }
 
-        virtual void adjustStackAfterCall(int l) {
-            fprintf(stderr, "adjustStackAfterCall(%d);\n", l);
-            if (l < 0 || l > 0x3FC) {
-                error("L out of range for stack adjustment: 0x%08x", l);
-            }
+        virtual void adjustStackAfterCall(int l, bool isIndirect) {
+            fprintf(stderr, "adjustStackAfterCall(%d, %d);\n", l, isIndirect);
             int argCount = l >> 2;
-            if (argCount > 4) {
-                int remainingArgs = argCount - 4;
-                o4(0xE28DDF00 | remainingArgs); // add    sp, sp, #0x3fc
+            int stackArgs = argCount > 4 ? argCount - 4 : 0;
+            int stackUse = stackArgs + (isIndirect ? 1 : 0);
+            if (stackUse) {
+                if (stackUse < 0 || stackUse > 255) {
+                    error("L out of range for stack adjustment: 0x%08x", l);
+                }
+                o4(0xE28DDF00 | stackUse); // add    sp, sp, #stackUse << 2
             }
-
         }
 
         virtual int jumpOffset() {
@@ -594,6 +612,7 @@
             }
             return 0;
         }
+
     private:
         static FILE* disasmOut;
 
@@ -635,6 +654,22 @@
             return BRANCH_REL_ADDRESS_MASK & (value >> 2);
         }
 
+        typedef int (*int2FnPtr)(int a, int b);
+        void callRuntime(int2FnPtr fn) {
+            o4(0xE59F2000); // ldr    r2, .L1
+            o4(0xEA000000); // b      .L99
+            o4((int) fn);   //.L1:  .word  fn
+            o4(0xE12FFF32); //.L99: blx    r2
+        }
+
+        static int runtime_DIV(int a, int b) {
+            return b / a;
+        }
+
+        static int runtime_MOD(int a, int b) {
+            return b % a;
+        }
+
         void error(const char* fmt,...) {
             va_list ap;
             va_start(ap, fmt);
@@ -644,6 +679,10 @@
         }
     };
 
+#endif // PROVIDE_X86_CODEGEN
+
+#ifdef PROVIDE_X86_CODEGEN
+
     class X86CodeGenerator : public CodeGenerator {
     public:
         X86CodeGenerator() {}
@@ -723,29 +762,28 @@
             gmov(6, ea); /* mov %eax, EA */
         }
 
-        virtual void loadEAX(int ea) {
+        virtual void loadEAX(int ea, bool isIncDec, int op) {
             gmov(8, ea); /* mov EA, %eax */
-        }
-
-        virtual void postIncrementOrDecrement(int n, int op) {
-            /* Implement post-increment or post decrement.
-             */
-            gmov(0, n); /* 83 ADD */
-            o(decodeOp(op));
+            if (isIncDec) {
+                /* Implement post-increment or post decrement.
+                 */
+                gmov(0, ea); /* 83 ADD */
+                o(decodeOp(op));
+            }
         }
 
         virtual int beginFunctionCallArguments() {
             return oad(0xec81, 0); /* sub $xxx, %esp */
         }
 
-        virtual void endFunctionCallArguments(int a, int l) {
-            * (int*) a = l;
-        }
-
         virtual void storeEAToArg(int l) {
             oad(0x248489, l); /* movl %eax, xxx(%esp) */
         }
 
+        virtual void endFunctionCallArguments(int a, int l) {
+            * (int*) a = l;
+        }
+
         virtual int callForward(int symbol) {
             return psym(0xe8, symbol); /* call xxx */
         }
@@ -758,7 +796,10 @@
             oad(0x2494ff, l); /* call *xxx(%esp) */
         }
 
-        virtual void adjustStackAfterCall(int l) {
+        virtual void adjustStackAfterCall(int l, bool isIndirect) {
+            if (isIndirect) {
+                l += 4;
+            }
             oad(0xc481, l); /* add $xxx, %esp */
         }
 
@@ -770,7 +811,45 @@
             return 1;
         }
 
+        /* output a symbol and patch all calls to it */
+        virtual void gsym(int t) {
+            int n;
+            int pc = getPC();
+            while (t) {
+                n = *(int *) t; /* next value */
+                *(int *) t = pc - t - 4;
+                t = n;
+            }
+        }
+
     private:
+
+        /** Output 1 to 4 bytes.
+         *
+         */
+        void o(int n) {
+            /* cannot use unsigned, so we must do a hack */
+            while (n && n != -1) {
+                ob(n & 0xff);
+                n = n >> 8;
+            }
+        }
+
+        /* psym is used to put an instruction with a data field which is a
+         reference to a symbol. It is in fact the same as oad ! */
+        int psym(int n, int t) {
+            return oad(n, t);
+        }
+
+        /* instruction + address */
+        int oad(int n, int t) {
+            o(n);
+            int result = getPC();
+            o4(t);
+            return result;
+        }
+
+
         static const int operatorHelper[];
 
         int decodeOp(int op) {
@@ -787,6 +866,8 @@
         }
     };
 
+#endif // PROVIDE_X86_CODEGEN
+
     /* vars: value of variables
      loc : local variable index
      glo : global variable index
@@ -796,7 +877,7 @@
      dstk: define stack
      dptr, dch: macro state
      */
-    int tok, tokc, tokl, ch, vars, rsym, loc, glo, sym_stk, dstk,
+    intptr_t tok, tokc, tokl, ch, vars, rsym, loc, glo, sym_stk, dstk,
             dptr, dch, last_id;
     void* pSymbolBase;
     void* pGlobalBase;
@@ -932,7 +1013,7 @@
             } else {
                 *(char *) dstk = TAG_TOK; /* no need to mark end of string (we
                  suppose data is initialized to zero by calloc) */
-                tok = (int) (strstr((char*) sym_stk, (char*) (last_id - 1))
+                tok = (intptr_t) (strstr((char*) sym_stk, (char*) (last_id - 1))
                         - sym_stk);
                 *(char *) dstk = 0; /* mark real end of ident for dlsym() */
                 tok = tok * 8 + TOK_IDENT;
@@ -1034,7 +1115,7 @@
         exit(1);
     }
 
-    void skip(int c) {
+    void skip(intptr_t c) {
         if (tok != c) {
             error("'%c' expected", c);
         }
@@ -1042,8 +1123,8 @@
     }
 
     /* l is one if '=' parsing wanted (quick hack) */
-    void unary(int l) {
-        int n, t, a, c;
+    void unary(intptr_t l) {
+        intptr_t n, t, a, c;
         t = 0;
         n = 1; /* type of expression 0 = forward, 1 = value, other =
          lvalue */
@@ -1108,7 +1189,7 @@
                 n = *(int *) t;
                 /* forward reference: try dlsym */
                 if (!n) {
-                    n = (int) dlsym(RTLD_DEFAULT, (char*) last_id);
+                    n = (intptr_t) dlsym(RTLD_DEFAULT, (char*) last_id);
                 }
                 if ((tok == '=') & l) {
                     /* assignment */
@@ -1117,9 +1198,8 @@
                     pGen->storeEAX(n);
                 } else if (tok != '(') {
                     /* variable */
-                    pGen->loadEAX(n);
+                    pGen->loadEAX(n, tokl == 11, tokc);
                     if (tokl == 11) {
-                        pGen->postIncrementOrDecrement(n, tokc);
                         next();
                     }
                 }
@@ -1150,17 +1230,16 @@
                 *(int *) t = pGen->callForward(*(int *) t);
             } else if (n == 1) {
                 pGen->callIndirect(l);
-                l = l + 4;
             } else {
-                pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset()); /* call xxx */
+                pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset());
             }
-            if (l)
-                pGen->adjustStackAfterCall(l);
+            if (l | (n == 1))
+                pGen->adjustStackAfterCall(l, n == 1);
         }
     }
 
-    void sum(int l) {
-        int t, n, a;
+    void sum(intptr_t l) {
+        intptr_t t, n, a;
         t = 0;
         if (l-- == 1)
             unary(1);
@@ -1207,8 +1286,8 @@
         return pGen->gtst(0, 0);
     }
 
-    void block(int l) {
-        int a, n, t;
+    void block(intptr_t l) {
+        intptr_t a, n, t;
 
         if (tok == TOK_IF) {
             next();
@@ -1250,7 +1329,7 @@
                 }
             }
             skip(')');
-            block((int) &a);
+            block((intptr_t) &a);
             pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
             pGen->gsym(a);
         } else if (tok == '{') {
@@ -1276,8 +1355,8 @@
     }
 
     /* 'l' is true if local declarations */
-    void decl(int l) {
-        int a;
+    void decl(bool l) {
+        intptr_t a;
 
         while ((tok == TOK_INT) | ((tok != -1) & (!l))) {
             if (tok == TOK_INT) {
@@ -1368,17 +1447,30 @@
         pGen = 0;
 
         if (architecture != NULL) {
-            if (strcmp(architecture, "arm") == 0) {
+#ifdef PROVIDE_ARM_CODEGEN
+            if (! pGen && strcmp(architecture, "arm") == 0) {
                 pGen = new ARMCodeGenerator();
-            } else if (strcmp(architecture, "x86") == 0) {
+            }
+#endif
+#ifdef PROVIDE_X86_CODEGEN
+            if (! pGen && strcmp(architecture, "x86") == 0) {
                 pGen = new X86CodeGenerator();
-            } else {
-                fprintf(stderr, "Unknown architecture %s", architecture);
+            }
+#endif
+            if (!pGen ) {
+                fprintf(stderr, "Unknown architecture %s\n", architecture);
             }
         }
 
         if (pGen == NULL) {
+#if defined(DEFAULT_ARM_CODEGEN)
             pGen = new ARMCodeGenerator();
+#elif defined(DEFAULT_X86_CODEGEN)
+            pGen = new X86CodeGenerator();
+#endif
+        }
+        if (pGen == NULL) {
+            fprintf(stderr, "No code generator defined.");
         }
     }
 
@@ -1390,11 +1482,11 @@
         const char* architecture;
     };
 
-    compiler() {
+    Compiler() {
         clear();
     }
 
-    ~compiler() {
+    ~Compiler() {
         cleanup();
     }
 
@@ -1403,16 +1495,19 @@
         clear();
         codeBuf.init(ALLOC_SIZE);
         setArchitecture(args.architecture);
+        if (!pGen) {
+            return -1;
+        }
         pGen->init(&codeBuf);
         file = in;
-        sym_stk = (int) calloc(1, ALLOC_SIZE);
-        dstk = (int) strcpy((char*) sym_stk,
+        sym_stk = (intptr_t) calloc(1, ALLOC_SIZE);
+        dstk = (intptr_t) strcpy((char*) sym_stk,
                 " int if else while break return for define main ")
                 + TOK_STR_SIZE;
         pGlobalBase = calloc(1, ALLOC_SIZE);
-        glo = (int) pGlobalBase;
+        glo = (intptr_t) pGlobalBase;
         pVarsBase = calloc(1, ALLOC_SIZE);
-        vars = (int) pVarsBase;
+        vars = (intptr_t) pVarsBase;
         inp();
         next();
         decl(0);
@@ -1441,10 +1536,10 @@
 
 };
 
-const char* compiler::operatorChars =
+const char* Compiler::operatorChars =
     "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
 
-const char compiler::operatorLevel[] =
+const char Compiler::operatorLevel[] =
     {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
             5, 5, /* ==, != */
             9, 10, /* &&, || */
@@ -1452,9 +1547,12 @@
             2, 2 /* ~ ! */
             };
 
-FILE* compiler::ARMCodeGenerator::disasmOut;
+#ifdef PROVIDE_ARM_CODEGEN
+FILE* Compiler::ARMCodeGenerator::disasmOut;
+#endif
 
-const int compiler::X86CodeGenerator::operatorHelper[] = {
+#ifdef PROVIDE_X86_CODEGEN
+const int Compiler::X86CodeGenerator::operatorHelper[] = {
         0x1,     // ++
         0xff,    // --
         0xc1af0f, // *
@@ -1478,11 +1576,12 @@
         0xd0f7, // ~
         0x4     // !
 };
+#endif
 
 } // namespace acc
 
 // This is a separate function so it can easily be set by breakpoint in gdb.
-int run(acc::compiler& c, int argc, char** argv) {
+int run(acc::Compiler& c, int argc, char** argv) {
     return c.run(argc, argv);
 }
 
@@ -1491,7 +1590,7 @@
     bool doDisassemble = false;
     const char* inFile = NULL;
     const char* outFile = NULL;
-    const char* architecture = "arm";
+    const char* architecture = NULL;
     int i;
     for (i = 1; i < argc; i++) {
         char* arg = argv[i];
@@ -1536,9 +1635,11 @@
             return 1;
         }
     }
-    acc::compiler compiler;
-    acc::compiler::args args;
-    args.architecture = architecture;
+    acc::Compiler compiler;
+    acc::Compiler::args args;
+    if (architecture != NULL) {
+        args.architecture = architecture;
+    }
     int compileResult = compiler.compile(in, args);
     if (in != stdin) {
         fclose(in);
diff --git a/libacc/test b/libacc/test
index 0b767da..28b7655 100755
--- a/libacc/test
+++ b/libacc/test
@@ -1,3 +1,13 @@
 #!/bin/sh
+rm -f tests/acc
 g++ acc.cpp disassem.cpp -g -ldl -o tests/acc && tests/acc tests/otcc.c -a x86 -d tests/otcc.out && diff tests/otcc.out tests/otcc.out-orig
-tests/acc -S tests/returnval.c
+if [ -x "tests/acc" ]; then
+  tests/acc -S tests/returnval.c
+
+  if [ "$(uname)" = "Linux" ]; then
+    if [ "$(uname -m)" = "i686" ]; then
+      echo "Linux i686. Testing otcc.c"
+      tests/acc tests/otcc.c tests/otcc.c tests/returnval.c
+    fi
+  fi
+fi
diff --git a/libacc/testarm b/libacc/testarm
new file mode 100755
index 0000000..d1a442e
--- /dev/null
+++ b/libacc/testarm
@@ -0,0 +1,4 @@
+#!/bin/sh
+adb remount
+adb push tests/returnval.c /system/bin/returnval.c
+mm -j8 && adb sync && adb shell /system/bin/acc -S /system/bin/returnval.c
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 3bc48fb..aaee8bf 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 \
@@ -62,7 +63,6 @@
     commonSources += \
         mspace.c \
         selector.c \
-        fdevent.c \
         tztime.c \
         adb_networking.c \
         zygote.c
diff --git a/libcutils/abort_socket.c b/libcutils/abort_socket.c
new file mode 100644
index 0000000..d732142
--- /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 & POLLIN) {
+            /* 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/libcutils/native_handle.c b/libcutils/native_handle.c
index 842e1ed..4089968 100644
--- a/libcutils/native_handle.c
+++ b/libcutils/native_handle.c
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "Gralloc"
+#define LOG_TAG "NativeHandle"
 
 #include <stdint.h>
 #include <errno.h>
@@ -25,30 +25,30 @@
 #include <cutils/log.h>
 #include <cutils/native_handle.h>
 
-native_handle* native_handle_create(int numFds, int numInts)
+native_handle_t* native_handle_create(int numFds, int numInts)
 {
-    native_handle* h = malloc(
-            sizeof(native_handle) + sizeof(int)*(numFds+numInts));
-    
-    h->version = sizeof(native_handle);
+    native_handle_t* h = malloc(
+            sizeof(native_handle_t) + sizeof(int)*(numFds+numInts));
+
+    h->version = sizeof(native_handle_t);
     h->numFds = numFds;
     h->numInts = numInts;
     return h;
 }
 
-int native_handle_delete(native_handle* h)
+int native_handle_delete(native_handle_t* h)
 {
     if (h) {
-        if (h->version != sizeof(native_handle))
+        if (h->version != sizeof(native_handle_t))
             return -EINVAL;
         free(h);
     }
     return 0;
 }
 
-int native_handle_close(const native_handle* h)
+int native_handle_close(const native_handle_t* h)
 {
-    if (h->version != sizeof(native_handle))
+    if (h->version != sizeof(native_handle_t))
         return -EINVAL;
 
     const int numFds = h->numFds;
diff --git a/libcutils/tzstrftime.c b/libcutils/tzstrftime.c
index 29c5015..e37d79a 100644
--- a/libcutils/tzstrftime.c
+++ b/libcutils/tzstrftime.c
@@ -172,10 +172,17 @@
 					pt, ptlim, modifier);
 				continue;
 			case 'B':
-				pt = _add((t->tm_mon < 0 ||
-					t->tm_mon >= MONSPERYEAR) ?
-					"?" : Locale->month[t->tm_mon],
-					pt, ptlim, modifier);
+				if (modifier == '-') {
+					pt = _add((t->tm_mon < 0 ||
+						t->tm_mon >= MONSPERYEAR) ?
+						"?" : Locale->standalone_month[t->tm_mon],
+						pt, ptlim, modifier);
+				} else {
+					pt = _add((t->tm_mon < 0 ||
+						t->tm_mon >= MONSPERYEAR) ?
+						"?" : Locale->month[t->tm_mon],
+						pt, ptlim, modifier);
+				}
 				continue;
 			case 'b':
 			case 'h':
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index 2f3e106..dd2b32d 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -16,6 +16,7 @@
                   src/NetlinkEvent.cpp        \
                   src/FrameworkCommand.cpp    \
                   src/SocketClient.cpp        \
+                  src/ServiceManager.cpp      \
 
 LOCAL_MODULE:= libsysutils
 
diff --git a/libsysutils/src/FrameworkClient.cpp b/libsysutils/src/FrameworkClient.cpp
index 237bb60..1686996 100644
--- a/libsysutils/src/FrameworkClient.cpp
+++ b/libsysutils/src/FrameworkClient.cpp
@@ -13,8 +13,7 @@
     pthread_mutex_init(&mWriteMutex, NULL);
 }
 
-int FrameworkClient::sendMsg(char *msg) {
-    LOGD("FrameworkClient::sendMsg(%s)", msg);
+int FrameworkClient::sendMsg(const char *msg) {
     if (mSocket < 0) {
         errno = EHOSTUNREACH;
         return -1;
@@ -28,7 +27,7 @@
     return 0;
 }
 
-int FrameworkClient::sendMsg(char *msg, char *data) {
+int FrameworkClient::sendMsg(const char *msg, const char *data) {
     char *buffer = (char *) alloca(strlen(msg) + strlen(data) + 1);
     if (!buffer) {
         errno = -ENOMEM;
diff --git a/libsysutils/src/ServiceManager.cpp b/libsysutils/src/ServiceManager.cpp
new file mode 100644
index 0000000..700ac91
--- /dev/null
+++ b/libsysutils/src/ServiceManager.cpp
@@ -0,0 +1,73 @@
+#include <errno.h>
+
+#include <sysutils/ServiceManager.h>
+
+#define LOG_TAG "Service"
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+ServiceManager::ServiceManager() {
+}
+
+int ServiceManager::start(const char *name) {
+    if (isRunning(name)) {
+        LOGW("Service '%s' is already running", name);
+        return 0;
+    }
+
+    LOGD("Starting service '%s'", name);
+    property_set("ctl.start", name);
+
+    int count = 200;
+    while(count--) {
+        sched_yield();
+        if (isRunning(name))
+            break;
+    }
+    if (!count) {
+        LOGW("Timed out waiting for service '%s' to start", name);
+        errno = ETIMEDOUT;
+        return -1;
+    }
+    LOGD("Sucessfully started '%s'", name);
+    return 0;
+}
+
+int ServiceManager::stop(const char *name) {
+    if (!isRunning(name)) {
+        LOGW("Service '%s' is already stopped", name);
+        return 0;
+    }
+
+    LOGD("Stopping service '%s'", name);
+    property_set("ctl.stop", name);
+
+    int count = 200;
+    while(count--) {
+        sched_yield();
+        if (!isRunning(name))
+            break;
+    }
+
+    if (!count) {
+        LOGW("Timed out waiting for service '%s' to stop", name);
+        errno = ETIMEDOUT;
+        return -1;
+    }
+    LOGD("Sucessfully stopped '%s'", name);
+    return 0;
+}
+
+bool ServiceManager::isRunning(const char *name) {
+    char propVal[PROPERTY_VALUE_MAX];
+    char propName[255];
+
+    snprintf(propName, sizeof(propVal), "init.svc.%s", name);
+
+
+    if (property_get(propName, propVal, NULL)) {
+        if (!strcmp(propVal, "running"))
+            return true;
+    }
+    return false;
+}
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index ab020ca..b229627 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -14,7 +14,7 @@
     pthread_mutex_init(&mWriteMutex, NULL);
 }
 
-int SocketClient::sendMsg(int code, char *msg, bool addErrno) {
+int SocketClient::sendMsg(int code, const char *msg, bool addErrno) {
     char *buf;
     
     if (addErrno) {
@@ -27,23 +27,24 @@
     return sendMsg(buf);
 }
 
-int SocketClient::sendMsg(char *msg) {
+int SocketClient::sendMsg(const char *msg) {
     if (mSocket < 0) {
         errno = EHOSTUNREACH;
         return -1;
     }
 
-    char *bp;
-  
+    char *tmp;
+    const char *bp = msg;
+
     if (msg[strlen(msg)] != '\n') {
-        bp = (char *) alloca(strlen(msg) + 1);
-        strcpy(bp, msg);
-        strcat(bp, "\n");
-    } else
-        bp = msg;
+        tmp = (char *) alloca(strlen(msg) + 1);
+        strcpy(tmp, msg);
+        strcat(tmp, "\n");
+        bp = tmp;
+    }
        
     int rc = 0;
-    char *p = bp;
+    const char *p = bp;
     int brtw = strlen(bp);
 
     pthread_mutex_lock(&mWriteMutex);
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index acc4a67..cb7dd80 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -173,7 +173,7 @@
     }
 }
 
-void SocketListener::sendBroadcast(int code, char *msg, bool addErrno) {
+void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
     pthread_mutex_lock(&mClientsLock);
     SocketClientCollection::iterator i;
 
@@ -185,7 +185,7 @@
     pthread_mutex_unlock(&mClientsLock);
 }
 
-void SocketListener::sendBroadcast(char *msg) {
+void SocketListener::sendBroadcast(const char *msg) {
     pthread_mutex_lock(&mClientsLock);
     SocketClientCollection::iterator i;
 
diff --git a/logcat/event-log-tags b/logcat/event-log-tags
index 28cad0a..f9355ec 100644
--- a/logcat/event-log-tags
+++ b/logcat/event-log-tags
@@ -323,6 +323,12 @@
 # PDP drop caused by network
 50109 pdp_network_drop (cid|1|5), (network_type|1|5)
 
+# CDMA data network setup failure
+50110 cdma_data_setup_failed (cause|1|5), (cid|1|5), (network_type|1|5)
+
+# CDMA data network drop
+50111 cdma_data_drop (cid|1|5), (network_type|1|5)
+
 # Do not change these names without updating tag in:
 #//device/dalvik/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.c
 51000 socket_stats (send|1|2),(recv|1|2),(ip|1|5),(port|1|5),(close|1|5)
diff --git a/nexus/CommandListener.cpp b/nexus/CommandListener.cpp
index d9ee971..fdf3fed 100644
--- a/nexus/CommandListener.cpp
+++ b/nexus/CommandListener.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 #include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 #include <errno.h>
 
 #define LOG_TAG "CommandListener"
@@ -25,6 +28,7 @@
 #include "Controller.h"
 #include "NetworkManager.h"
 #include "WifiController.h"
+#include "VpnController.h"
 #include "ErrorCode.h"
 
 CommandListener::CommandListener() :
@@ -40,6 +44,8 @@
     registerCmd(new WifiGetVarCmd());
 
     registerCmd(new VpnEnableCmd());
+    registerCmd(new VpnSetVarCmd());
+    registerCmd(new VpnGetVarCmd());
     registerCmd(new VpnDisableCmd());
 }
  
@@ -261,6 +267,79 @@
     return 0;
 }
 
+CommandListener::VpnSetVarCmd::VpnSetVarCmd() :
+                 NexusCommand("vpn_setvar") {
+} 
+
+int CommandListener::VpnSetVarCmd::runCommand(SocketClient *cli, char *data) {
+    VpnController *vc = (VpnController *) NetworkManager::Instance()->findController("VPN");
+
+    char *bword;
+    char *last;
+    char varname[32];
+    char val[250];
+
+    if (!(bword = strtok_r(data, ":", &last)))
+        goto out_inval;
+
+    strncpy(varname, bword, sizeof(varname));
+
+    if (!(bword = strtok_r(NULL, ":", &last)))
+        goto out_inval;
+
+    strncpy(val, bword, sizeof(val));
+
+    if (!strcasecmp(varname, "vpn_gateway")) {
+        if (vc->setVpnGateway(val))
+            goto out_inval;
+    } else {
+        cli->sendMsg(ErrorCode::CommandParameterError, "Variable not found.", true);
+        return 0;
+    }
+
+    cli->sendMsg(ErrorCode::CommandOkay, "Variable written.", false);
+    return 0;
+
+out_inval:
+    errno = EINVAL;
+    cli->sendMsg(ErrorCode::CommandParameterError, "Failed to set variable.", true);
+    return 0;
+}
+
+CommandListener::VpnGetVarCmd::VpnGetVarCmd() :
+                 NexusCommand("vpn_getvar") {
+} 
+
+int CommandListener::VpnGetVarCmd::runCommand(SocketClient *cli, char *data) {
+    VpnController *vc = (VpnController *) NetworkManager::Instance()->findController("VPN");
+
+    char *bword;
+    char *last;
+    char varname[32];
+
+    if (!(bword = strtok_r(data, ":", &last)))
+        goto out_inval;
+   
+    strncpy(varname, bword, sizeof(varname));
+
+    if (!strcasecmp(varname, "vpn_gateway")) {
+        char buffer[255];
+
+        sprintf(buffer, "%s:%s", varname, inet_ntoa(vc->getVpnGateway()));
+        cli->sendMsg(ErrorCode::VariableRead, buffer, false);
+    } else {
+        cli->sendMsg(ErrorCode::CommandParameterError, "Variable not found.", true);
+        return 0;
+    }
+
+    cli->sendMsg(ErrorCode::CommandOkay, "Variable read.", false);
+    return 0;
+out_inval:
+    errno = EINVAL;
+    cli->sendMsg(ErrorCode::CommandParameterError, "Failed to get variable.", true);
+    return 0;
+}
+
 CommandListener::VpnDisableCmd::VpnDisableCmd() :
                  NexusCommand("vpn_disable") {
 } 
diff --git a/nexus/CommandListener.h b/nexus/CommandListener.h
index 7bc89e3..a44aa29 100644
--- a/nexus/CommandListener.h
+++ b/nexus/CommandListener.h
@@ -95,6 +95,20 @@
         int runCommand(SocketClient *c, char *data);
     };
 
+    class VpnSetVarCmd : public NexusCommand {
+    public:
+        VpnSetVarCmd();
+        virtual ~VpnSetVarCmd() {}
+        int runCommand(SocketClient *c, char *data);
+    };
+
+    class VpnGetVarCmd : public NexusCommand {
+    public:
+        VpnGetVarCmd();
+        virtual ~VpnGetVarCmd() {}
+        int runCommand(SocketClient *c, char *data);
+    };
+
     class VpnDisableCmd : public NexusCommand {
     public:
         VpnDisableCmd();
diff --git a/nexus/ErrorCode.h b/nexus/ErrorCode.h
index 8ca6cae..57c99c2 100644
--- a/nexus/ErrorCode.h
+++ b/nexus/ErrorCode.h
@@ -26,6 +26,9 @@
     static const int WifiScanResult = 125;
     static const int WifiNetworkList = 126;
 
+    static const int VariableRead = 127;
+    static const int VariableWrite = 128;
+
     // 200 series - Requested action has been successfully completed
     static const int CommandOkay = 200;
 
diff --git a/nexus/OpenVpnController.cpp b/nexus/OpenVpnController.cpp
index eff653a..411a0c7 100644
--- a/nexus/OpenVpnController.cpp
+++ b/nexus/OpenVpnController.cpp
@@ -14,17 +14,28 @@
  * limitations under the License.
  */
 #include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
 #define LOG_TAG "OpenVpnController"
 #include <cutils/log.h>
 #include <cutils/properties.h>
 
+#include <sysutils/ServiceManager.h>
+
 #include "OpenVpnController.h"
 
 #define DAEMON_PROP_NAME "vpn.openvpn.status"
 
+#define DAEMON_CONFIG_FILE "/data/misc/openvpn/openvpn.conf"
+
 OpenVpnController::OpenVpnController() :
                    VpnController() {
+    mServiceManager = new ServiceManager();
+}
+
+OpenVpnController::~OpenVpnController() {
+    delete mServiceManager;
 }
 
 int OpenVpnController::start() {
@@ -36,69 +47,24 @@
 }
 
 int OpenVpnController::enable() {
-
-    // Validate configuration file
-   
-    // Validate key file
-
-    if (startServiceDaemon())
-        return -1;
-
-    errno = -ENOSYS;
-    return -1;
-}
-
-int OpenVpnController::startServiceDaemon() {
-    char status[PROPERTY_VALUE_MAX];
-    int count = 100;
-
-    property_set("ctl.start", "openvpn");
-    sched_yield();
-
-    while (count-- > 0) {
-        if (property_get(DAEMON_PROP_NAME, status, NULL)) {
-            if (strcmp(status, "ok") == 0)
-                return 0;
-            else if (strcmp(DAEMON_PROP_NAME, "failed") == 0)
-                return -1;
-        }
-        usleep(200000);
-    }
-    property_set(DAEMON_PROP_NAME, "timeout");
-    return -1;
-}
-
-int OpenVpnController::stopServiceDaemon() {
-    char status[PROPERTY_VALUE_MAX] = {'\0'};
-    int count = 50;
-
-    if (property_get(DAEMON_PROP_NAME, status, NULL) &&
-        !strcmp(status, "stopped")) {
-        LOGD("Service already stopped");
-        return 0;
-    }
-
-    property_set("ctl.stop", "openvpn");
-    sched_yield();
-
-    while (count-- > 0) {
-        if (property_get(DAEMON_PROP_NAME, status, NULL)) {
-            if (!strcmp(status, "stopped"))
-                break;
-        }
-        usleep(100000);
-    }
-
-    if (!count) {
-        LOGD("Timed out waiting for openvpn to stop");
-        errno = ETIMEDOUT;
+    char svc[PROPERTY_VALUE_MAX];
+    char tmp[64];
+    
+    if (!getProperty("vpn.gateway", tmp, sizeof(tmp))) {
+        LOGE("Error reading property 'vpn.gateway' (%s)", strerror(errno));
         return -1;
     }
+    snprintf(svc, sizeof(svc), "openvpn:--remote %s 1194", tmp);
+
+    if (mServiceManager->start(svc))
+        return -1;
 
     return 0;
 }
 
 int OpenVpnController::disable() {
-    errno = -ENOSYS;
-    return -1;
+
+    if (mServiceManager->stop("openvpn"))
+        return -1;
+    return 0;
 }
diff --git a/nexus/OpenVpnController.h b/nexus/OpenVpnController.h
index 1ecc3fb..b321029 100644
--- a/nexus/OpenVpnController.h
+++ b/nexus/OpenVpnController.h
@@ -19,22 +19,20 @@
 
 #include "VpnController.h"
 
+class ServiceManager;
+
 class OpenVpnController : public VpnController {
+private:
+    ServiceManager *mServiceManager;
 
 public:
     OpenVpnController();
-    virtual ~OpenVpnController() {}
+    virtual ~OpenVpnController();
 
     int start();
     int stop();
     int enable();
     int disable();
-
-protected:
-
-private:
-    int startServiceDaemon();
-    int stopServiceDaemon();
 };
 
 #endif
diff --git a/nexus/Supplicant.cpp b/nexus/Supplicant.cpp
index 22964bb..6737d91 100644
--- a/nexus/Supplicant.cpp
+++ b/nexus/Supplicant.cpp
@@ -25,12 +25,7 @@
 
 #include "private/android_filesystem_config.h"
 
-#undef HAVE_LIBC_SYSTEM_PROPERTIES
-
-#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-#endif
+#include <sysutils/ServiceManager.h>
 
 #include "Supplicant.h"
 #include "SupplicantListener.h"
@@ -44,12 +39,10 @@
 
 #define IFACE_DIR        "/data/system/wpa_supplicant"
 #define DRIVER_PROP_NAME "wlan.driver.status"
-#define SUPPLICANT_NAME  "wpa_supplicant"
-#define SUPP_PROP_NAME   "init.svc.wpa_supplicant"
+#define SUPPLICANT_SERVICE_NAME  "wpa_supplicant"
 #define SUPP_CONFIG_TEMPLATE "/system/etc/wifi/wpa_supplicant.conf"
 #define SUPP_CONFIG_FILE "/data/misc/wifi/wpa_supplicant.conf"
 
-
 Supplicant::Supplicant() {
     mCtrl = NULL;
     mMonitor = NULL;
@@ -57,62 +50,25 @@
 
     mState = SupplicantState::UNKNOWN;
 
-    mLatestScanResults = new ScanResultCollection();
+    mServiceManager = new ServiceManager();
 
+    mLatestScanResults = new ScanResultCollection();
     pthread_mutex_init(&mLatestScanResultsLock, NULL);
 }
 
+Supplicant::~Supplicant() {
+    delete mServiceManager;
+}
+
 int Supplicant::start() {
 
     if (setupConfig()) {
         LOGW("Unable to setup supplicant.conf");
     }
-    
-    char status[PROPERTY_VALUE_MAX] = {'\0'};
-    int count = 200;
-#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
-    const prop_info *pi;
-    unsigned int serial = 0;
-#endif
-
-    if (property_get(SUPP_PROP_NAME, status, NULL) &&
-        !strcmp(status, "running")) {
-    } else {
-#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
-        pi = __system_property_find(SUPP_PROP_NAME);
-        if (pi != NULL)
-            serial = pi->serial;
-#endif
-
-        LOGD("Starting Supplicant");
-        property_set("ctl.start", SUPPLICANT_NAME);
-        sched_yield();
-        while (count--) {
-#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
-            if (!pi)
-                pi = __system_property_find(SUPP_PROP_NAME);
-            if (pi) {
-                __system_property_read(pi, NULL, status);
-                if (strcmp(status, "running") == 0)
-                    break;
-                else if (pi->serial != serial &&
-                        strcmp(status, "stopped") == 0) {
-                    errno = EIO;
-                    return -1;
-                }
-            }
-#else
-            if (property_get(SUPP_PROP_NAME, status, NULL)) {
-                if (!strcmp(status, "running"))
-                    break;
-            }
-#endif
-            usleep(100000);
-        }
-        if (!count) {
-            errno = ETIMEDOUT;
-            return -1;
-        }
+ 
+    if (mServiceManager->start(SUPPLICANT_SERVICE_NAME)) {
+        LOGE("Error starting supplicant (%s)", strerror(errno));
+        return -1;
     }
 
     wpa_ctrl_cleanup();
@@ -125,30 +81,13 @@
 
 int Supplicant::stop() {
 
-    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
-    int count = 50; 
-
     if (mListener->stopListener()) {
         LOGW("Unable to stop supplicant listener (%s)", strerror(errno));
         return -1;
     }
 
-    if (property_get(SUPP_PROP_NAME, supp_status, NULL)
-        && strcmp(supp_status, "stopped") == 0) {
-        LOGD("Supplicant already stopped");
-        return 0;
-    }
-
-    LOGD("Stopping Supplicant");
-    property_set("ctl.stop", SUPPLICANT_NAME);
-    sched_yield();
-
-    while (count-- > 0) {
-        if (property_get(SUPP_PROP_NAME, supp_status, NULL)) {
-            if (strcmp(supp_status, "stopped") == 0)
-                break;
-        }
-        usleep(100000);
+    if (mServiceManager->stop(SUPPLICANT_SERVICE_NAME)) {
+        LOGW("Error stopping supplicant (%s)", strerror(errno));
     }
 
     if (mCtrl) {
@@ -160,35 +99,15 @@
         mMonitor = NULL;
     }
 
-    if (!count) {
-        LOGD("Timed out waiting for supplicant to stop");
-        errno = ETIMEDOUT;
-        return -1;
-    }
-
-    LOGD("Supplicant shutdown");
-
     return 0;
 }
 
 bool Supplicant::isStarted() {
-    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
-
-    property_get(SUPP_PROP_NAME, supp_status, NULL);
-
-    if (!strcmp(supp_status, "running"))
-        return true;
-
-    return false;
+    return mServiceManager->isRunning(SUPPLICANT_SERVICE_NAME);
 }
 
 int Supplicant::connectToSupplicant() {
-    char ifname[256];
-    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
-
-    LOGD("connectToSupplicant()");
-    if (!property_get(SUPP_PROP_NAME, supp_status, NULL)
-            || strcmp(supp_status, "running") != 0) {
+    if (!isStarted()) {
         LOGE("Supplicant not running, cannot connect");
         return -1;
     }
@@ -229,7 +148,7 @@
         return -1;
     }
 
-    LOGD("sendCommand(): -> '%s'", cmd);
+//    LOGD("sendCommand(): -> '%s'", cmd);
 
     int rc;
     if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2)  {
@@ -245,7 +164,7 @@
         !strncmp(cmd, "SCAN_RESULTS", 12)) 
         reply[*reply_len] = '\0';
 
-    LOGD("sendCommand(): <- '%s'", reply);
+//    LOGD("sendCommand(): <- '%s'", reply);
     return 0;
 }
 
diff --git a/nexus/Supplicant.h b/nexus/Supplicant.h
index 4a7ec3a..2ea0892 100644
--- a/nexus/Supplicant.h
+++ b/nexus/Supplicant.h
@@ -19,6 +19,7 @@
 struct wpa_ctrl;
 class SupplicantListener;
 class SupplicantEvent;
+class ServiceManager;
 
 #include <pthread.h>
 
@@ -31,13 +32,14 @@
     struct wpa_ctrl      *mMonitor;
     SupplicantListener   *mListener;
     int                  mState;
+    ServiceManager       *mServiceManager;
 
     ScanResultCollection *mLatestScanResults;
     pthread_mutex_t      mLatestScanResultsLock;
   
 public:
     Supplicant();
-    virtual ~Supplicant() {}
+    virtual ~Supplicant();
 
     int start();
     int stop();
@@ -50,7 +52,6 @@
     int removeNetwork(int networkId);
     WifiNetworkCollection *createNetworkList();
 
-
     int getState() { return mState; }
 
 
diff --git a/nexus/VpnController.cpp b/nexus/VpnController.cpp
index 17bfe41..cd24c19 100644
--- a/nexus/VpnController.cpp
+++ b/nexus/VpnController.cpp
@@ -13,7 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#include <string.h>
 #include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
 #include "VpnController.h"
 
 VpnController::VpnController() :
@@ -21,21 +27,34 @@
 }
 
 int VpnController::start() {
-    errno = -ENOSYS;
+    errno = ENOSYS;
     return -1;
 }
 
 int VpnController::stop() {
-    errno = -ENOSYS;
+    errno = ENOSYS;
     return -1;
 }
 
 int VpnController::enable() {
-    errno = -ENOSYS;
+    errno = ENOSYS;
     return -1;
 }
 
 int VpnController::disable() {
-    errno = -ENOSYS;
+    errno = ENOSYS;
     return -1;
 }
+
+int VpnController::setVpnGateway(const char *vpnGw) {
+    if (!inet_aton(vpnGw, &mVpnGateway)) {
+        errno = EINVAL;
+        return -1;
+    }
+    return 0;
+}
+
+int VpnController::setVpnGateway(struct in_addr *vpnGw) {
+    memcpy(&mVpnGateway, vpnGw, sizeof(struct in_addr));
+    return 0;
+}
diff --git a/nexus/VpnController.h b/nexus/VpnController.h
index 049fe6e..4088e6a 100644
--- a/nexus/VpnController.h
+++ b/nexus/VpnController.h
@@ -16,9 +16,15 @@
 #ifndef _VPN_CONTROLLER_H
 #define _VPN_CONTROLLER_H
 
+#include <netinet/in.h>
+
 #include "Controller.h"
 
 class VpnController : public Controller {
+    /*
+     * Gateway of the VPN server to connect to
+     */
+    struct in_addr mVpnGateway;
 
 public:
     VpnController();
@@ -30,6 +36,10 @@
     virtual int enable();
     virtual int disable();
 
+    struct in_addr &getVpnGateway() { return mVpnGateway; }
+    int setVpnGateway(const char *vpnGw);
+    int setVpnGateway(struct in_addr *vpnGw);
+
 protected:
 };
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index c20eeaa..9853cc6 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -246,6 +246,12 @@
     group audio
     oneshot
 
+service bootanim /system/bin/bootanimation
+    user graphics
+    group graphics
+    disabled
+    oneshot
+
 service dbus /system/bin/dbus-daemon --system --nofork
     socket dbus stream 660 bluetooth bluetooth
     user bluetooth
diff --git a/vold/volmgr_vfat.c b/vold/volmgr_vfat.c
index 344a166..4013df8 100644
--- a/vold/volmgr_vfat.c
+++ b/vold/volmgr_vfat.c
@@ -39,6 +39,7 @@
 int vfat_check(blkdev_t *dev)
 {
     int rc;
+    boolean rw = true;
 
 #if VFAT_DEBUG
     LOG_VOL("vfat_check(%d:%d):", dev->major, dev->minor);
@@ -50,47 +51,51 @@
         return 0;
     }
 
-#ifdef VERIFY_PASS
-    char *args[7];
-    args[0] = FSCK_MSDOS_PATH;
-    args[1] = "-v";
-    args[2] = "-V";
-    args[3] = "-w";
-    args[4] = "-p";
-    args[5] = blkdev_get_devpath(dev);
-    args[6] = NULL;
-    rc = logwrap(6, args);
-    free(args[5]);
-#else
-    char *args[6];
-    args[0] = FSCK_MSDOS_PATH;
-    args[1] = "-v";
-    args[2] = "-w";
-    args[3] = "-p";
-    args[4] = blkdev_get_devpath(dev);
-    args[5] = NULL;
-    rc = logwrap(5, args);
-    free(args[4]);
-#endif
+    do {
 
-    if (rc == 0) {
-        LOG_VOL("Filesystem check completed OK");
-        return 0;
-    } else if (rc == 1) {
-        LOG_VOL("Filesystem check failed (general failure)");
-        return -EINVAL;
-    } else if (rc == 2) {
-        LOG_VOL("Filesystem check failed (invalid usage)");
-        return -EIO;
-    } else if (rc == 4) {
-        LOG_VOL("Filesystem check completed (errors fixed)");
-    } else if (rc == 8) {
-        LOG_VOL("Filesystem check failed (not a FAT filesystem)");
-        return -ENODATA;
-    } else {
-        LOG_VOL("Filesystem check failed (unknown exit code %d)", rc);
-        return -EIO;
-    }
+        char *args[6];
+        args[0] = FSCK_MSDOS_PATH;
+        args[1] = "-v";
+
+        if (rw) {
+            args[2] = "-w";
+            args[3] = "-p";
+            args[4] = blkdev_get_devpath(dev);
+            args[5] = NULL;
+            rc = logwrap(5, args);
+            free(args[4]);
+        } else {
+            args[2] = "-n";
+            args[3] = blkdev_get_devpath(dev);
+            args[4] = NULL;
+            rc = logwrap(4, args);
+            free(args[3]);
+        }
+
+        if (rc == 0) {
+            LOG_VOL("Filesystem check completed OK");
+            return 0;
+        } else if (rc == 1) {
+            LOG_VOL("Filesystem check failed (general failure)");
+            return -EINVAL;
+        } else if (rc == 2) {
+            LOG_VOL("Filesystem check failed (invalid usage)");
+            return -EIO;
+        } else if (rc == 4) {
+            LOG_VOL("Filesystem check completed (errors fixed)");
+        } else if (rc == 6) {
+            LOG_VOL("Filesystem read-only - retrying check RO");
+            rw = false;
+            continue;
+        } else if (rc == 8) {
+            LOG_VOL("Filesystem check failed (not a FAT filesystem)");
+            return -ENODATA;
+        } else {
+            LOG_VOL("Filesystem check failed (unknown exit code %d)", rc);
+            return -EIO;
+        }
+    } while (0);
+
     return 0;
 }
 
@@ -105,7 +110,7 @@
     LOG_VOL("vfat_mount(%d:%d, %s, %d):", dev->major, dev->minor, vol->mount_point, safe_mode);
 #endif
 
-    flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
+    flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC | MS_SYNCHRONOUS;
 
     if (vol->state == volstate_mounted) {
         LOG_VOL("Remounting %d:%d on %s, safe mode %d", dev->major,
@@ -113,15 +118,22 @@
         flags |= MS_REMOUNT;
     }
 
+    /*
+     * The mount masks restrict access so that:
+     * 1. The 'system' user cannot access the SD card at all - 
+     *    (protects system_server from grabbing file references)
+     * 2. Group users can RWX
+     * 3. Others can only RX
+     */
     rc = mount(devpath, vol->mount_point, "vfat", flags,
-               "utf8,uid=1000,gid=1000,fmask=711,dmask=700,shortname=mixed");
+               "utf8,uid=1000,gid=1015,fmask=702,dmask=702,shortname=mixed");
 
     if (rc && errno == EROFS) {
         LOGE("vfat_mount(%d:%d, %s): Read only filesystem - retrying mount RO",
              dev->major, dev->minor, vol->mount_point);
         flags |= MS_RDONLY;
         rc = mount(devpath, vol->mount_point, "vfat", flags,
-                   "utf8,uid=1000,gid=1000,fmask=711,dmask=700,shortname=mixed");
+                   "utf8,uid=1000,gid=1015,fmask=702,dmask=702,shortname=mixed");
     }
 
 #if VFAT_DEBUG