Code drop from //branches/cupcake/...@124589
diff --git a/Android.mk b/Android.mk
index 44ea560..8b79ceb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -19,8 +19,9 @@
   include $(call first-makefiles-under,$(LOCAL_PATH))
 else
   include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
+	      adb \
 	      libcutils \
-              liblog \
+	      liblog \
 	      libnetutils \
 	      libpixelflinger \
 	      libzipfile \
diff --git a/adb/Android.mk b/adb/Android.mk
index 8ac5eb4..c06485f 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -7,6 +7,7 @@
 
 # adb host tool
 # =========================================================
+ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean (also unused with the sim)
 include $(CLEAR_VARS)
 
 # Default to a virtual (sockets) usb interface
@@ -29,7 +30,7 @@
   USB_SRCS := usb_windows.c
   EXTRA_SRCS := get_my_path_windows.c
   EXTRA_STATIC_LIBS := AdbWinApi
-  LOCAL_C_INCLUDES += /usr/include/w32api/ddk $(LOCAL_PATH)/../windows/usb/api
+  LOCAL_C_INCLUDES += /usr/include/w32api/ddk development/host/windows/usb/api/
   ifneq ($(strip $(USE_CYGWIN)),)
     LOCAL_LDLIBS += -lpthread
   else
@@ -51,7 +52,8 @@
 	file_sync_client.c \
 	$(EXTRA_SRCS) \
 	$(USB_SRCS) \
-	shlist.c
+	shlist.c \
+	utils.c \
 
 
 ifneq ($(USE_SYSDEPS_WIN32),)
@@ -69,6 +71,8 @@
 
 include $(BUILD_HOST_EXECUTABLE)
 
+$(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
+
 ifeq ($(HOST_OS),windows)
 $(LOCAL_INSTALLED_MODULE): $(HOST_OUT_EXECUTABLES)/AdbWinApi.dll
 endif
@@ -81,10 +85,25 @@
 include $(BUILD_HOST_EXECUTABLE)
 endif
 
+endif
 
 # adbd device daemon
 # =========================================================
-ifeq ($(TARGET_ARCH),arm)
+
+# build adbd in all non-simulator builds
+BUILD_ADBD := false
+ifneq ($(TARGET_SIMULATOR),true)
+    BUILD_ADBD := true
+endif
+
+# build adbd for the Linux simulator build
+# so we can use it to test the adb USB gadget driver on x86
+ifeq ($(HOST_OS),linux)
+    BUILD_ADBD := true
+endif
+
+
+ifeq ($(BUILD_ADBD),true)
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
@@ -99,18 +118,31 @@
 	framebuffer_service.c \
 	remount_service.c \
 	usb_linux_client.c \
-	log_service.c
+	log_service.c \
+	utils.c \
 
-
-LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -DANDROID_GADGET=1 -Wall -Wno-unused-parameter
+LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
 LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
+
+# TODO: This should probably be board specific, whether or not the kernel has
+# the gadget driver; rather than relying on the architecture type.
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_CFLAGS += -DANDROID_GADGET=1
+endif
+
 LOCAL_MODULE := adbd
 
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
 
-LOCAL_STATIC_LIBRARIES := libcutils libc
+ifeq ($(TARGET_SIMULATOR),true)
+  LOCAL_STATIC_LIBRARIES := libcutils
+  LOCAL_LDLIBS += -lpthread
+  include $(BUILD_HOST_EXECUTABLE)
+else
+  LOCAL_STATIC_LIBRARIES := libcutils libc
+  include $(BUILD_EXECUTABLE)
+endif
 
-include $(BUILD_EXECUTABLE)
 endif
diff --git a/adb/OVERVIEW.TXT b/adb/OVERVIEW.TXT
new file mode 100644
index 0000000..6a5191a
--- /dev/null
+++ b/adb/OVERVIEW.TXT
@@ -0,0 +1,139 @@
+Implementation notes regarding ADB.
+
+I. General Overview:
+
+The Android Debug Bridge (ADB) is used to:
+
+- keep track of all Android devices and emulators instances
+  connected to or running on a given host developer machine
+
+- implement various control commands (e.g. "adb shell", "adb pull", etc..)
+  for the benefit of clients (command-line users, or helper programs like
+  DDMS). These commands are what is called a 'service' in ADB.
+
+As a whole, everything works through the following components:
+
+  1. The ADB server
+
+    This is a background process that runs on the host machine. Its purpose
+    if to sense the USB ports to know when devices are attached/removed,
+    as well as when emulator instances start/stop.
+
+    It thus maintains a list of "connected devices" and assigns a 'state'
+    to each one of them: OFFLINE, BOOTLOADER, RECOVERY or ONLINE (more on
+    this below).
+
+    The ADB server is really one giant multiplexing loop whose purpose is
+    to orchestrate the exchange of data (packets, really) between clients,
+    services and devices.
+
+
+  2. The ADB daemon (adbd)
+
+    The 'adbd' program runs as a background process within an Android device
+    or emulated system. Its purpose is to connect to the ADB server
+    (through USB for devices, through TCP for emulators) and provide a
+    few services for clients that run on the host.
+
+    The ADB server considers that a device is ONLINE when it has succesfully
+    connected to the adbd program within it. Otherwise, the device is OFFLINE,
+    meaning that the ADB server detected a new device/emulator, but could not
+    connect to the adbd daemon.
+
+    the BOOTLOADER and RECOVERY states correspond to alternate states of
+    devices when they are in the bootloader or recovery mode.
+
+  3. The ADB command-line client
+
+    The 'adb' command-line program is used to run adb commands from a shell
+    or a script. It first tries to locate the ADB server on the host machine,
+    and will start one automatically if none is found.
+
+    then, the client sends its service requests to the ADB server. It doesn't
+    need to know.
+
+    Currently, a single 'adb' binary is used for both the server and client.
+    this makes distribution and starting the server easier.
+
+
+  4. Services
+
+    There are essentially two kinds of services that a client can talk to.
+
+    Host Services:
+      these services run within the ADB Server and thus do not need to
+      communicate with a device at all. A typical example is "adb devices"
+      which is used to return the list of currently known devices and their
+      state. They are a few couple other services though.
+
+    Local Services:
+      these services either run within the adbd daemon, or are started by
+      it on the device. The ADB server is used to multiplex streams
+      between the client and the service running in adbd. In this case
+      its role is to initiate the connection, then of being a pass-through
+      for the data.
+
+
+II. Protocol details:
+
+  1. Client <-> Server protocol:
+
+    This details the protocol used between ADB clients and the ADB
+    server itself. The ADB server listens on TCP:localhost:5037.
+
+    A client sends a request using the following format:
+
+        1. A 4-byte hexadecimal string giving the length of the payload
+        2. Followed by the payload itself.
+
+    For example, to query the ADB server for its internal version number,
+    the client will do the following:
+
+        1. Connect to tcp:localhost:5037
+        2. Send the string "000Chost:version" to the corresponding socket
+
+    The 'host:' prefix is used to indicate that the request is addressed
+    to the server itself (we will talk about other kinds of requests later).
+    The content length is encoded in ASCII for easier debugging.
+
+    The server should answer a request with one of the following:
+
+        1. For success, the 4-byte "OKAY" string
+
+        2. For failure, the 4-byte "FAIL" string, followed by a
+           4-byte hex length, followed by a string giving the reason
+           for failure.
+
+        3. As a special exception, for 'host:version', a 4-byte
+           hex string corresponding to the server's internal version number
+
+    Note that the connection is still alive after an OKAY, which allows the
+    client to make other requests. But in certain cases, an OKAY will even
+    change the state of the connection. 
+
+    For example, the case of the 'host:transport:<serialnumber>' request,
+    where '<serialnumber>' is used to identify a given device/emulator; after
+    the "OKAY" answer, all further requests made by the client will go
+    directly to the corresponding adbd daemon.
+
+    The file SERVICES.TXT lists all services currently implemented by ADB.
+
+
+  2. Transports:
+
+    An ADB transport models a connection between the ADB server and one device
+    or emulator. There are currently two kinds of transports:
+
+       - USB transports, for physical devices through USB
+
+       - Local transports, for emulators running on the host, connected to
+         the server through TCP
+
+    In theory, it should be possible to write a local transport that proxies
+    a connection between an ADB server and a device/emulator connected to/
+    running on another machine. This hasn't been done yet though.
+
+    Each transport can carry one or more multiplexed streams between clients
+    and the device/emulator they point to. The ADB server must handle
+    unexpected transport disconnections (e.g. when a device is physically
+    unplugged) properly.
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
new file mode 100644
index 0000000..d059e18
--- /dev/null
+++ b/adb/SERVICES.TXT
@@ -0,0 +1,245 @@
+This file tries to document all requests a client can make
+to the ADB server of an adbd daemon. See the OVERVIEW.TXT document
+to understand what's going on here.
+
+HOST SERVICES:
+
+host:version
+    Ask the ADB server for its internal version number.
+
+    As a special exception, the server will respond with a 4-byte
+    hex string corresponding to its internal version number, without
+    any OKAY or FAIL.
+
+host:kill
+    Ask the ADB server to quit immediately. This is used when the
+    ADB client detects that an obsolete server is running after an
+    upgrade.
+
+host:devices
+    Ask to return the list of available Android devices and their
+    state. After the OKAY, this is followed by a 4-byte hex len,
+    and a string that will be dumped as-is by the client, then
+    the connection is closed
+
+host:track-devices
+    This is a variant of host:devices which doesn't close the
+    connection. Instead, a new device list description is sent
+    each time a device is added/removed or the state of a given
+    device changes (hex4 + content). This allows tools like DDMS
+    to track the state of connected devices in real-time without
+    polling the server repeatedly.
+
+host:emulator:<port>
+    This is a special query that is sent to the ADB server when a
+    new emulator starts up. <port> is a decimal number corresponding
+    to the emulator's ADB control port, i.e. the TCP port that the
+    emulator will forward automatically to the adbd daemon running
+    in the emulator system.
+
+    This mechanism allows the ADB server to know when new emulator
+    instances start.
+
+host:transport:<serial-number>
+    Ask to switch the connection to the device/emulator identified by
+    <serial-number>. After the OKAY response, every client request will
+    be sent directly to the adbd daemon running on the device.
+    (Used to implement the -s option)
+
+host:transport-usb
+    Ask to switch the connection to one device connected through USB
+    to the host machine. This will fail if there are more than one such
+    devices. (Used to implement the -d convenience option)
+
+host:transport-local
+    Ask to switch the connection to one emulator connected through TCP.
+    This will fail if there is more than one such emulator instance
+    running. (Used to implement the -e convenience option)
+
+host:transport-any
+    Another host:transport variant. Ask to switch the connection to
+    either the device or emulator connect to/running on the host.
+    Will fail if there is more than one such device/emulator available.
+    (Used when neither -s, -d or -e are provided)
+
+host-serial:<serial-number>:<request>
+    This is a special form of query, where the 'host-serial:<serial-number>:'
+    prefix can be used to indicate that the client is asking the ADB server
+    for information related to a specific device. <request> can be in one
+    of the format described below.
+
+host-usb:<request>
+    A variant of host-serial used to target the single USB device connected
+    to the host. This will fail if there is none or more than one.
+
+host-local:<request>
+    A variant of host-serial used to target the single emulator instance
+    running on the host. This will fail if therre is none or more than one.
+
+host:<request>
+    When asking for information related to a device, 'host:' can also be
+    interpreted as 'any single device or emulator connected to/running on
+    the host'.
+
+<host-prefix>:get-product
+    XXX
+
+<host-prefix>:get-serialno
+    Returns the serial number of the corresponding device/emulator.
+    Note that emulator serial numbers are of the form "emulator-5554"
+
+<host-prefix>:get-state
+    Returns the state of a given device as a string.
+
+<host-prefix>:forward:<local>:<remote>
+    Asks the ADB server to forward local connections from <local>
+    to the <remote> address on a given device.
+
+    There, <host-prefix> can be one of the
+    host-serial/host-usb/host-local/host prefixes as described previously
+    and indicates which device/emulator to target.
+
+    the format of <local> is one of:
+
+        tcp:<port>      -> TCP connection on localhost:<port>
+        local:<path>    -> Unix local domain socket on <path>
+
+    the format of <remote> is one of:
+
+        tcp:<port>      -> TCP localhost:<port> on device
+        local:<path>    -> Unix local domain socket on device
+        jdwp:<pid>      -> JDWP thread on VM process <pid>
+
+    or even any one of the local services described below.
+
+
+
+LOCAL SERVICES:
+
+All the queries below assumed that you already switched the transport
+to a real device, or that you have used a query prefix as described
+above.
+
+shell:command arg1 arg2 ...
+    Run 'command arg1 arg2 ...' in a shell on the device, and return
+    its output and error streams. Note that arguments must be separated
+    by spaces. If an argument contains a space, it must be quoted with
+    double-quotes. Arguments cannot contain double quotes or things
+    will go very wrong.
+
+    Note that this is the non-interactive version of "adb shell"
+
+shell:
+    Start an interactive shell session on the device. Redirect
+    stdin/stdout/stderr as appropriate. Note that the ADB server uses
+    this to implement "adb shell", but will also cook the input before
+    sending it to the device (see interactive_shell() in commandline.c)
+
+bootdebug:
+    Ask debugging information to the bootloader. The adbd daemon will
+    respond with FAIL to this request.
+
+bootloader:<command>
+    Send a request to the bootloader. This can also work if the device
+    is currently in the bootloader state. The adbd daemon will respond
+    with FAIL to such requests.
+
+remount:
+    Ask adbd to remount the device's filesystem in read-write mode,
+    instead of read-only. This is usually necessary before performing
+    an "adb sync" or "adb push" request.
+
+    This request may not succeed on certain builds which do not allow
+    that.
+
+dev:<path>
+    Opens a device file and connects the client directly to it for
+    read/write purposes. Useful for debugging, but may require special
+    priviledges and thus may not run on all devices. <path> is a full
+    path from the root of the filesystem.
+
+tcp:<port>
+    Tries to connect to tcp port <port> on localhost.
+
+tcp:<port>:<server-name>
+    Tries to connect to tcp port <port> on machine <server-name> from
+    the device. This can be useful to debug some networking/proxy
+    issues that can only be revealed on the device itself.
+
+local:<path>
+    Tries to connect to a Unix domain socket <path> on the device
+
+localreserved:<path>
+localabstract:<path>
+localfilesystem:<path>
+    Variants of local:<path> that are used to access other Android
+    socket namespaces.
+
+log:<name>
+    Opens one of the system logs (/dev/log/<name>) and allows the client
+    to read them directly. Used to implement 'adb logcat'. The stream
+    will be read-only for the client.
+
+framebuffer:
+    This service is used to send snapshots of the framebuffer to a client.
+    It requires sufficient priviledges but works as follow:
+
+      After the OKAY, the service sends 16-byte binary structure
+      containing the following fields (little-endian format):
+
+            depth:   uint32_t:    framebuffer depth
+            size:    uint32_t:    framebuffer size in bytes
+            width:   uint32_t:    framebuffer width in pixels
+            height:  uint32_t:    framebuffer height in pixels
+
+      With the current implementation, depth is always 16, and
+      size is always width*height*2
+
+      Then, each time the client wants a snapshot, it should send
+      one byte through the channel, which will trigger the service
+      to send it 'size' bytes of framebuffer data.
+
+      If the adbd daemon doesn't have sufficient priviledges to open
+      the framebuffer device, the connection is simply closed immediately.
+
+dns:<server-name>
+    This service is an exception because it only runs within the ADB server.
+    It is used to implement USB networking, i.e. to provide a network connection
+    to the device through the host machine (note: this is the exact opposite of
+    network thetering).
+
+    It is used to perform a gethostbyname(<address>) on the host and return
+    the corresponding IP address as a 4-byte string.
+
+recover:<size>
+    This service is used to upload a recovery image to the device. <size>
+    must be a number corresponding to the size of the file. The service works
+    by:
+
+       - creating a file named /tmp/update
+       - reading 'size' bytes from the client and writing them to /tmp/update
+       - when everything is read succesfully, create a file named /tmp/update.start
+
+    This service can only work when the device is in recovery mode. Otherwise,
+    the /tmp directory doesn't exist and the connection will be closed immediately.
+
+jdwp:<pid>
+    Connects to the JDWP thread running in the VM of process <pid>.
+
+track-jdwp
+    This is used to send the list of JDWP pids periodically to the client.
+    The format of the returned data is the following:
+
+        <hex4>:    the length of all content as a 4-char hexadecimal string
+        <content>: a series of ASCII lines of the following format:
+                        <pid> "\n"
+
+    This service is used by DDMS to know which debuggable processes are running
+    on the device/emulator.
+
+    Note that there is no single-shot service to retrieve the list only once.
+
+sync:
+    This starts the file synchronisation service, used to implement "adb push"
+    and "adb pull". Since this service is pretty complex, it will be detailed
+    in a companion document named SYNC.TXT
diff --git a/adb/adb.c b/adb/adb.c
index a50ef33..27d0c81 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -67,59 +67,59 @@
  */
 void  adb_trace_init(void)
 {
-	const char*  p = getenv("ADB_TRACE");
-	const char*  q;
+    const char*  p = getenv("ADB_TRACE");
+    const char*  q;
 
-	static const struct {
-		const char*  tag;
-		int           flag;
-	} tags[] = {
-	    { "1", 0 },
-		{ "all", 0 },
-		{ "adb", TRACE_ADB },
-		{ "sockets", TRACE_SOCKETS },
-		{ "packets", TRACE_PACKETS },
-		{ "rwx", TRACE_RWX },
-		{ "usb", TRACE_USB },
-		{ "sync", TRACE_SYNC },
-		{ "sysdeps", TRACE_SYSDEPS },
+    static const struct {
+        const char*  tag;
+        int           flag;
+    } tags[] = {
+        { "1", 0 },
+        { "all", 0 },
+        { "adb", TRACE_ADB },
+        { "sockets", TRACE_SOCKETS },
+        { "packets", TRACE_PACKETS },
+        { "rwx", TRACE_RWX },
+        { "usb", TRACE_USB },
+        { "sync", TRACE_SYNC },
+        { "sysdeps", TRACE_SYSDEPS },
         { "transport", TRACE_TRANSPORT },
         { "jdwp", TRACE_JDWP },
-		{ NULL, 0 }
-	};
+        { NULL, 0 }
+    };
 
-	if (p == NULL)
-		return;
+    if (p == NULL)
+            return;
 
-	/* use a comma/column/semi-colum/space separated list */
-	while (*p) {
-		int  len, tagn;
+    /* use a comma/column/semi-colum/space separated list */
+    while (*p) {
+        int  len, tagn;
 
-		q = strpbrk(p, " ,:;");
-		if (q == NULL) {
-			q = p + strlen(p);
-		}
-		len = q - p;
+        q = strpbrk(p, " ,:;");
+        if (q == NULL) {
+            q = p + strlen(p);
+        }
+        len = q - p;
 
-		for (tagn = 0; tags[tagn].tag != NULL; tagn++)
-		{
-			int  taglen = strlen(tags[tagn].tag);
+        for (tagn = 0; tags[tagn].tag != NULL; tagn++)
+        {
+            int  taglen = strlen(tags[tagn].tag);
 
-			if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
-			{
-				int  flag = tags[tagn].flag;
-				if (flag == 0) {
-					adb_trace_mask = ~0;
-					return;
-				}
-				adb_trace_mask |= (1 << flag);
-				break;
-			}
-		}
-		p = q;
-		if (*p)
-			p++;
-	}
+            if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
+            {
+                int  flag = tags[tagn].flag;
+                if (flag == 0) {
+                    adb_trace_mask = ~0;
+                    return;
+                }
+                adb_trace_mask |= (1 << flag);
+                break;
+            }
+        }
+        p = q;
+        if (*p)
+            p++;
+    }
 }
 
 
@@ -783,8 +783,8 @@
 
         // child process
         int result = execl(path, "adb", "fork-server", "server", NULL);
-	    // this should not return
-	    fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
+        // this should not return
+        fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
     } else  {
         // parent side of the fork
 
@@ -894,7 +894,7 @@
     if(access("/dev/android_adb", F_OK) == 0 ||
        access("/dev/android", F_OK) == 0) {
         usb_init();
-	} else {
+    } else {
         local_init();
     }
     init_jdwp();
diff --git a/adb/adb.h b/adb/adb.h
index 5a74b7b..a17c8dd 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -79,6 +79,11 @@
         */
     unsigned id;
 
+        /* flag: set when the socket's peer has closed
+        ** but packets are still queued for delivery
+        */
+    int    closing;
+
         /* the asocket we are connected to
         */
 
@@ -309,15 +314,15 @@
  * the adb_trace_init() function implemented in adb.c
  */
 typedef enum {
-	TRACE_ADB = 0,
-	TRACE_SOCKETS,
-	TRACE_PACKETS,
-	TRACE_TRANSPORT,
-	TRACE_RWX,
-	TRACE_USB,
-	TRACE_SYNC,
-	TRACE_SYSDEPS,
-        TRACE_JDWP,
+    TRACE_ADB = 0,
+    TRACE_SOCKETS,
+    TRACE_PACKETS,
+    TRACE_TRANSPORT,
+    TRACE_RWX,
+    TRACE_USB,
+    TRACE_SYNC,
+    TRACE_SYSDEPS,
+    TRACE_JDWP,
 } AdbTrace;
 
 #if ADB_TRACE
diff --git a/adb/adb_client.c b/adb/adb_client.c
index c1b87ee..5868744 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -211,7 +211,7 @@
             return -1;
         } else {
             fprintf(stdout,"* daemon started successfully *\n");
-		}
+        }
         /* give the server some time to start properly and detect devices */
         adb_sleep_ms(2000);
         // fall through to _adb_connect
@@ -223,13 +223,13 @@
 
         // if we have a file descriptor, then parse version result
         if(fd >= 0) {
-	        if(readx(fd, buf, 4)) goto error;
+            if(readx(fd, buf, 4)) goto error;
 
-		    buf[4] = 0;
-		    n = strtoul(buf, 0, 16);
-		    if(n > (int)sizeof(buf)) goto error;
-		    if(readx(fd, buf, n)) goto error;
-		    adb_close(fd);
+            buf[4] = 0;
+            n = strtoul(buf, 0, 16);
+            if(n > (int)sizeof(buf)) goto error;
+            if(readx(fd, buf, n)) goto error;
+            adb_close(fd);
 
             if (sscanf(buf, "%04x", &version) != 1) goto error;
         } else {
@@ -240,14 +240,14 @@
         }
 
         if(version != ADB_SERVER_VERSION) {
-	        printf("adb server is out of date.  killing...\n");
-	        fd = _adb_connect("host:kill");
-	        adb_close(fd);
+            printf("adb server is out of date.  killing...\n");
+            fd = _adb_connect("host:kill");
+            adb_close(fd);
 
-                /* XXX can we better detect its death? */
-	        adb_sleep_ms(2000);
+            /* XXX can we better detect its death? */
+            adb_sleep_ms(2000);
             goto start_server;
-	    }
+        }
     }
 
     // if the command is start-server, we are done.
diff --git a/adb/commandline.c b/adb/commandline.c
index c1ef8b0..cbf079c 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -296,8 +296,8 @@
                             buf_ptr[cmdlen] = '\0';
                             if( (item = shListFindItem( &history, (void *)buf_ptr, shItemCmp )) == NULL ) {
                                 shListInsFirstItem( &history, (void *)buf_ptr );
-				item = &history;
-			    }
+                                item = &history;
+                            }
                         }
                     }
                     cmdlen = 0;
@@ -322,8 +322,8 @@
                 default:
 #ifdef SH_HISTORY
                     if( buf[n] == SH_DEL_CHAR ) {
-			if( cmdlen > 0 )
-                    	    cmdlen--;
+                        if( cmdlen > 0 )
+                            cmdlen--;
                     }
                     else {
                         realbuf[cmdlen] = buf[n];
@@ -478,7 +478,7 @@
 #ifdef _WIN32
     /* XXX: TODO */
 #else
-	int  fd;
+    int  fd;
     fd = unix_open("/dev/null", O_WRONLY);
     dup2(fd, 2);
     adb_close(fd);
@@ -512,7 +512,7 @@
     }
 }
 
-/** duplicate string and quote all \ " ( ) chars */
+/** duplicate string and quote all \ " ( ) chars + space character. */
 static char *
 dupAndQuote(const char *s)
 {
@@ -527,7 +527,7 @@
 
     for( ;*ts != '\0'; ts++) {
         alloc_len++;
-        if (*ts == '"' || *ts == '\\') {
+        if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
             alloc_len++;
         }
     }
@@ -538,7 +538,7 @@
     dest = ret;
 
     for ( ;*ts != '\0'; ts++) {
-        if (*ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
+        if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
             *dest++ = '\\';
         }
 
@@ -561,7 +561,7 @@
 {
 #ifdef HAVE_WIN32_PROC
     fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
-	return -1;
+    return -1;
 #else
     char *adb_service_name;
     pid_t pid;
@@ -657,8 +657,8 @@
     quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
 
     snprintf(buf, sizeof(buf),
-            "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
-	    quoted_log_tags);
+        "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
+        quoted_log_tags);
 
     free(quoted_log_tags);
 
@@ -847,7 +847,7 @@
     if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
         gProductOutPath = NULL;
     }
-    // TODO: also try TARGET_PRODUCT as a hint
+    // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
 
         /* modifiers and flags */
     while(argc > 0) {
@@ -1077,15 +1077,15 @@
             return 1;
         }
 
-		/* Allow a command to be run after wait-for-device,
-		 * e.g. 'adb wait-for-device shell'.
-		 */
-		if(argc > 1) {
-			argc--;
-			argv++;
-			goto top;
-		}
-		return 0;
+        /* Allow a command to be run after wait-for-device,
+            * e.g. 'adb wait-for-device shell'.
+            */
+        if(argc > 1) {
+            argc--;
+            argv++;
+            goto top;
+        }
+        return 0;
     }
 
     if(!strcmp(argv[0], "forward")) {
@@ -1299,7 +1299,7 @@
     while(argc-- > 0) {
         char *quoted;
 
-        quoted = dupAndQuote (*argv++);
+        quoted = dupAndQuote(*argv++);
 
         strncat(buf, " ", sizeof(buf)-1);
         strncat(buf, quoted, sizeof(buf)-1);
@@ -1312,6 +1312,18 @@
 
 int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
 {
+    /* if the user choose the -k option, we refuse to do it until devices are
+       out with the option to uninstall the remaining data somehow (adb/ui) */
+    if (argc == 3 && strcmp(argv[1], "-k") == 0)
+    {
+        printf(
+            "The -k option uninstalls the application while retaining the data/cache.\n"
+            "At the moment, there is no way to remove the remaining data.\n"
+            "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
+            "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
+        return -1;
+    }
+
     /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
     return pm_command(transport, serial, argc, argv);
 }
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index f9e80ed..4e6d385 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -55,7 +55,7 @@
     if(total_bytes == 0) return;
 
     if (t == 0)  /* prevent division by 0 :-) */
-		t = 1000000;
+        t = 1000000;
 
     fprintf(stderr,"%lld KB/s (%d bytes in %lld.%03llds)\n",
             ((((long long) total_bytes) * 1000000LL) / t) / 1024LL,
@@ -227,14 +227,14 @@
 
         if(ret < 0) {
             if(errno == EINTR)
-	        continue;
+                continue;
             fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
             break;
         }
 
         sbuf->size = htoll(ret);
         if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){
-	        err = -1;
+            err = -1;
             break;
         }
         total_bytes += ret;
@@ -259,7 +259,7 @@
         memcpy(sbuf->data, &file_buffer[total], count);
         sbuf->size = htoll(count);
         if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){
-	        err = -1;
+            err = -1;
             break;
         }
         total += count;
@@ -277,7 +277,7 @@
     len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
     if(len < 0) {
         fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
-	return -1;
+        return -1;
     }
     sbuf->data[len] = '\0';
 
@@ -377,10 +377,10 @@
     }
 
     if (file_buffer) {
-	    write_data_buffer(fd, file_buffer, size, sbuf);
-	    free(file_buffer);
+        write_data_buffer(fd, file_buffer, size, sbuf);
+        free(file_buffer);
     } else if (S_ISREG(mode))
-    	write_data_file(fd, lpath, sbuf);
+        write_data_file(fd, lpath, sbuf);
 #ifdef HAVE_SYMLINKS
     else if (S_ISLNK(mode))
         write_data_link(fd, lpath, sbuf);
@@ -641,7 +641,7 @@
         } else {
             ci = mkcopyinfo(lpath, rpath, name, 0);
             if(lstat(ci->src, &st)) {
-            	closedir(d);
+                closedir(d);
                 fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
                 return -1;
             }
@@ -651,7 +651,7 @@
             } else {
                 ci->time = st.st_mtime;
                 ci->mode = st.st_mode;
-		ci->size = st.st_size;
+                ci->size = st.st_size;
                 ci->next = *filelist;
                 *filelist = ci;
             }
@@ -707,12 +707,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;
-	    }
+            }
         }
     }
     for(ci = filelist; ci != 0; ci = next) {
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index 21f8af7..a231e93 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -164,12 +164,12 @@
     }
     if(fd < 0) {
         if(fail_errno(s))
-	    return -1;
+            return -1;
         fd = -1;
     }
 
     for(;;) {
-	unsigned int len;
+        unsigned int len;
 
         if(readx(s, &msg.data, sizeof(msg.data)))
             goto fail;
@@ -264,7 +264,7 @@
             return -1;
     } else {
         fail_message(s, "invalid data message: expected ID_DONE");
-	return -1;
+        return -1;
     }
 
     return 0;
diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c
index 1d2c4b5..0de0dd5 100644
--- a/adb/framebuffer_service.c
+++ b/adb/framebuffer_service.c
@@ -24,6 +24,7 @@
 #include "adb.h"
 
 #include <linux/fb.h>
+#include <sys/ioctl.h>
 #include <sys/mman.h>
 
 /* TODO:
@@ -37,9 +38,9 @@
     int fb;
     void *ptr = MAP_FAILED;
     char x;
-    
+
     unsigned fbinfo[4];
-    
+
     fb = open("/dev/graphics/fb0", O_RDONLY);
     if(fb < 0) goto done;
 
@@ -53,14 +54,14 @@
 
     ptr = mmap(0, fbinfo[1], PROT_READ, MAP_SHARED, fb, 0);
     if(ptr == MAP_FAILED) goto done;
-    
+
     if(writex(fd, fbinfo, sizeof(unsigned) * 4)) goto done;
 
     for(;;) {
         if(readx(fd, &x, 1)) goto done;
         if(writex(fd, ptr, fbinfo[1])) goto done;
     }
-    
+
 done:
     if(ptr != MAP_FAILED) munmap(ptr, fbinfo[1]);
     if(fb >= 0) close(fb);
diff --git a/adb/get_my_path_windows.c b/adb/get_my_path_windows.c
index 64a597d..fc7143c 100644
--- a/adb/get_my_path_windows.c
+++ b/adb/get_my_path_windows.c
@@ -20,12 +20,12 @@
 
 void get_my_path(char exe[PATH_MAX])
 {
-	char*  r;
+    char*  r;
 
-	GetModuleFileName( NULL, exe, PATH_MAX-1 );
-	exe[PATH_MAX-1] = 0;
-	r = strrchr( exe, '\\' );
-	if (r)
-		*r = 0;
+    GetModuleFileName( NULL, exe, PATH_MAX-1 );
+    exe[PATH_MAX-1] = 0;
+    r = strrchr( exe, '\\' );
+    if (r)
+        *r = 0;
 }
 
diff --git a/adb/jdwp_service.c b/adb/jdwp_service.c
index 43dc69e..ae7f12d 100644
--- a/adb/jdwp_service.c
+++ b/adb/jdwp_service.c
@@ -287,7 +287,7 @@
                 if (len <= 0) {
                     if (len < 0 && errno == EINTR)
                         continue;
-		    if (len < 0 && errno == EAGAIN)
+                    if (len < 0 && errno == EAGAIN)
                         return;
                     else {
                         D("terminating JDWP %d connection: %s\n", proc->pid,
@@ -295,7 +295,7 @@
                         break;
                     }
                 }
-		else {
+                else {
                     D( "ignoring unexpected JDWP %d control socket activity (%d bytes)\n",
                        proc->pid, len );
                 }
diff --git a/adb/sockets.c b/adb/sockets.c
index b9c9ae1..9f1b598 100644
--- a/adb/sockets.c
+++ b/adb/sockets.c
@@ -50,6 +50,15 @@
     .prev = &local_socket_list,
 };
 
+/* the the list of currently closing local sockets.
+** these have no peer anymore, but still packets to
+** write to their fd.
+*/
+static asocket local_socket_closing_list = {
+    .next = &local_socket_closing_list,
+    .prev = &local_socket_closing_list,
+};
+
 asocket *find_local_socket(unsigned id)
 {
     asocket *s;
@@ -64,16 +73,22 @@
     return result;
 }
 
+static void
+insert_local_socket(asocket*  s, asocket*  list)
+{
+    s->next       = list;
+    s->prev       = s->next->prev;
+    s->prev->next = s;
+    s->next->prev = s;
+}
+
+
 void install_local_socket(asocket *s)
 {
     adb_mutex_lock(&socket_list_lock);
 
     s->id = local_socket_next_id++;
-
-    s->next = &local_socket_list;
-    s->prev = local_socket_list.prev;
-    s->prev->next = s;
-    s->next->prev = s;
+    insert_local_socket(s, &local_socket_list);
 
     adb_mutex_unlock(&socket_list_lock);
 }
@@ -177,19 +192,11 @@
     adb_mutex_unlock(&socket_list_lock);
 }
 
-static void local_socket_close_locked(asocket *s)
+// be sure to hold the socket list lock when calling this
+static void local_socket_destroy(asocket  *s)
 {
     apacket *p, *n;
 
-    if(s->peer) {
-        s->peer->peer = 0;
-        // tweak to avoid deadlock
-        if (s->peer->close == local_socket_close)
-            local_socket_close_locked(s->peer);
-        else
-            s->peer->close(s->peer);
-    }
-
         /* IMPORTANT: the remove closes the fd
         ** that belongs to this socket
         */
@@ -201,16 +208,94 @@
         n = p->next;
         put_apacket(p);
     }
-
-    D("LS(%d): closed\n", s->id);
     remove_socket(s);
     free(s);
 }
 
+
+static void local_socket_close_locked(asocket *s)
+{
+    if(s->peer) {
+        s->peer->peer = 0;
+        // tweak to avoid deadlock
+        if (s->peer->close == local_socket_close)
+            local_socket_close_locked(s->peer);
+        else
+            s->peer->close(s->peer);
+    }
+
+        /* If we are already closing, or if there are no
+        ** pending packets, destroy immediately
+        */
+    if (s->closing || s->pkt_first == NULL) {
+        int   id = s->id;
+        local_socket_destroy(s);
+        D("LS(%d): closed\n", id);
+        return;
+    }
+
+        /* otherwise, put on the closing list
+        */
+    D("LS(%d): closing\n", s->id);
+    s->closing = 1;
+    fdevent_del(&s->fde, FDE_READ);
+    remove_socket(s);
+    insert_local_socket(s, &local_socket_closing_list);
+}
+
 static void local_socket_event_func(int fd, unsigned ev, void *_s)
 {
     asocket *s = _s;
 
+    /* put the FDE_WRITE processing before the FDE_READ
+    ** in order to simplify the code.
+    */
+    if(ev & FDE_WRITE){
+        apacket *p;
+
+        while((p = s->pkt_first) != 0) {
+            while(p->len > 0) {
+                int r = adb_write(fd, p->ptr, p->len);
+                if(r > 0) {
+                    p->ptr += r;
+                    p->len -= r;
+                    continue;
+                }
+                if(r < 0) {
+                    /* returning here is ok because FDE_READ will
+                    ** be processed in the next iteration loop
+                    */
+                    if(errno == EAGAIN) return;
+                    if(errno == EINTR) continue;
+                }
+                s->close(s);
+                return;
+            }
+
+            if(p->len == 0) {
+                s->pkt_first = p->next;
+                if(s->pkt_first == 0) s->pkt_last = 0;
+                put_apacket(p);
+            }
+        }
+
+            /* if we sent the last packet of a closing socket,
+            ** we can now destroy it.
+            */
+        if (s->closing) {
+            s->close(s);
+            return;
+        }
+
+            /* no more packets queued, so we can ignore
+            ** writable events again and tell our peer
+            ** to resume writing
+            */
+        fdevent_del(&s->fde, FDE_WRITE);
+        s->peer->ready(s->peer);
+    }
+
+
     if(ev & FDE_READ){
         apacket *p = get_apacket();
         unsigned char *x = p->data;
@@ -244,7 +329,12 @@
 
             if(r < 0) {
                     /* error return means they closed us as a side-effect
-                    ** and we must retutn immediately
+                    ** and we must return immediately.
+                    **
+                    ** note that if we still have buffered packets, the
+                    ** socket will be placed on the closing socket list.
+                    ** this handler function will be called again
+                    ** to process FDE_WRITE events.
                     */
                 return;
             }
@@ -261,42 +351,6 @@
         if(is_eof) {
             s->close(s);
         }
-        return;
-    }
-
-    if(ev & FDE_WRITE){
-        apacket *p;
-
-        while((p = s->pkt_first) != 0) {
-            while(p->len > 0) {
-                int r = adb_write(fd, p->ptr, p->len);
-                if(r > 0) {
-                    p->ptr += r;
-                    p->len -= r;
-                    continue;
-                }
-                if(r < 0) {
-                    if(errno == EAGAIN) return;
-                    if(errno == EINTR) continue;
-                }
-                s->close(s);
-                return;
-            }
-
-            if(p->len == 0) {
-                s->pkt_first = p->next;
-                if(s->pkt_first == 0) s->pkt_last = 0;
-                put_apacket(p);
-            }
-        }
-
-            /* no more packets queued, so we can ignore
-            ** writable events again and tell our peer
-            ** to resume writing
-            */
-        fdevent_del(&s->fde, FDE_WRITE);
-        s->peer->ready(s->peer);
-        return;
     }
 
     if(ev & FDE_ERROR){
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index 9d6a596..c2a9a98 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -940,12 +940,12 @@
         /* we can append to region A */
         if (avail > len)
             avail = len;
-         
+
         memcpy( bip->buff + bip->a_end, src, avail );
         src   += avail;
         count += avail;
         len   -= avail;
-     
+
         bip->a_end += avail;
         if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) {
             bip->can_write = 0;
@@ -953,25 +953,25 @@
             goto Exit;
         }
     }
-    
+
     if (len == 0)
         goto Exit;
 
     avail = bip->a_start - bip->b_end;
     assert( avail > 0 );  /* since can_write is TRUE */
-    
+
     if (avail > len)
         avail = len;
-        
+
     memcpy( bip->buff + bip->b_end, src, avail );
     count += avail;
     bip->b_end += avail;
-    
+
     if (bip->b_end == bip->a_start) {
         bip->can_write = 0;
         ResetEvent( bip->evt_write );
     }
-    
+
 Exit:
     assert( count > 0 );
 
@@ -979,7 +979,7 @@
         bip->can_read = 1;
         SetEvent( bip->evt_read );
     }
-  
+
     BIPD(( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n", 
             bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
     LeaveCriticalSection( &bip->lock );
@@ -991,12 +991,12 @@
 bip_buffer_read( BipBuffer  bip, void*  dst, int  len )
 {
     int  avail, count = 0;
-    
+
     if (len <= 0)
         return 0;
-    
+
     BIPD(( "bip_buffer_read: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-    
+
     EnterCriticalSection( &bip->lock );
     while ( !bip->can_read )
     {
@@ -1007,7 +1007,7 @@
 #else    
         int  ret;
         LeaveCriticalSection( &bip->lock );
-        
+
         if (bip->closed) {
             errno = EPIPE;
             return -1;
@@ -1023,30 +1023,30 @@
             return -1;
         }
         EnterCriticalSection( &bip->lock );
-#endif        
+#endif
     }
 
     BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-   
+
     avail = bip->a_end - bip->a_start;
     assert( avail > 0 );  /* since can_read is TRUE */
-    
+
     if (avail > len)
         avail = len;
-    
+
     memcpy( dst, bip->buff + bip->a_start, avail );
     dst   += avail;
     count += avail;
     len   -= avail;
-    
+
     bip->a_start += avail;
     if (bip->a_start < bip->a_end)
         goto Exit;
-    
+
     bip->a_start = 0;
     bip->a_end   = bip->b_end;
     bip->b_end   = 0;
-    
+
     avail = bip->a_end;
     if (avail > 0) {
         if (avail > len)
@@ -1054,13 +1054,13 @@
         memcpy( dst, bip->buff, avail );
         count += avail;
         bip->a_start += avail;
-        
+
         if ( bip->a_start < bip->a_end )
             goto Exit;
-            
+
         bip->a_start = bip->a_end = 0;
     }
-    
+
     bip->can_read = 0;
     ResetEvent( bip->evt_read );
 
@@ -1071,22 +1071,22 @@
         bip->can_write = 1;
         SetEvent( bip->evt_write );
     }
-    
+
     BIPDUMP( (const unsigned char*)dst - count, count );
     BIPD(( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n", 
             bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
     LeaveCriticalSection( &bip->lock );
-    
+
     return count;
 }
- 
+
 typedef struct SocketPairRec_ 
 {
     BipBufferRec  a2b_bip;
     BipBufferRec  b2a_bip;
     FH            a_fd;
     int           used;
-    
+
 } SocketPairRec;
 
 void _fh_socketpair_init( FH  f )
@@ -1103,7 +1103,7 @@
         if ( f == pair->a_fd ) {
             pair->a_fd = NULL;
         }
-        
+
         bip_buffer_close( &pair->b2a_bip );
         bip_buffer_close( &pair->a2b_bip );
 
@@ -1199,7 +1199,7 @@
 
     sv[0] = _fh_to_int(fa);
     sv[1] = _fh_to_int(fb);
-    
+
     pair->a2b_bip.fdin  = sv[0];
     pair->a2b_bip.fdout = sv[1];
     pair->b2a_bip.fdin  = sv[1];
@@ -1303,7 +1303,7 @@
     hook->stop    = NULL;
     hook->check   = NULL;
     hook->peek    = NULL;
-    
+
     return hook;
 }
 
@@ -1324,7 +1324,7 @@
     FH        f   = hook->fh;
     int       fd  = _fh_to_int(f);
     fdevent*  fde = fd_table[ fd - WIN32_FH_BASE ];
-    
+
     if (fde != NULL && fde->fd == fd) {
         if ((fde->state & FDE_PENDING) == 0) {
             fde->state |= FDE_PENDING;
@@ -1365,7 +1365,7 @@
     FH          f = _fh_from_int(fd);
     EventHook  *pnode;
     EventHook   node;
-    
+
     if (f == NULL)  /* invalid arg */ {
         D("event_looper_hook: invalid fd=%d\n", fd);
         return;
@@ -1397,7 +1397,7 @@
     FH          fh    = _fh_from_int(fd);
     EventHook  *pnode = event_looper_find_p( looper, fh );
     EventHook   node  = *pnode;
-    
+
     if (node != NULL) {
         int  events2 = events & node->wanted;
         if ( events2 == 0 ) {
@@ -1424,7 +1424,7 @@
 {
     EventLooper  looper = &win32_looper;
     int          events = fde->state & FDE_EVENTMASK;
-    
+
     if (events != 0)
         event_looper_hook( looper, fde->fd, events );
 }
@@ -1433,7 +1433,7 @@
 {
     EventLooper  looper = &win32_looper;
     int          events = fde->state & FDE_EVENTMASK;
-    
+
     if (events != 0)
         event_looper_unhook( looper, fde->fd, events );
 }
@@ -1462,7 +1462,7 @@
     EventLooper  looper = &win32_looper;
     EventHook    hook;
     int          gotone = 0;
-    
+
     /* if we have at least one ready hook, execute it/them */
     for (hook = looper->hooks; hook; hook = hook->next) {
         hook->ready = 0;
@@ -1479,7 +1479,7 @@
     if (!gotone)
     {
         looper->htab_count = 0;
-            
+
         for (hook = looper->hooks; hook; hook = hook->next) 
         {
             if (hook->start && !hook->start(hook)) {
@@ -1519,7 +1519,7 @@
                 D( "adb_win32: wait failed, error %ld\n", GetLastError() );
             } else {
                 D( "adb_win32: got one (index %d)\n", wait_ret );
-            
+
                 /* according to Cygwin, some objects like consoles wake up on "inappropriate" events
                  * like mouse movements. we need to filter these with the "check" function
                  */
@@ -1561,7 +1561,7 @@
     if(fd < 0) {
         FATAL("bogus negative fd (%d)\n", fde->fd);
     }
-    
+
     if(fd >= fd_table_max) {
         int oldmax = fd_table_max;
         if(fde->fd > 32000) {
@@ -1587,7 +1587,7 @@
 static void fdevent_unregister(fdevent *fde)
 {
     int  fd = fde->fd - WIN32_FH_BASE;
-    
+
     if((fd < 0) || (fd >= fd_table_max)) {
         FATAL("fd out of range (%d)\n", fde->fd);
     }
@@ -1626,9 +1626,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;
@@ -1689,9 +1689,9 @@
 void fdevent_set(fdevent *fde, unsigned events)
 {
     events &= FDE_EVENTMASK;
-    
+
     if((fde->state & FDE_EVENTMASK) == (int)events) return;
-    
+
     if(fde->state & FDE_ACTIVE) {
         fdevent_update(fde, events);
         dump_fde(fde, "update");
@@ -1727,13 +1727,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;
@@ -1793,7 +1793,7 @@
 static void  _event_socket_prepare( EventHook  hook )
 {
     WSANETWORKEVENTS  evts;
-    
+
     /* look if some of the events we want already happened ? */
     if (!WSAEnumNetworkEvents( hook->fh->fh_socket, NULL, &evts ))
         _event_socket_verify( hook, &evts );
@@ -1819,13 +1819,13 @@
     /* create an event which we're going to wait for */
     FH    fh    = hook->fh;
     long  flags = _socket_wanted_to_flags( hook->wanted );
-    
+
     hook->h = fh->event;
     if (hook->h == INVALID_HANDLE_VALUE) {
         D( "_event_socket_start: no event for %s\n", fh->name );
         return 0;
     }
-    
+
     if ( flags != fh->mask ) {
         D( "_event_socket_start: hooking %s for %x (flags %ld)\n", hook->fh->name, hook->wanted, flags );
         if ( WSAEventSelect( fh->fh_socket, hook->h, flags ) ) {
@@ -1850,7 +1850,7 @@
     int               result = 0;
     FH                fh = hook->fh;
     WSANETWORKEVENTS  evts;
-    
+
     if (!WSAEnumNetworkEvents( fh->fh_socket, hook->h, &evts ) ) {
         _event_socket_verify( hook, &evts );
         result = (hook->ready != 0);
@@ -1866,7 +1866,7 @@
 {
     WSANETWORKEVENTS  evts;
     FH                fh = hook->fh;
-    
+
     /* look if some of the events we want already happened ? */
     if (!WSAEnumNetworkEvents( fh->fh_socket, NULL, &evts )) {
         _event_socket_verify( hook, &evts );
@@ -1886,40 +1886,40 @@
     hook->stop    = _event_socket_stop;
     hook->check   = _event_socket_check;
     hook->peek    = _event_socket_peek;
-    
+
     _event_socket_start( hook );
 }
 
 /** SOCKETPAIR EVENT HOOKS
  **/
- 
+
 static void  _event_socketpair_prepare( EventHook  hook )
 {
     FH          fh   = hook->fh;
     SocketPair  pair = fh->fh_pair;
     BipBuffer   rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
     BipBuffer   wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
-   
+
     if (hook->wanted & FDE_READ && rbip->can_read)
         hook->ready |= FDE_READ;
-    
+
     if (hook->wanted & FDE_WRITE && wbip->can_write) 
         hook->ready |= FDE_WRITE;
  }
- 
+
  static int  _event_socketpair_start( EventHook  hook )
  {
     FH          fh   = hook->fh;
     SocketPair  pair = fh->fh_pair;
     BipBuffer   rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
     BipBuffer   wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
-    
+
     if (hook->wanted == FDE_READ)
         hook->h = rbip->evt_read;
-        
+
     else if (hook->wanted == FDE_WRITE)
         hook->h = wbip->evt_write;
-    
+
     else {
         D("_event_socketpair_start: can't handle FDE_READ+FDE_WRITE\n" );
         return 0;
diff --git a/adb/transport_local.c b/adb/transport_local.c
index 0e8b732..be01f29 100644
--- a/adb/transport_local.c
+++ b/adb/transport_local.c
@@ -76,7 +76,7 @@
     }
 
     if(check_data(p)) {
-	D("bad data: terminated (data)\n");
+        D("bad data: terminated (data)\n");
         return -1;
     }
 
@@ -107,15 +107,16 @@
     char buf[64];
     int  fd = -1;
 
-    fd = socket_loopback_client(port, SOCK_STREAM);
 #if ADB_HOST
-    if(fd < 0) {
-        const char *host = getenv("ADBHOST");
-        if(host) {
-            fd = socket_network_client(host, port, SOCK_STREAM);
-        }
+    const char *host = getenv("ADBHOST");
+    if (host) {
+        fd = socket_network_client(host, port, SOCK_STREAM);
     }
 #endif
+    if (fd < 0) {
+        fd = socket_loopback_client(port, SOCK_STREAM);
+    }
+
     if (fd >= 0) {
         D("client: connected on remote on fd %d\n", fd);
         close_on_exec(fd);
diff --git a/adb/transport_usb.c b/adb/transport_usb.c
index 4da7e8b..01c4a7e 100644
--- a/adb/transport_usb.c
+++ b/adb/transport_usb.c
@@ -55,7 +55,7 @@
     }
 
     fix_endians(p);
-    
+
     if(check_header(p)) {
         D("remote usb: check_header failed\n");
         return -1;
@@ -79,9 +79,9 @@
 static int remote_write(apacket *p, atransport *t)
 {
     unsigned size = p->msg.data_length;
-    
+
     fix_endians(p);
-    
+
     if(usb_write(t->usb, &p->msg, sizeof(amessage))) {
         D("remote usb: 1 - write terminated\n");
         return -1;
@@ -91,7 +91,7 @@
         D("remote usb: 2 - write terminated\n");
         return -1;
     }
-        
+
     return 0;
 }
 
@@ -117,7 +117,7 @@
     t->connection_state = CS_OFFLINE;
     t->type = kTransportUsb;
     t->usb = h;
-    
+
 #if ADB_HOST
     HOST = 1;
 #else
@@ -135,7 +135,7 @@
             /* not supported */
         return 0;
     }
-    
+
         /* class:vendor (0xff) subclass:android (0x42) proto:adb (0x01) */
     if(usb_class == 0xff) {
         if((usb_subclass == 0x42) && (usb_protocol == 0x01)) {
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c
index e265a1c..530bd04 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.c
@@ -118,7 +118,7 @@
     h->fd = -1;
     adb_cond_init(&h->notify, 0);
     adb_mutex_init(&h->lock, 0);
-    
+
     // Open the file /dev/android_adb_enable to trigger 
     // the enabling of the adb USB function in the kernel.
     // We never touch this file again - just leave it open
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index 8ea84f9..49e1eef 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -72,13 +72,13 @@
     CFRunLoopSourceRef      runLoopSource;
     SInt32					vendor, product;
     int                     i;
-    
+
     //* To set up asynchronous notifications, create a notification port and
     //* add its run loop event source to the program's run loop
     notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
     runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
     CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
-    
+
     memset(notificationIterators, 0, sizeof(notificationIterators));
 
     //* loop through all supported vendor/product pairs
@@ -86,19 +86,19 @@
         //* Create our matching dictionary to find the Android device
         //* IOServiceAddMatchingNotification consumes the reference, so we do not need to release this
         matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
-    
+
         if (!matchingDict) {
             DBG("ERR: Couldn't create USB matching dictionary.\n");
             return -1;
         }
-    
+
         //* Set up two matching dictionaries, one for each product ID we support.
         //* This will cause the kernel to notify us only if the vendor and product IDs match.
         vendor = kSupportedDevices[i].vid;
         product = kSupportedDevices[i].pid;
-      	CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor));
-      	CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product));
-    
+        CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor));
+        CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product));
+
         //* Now set up two notifications: one to be called when a raw device
         //* is first matched by the I/O Kit and another to be called when the
         //* device is terminated.
@@ -110,7 +110,7 @@
                 AndroidDeviceAdded,
                 NULL,
                 &notificationIterators[i]);
-    
+
         //* Iterate over set of matching devices to access already-present devices
         //* and to arm the notification
         AndroidDeviceAdded(NULL, notificationIterators[i]);
@@ -173,7 +173,7 @@
 
             if (kr == kIOReturnSuccess && req.wLenDone > 0) {
                 int i, count;
-                
+
                 // skip first word, and copy the rest to the serial string, changing shorts to bytes.
                 count = (req.wLenDone - 1) / 2;
                 for (i = 0; i < count; i++)
@@ -401,8 +401,8 @@
     currentRunLoop = 0;
 
     for (i = 0; i < kSupportedDeviceCount; i++) {
-	    IOObjectRelease(notificationIterators[i]);
-	}
+        IOObjectRelease(notificationIterators[i]);
+    }
     IONotificationPortDestroy(notificationPort);
 
     DBG("RunLoopThread done\n");
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index 5b0f11f..7ddaa0c 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -308,11 +308,11 @@
     while (len > 0) {
       int xfer = (len > 4096) ? 4096 : len;
 
-	    ret = AdbReadEndpointSync(handle->adb_read_pipe,
-	                              (void*)data,
-	                              (unsigned long)xfer,
-	                              &read,
-	                              time_out);
+      ret = AdbReadEndpointSync(handle->adb_read_pipe,
+                                  (void*)data,
+                                  (unsigned long)xfer,
+                                  &read,
+                                  time_out);
       errno = GetLastError();
       D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, errno);
       if (ret) {
@@ -475,11 +475,11 @@
     // Lets see if we already have this device in the list
     if (!known_device(interf_name)) {
       // This seems to be a new device. Open it!
-	    handle = do_usb_open(next_interface->device_name);
-	    if (NULL != handle) {
+        handle = do_usb_open(next_interface->device_name);
+        if (NULL != handle) {
         // Lets see if this interface (device) belongs to us
         if (recognized_device(handle)) {
-	        D("adding a new device %s\n", interf_name);
+          D("adding a new device %s\n", interf_name);
           char serial_number[512];
           unsigned long serial_number_len = sizeof(serial_number);
           if (AdbGetSerialNumber(handle->adb_interface,
@@ -488,7 +488,7 @@
                                 true)) {
             // Lets make sure that we don't duplicate this device
             if (register_new_device(handle)) {
-	            register_usb_transport(handle, serial_number);
+              register_usb_transport(handle, serial_number);
             } else {
               D("register_new_device failed for %s\n", interf_name);
               usb_cleanup_handle(handle);
diff --git a/adb/utils.c b/adb/utils.c
new file mode 100644
index 0000000..91518ba
--- /dev/null
+++ b/adb/utils.c
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+#include "utils.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+char*
+buff_addc (char*  buff, char*  buffEnd, int  c)
+{
+    int  avail = buffEnd - buff;
+
+    if (avail <= 0)  /* already in overflow mode */
+        return buff;
+
+    if (avail == 1) {  /* overflowing, the last byte is reserved for zero */
+        buff[0] = 0;
+        return buff + 1;
+    }
+
+    buff[0] = (char) c;  /* add char and terminating zero */
+    buff[1] = 0;
+    return buff + 1;
+}
+
+char*
+buff_adds (char*  buff, char*  buffEnd, const char*  s)
+{
+    int  slen = strlen(s);
+
+    return buff_addb(buff, buffEnd, s, slen);
+}
+
+char*
+buff_addb (char*  buff, char*  buffEnd, const void*  data, int  len)
+{
+    int  avail = (buffEnd - buff);
+
+    if (avail <= 0 || len <= 0)  /* already overflowing */
+        return buff;
+
+    if (len > avail)
+        len = avail;
+
+    memcpy(buff, data, len);
+
+    buff += len;
+
+    /* ensure there is a terminating zero */
+    if (buff >= buffEnd) {  /* overflow */
+        buff[-1] = 0;
+    } else
+        buff[0] = 0;
+
+    return buff;
+}
+
+char*
+buff_add  (char*  buff, char*  buffEnd, const char*  format, ... )
+{
+    int      avail;
+
+    avail = (buffEnd - buff);
+
+    if (avail > 0) {
+        va_list  args;
+        int      nn;
+
+        va_start(args, format);
+        nn = vsnprintf( buff, avail, format, args);
+        va_end(args);
+
+        if (nn < 0) {
+            /* some C libraries return -1 in case of overflow,
+             * but they will also do that if the format spec is
+             * invalid. We assume ADB is not buggy enough to
+             * trigger that last case. */
+            nn = avail;
+        }
+        else if (nn > avail) {
+            nn = avail;
+        }
+
+        buff += nn;
+
+        /* ensure that there is a terminating zero */
+        if (buff >= buffEnd)
+            buff[-1] = 0;
+        else
+            buff[0] = 0;
+    }
+    return buff;
+}
diff --git a/adb/utils.h b/adb/utils.h
new file mode 100644
index 0000000..f70ecd2
--- /dev/null
+++ b/adb/utils.h
@@ -0,0 +1,68 @@
+/*
+ * 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 _ADB_UTILS_H
+#define _ADB_UTILS_H
+
+/* bounded buffer functions */
+
+/* all these functions are used to append data to a bounded buffer.
+ *
+ * after each operation, the buffer is guaranteed to be zero-terminated,
+ * even in the case of an overflow. they all return the new buffer position
+ * which allows one to use them in succession, only checking for overflows
+ * at the end. For example:
+ *
+ *    BUFF_DECL(temp,p,end,1024);
+ *    char*    p;
+ *
+ *    p = buff_addc(temp, end, '"');
+ *    p = buff_adds(temp, end, string);
+ *    p = buff_addc(temp, end, '"');
+ *
+ *    if (p >= end) {
+ *        overflow detected. note that 'temp' is
+ *        zero-terminated for safety. 
+ *    }
+ *    return strdup(temp);
+ */
+
+/* tries to add a character to the buffer, in case of overflow
+ * this will only write a terminating zero and return buffEnd.
+ */
+char*   buff_addc (char*  buff, char*  buffEnd, int  c);
+
+/* tries to add a string to the buffer */
+char*   buff_adds (char*  buff, char*  buffEnd, const char*  s);
+
+/* tries to add a bytes to the buffer. the input can contain zero bytes,
+ * but a terminating zero will always be appended at the end anyway
+ */
+char*   buff_addb (char*  buff, char*  buffEnd, const void*  data, int  len);
+
+/* tries to add a formatted string to a bounded buffer */
+char*   buff_add  (char*  buff, char*  buffEnd, const char*  format, ... );
+
+/* convenience macro used to define a bounded buffer, as well as
+ * a 'cursor' and 'end' variables all in one go.
+ *
+ * note: this doesn't place an initial terminating zero in the buffer,
+ * you need to use one of the buff_ functions for this. or simply
+ * do _cursor[0] = 0 manually.
+ */
+#define  BUFF_DECL(_buff,_cursor,_end,_size)   \
+    char   _buff[_size], *_cursor=_buff, *_end = _cursor + (_size)
+
+#endif /* _ADB_UTILS_H */
diff --git a/cpio/Android.mk b/cpio/Android.mk
index f340fd6..8d01852 100644
--- a/cpio/Android.mk
+++ b/cpio/Android.mk
@@ -10,4 +10,4 @@
 
 include $(BUILD_HOST_EXECUTABLE)
 
-$(call dist-for-goals,user userdebug droid,$(LOCAL_BUILT_MODULE))
+$(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 03046bd..b22e1a8 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -1,5 +1,7 @@
 # Copyright 2005 The Android Open Source Project
 
+ifeq ($(TARGET_ARCH),arm)
+
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -20,3 +22,5 @@
 #LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_SHARED_LIBRARIES := libcutils libc
 include $(BUILD_EXECUTABLE)
+
+endif # TARGET_ARCH == arm
diff --git a/debuggerd/unwind-arm.c b/debuggerd/unwind-arm.c
index fdc0a6a..9642d2e 100644
--- a/debuggerd/unwind-arm.c
+++ b/debuggerd/unwind-arm.c
@@ -381,13 +381,15 @@
 }
 
 /* Print out the current call level, pc, and module name in the crash log */
-static _Unwind_Reason_Code log_function(_Unwind_Context *context, int tfd,
+static _Unwind_Reason_Code log_function(_Unwind_Context *context, pid_t pid, 
+                                        int tfd,
                                         int stack_level,
                                         mapinfo *map,
                                         unsigned int sp_list[],
                                         bool at_fault)
 {
     _uw pc;
+    _uw rel_pc; 
     phase2_vrs *vrs = (phase2_vrs*) context;
     const mapinfo *mi;
     bool only_in_tombstone = !at_fault;
@@ -404,19 +406,53 @@
     // For deeper framers, rollback pc by one instruction
     else {
         pc = vrs->core.r[R_PC];
-        // Thumb mode
+        /* Thumb mode - need to check whether the bl(x) has long offset or not.
+         * Examples:
+         *
+         * arm blx in the middle of thumb:
+         * 187ae:       2300            movs    r3, #0
+         * 187b0:       f7fe ee1c       blx     173ec
+         * 187b4:       2c00            cmp     r4, #0
+         *
+         * arm bl in the middle of thumb:
+         * 187d8:       1c20            adds    r0, r4, #0
+         * 187da:       f136 fd15       bl      14f208
+         * 187de:       2800            cmp     r0, #0
+         *
+         * pure thumb:
+         * 18894:       189b            adds    r3, r3, r2
+         * 18896:       4798            blx     r3
+         * 18898:       b001            add     sp, #4
+         */
         if (pc & 1) {
-            pc = (pc & ~1) - 2;
+            _uw prev_word;
+            pc = (pc & ~1);
+            prev_word = get_remote_word(pid, (void *) pc-4);
+            // Long offset 
+            if ((prev_word & 0xf0000000) == 0xf0000000 && 
+                (prev_word & 0x0000e000) == 0x0000e000) {
+                pc -= 4;
+            }
+            else {
+                pc -= 2;
+            }
         }
         else { 
             pc -= 4;
         }
     }
 
-    mi = pc_to_mapinfo(map, pc);
+    /* We used to print the absolute PC in the back trace, and mask out the top
+     * 3 bits to guesstimate the offset in the .so file. This is not working for
+     * non-prelinked libraries since the starting offset may not be aligned on 
+     * 1MB boundaries, and the library may be larger than 1MB. So for .so 
+     * addresses we print the relative offset in back trace.
+     */
+    rel_pc = pc;
+    mi = pc_to_mapinfo(map, pc, &rel_pc);
 
     _LOG(tfd, only_in_tombstone, 
-         "         #%02d  pc %08x  %s\n", stack_level, pc, 
+         "         #%02d  pc %08x  %s\n", stack_level, rel_pc, 
          mi ? mi->name : "");
 
     return _URC_NO_REASON;
@@ -459,7 +495,7 @@
      */
     if (get_eitp(saved_vrs.core.r[R_PC], pid, map, NULL) == NULL) { 
         *frame0_pc_sane = 0;
-        log_function ((_Unwind_Context *) &saved_vrs, tfd, stack_level, 
+        log_function ((_Unwind_Context *) &saved_vrs, pid, tfd, stack_level, 
                       map, sp_list, at_fault);
         saved_vrs.core.r[R_PC] = saved_vrs.core.r[R_LR];
         stack_level++;
@@ -493,7 +529,7 @@
         _Unwind_SetGR((_Unwind_Context *)&saved_vrs, 12, (_Unwind_Ptr) ucbp);
 
         /* Call log function.  */
-        if (log_function ((_Unwind_Context *) &saved_vrs, tfd, stack_level, 
+        if (log_function ((_Unwind_Context *) &saved_vrs, pid, tfd, stack_level,
                           map, sp_list, at_fault) != _URC_NO_REASON) {
             code = _URC_FAILURE;
             break;
diff --git a/debuggerd/utility.c b/debuggerd/utility.c
index 0cb790f..8f3931c 100644
--- a/debuggerd/utility.c
+++ b/debuggerd/utility.c
@@ -18,6 +18,7 @@
 #include <sys/ptrace.h>
 #include <sys/exec_elf.h>
 #include <assert.h>
+#include <string.h>
 #include <errno.h>
 
 #include "utility.h"
@@ -66,10 +67,14 @@
 }
 
 /* Find the containing map info for the pc */
-const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc)
+const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc)
 {
     while(mi) {
         if((pc >= mi->start) && (pc < mi->end)){
+            // Only calculate the relative offset for shared libraries
+            if (strstr(mi->name, ".so")) {
+                *rel_pc = pc - mi->start;
+            }
             return mi;
         }
         mi = mi->next;
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 802e3ad..49f5951 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -45,7 +45,7 @@
 extern void get_remote_struct(int pid, void *src, void *dst, size_t size);
 
 /* Find the containing map for the pc */
-const mapinfo *pc_to_mapinfo (mapinfo *mi, unsigned pc);
+const mapinfo *pc_to_mapinfo (mapinfo *mi, unsigned pc, unsigned *rel_pc);
 
 /* Map a pc address to the name of the containing ELF file */
 const char *map_to_name(mapinfo *mi, unsigned pc, const char* def);
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 5e9941d..7a9d35f 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -43,7 +43,7 @@
 LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz
 
 include $(BUILD_HOST_EXECUTABLE)
-$(call dist-for-goals,user userdebug droid,$(LOCAL_BUILT_MODULE))
+$(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
 
 ifeq ($(HOST_OS),linux)
 include $(CLEAR_VARS)
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 64a4045..4079a38 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -47,6 +47,7 @@
 static const char *product = 0;
 static const char *cmdline = 0;
 static int wipe_data = 0;
+static unsigned short vendor_id = 0;
 
 void die(const char *fmt, ...)
 {
@@ -135,7 +136,8 @@
 
 int match_fastboot(usb_ifc_info *info)
 {
-    if((info->dev_vendor != 0x18d1) &&
+    if(!(vendor_id && (info->dev_vendor == vendor_id)) &&
+       (info->dev_vendor != 0x18d1) &&
        (info->dev_vendor != 0x0bb4)) return -1;
     if(info->ifc_class != 0xff) return -1;
     if(info->ifc_subclass != 0x42) return -1;
@@ -208,6 +210,7 @@
             "  -s <serial number>                       specify device serial number\n"
             "  -p <product>                             specify product name\n"
             "  -c <cmdline>                             override kernel commandline\n"
+            "  -i <vendor id>                           specify a custom USB vendor id\n"
         );
     exit(1);
 }
@@ -553,6 +556,16 @@
             require(2);
             cmdline = argv[1];
             skip(2);
+        } else if(!strcmp(*argv, "-i")) {
+            char *endptr = NULL;
+            unsigned long val;
+
+            require(2);
+            val = strtoul(argv[1], &endptr, 0);
+            if (!endptr || *endptr != '\0' || (val & ~0xffff))
+                die("invalid vendor id '%s'", argv[1]);
+            vendor_id = (unsigned short)val;
+            skip(2);
         } else if(!strcmp(*argv, "getvar")) {
             require(2);
             fb_queue_display(argv[1], argv[1]);
diff --git a/include/arch/linux-arm/AndroidConfig.h b/include/arch/linux-arm/AndroidConfig.h
index d7e182a..b2dabf2 100644
--- a/include/arch/linux-arm/AndroidConfig.h
+++ b/include/arch/linux-arm/AndroidConfig.h
@@ -48,6 +48,12 @@
 #define HAVE_FUTEX
 
 /*
+ * Define if we already have the futex wrapper functions defined. Yes if
+ * compiling against bionic.
+ */
+#define HAVE_FUTEX_WRAPPERS 1
+
+/*
  * Process creation model.  Choose one:
  *
  * HAVE_FORKEXEC - use fork() and exec()
diff --git a/include/arch/target_linux-x86/AndroidConfig.h b/include/arch/target_linux-x86/AndroidConfig.h
new file mode 100644
index 0000000..4aa44f8
--- /dev/null
+++ b/include/arch/target_linux-x86/AndroidConfig.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2005 The Android Open Source Project
+ *
+ * Android config -- "target_linux-x86".  Used for x86 linux target devices.
+ */
+#ifndef _ANDROID_CONFIG_H
+#define _ANDROID_CONFIG_H
+
+/*
+ * ===========================================================================
+ *                              !!! IMPORTANT !!!
+ * ===========================================================================
+ *
+ * This file is included by ALL C/C++ source files.  Don't put anything in
+ * here unless you are absolutely certain it can't go anywhere else.
+ *
+ * Any C++ stuff must be wrapped with "#ifdef __cplusplus".  Do not use "//"
+ * comments.
+ */
+
+/*
+ * Threading model.  Choose one:
+ *
+ * HAVE_PTHREADS - use the pthreads library.
+ * HAVE_WIN32_THREADS - use Win32 thread primitives.
+ *  -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
+ */
+#define HAVE_PTHREADS
+
+/*
+ * Do we have the futex syscall?
+ */
+
+#define HAVE_FUTEX
+
+/*
+ * Define if we already have the futex wrapper functions defined. Yes if
+ * compiling against bionic.
+ */
+#define HAVE_FUTEX_WRAPPERS 1
+
+/*
+ * Process creation model.  Choose one:
+ *
+ * HAVE_FORKEXEC - use fork() and exec()
+ * HAVE_WIN32_PROC - use CreateProcess()
+ */
+#define HAVE_FORKEXEC
+
+/*
+ * Process out-of-memory adjustment.  Set if running on Linux,
+ * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
+ * badness adjustment.
+ */
+#define HAVE_OOM_ADJ
+
+/*
+ * IPC model.  Choose one:
+ *
+ * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
+ * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
+ * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
+ * HAVE_ANDROID_IPC - use Android versions (?, mmap).
+ */
+#define HAVE_ANDROID_IPC 1
+
+/*
+ * Memory-mapping model. Choose one:
+ *
+ * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
+ * HAVE_WIN32_FILEMAP - use Win32 filemaps
+ */
+#define  HAVE_POSIX_FILEMAP 1
+
+/*
+ * Define this if you have <termio.h>
+ */
+#define  HAVE_TERMIO_H 1
+
+/*
+ * Define this if you build against have Microsoft C runtime (MSVCRT.DLL)
+ */
+/* #define HAVE_MS_C_RUNTIME */
+
+/*
+ * Define this if you have sys/uio.h
+ */
+#define  HAVE_SYS_UIO_H 1
+
+/*
+ * Define this if your platforms implements symbolic links
+ * in its filesystems
+ */
+#define HAVE_SYMLINKS 1
+
+/*
+ * Define this if we have localtime_r().
+ */
+/* #define HAVE_LOCALTIME_R */
+
+/*
+ * Define this if we have gethostbyname_r().
+ */
+/* #define HAVE_GETHOSTBYNAME_R */
+
+/*
+ * Define this if we have ioctl().
+ */
+#define HAVE_IOCTL
+
+/*
+ * Define this if we want to use WinSock.
+ */
+/* #define HAVE_WINSOCK */
+
+/*
+ * Define this if have clock_gettime() and friends
+ *
+ */
+#define HAVE_POSIX_CLOCKS
+
+/*
+ * Define this if we have pthread_cond_timedwait_monotonic() and
+ * clock_gettime(CLOCK_MONOTONIC).
+ */
+#define HAVE_TIMEDWAIT_MONOTONIC
+
+/*
+ * Define this if we have linux style epoll()
+ */
+#define HAVE_EPOLL
+
+/*
+ * Endianness of the target machine.  Choose one:
+ *
+ * HAVE_ENDIAN_H -- have endian.h header we can include.
+ * HAVE_LITTLE_ENDIAN -- we are little endian.
+ * HAVE_BIG_ENDIAN -- we are big endian.
+ */
+#define HAVE_ENDIAN_H
+#define HAVE_LITTLE_ENDIAN
+
+/*
+ * We need to choose between 32-bit and 64-bit off_t.  All of our code should
+ * agree on the same size.  For desktop systems, use 64-bit values,
+ * because some of our libraries (e.g. wxWidgets) expect to be built that way.
+ */
+/*
+ * #define _FILE_OFFSET_BITS 64
+ * #define _LARGEFILE_SOURCE 1
+ */
+
+/*
+ * Defined if we have the backtrace() call for retrieving a stack trace.
+ * Needed for CallStack to operate; if not defined, CallStack is
+ * non-functional.
+ */
+#define HAVE_BACKTRACE 0
+
+/*
+ * Defined if we have the dladdr() call for retrieving the symbol associated
+ * with a memory address.  If not defined, stack crawls will not have symbolic
+ * information.
+ */
+#define HAVE_DLADDR 0
+
+/*
+ * Defined if we have the cxxabi.h header for demangling C++ symbols.  If
+ * not defined, stack crawls will be displayed with raw mangled symbols
+ */
+#define HAVE_CXXABI 0
+
+/*
+ * Defined if we have the gettid() system call.
+ */
+#define HAVE_GETTID
+
+/* 
+ * Defined if we have the sched_setscheduler() call
+ */
+#define HAVE_SCHED_SETSCHEDULER
+
+/*
+ * Add any extra platform-specific defines here.
+ */
+#ifndef __linux__
+#define __linux__
+#endif
+
+/*
+ * Define if we have <malloc.h> header
+ */
+#define HAVE_MALLOC_H
+
+/* 
+ * Define if we're running on *our* linux on device or emulator.
+ */
+#define HAVE_ANDROID_OS 1
+
+/*
+ * Define if we have Linux-style non-filesystem Unix Domain Sockets
+ */
+#define HAVE_LINUX_LOCAL_SOCKET_NAMESPACE 1
+
+/*
+ * Define if we have Linux's inotify in <sys/inotify.h>.
+ */
+#define HAVE_INOTIFY 1
+
+/*
+ * Define if we have madvise() in <sys/mman.h>
+ */
+#define HAVE_MADVISE 1
+
+/*
+ * Define if we have Linux's dbus 
+ */
+#define HAVE_DBUS 1
+
+/*
+ * Define if tm struct has tm_gmtoff field
+ */
+#define HAVE_TM_GMTOFF 1
+
+/*
+ * Define if dirent struct has d_type field
+ */
+#define HAVE_DIRENT_D_TYPE 1
+
+/*
+ * Define if libc includes Android system properties implementation.
+ */
+#define HAVE_LIBC_SYSTEM_PROPERTIES 1
+
+/*
+ * Define if system provides a system property server (should be
+ * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
+ */
+/* #define HAVE_SYSTEM_PROPERTY_SERVER */
+
+/*
+ * What CPU architecture does this platform use?
+ */
+#define ARCH_X86
+
+/*
+ * sprintf() format string for shared library naming.
+ */
+#define OS_SHARED_LIB_FORMAT_STR    "lib%s.so"
+
+/*
+ * Do we have __memcmp16()?
+ */
+/* #define HAVE__MEMCMP16  1 */
+
+/*
+ * type for the third argument to mincore().
+ */
+#define MINCORE_POINTER_TYPE unsigned char *
+
+/*
+ * Do we have the sigaction flag SA_NOCLDWAIT?
+ */
+#define HAVE_SA_NOCLDWAIT
+
+/*
+ * The default path separator for the platform
+ */
+#define OS_PATH_SEPARATOR '/'
+
+/*
+ * Is the filesystem case sensitive?
+ */
+#define OS_CASE_SENSITIVE
+
+/*
+ * Define if <sys/socket.h> exists.
+ */
+#define HAVE_SYS_SOCKET_H 1
+
+/*
+ * Define if the strlcpy() function exists on the system.
+ */
+#define HAVE_STRLCPY 1
+
+/*
+ * Define if prctl() exists
+ */
+#define HAVE_PRCTL 1
+
+/*
+ * Whether or not _Unwind_Context is defined as a struct.
+ */
+#define HAVE_UNWIND_CONTEXT_STRUCT
+
+#endif /* _ANDROID_CONFIG_H */
diff --git a/include/cutils/tztime.h b/include/cutils/tztime.h
index 59c0670..9b3ece8 100644
--- a/include/cutils/tztime.h
+++ b/include/cutils/tztime.h
@@ -24,6 +24,21 @@
 time_t mktime_tz(struct tm * const tmp, char const * tz);
 void localtime_tz(const time_t * const timep, struct tm * tmp, const char* tz);
 
+struct strftime_locale {
+    const char *mon[12];    /* short names */
+    const char *month[12];  /* long names */
+    const char *wday[7];    /* short names */
+    const char *weekday[7]; /* long names */
+    const char *X_fmt;
+    const char *x_fmt;
+    const char *c_fmt;
+    const char *am;
+    const char *pm;
+    const char *date_fmt;
+};
+
+size_t strftime_tz(char *s, size_t max, const char *format, const struct tm *tm, const struct strftime_locale *locale);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/pixelflinger/format.h b/include/pixelflinger/format.h
index ad0d29d..308e560 100644
--- a/include/pixelflinger/format.h
+++ b/include/pixelflinger/format.h
@@ -30,6 +30,7 @@
     GGL_PIXEL_FORMAT_RGBX_8888   =   2,  // 3x8-bit RGB stored in 32-bit chunks
     GGL_PIXEL_FORMAT_RGB_888     =   3,  // 3x8-bit RGB
     GGL_PIXEL_FORMAT_RGB_565     =   4,  // 16-bit RGB
+    GGL_PIXEL_FORMAT_BGRA_8888   =   5,  // 4x8-bit BGRA
     GGL_PIXEL_FORMAT_RGBA_5551   =   6,  // 16-bit RGBA
     GGL_PIXEL_FORMAT_RGBA_4444   =   7,  // 16-bit RGBA
 
@@ -38,9 +39,11 @@
     GGL_PIXEL_FORMAT_LA_88       = 0xA,  // 16-bit LA
     GGL_PIXEL_FORMAT_RGB_332     = 0xB,  // 8-bit RGB (non paletted)
 
-    // YCbCr formats
+    // YCbCr formats (SP=semi-planar, P=planar)
     GGL_PIXEL_FORMAT_YCbCr_422_SP= 0x10,
     GGL_PIXEL_FORMAT_YCbCr_420_SP= 0x11,
+    GGL_PIXEL_FORMAT_YCbCr_422_P = 0x14,
+    GGL_PIXEL_FORMAT_YCbCr_420_P = 0x15,
 
     // reserved/special formats
     GGL_PIXEL_FORMAT_Z_16       =  0x18,
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 13e134b..c855187 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -150,8 +150,10 @@
     { 00550, AID_ROOT,      AID_SHELL,     "system/etc/init.testmenu" },
     { 00550, AID_ROOT,      AID_SHELL,     "system/etc/init.gprs-pppd" },
     { 00550, AID_DHCP,      AID_SHELL,     "system/etc/dhcpcd/dhcpcd-run-hooks" },
-    { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/hcid.conf" },
     { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/dbus.conf" },
+    { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/hcid.conf" },
+    { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/input.conf" },
+    { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/audio.conf" },
     { 00440, AID_RADIO,     AID_AUDIO,     "/system/etc/AudioPara4.csv" },
     { 00644, AID_SYSTEM,    AID_SYSTEM,    "data/app/*" },
     { 00644, AID_SYSTEM,    AID_SYSTEM,    "data/app-private/*" },
diff --git a/include/private/pixelflinger/ggl_context.h b/include/private/pixelflinger/ggl_context.h
index 241a0ab..3a030c5 100644
--- a/include/private/pixelflinger/ggl_context.h
+++ b/include/private/pixelflinger/ggl_context.h
@@ -147,11 +147,11 @@
 GGL_RESERVE_NEEDS( P_RESERVED1,    10,22 )
 
 GGL_RESERVE_NEEDS( T_FORMAT,        0, 6 )
-GGL_RESERVE_NEEDS( T_RESERVED0,     6, 2 )
+GGL_RESERVE_NEEDS( T_RESERVED0,     6, 1 )
+GGL_RESERVE_NEEDS( T_POT,           7, 1 )
 GGL_RESERVE_NEEDS( T_S_WRAP,        8, 2 )
 GGL_RESERVE_NEEDS( T_T_WRAP,       10, 2 )
-GGL_RESERVE_NEEDS( T_ENV,          12, 2 )
-GGL_RESERVE_NEEDS( T_POT,          14, 1 )
+GGL_RESERVE_NEEDS( T_ENV,          12, 3 )
 GGL_RESERVE_NEEDS( T_LINEAR,       15, 1 )
 
 const int GGL_NEEDS_WRAP_CLAMP_TO_EDGE  = 0;
@@ -182,12 +182,14 @@
     case GGL_MODULATE:  return 1;
     case GGL_DECAL:     return 2;
     case GGL_BLEND:     return 3;
+    case GGL_ADD:       return 4;
     }
     return 0;
 }
 
 inline uint32_t ggl_needs_to_env(uint32_t n) {
-    const uint32_t envs[] = { GGL_REPLACE, GGL_MODULATE, GGL_DECAL, GGL_BLEND };
+    const uint32_t envs[] = { GGL_REPLACE, GGL_MODULATE, 
+            GGL_DECAL, GGL_BLEND, GGL_ADD };
     return envs[n];
 
 }
diff --git a/init/README.BOOTCHART b/init/README.BOOTCHART
index 4899369..70cf2c3 100644
--- a/init/README.BOOTCHART
+++ b/init/README.BOOTCHART
@@ -1,32 +1,50 @@
-this version of init contains code to perform "bootcharting", i.e. generating log
+This version of init contains code to perform "bootcharting", i.e. generating log
 files that can be later processed by the tools provided by www.bootchart.org.
 
-to activate it, you need to define build 'init' with the INIT_BOOTCHART environment
-variable defined to 'true', then create a file on the /data partition with a command
-like the following:
+To activate it, you need to define build 'init' with the INIT_BOOTCHART environment
+variable defined to 'true', for example:
 
-  adb shell 'echo 1 > /data/bootchart'
+    touch system/init/init.c
+    m INIT_BOOTCHART=true
 
-if the '/data/bootchart' file doesn't exist, or doesn't contain a '1' in its first
-byte, init will proceed normally.
+On the emulator, use the new -bootchart <timeout> option to boot with bootcharting
+activated for <timeout> seconds.
 
-by default, the bootchart log stops after 2 minutes, but you can stop it earlier
-with the following command while the device is booting:
+Otherwise, flash your device, and start it. Then create a file on the /data partition
+with a command like the following:
+
+  adb shell 'echo $TIMEOUT > /data/bootchart-start'
+
+Where the value of $TIMEOUT corresponds to the wanted bootcharted period in seconds;
+for example, to bootchart for 2 minutes, do:
+
+  adb shell 'echo 120 > /data/bootchart-start'
+
+Reboot your device, bootcharting will begin and stop after the period you gave.
+You can also stop the bootcharting at any moment by doing the following:
 
   adb shell 'echo 1 > /data/bootchart-stop'
 
-note that /data/bootchart-stop is deleted automatically by init at the end of the
-bootcharting. this is not the case of /data/bootchart, so don't forget to delete it
+Note that /data/bootchart-stop is deleted automatically by init at the end of the
+bootcharting. This is not the case of /data/bootchart-start, so don't forget to delete it
 when you're done collecting data:
 
-  adb shell rm /data/bootchart
+  adb shell rm /data/bootchart-start
 
-the log files are placed in /tmp/bootchart/. you must run the script tools/grab-bootchart.sh
+The log files are placed in /data/bootchart/. you must run the script tools/grab-bootchart.sh
 which will use ADB to retrieve them and create a bootchart.tgz file that can be used with
 the bootchart parser/renderer, or even uploaded directly to the form located at:
 
   http://www.bootchart.org/download.html
 
+NOTE: the bootchart.org webform doesn't seem to work at the moment, you can generate an
+      image on your machine by doing the following:
+
+         1/ download the sources from www.bootchart.org
+         2/ unpack them
+         3/ in the source directory, type 'ant' to build the bootchart program
+         4/ type 'java -jar bootchart.jar /path/to/bootchart.tgz
+
 technical note:
 
 this implementation of bootcharting does use the 'bootchartd' script provided by
diff --git a/init/bootchart.c b/init/bootchart.c
index 2afe98b..f72fcaa 100644
--- a/init/bootchart.c
+++ b/init/bootchart.c
@@ -1,3 +1,19 @@
+/*
+ * 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.
+ */
+
 /* this code is used to generate a boot sequence profile that can be used
  * with the 'bootchart' graphics generation tool. see www.bootchart.org
  * note that unlike the original bootchartd, this is not a Bash script but
@@ -16,17 +32,18 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <sys/stat.h>
+#include "bootchart.h"
 
 #define VERSION         "0.8"
 #define SAMPLE_PERIOD   0.2
-#define LOG_ROOT        "/tmp/bootchart"
+#define LOG_ROOT        "/data/bootchart"
 #define LOG_STAT        LOG_ROOT"/proc_stat.log"
 #define LOG_PROCS       LOG_ROOT"/proc_ps.log"
 #define LOG_DISK        LOG_ROOT"/proc_diskstats.log"
 #define LOG_HEADER      LOG_ROOT"/header"
 #define LOG_ACCT        LOG_ROOT"/kernel_pacct"
 
-#define LOG_STARTFILE   "/data/bootchart"
+#define LOG_STARTFILE   "/data/bootchart-start"
 #define LOG_STOPFILE    "/data/bootchart-stop"
 
 static int
@@ -54,12 +71,11 @@
         len = unix_read(fd, buff, buffsize-1);
         close(fd);
     }
-    buff[len] = 0;
+    buff[len > 0 ? len : 0] = 0;
     return len;
 }
 
 #define FILE_BUFF_SIZE    65536
-#define FILE_BUFF_RESERVE (FILE_BUFF_SIZE - 4096)
 
 typedef struct {
     int   count;
@@ -81,7 +97,7 @@
         int  avail = sizeof(buff->data) - buff->count;
         if (avail > len)
             avail = len;
-        
+
         memcpy( buff->data + buff->count, src, avail );
         len -= avail;
         src  = (char*)src + avail;
@@ -115,7 +131,7 @@
     time_t     now_t = time(NULL);
     struct tm  now = *localtime(&now_t);
     strftime(date, sizeof(date), "%x %X", &now);
-    
+
     out = fopen( LOG_HEADER, "w" );
     if (out == NULL)
         return;
@@ -123,7 +139,7 @@
     proc_read("/proc/cmdline", cmdline, sizeof(cmdline));
     proc_read("/proc/version", uname, sizeof(uname));
     proc_read("/proc/cpuinfo", cpuinfo, sizeof(cpuinfo));
-   
+
     cpu = strchr( cpuinfo, ':' );
     if (cpu) {
         char*  p = strchr(cpu, '\n');
@@ -131,7 +147,7 @@
         if (p)
             *p = 0;
     }
-   
+
     fprintf(out, "version = %s\n", VERSION);
     fprintf(out, "title = Boot chart for Android ( %s )\n", date);
     fprintf(out, "system.uname = %s\n", uname);
@@ -174,7 +190,6 @@
     fd = open("/proc/uptime",O_RDONLY);
     if (fd >= 0) {
         int  ret;
-        close_on_exec(fd);
         ret = unix_read(fd, buff, 64);
         close(fd);
         buff[64] = 0;
@@ -212,7 +227,7 @@
             ret = unix_read(fd, buff, sizeof(buff));
             if (ret <= 0)
                 break;
-                
+
             file_buff_write(log, buff, ret);
             if (ret < (int)sizeof(buff))
                 break;
@@ -230,7 +245,7 @@
     struct dirent*  entry;
 
     do_log_uptime(log);
-    
+
     while ((entry = readdir(dir)) != NULL) {
         /* only match numeric values */
         char*  end;
@@ -241,7 +256,7 @@
             char  cmdline[1024];
             int   len;
             int   fd;
-            
+
             /* read command line and extract program name */
             snprintf(filename,sizeof(filename),"/proc/%d/cmdline",pid);
             proc_read(filename, cmdline, sizeof(cmdline));
@@ -285,11 +300,36 @@
 {
     int  ret;
     char buff[4];
-    
+    int  timeout = 0, count = 0;
+
     buff[0] = 0;
     proc_read( LOG_STARTFILE, buff, sizeof(buff) );
-    if (buff[0] != '1')
-        return -1;
+    if (buff[0] != 0) {
+        timeout = atoi(buff);
+    }
+    else {
+        /* when running with emulator, androidboot.bootchart=<timeout>
+         * might be passed by as kernel parameters to specify the bootchart
+         * timeout. this is useful when using -wipe-data since the /data
+         * partition is fresh
+         */
+        char  cmdline[1024];
+        char* s;
+#define  KERNEL_OPTION  "androidboot.bootchart="
+        proc_read( "/proc/cmdline", cmdline, sizeof(cmdline) );
+        s = strstr(cmdline, KERNEL_OPTION);
+        if (s) {
+            s      += sizeof(KERNEL_OPTION)-1;
+            timeout = atoi(s);
+        }
+    }
+    if (timeout == 0)
+        return 0;
+
+    if (timeout > BOOTCHART_MAX_TIME_SEC)
+        timeout = BOOTCHART_MAX_TIME_SEC;
+
+    count = (timeout*1000 + BOOTCHART_POLLING_MS-1)/BOOTCHART_POLLING_MS;
 
     do {ret=mkdir(LOG_ROOT,0755);}while (ret < 0 && errno == EINTR);
 
@@ -307,7 +347,7 @@
     }
 
     log_header();
-    return 0;
+    return count;
 }
 
 /* called each time you want to perform a bootchart sampling op */
@@ -324,6 +364,7 @@
             return -1;
         }
     }
+
     return 0;
 }
 
diff --git a/init/bootchart.h b/init/bootchart.h
new file mode 100644
index 0000000..39d2d4f
--- /dev/null
+++ b/init/bootchart.h
@@ -0,0 +1,36 @@
+/*
+ * 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 _BOOTCHART_H
+#define _BOOTCHART_H
+
+#ifndef BOOTCHART
+# define  BOOTCHART  0
+#endif
+
+#if BOOTCHART
+
+extern int   bootchart_init(void);
+extern int   bootchart_step(void);
+extern void  bootchart_finish(void);
+
+# define BOOTCHART_POLLING_MS   200   /* polling period in ms */
+# define BOOTCHART_DEFAULT_TIME_SEC    (2*60)  /* default polling time in seconds */
+# define BOOTCHART_MAX_TIME_SEC        (10*60) /* max polling time in seconds */
+
+#endif /* BOOTCHART */
+
+#endif /* _BOOTCHART_H */
diff --git a/init/builtins.c b/init/builtins.c
index ba34410..95fb223 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -64,7 +64,7 @@
     }
 }
 
-static int insmod(const char *filename)
+static int insmod(const char *filename, char *options)
 {
     void *module;
     unsigned size;
@@ -74,7 +74,7 @@
     if (!module)
         return -1;
 
-    ret = init_module(module, size, "");
+    ret = init_module(module, size, options);
 
     free(module);
 
@@ -172,9 +172,35 @@
     return __ifupdown(args[1], 1);
 }
 
+
+static int do_insmod_inner(int nargs, char **args, int opt_len)
+{
+    char options[opt_len + 1];
+    int i;
+
+    options[0] = '\0';
+    if (nargs > 2) {
+        strcpy(options, args[2]);
+        for (i = 3; i < nargs; ++i) {
+            strcat(options, " ");
+            strcat(options, args[i]);
+        }
+    }
+
+    return insmod(args[1], options);
+}
+
 int do_insmod(int nargs, char **args)
 {
-    return insmod(args[1]);
+    int i;
+    int size = 0;
+
+    if (nargs > 2) {
+        for (i = 2; i < nargs; ++i)
+            size += strlen(args[i]) + 1;
+    }
+
+    return do_insmod_inner(nargs, args, size);
 }
 
 int do_import(int nargs, char **args)
@@ -326,6 +352,20 @@
     return symlink(args[1], args[2]);
 }
 
+int do_sysclktz(int nargs, char **args)
+{
+    struct timezone tz;
+
+    if (nargs != 2)
+        return -1;
+
+    memset(&tz, 0, sizeof(tz));
+    tz.tz_minuteswest = atoi(args[1]);   
+    if (settimeofday(NULL, &tz))
+        return -1;
+    return 0;
+}
+
 int do_write(int nargs, char **args)
 {
     return write_file(args[1], args[2]);
diff --git a/init/devices.c b/init/devices.c
index 7aea246..f86eab9 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -98,9 +98,12 @@
         /* these should not be world writable */
     { "/dev/android_adb",   0660,   AID_ADB,        AID_ADB,        0 },
     { "/dev/android_adb_enable",   0660,   AID_ADB,        AID_ADB,        0 },
-    { "/dev/ttyMSM0",       0660,   AID_BLUETOOTH,  AID_BLUETOOTH,  0 },
+    /* TODO: remove legacy ttyMSM0 */
+    { "/dev/ttyMSM0",       0600,   AID_BLUETOOTH,  AID_BLUETOOTH,  0 },
+    { "/dev/ttyHS0",        0600,   AID_BLUETOOTH,  AID_BLUETOOTH,  0 },
+    { "/dev/uinput",        0600,   AID_BLUETOOTH,  AID_BLUETOOTH,  0 },
     { "/dev/alarm",         0664,   AID_SYSTEM,     AID_RADIO,      0 },
-    { "/dev/tty0",          0666,   AID_ROOT,       AID_SYSTEM,     0 },
+    { "/dev/tty0",          0660,   AID_ROOT,       AID_SYSTEM,     0 },
     { "/dev/graphics/",     0660,   AID_ROOT,       AID_GRAPHICS,   1 },
     { "/dev/hw3d",          0660,   AID_SYSTEM,     AID_GRAPHICS,   0 },
     { "/dev/input/",        0660,   AID_ROOT,       AID_INPUT,      1 },
@@ -360,29 +363,29 @@
         return;
 
         /* are we block or char? where should we live? */
-    if(!strncmp(uevent->path, "/block", 6)) {
+    if(!strncmp(uevent->subsystem, "block", 5)) {
         block = 1;
         base = "/dev/block/";
         mkdir(base, 0755);
     } else {
         block = 0;
             /* this should probably be configurable somehow */
-        if(!strncmp(uevent->path, "/class/graphics/", 16)) {
+        if(!strncmp(uevent->subsystem, "graphics", 8)) {
             base = "/dev/graphics/";
             mkdir(base, 0755);
-        } else if (!strncmp(uevent->path, "/class/oncrpc/", 14)) {
+        } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
             base = "/dev/oncrpc/";
             mkdir(base, 0755);
-        } else if (!strncmp(uevent->path, "/class/adsp/", 12)) {
+        } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
             base = "/dev/adsp/";
             mkdir(base, 0755);
-      } else if(!strncmp(uevent->path, "/class/input/", 13)) {
+      } else if(!strncmp(uevent->subsystem, "input", 5)) {
             base = "/dev/input/";
             mkdir(base, 0755);
-        } else if(!strncmp(uevent->path, "/class/mtd/", 11)) {
+        } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
             base = "/dev/mtd/";
             mkdir(base, 0755);
-        } else if(!strncmp(uevent->path, "/class/misc/", 12) &&
+        } else if(!strncmp(uevent->subsystem, "misc", 4) &&
                     !strncmp(name, "log_", 4)) {
             base = "/dev/log/";
             mkdir(base, 0755);
diff --git a/init/grab-bootchart.sh b/init/grab-bootchart.sh
index 57c9556..7fe8904 100755
--- a/init/grab-bootchart.sh
+++ b/init/grab-bootchart.sh
@@ -9,13 +9,13 @@
 rm -rf $TMPDIR
 mkdir -p $TMPDIR
 
-LOGROOT=/tmp/bootchart
+LOGROOT=/data/bootchart
 TARBALL=bootchart.tgz
 
 FILES="header proc_stat.log proc_ps.log proc_diskstats.log kernel_pacct"
 
 for f in $FILES; do
-    adb pull $LOGROOT/$f $TMPDIR/$f &> /dev/null
+    adb pull $LOGROOT/$f $TMPDIR/$f 2>&1 > /dev/null
 done
 (cd $TMPDIR && tar -czf $TARBALL $FILES)
 cp -f $TMPDIR/$TARBALL ./$TARBALL
diff --git a/init/init.c b/init/init.c
index f6e9b39..3616840 100644
--- a/init/init.c
+++ b/init/init.c
@@ -43,21 +43,12 @@
 #include "devices.h"
 #include "init.h"
 #include "property_service.h"
-
-#ifndef BOOTCHART
-# define  BOOTCHART  0
-#endif
+#include "bootchart.h"
 
 static int property_triggers_enabled = 0;
 
 #if BOOTCHART
 static int   bootchart_count;
-extern int   bootchart_init(void);
-extern int   bootchart_step(void);
-extern void  bootchart_finish(void);
-# define BOOTCHART_POLLING_MS   200 /* polling period in ms */
-# define BOOTCHART_MAX_TIME_MS  (2*60*1000) /* max polling time from boot */
-# define BOOTCHART_MAX_COUNT    (BOOTCHART_MAX_TIME_MS/BOOTCHART_POLLING_MS)
 #endif
 
 static char console[32];
@@ -834,11 +825,13 @@
     ufds[2].events = POLLIN;
 
 #if BOOTCHART
-    if (bootchart_init() < 0)
+    bootchart_count = bootchart_init();
+    if (bootchart_count < 0) {
         ERROR("bootcharting init failure\n");
-    else {
-        NOTICE("bootcharting started\n");
-        bootchart_count = BOOTCHART_MAX_COUNT;
+    } else if (bootchart_count > 0) {
+        NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);
+    } else {
+        NOTICE("bootcharting ignored\n");
     }
 #endif
 
diff --git a/init/keywords.h b/init/keywords.h
index f09bad2..058996e 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -19,6 +19,7 @@
 int do_stop(int nargs, char **args);
 int do_trigger(int nargs, char **args);
 int do_symlink(int nargs, char **args);
+int do_sysclktz(int nargs, char **args);
 int do_write(int nargs, char **args);
 int do_chown(int nargs, char **args);
 int do_chmod(int nargs, char **args);
@@ -60,6 +61,7 @@
     KEYWORD(stop,        COMMAND, 1, do_stop)
     KEYWORD(trigger,     COMMAND, 1, do_trigger)
     KEYWORD(symlink,     COMMAND, 1, do_symlink)
+    KEYWORD(sysclktz,    COMMAND, 1, do_sysclktz)
     KEYWORD(user,        OPTION,  0, 0)
     KEYWORD(write,       COMMAND, 2, do_write)
     KEYWORD(chown,       COMMAND, 2, do_chown)
diff --git a/init/parser.c b/init/parser.c
index 95bf017..a51691b 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -183,6 +183,7 @@
         if (!strcmp(s, "tart")) return K_start;
         if (!strcmp(s, "top")) return K_stop;
         if (!strcmp(s, "ymlink")) return K_symlink;
+	if (!strcmp(s, "ysclktz")) return K_sysclktz;
         break;
     case 't':
         if (!strcmp(s, "rigger")) return K_trigger;
diff --git a/init/property_service.c b/init/property_service.c
index 0bc403f..7a6416b 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -343,7 +343,7 @@
     socklen_t addr_size = sizeof(addr);
     socklen_t cr_size = sizeof(cr);
 
-    if ((s = accept(fd, &addr, &addr_size)) < 0) {
+    if ((s = accept(fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
         return;
     }
 
diff --git a/init/readme.txt b/init/readme.txt
index 360a1b7..665090b 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -194,6 +194,9 @@
 symlink <target> <path>
    Create a symbolic link at <path> with the value <target>
 
+sysclktz <mins_west_of_gmt>
+   Set the system clock base (0 if system clock ticks in GMT)
+
 trigger <event>
    Trigger an event.  Used to queue an action from another
    action.
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 3d0c12b..a43f7e3 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -60,6 +60,7 @@
         selector.c \
         fdevent.c \
         tztime.c \
+        tzstrftime.c \
         adb_networking.c \
 	zygote.c
 endif
@@ -91,8 +92,14 @@
 # ========================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(commonSources) memset32.S atomic-android-arm.S mq.c \
-	ashmem-dev.c
+LOCAL_SRC_FILES := $(commonSources) ashmem-dev.c mq.c
+
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_SRC_FILES += memset32.S atomic-android-arm.S
+else  # !arm
+LOCAL_SRC_FILES += memory.c
+endif # !arm
+
 LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
 LOCAL_STATIC_LIBRARIES := liblog
 include $(BUILD_STATIC_LIBRARY)
diff --git a/libcutils/atomic-android-arm.S b/libcutils/atomic-android-arm.S
index 2a4c34f..c56ec5d 100644
--- a/libcutils/atomic-android-arm.S
+++ b/libcutils/atomic-android-arm.S
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <machine/cpu-features.h>
+
 /*
  * NOTE: these atomic operations are SMP safe on all architectures, 
  * except swap(), see below.
@@ -59,8 +61,14 @@
 1: @ android_atomic_write
     ldr     r0, [r2]
     mov     r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
     add     lr, pc, #4
     add     pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+    add     r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+    mov     lr, pc
+    bx      r3
+#endif
     bcc     1b
     ldmia   sp!, {r4, lr}
     bx      lr
@@ -78,9 +86,16 @@
 1: @ android_atomic_inc
     ldr     r0, [r2]
     mov     r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
     add     lr, pc, #4
     add     r1, r0, #1
     add     pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+    add     r1, r0, #1
+    add     r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+    mov     lr, pc
+    bx      r3
+#endif
     bcc     1b
     sub     r0, r1, #1
     ldmia   sp!, {r4, lr}
@@ -99,9 +114,16 @@
 1: @ android_atomic_dec
     ldr     r0, [r2]
     mov     r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
     add     lr, pc, #4
     sub     r1, r0, #1
     add     pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+    sub     r1, r0, #1
+    add     r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+    mov     lr, pc
+    bx      r3
+#endif
     bcc     1b
     add     r0, r1, #1
     ldmia   sp!, {r4, lr}
@@ -121,9 +143,16 @@
 1: @ android_atomic_add
     ldr     r0, [r2]
     mov     r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
     add     lr, pc, #4
     add     r1, r0, r4
     add     pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+    add     r1, r0, r4
+    add     r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+    mov     lr, pc
+    bx      r3
+#endif
     bcc     1b
     sub     r0, r1, r4
     ldmia   sp!, {r4, lr}
@@ -144,10 +173,18 @@
 1: @ android_atomic_and
     ldr     r0, [r2]            /* r0 = address[0] */
     mov     r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
     add     lr, pc, #8
     mov     r5, r0              /* r5 = save address[0] */
     and     r1, r0, r4          /* r1 = new value */
     add     pc, r3, #(kernel_cmpxchg - kernel_atomic_base)  /* call cmpxchg() */
+#else
+    mov     r5, r0              /* r5 = save address[0] */
+    and     r1, r0, r4          /* r1 = new value */
+    add     r3, r3, #(kernel_cmpxchg - kernel_atomic_base)  /* call cmpxchg() */
+    mov     lr, pc
+    bx      r3
+#endif
     bcc     1b
     mov     r0, r5
     ldmia   sp!, {r4, r5, lr}
@@ -167,10 +204,18 @@
 1: @ android_atomic_or
     ldr     r0, [r2]            /* r0 = address[0] */
     mov     r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
     add     lr, pc, #8
     mov     r5, r0              /* r5 = save address[0] */
     orr     r1, r0, r4          /* r1 = new value */
     add     pc, r3, #(kernel_cmpxchg - kernel_atomic_base)  /* call cmpxchg() */
+#else
+    mov     r5, r0              /* r5 = save address[0] */
+    orr     r1, r0, r4          /* r1 = new value */
+    add     r3, r3, #(kernel_cmpxchg - kernel_atomic_base)  /* call cmpxchg() */
+    mov     lr, pc
+    bx      r3
+#endif
     bcc     1b
     mov     r0, r5
     ldmia   sp!, {r4, r5, lr}
@@ -202,9 +247,16 @@
     mov     r4, r0          /* r4 = save oldvalue */
 1: @ android_atomic_cmpxchg
     mov     r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
     add     lr, pc, #4
     mov     r0, r4          /* r0 = oldvalue */
     add     pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+    mov     r0, r4          /* r0 = oldvalue */
+    add     r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+    mov     lr, pc
+    bx      r3
+#endif
     bcs     2f              /* swap was made. we're good, return. */
     ldr     r3, [r2]        /* swap not made, see if it's because *ptr!=oldvalue */
     cmp     r3, r4
diff --git a/libcutils/tzstrftime.c b/libcutils/tzstrftime.c
new file mode 100644
index 0000000..29c5015
--- /dev/null
+++ b/libcutils/tzstrftime.c
@@ -0,0 +1,834 @@
+#ifndef lint
+#ifndef NOID
+static char	elsieid[] = "@(#)strftime.c	8.1";
+/*
+** Based on the UCB version with the ID appearing below.
+** This is ANSIish only when "multibyte character == plain character".
+*/
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+#include <time.h>
+#include <tzfile.h>
+#include <limits.h>
+#include <cutils/tztime.h>
+
+/*
+** Copyright (c) 1989 The Regents of the University of California.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms are permitted
+** provided that the above copyright notice and this paragraph are
+** duplicated in all such forms and that any documentation,
+** advertising materials, and other materials related to such
+** distribution and use acknowledge that the software was developed
+** by the University of California, Berkeley. The name of the
+** University may not be used to endorse or promote products derived
+** from this software without specific prior written permission.
+** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifndef LIBC_SCCS
+#ifndef lint
+static const char	sccsid[] = "@(#)strftime.c	5.4 (Berkeley) 3/14/89";
+#endif /* !defined lint */
+#endif /* !defined LIBC_SCCS */
+
+#include <ctype.h>
+
+#define P(x) x
+
+static char *	_add P((const char *, char *, const char *, int));
+static char *	_conv P((int, const char *, char *, const char *));
+static char *	_fmt P((const char *, const struct tm *, char *, const char *,
+			int *, const struct strftime_locale *Locale));
+static char *	_yconv P((int, int, int, int, char *, const char *, int));
+static char *	getformat P((int, char *, char *, char *, char *));
+
+extern char *	tzname[];
+
+
+
+
+
+/* from private.h */
+
+#ifndef TYPE_BIT
+#define TYPE_BIT(type)  (sizeof (type) * CHAR_BIT)
+#endif /* !defined TYPE_BIT */
+
+#ifndef TYPE_SIGNED
+#define TYPE_SIGNED(type) (((type) -1) < 0)
+#endif /* !defined TYPE_SIGNED */
+
+#ifndef INT_STRLEN_MAXIMUM
+/*
+ * ** 302 / 1000 is log10(2.0) rounded up.
+ * ** Subtract one for the sign bit if the type is signed;
+ * ** add one for integer division truncation;
+ * ** add one more for a minus sign if the type is signed.
+ * */
+#define INT_STRLEN_MAXIMUM(type) \
+    ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
+    1 + TYPE_SIGNED(type))
+#endif /* !defined INT_STRLEN_MAXIMUM */
+
+/* end of part from private.h */
+
+
+
+
+#ifndef YEAR_2000_NAME
+#define YEAR_2000_NAME	"CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
+#endif /* !defined YEAR_2000_NAME */
+
+#define IN_NONE	0
+#define IN_SOME	1
+#define IN_THIS	2
+#define IN_ALL	3
+
+#define FORCE_LOWER_CASE 0x100
+
+size_t
+strftime_tz(s, maxsize, format, t, Locale)
+char * const		s;
+const size_t		maxsize;
+const char * const	format;
+const struct tm * const	t;
+const struct strftime_locale *Locale;
+{
+	char *	p;
+	int	warn;
+
+	warn = IN_NONE;
+	p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, Locale);
+#if 0
+	if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
+		(void) fprintf(stderr, "\n");
+		if (format == NULL)
+			(void) fprintf(stderr, "NULL strftime format ");
+		else	(void) fprintf(stderr, "strftime format \"%s\" ",
+				format);
+		(void) fprintf(stderr, "yields only two digits of years in ");
+		if (warn == IN_SOME)
+			(void) fprintf(stderr, "some locales");
+		else if (warn == IN_THIS)
+			(void) fprintf(stderr, "the current locale");
+		else	(void) fprintf(stderr, "all locales");
+		(void) fprintf(stderr, "\n");
+	}
+#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
+	if (p == s + maxsize)
+		return 0;
+	*p = '\0';
+	return p - s;
+}
+
+static char *getformat(int modifier, char *normal, char *underscore,
+                       char *dash, char *zero) {
+    switch (modifier) {
+    case '_':
+        return underscore;
+
+    case '-':
+        return dash;
+
+    case '0':
+        return zero;
+    }
+
+    return normal;
+}
+
+static char *
+_fmt(format, t, pt, ptlim, warnp, Locale)
+const char *		format;
+const struct tm * const	t;
+char *			pt;
+const char * const	ptlim;
+int *			warnp;
+const struct strftime_locale *Locale;
+{
+	for ( ; *format; ++format) {
+		if (*format == '%') {
+            int modifier = 0;
+label:
+			switch (*++format) {
+			case '\0':
+				--format;
+				break;
+			case 'A':
+				pt = _add((t->tm_wday < 0 ||
+					t->tm_wday >= DAYSPERWEEK) ?
+					"?" : Locale->weekday[t->tm_wday],
+					pt, ptlim, modifier);
+				continue;
+			case 'a':
+				pt = _add((t->tm_wday < 0 ||
+					t->tm_wday >= DAYSPERWEEK) ?
+					"?" : Locale->wday[t->tm_wday],
+					pt, ptlim, modifier);
+				continue;
+			case 'B':
+				pt = _add((t->tm_mon < 0 ||
+					t->tm_mon >= MONSPERYEAR) ?
+					"?" : Locale->month[t->tm_mon],
+					pt, ptlim, modifier);
+				continue;
+			case 'b':
+			case 'h':
+				pt = _add((t->tm_mon < 0 ||
+					t->tm_mon >= MONSPERYEAR) ?
+					"?" : Locale->mon[t->tm_mon],
+					pt, ptlim, modifier);
+				continue;
+			case 'C':
+				/*
+				** %C used to do a...
+				**	_fmt("%a %b %e %X %Y", t);
+				** ...whereas now POSIX 1003.2 calls for
+				** something completely different.
+				** (ado, 1993-05-24)
+				*/
+				pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
+					pt, ptlim, modifier);
+				continue;
+			case 'c':
+				{
+				int warn2 = IN_SOME;
+
+				pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp, Locale);
+				if (warn2 == IN_ALL)
+					warn2 = IN_THIS;
+				if (warn2 > *warnp)
+					*warnp = warn2;
+				}
+				continue;
+			case 'D':
+                                pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, Locale);
+				continue;
+			case 'd':
+                                pt = _conv(t->tm_mday,
+                                           getformat(modifier, "%02d",
+                                                     "%2d", "%d", "%02d"),
+                                           pt, ptlim);
+				continue;
+			case 'E':
+			case 'O':
+				/*
+				** C99 locale modifiers.
+				** The sequences
+				**	%Ec %EC %Ex %EX %Ey %EY
+				**	%Od %oe %OH %OI %Om %OM
+				**	%OS %Ou %OU %OV %Ow %OW %Oy
+				** are supposed to provide alternate
+				** representations.
+				*/
+				goto label;
+            case '_':
+            case '-':
+            case '0':
+            case '^':
+            case '#':
+                modifier = *format;
+                goto label;
+			case 'e':
+				pt = _conv(t->tm_mday,
+                                           getformat(modifier, "%2d",
+                                                     "%2d", "%d", "%02d"),
+                                           pt, ptlim);
+				continue;
+			case 'F':
+				pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, Locale);
+				continue;
+			case 'H':
+				pt = _conv(t->tm_hour,
+                                           getformat(modifier, "%02d",
+                                                     "%2d", "%d", "%02d"),
+                                           pt, ptlim);
+				continue;
+			case 'I':
+				pt = _conv((t->tm_hour % 12) ?
+					(t->tm_hour % 12) : 12,
+					getformat(modifier, "%02d",
+                                                  "%2d", "%d", "%02d"),
+                                        pt, ptlim);
+				continue;
+			case 'j':
+				pt = _conv(t->tm_yday + 1,
+                           getformat(modifier, "%03d", "%3d", "%d", "%03d"),
+                           pt, ptlim);
+				continue;
+			case 'k':
+				/*
+				** This used to be...
+				**	_conv(t->tm_hour % 12 ?
+				**		t->tm_hour % 12 : 12, 2, ' ');
+				** ...and has been changed to the below to
+				** match SunOS 4.1.1 and Arnold Robbins'
+				** strftime version 3.0. That is, "%k" and
+				** "%l" have been swapped.
+				** (ado, 1993-05-24)
+				*/
+				pt = _conv(t->tm_hour,
+                                           getformat(modifier, "%2d",
+                                                     "%2d", "%d", "%02d"),
+                                           pt, ptlim);
+				continue;
+#ifdef KITCHEN_SINK
+			case 'K':
+				/*
+				** After all this time, still unclaimed!
+				*/
+				pt = _add("kitchen sink", pt, ptlim, modifier);
+				continue;
+#endif /* defined KITCHEN_SINK */
+			case 'l':
+				/*
+				** This used to be...
+				**	_conv(t->tm_hour, 2, ' ');
+				** ...and has been changed to the below to
+				** match SunOS 4.1.1 and Arnold Robbin's
+				** strftime version 3.0. That is, "%k" and
+				** "%l" have been swapped.
+				** (ado, 1993-05-24)
+				*/
+				pt = _conv((t->tm_hour % 12) ?
+					(t->tm_hour % 12) : 12,
+					getformat(modifier, "%2d",
+                                                  "%2d", "%d", "%02d"),
+                                        pt, ptlim);
+				continue;
+			case 'M':
+				pt = _conv(t->tm_min,
+                                           getformat(modifier, "%02d",
+                                                     "%2d", "%d", "%02d"),
+                                           pt, ptlim);
+				continue;
+			case 'm':
+				pt = _conv(t->tm_mon + 1,
+                                           getformat(modifier, "%02d",
+                                                     "%2d", "%d", "%02d"),
+                                           pt, ptlim);
+				continue;
+			case 'n':
+				pt = _add("\n", pt, ptlim, modifier);
+				continue;
+			case 'p':
+				pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
+					Locale->pm :
+					Locale->am,
+					pt, ptlim, modifier);
+				continue;
+			case 'P':
+				pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
+					Locale->pm :
+					Locale->am,
+					pt, ptlim, FORCE_LOWER_CASE);
+				continue;
+			case 'R':
+				pt = _fmt("%H:%M", t, pt, ptlim, warnp, Locale);
+				continue;
+			case 'r':
+				pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp, Locale);
+				continue;
+			case 'S':
+				pt = _conv(t->tm_sec,
+                                           getformat(modifier, "%02d",
+                                                     "%2d", "%d", "%02d"),
+                                           pt, ptlim);
+				continue;
+			case 's':
+				{
+					struct tm	tm;
+					char		buf[INT_STRLEN_MAXIMUM(
+								time_t) + 1];
+					time_t		mkt;
+
+					tm = *t;
+					mkt = mktime(&tm);
+					if (TYPE_SIGNED(time_t))
+						(void) sprintf(buf, "%ld",
+							(long) mkt);
+					else	(void) sprintf(buf, "%lu",
+							(unsigned long) mkt);
+					pt = _add(buf, pt, ptlim, modifier);
+				}
+				continue;
+			case 'T':
+				pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, Locale);
+				continue;
+			case 't':
+				pt = _add("\t", pt, ptlim, modifier);
+				continue;
+			case 'U':
+				pt = _conv((t->tm_yday + DAYSPERWEEK -
+					t->tm_wday) / DAYSPERWEEK,
+					getformat(modifier, "%02d",
+                                                  "%2d", "%d", "%02d"),
+                                        pt, ptlim);
+				continue;
+			case 'u':
+				/*
+				** From Arnold Robbins' strftime version 3.0:
+				** "ISO 8601: Weekday as a decimal number
+				** [1 (Monday) - 7]"
+				** (ado, 1993-05-24)
+				*/
+				pt = _conv((t->tm_wday == 0) ?
+					DAYSPERWEEK : t->tm_wday, "%d", pt, ptlim);
+				continue;
+			case 'V':	/* ISO 8601 week number */
+			case 'G':	/* ISO 8601 year (four digits) */
+			case 'g':	/* ISO 8601 year (two digits) */
+/*
+** From Arnold Robbins' strftime version 3.0: "the week number of the
+** year (the first Monday as the first day of week 1) as a decimal number
+** (01-53)."
+** (ado, 1993-05-24)
+**
+** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
+** "Week 01 of a year is per definition the first week which has the
+** Thursday in this year, which is equivalent to the week which contains
+** the fourth day of January. In other words, the first week of a new year
+** is the week which has the majority of its days in the new year. Week 01
+** might also contain days from the previous year and the week before week
+** 01 of a year is the last week (52 or 53) of the previous year even if
+** it contains days from the new year. A week starts with Monday (day 1)
+** and ends with Sunday (day 7). For example, the first week of the year
+** 1997 lasts from 1996-12-30 to 1997-01-05..."
+** (ado, 1996-01-02)
+*/
+				{
+					int	year;
+					int	base;
+					int	yday;
+					int	wday;
+					int	w;
+
+					year = t->tm_year;
+					base = TM_YEAR_BASE;
+					yday = t->tm_yday;
+					wday = t->tm_wday;
+					for ( ; ; ) {
+						int	len;
+						int	bot;
+						int	top;
+
+						len = isleap_sum(year, base) ?
+							DAYSPERLYEAR :
+							DAYSPERNYEAR;
+						/*
+						** What yday (-3 ... 3) does
+						** the ISO year begin on?
+						*/
+						bot = ((yday + 11 - wday) %
+							DAYSPERWEEK) - 3;
+						/*
+						** What yday does the NEXT
+						** ISO year begin on?
+						*/
+						top = bot -
+							(len % DAYSPERWEEK);
+						if (top < -3)
+							top += DAYSPERWEEK;
+						top += len;
+						if (yday >= top) {
+							++base;
+							w = 1;
+							break;
+						}
+						if (yday >= bot) {
+							w = 1 + ((yday - bot) /
+								DAYSPERWEEK);
+							break;
+						}
+						--base;
+						yday += isleap_sum(year, base) ?
+							DAYSPERLYEAR :
+							DAYSPERNYEAR;
+					}
+#ifdef XPG4_1994_04_09
+					if ((w == 52 &&
+						t->tm_mon == TM_JANUARY) ||
+						(w == 1 &&
+						t->tm_mon == TM_DECEMBER))
+							w = 53;
+#endif /* defined XPG4_1994_04_09 */
+					if (*format == 'V')
+						pt = _conv(w,
+                                                           getformat(modifier,
+                                                                     "%02d",
+                                                                     "%2d",
+                                                                     "%d",
+                                                                     "%02d"),
+							   pt, ptlim);
+					else if (*format == 'g') {
+						*warnp = IN_ALL;
+						pt = _yconv(year, base, 0, 1,
+							pt, ptlim, modifier);
+					} else	pt = _yconv(year, base, 1, 1,
+							pt, ptlim, modifier);
+				}
+				continue;
+			case 'v':
+				/*
+				** From Arnold Robbins' strftime version 3.0:
+				** "date as dd-bbb-YYYY"
+				** (ado, 1993-05-24)
+				*/
+				pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, Locale);
+				continue;
+			case 'W':
+				pt = _conv((t->tm_yday + DAYSPERWEEK -
+					(t->tm_wday ?
+					(t->tm_wday - 1) :
+					(DAYSPERWEEK - 1))) / DAYSPERWEEK,
+					getformat(modifier, "%02d",
+                                                  "%2d", "%d", "%02d"),
+                                        pt, ptlim);
+				continue;
+			case 'w':
+				pt = _conv(t->tm_wday, "%d", pt, ptlim);
+				continue;
+			case 'X':
+				pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp, Locale);
+				continue;
+			case 'x':
+				{
+				int	warn2 = IN_SOME;
+
+				pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2, Locale);
+				if (warn2 == IN_ALL)
+					warn2 = IN_THIS;
+				if (warn2 > *warnp)
+					*warnp = warn2;
+				}
+				continue;
+			case 'y':
+				*warnp = IN_ALL;
+				pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
+					pt, ptlim, modifier);
+				continue;
+			case 'Y':
+				pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
+					pt, ptlim, modifier);
+				continue;
+			case 'Z':
+#ifdef TM_ZONE
+				if (t->TM_ZONE != NULL)
+					pt = _add(t->TM_ZONE, pt, ptlim,
+                                                  modifier);
+				else
+#endif /* defined TM_ZONE */
+				if (t->tm_isdst >= 0)
+					pt = _add(tzname[t->tm_isdst != 0],
+						pt, ptlim, modifier);
+				/*
+				** C99 says that %Z must be replaced by the
+				** empty string if the time zone is not
+				** determinable.
+				*/
+				continue;
+			case 'z':
+				{
+				int		diff;
+				char const *	sign;
+
+				if (t->tm_isdst < 0)
+					continue;
+#ifdef TM_GMTOFF
+				diff = t->TM_GMTOFF;
+#else /* !defined TM_GMTOFF */
+				/*
+				** C99 says that the UTC offset must
+				** be computed by looking only at
+				** tm_isdst. This requirement is
+				** incorrect, since it means the code
+				** must rely on magic (in this case
+				** altzone and timezone), and the
+				** magic might not have the correct
+				** offset. Doing things correctly is
+				** tricky and requires disobeying C99;
+				** see GNU C strftime for details.
+				** For now, punt and conform to the
+				** standard, even though it's incorrect.
+				**
+				** C99 says that %z must be replaced by the
+				** empty string if the time zone is not
+				** determinable, so output nothing if the
+				** appropriate variables are not available.
+				*/
+				if (t->tm_isdst == 0)
+#ifdef USG_COMPAT
+					diff = -timezone;
+#else /* !defined USG_COMPAT */
+					continue;
+#endif /* !defined USG_COMPAT */
+				else
+#ifdef ALTZONE
+					diff = -altzone;
+#else /* !defined ALTZONE */
+					continue;
+#endif /* !defined ALTZONE */
+#endif /* !defined TM_GMTOFF */
+				if (diff < 0) {
+					sign = "-";
+					diff = -diff;
+				} else	sign = "+";
+				pt = _add(sign, pt, ptlim, modifier);
+				diff /= SECSPERMIN;
+				diff = (diff / MINSPERHOUR) * 100 +
+					(diff % MINSPERHOUR);
+				pt = _conv(diff,
+                                           getformat(modifier, "%04d",
+                                                     "%4d", "%d", "%04d"),
+                                           pt, ptlim);
+				}
+				continue;
+			case '+':
+				pt = _fmt(Locale->date_fmt, t, pt, ptlim,
+					warnp, Locale);
+				continue;
+			case '%':
+			/*
+			** X311J/88-090 (4.12.3.5): if conversion char is
+			** undefined, behavior is undefined. Print out the
+			** character itself as printf(3) also does.
+			*/
+			default:
+				break;
+			}
+		}
+		if (pt == ptlim)
+			break;
+		*pt++ = *format;
+	}
+	return pt;
+}
+
+static char *
+_conv(n, format, pt, ptlim)
+const int		n;
+const char * const	format;
+char * const		pt;
+const char * const	ptlim;
+{
+	char	buf[INT_STRLEN_MAXIMUM(int) + 1];
+
+	(void) sprintf(buf, format, n);
+	return _add(buf, pt, ptlim, 0);
+}
+
+static char *
+_add(str, pt, ptlim, modifier)
+const char *		str;
+char *			pt;
+const char * const	ptlim;
+int                     modifier;
+{
+        int c;
+
+        switch (modifier) {
+        case FORCE_LOWER_CASE:
+                while (pt < ptlim && (*pt = tolower(*str++)) != '\0') {
+                        ++pt;
+                }
+                break;
+
+        case '^':
+                while (pt < ptlim && (*pt = toupper(*str++)) != '\0') {
+                        ++pt;
+                }
+                break;
+
+        case '#':
+                while (pt < ptlim && (c = *str++) != '\0') {
+                        if (isupper(c)) {
+                                c = tolower(c);
+                        } else if (islower(c)) {
+                                c = toupper(c);
+                        }
+                        *pt = c;
+                        ++pt;
+                }
+
+                break;
+
+        default:
+                while (pt < ptlim && (*pt = *str++) != '\0') {
+                        ++pt;
+                }
+        }
+
+	return pt;
+}
+
+/*
+** POSIX and the C Standard are unclear or inconsistent about
+** what %C and %y do if the year is negative or exceeds 9999.
+** Use the convention that %C concatenated with %y yields the
+** same output as %Y, and that %Y contains at least 4 bytes,
+** with more only if necessary.
+*/
+
+static char *
+_yconv(a, b, convert_top, convert_yy, pt, ptlim, modifier)
+const int		a;
+const int		b;
+const int		convert_top;
+const int		convert_yy;
+char *			pt;
+const char * const	ptlim;
+int                     modifier;
+{
+	register int	lead;
+	register int	trail;
+
+#define DIVISOR	100
+	trail = a % DIVISOR + b % DIVISOR;
+	lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
+	trail %= DIVISOR;
+	if (trail < 0 && lead > 0) {
+		trail += DIVISOR;
+		--lead;
+	} else if (lead < 0 && trail > 0) {
+		trail -= DIVISOR;
+		++lead;
+	}
+	if (convert_top) {
+		if (lead == 0 && trail < 0)
+			pt = _add("-0", pt, ptlim, modifier);
+		else	pt = _conv(lead, getformat(modifier, "%02d",
+                                                   "%2d", "%d", "%02d"),
+                                   pt, ptlim);
+	}
+	if (convert_yy)
+		pt = _conv(((trail < 0) ? -trail : trail),
+                           getformat(modifier, "%02d", "%2d", "%d", "%02d"),
+                           pt, ptlim);
+	return pt;
+}
+
+#ifdef LOCALE_HOME
+static struct lc_time_T *
+_loc P((void))
+{
+	static const char	locale_home[] = LOCALE_HOME;
+	static const char	lc_time[] = "LC_TIME";
+	static char *		locale_buf;
+
+	int			fd;
+	int			oldsun;	/* "...ain't got nothin' to do..." */
+	char *			lbuf;
+	char *			name;
+	char *			p;
+	const char **		ap;
+	const char *		plim;
+	char			filename[FILENAME_MAX];
+	struct stat		st;
+	size_t			namesize;
+	size_t			bufsize;
+
+	/*
+	** Use localebuf.mon[0] to signal whether locale is already set up.
+	*/
+	if (localebuf.mon[0])
+		return &localebuf;
+	name = setlocale(LC_TIME, (char *) NULL);
+	if (name == NULL || *name == '\0')
+		goto no_locale;
+	/*
+	** If the locale name is the same as our cache, use the cache.
+	*/
+	lbuf = locale_buf;
+	if (lbuf != NULL && strcmp(name, lbuf) == 0) {
+		p = lbuf;
+		for (ap = (const char **) &localebuf;
+			ap < (const char **) (&localebuf + 1);
+				++ap)
+					*ap = p += strlen(p) + 1;
+		return &localebuf;
+	}
+	/*
+	** Slurp the locale file into the cache.
+	*/
+	namesize = strlen(name) + 1;
+	if (sizeof filename <
+		((sizeof locale_home) + namesize + (sizeof lc_time)))
+			goto no_locale;
+	oldsun = 0;
+	(void) sprintf(filename, "%s/%s/%s", locale_home, name, lc_time);
+	fd = open(filename, O_RDONLY);
+	if (fd < 0) {
+		/*
+		** Old Sun systems have a different naming and data convention.
+		*/
+		oldsun = 1;
+		(void) sprintf(filename, "%s/%s/%s", locale_home,
+			lc_time, name);
+		fd = open(filename, O_RDONLY);
+		if (fd < 0)
+			goto no_locale;
+	}
+	if (fstat(fd, &st) != 0)
+		goto bad_locale;
+	if (st.st_size <= 0)
+		goto bad_locale;
+	bufsize = namesize + st.st_size;
+	locale_buf = NULL;
+	lbuf = (lbuf == NULL) ? malloc(bufsize) : realloc(lbuf, bufsize);
+	if (lbuf == NULL)
+		goto bad_locale;
+	(void) strcpy(lbuf, name);
+	p = lbuf + namesize;
+	plim = p + st.st_size;
+	if (read(fd, p, (size_t) st.st_size) != st.st_size)
+		goto bad_lbuf;
+	if (close(fd) != 0)
+		goto bad_lbuf;
+	/*
+	** Parse the locale file into localebuf.
+	*/
+	if (plim[-1] != '\n')
+		goto bad_lbuf;
+	for (ap = (const char **) &localebuf;
+		ap < (const char **) (&localebuf + 1);
+			++ap) {
+				if (p == plim)
+					goto bad_lbuf;
+				*ap = p;
+				while (*p != '\n')
+					++p;
+				*p++ = '\0';
+	}
+	if (oldsun) {
+		/*
+		** SunOS 4 used an obsolescent format; see localdtconv(3).
+		** c_fmt had the ``short format for dates and times together''
+		** (SunOS 4 date, "%a %b %e %T %Z %Y" in the C locale);
+		** date_fmt had the ``long format for dates''
+		** (SunOS 4 strftime %C, "%A, %B %e, %Y" in the C locale).
+		** Discard the latter in favor of the former.
+		*/
+		localebuf.date_fmt = localebuf.c_fmt;
+	}
+	/*
+	** Record the successful parse in the cache.
+	*/
+	locale_buf = lbuf;
+
+	return &localebuf;
+
+bad_lbuf:
+	free(lbuf);
+bad_locale:
+	(void) close(fd);
+no_locale:
+	localebuf = C_time_locale;
+	locale_buf = NULL;
+	return &localebuf;
+}
+#endif /* defined LOCALE_HOME */
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index 97fe76d..ba98933 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -181,6 +181,22 @@
     return 0;
 }
 
+/**
+ * Release the current DHCP client lease.
+ */
+int dhcp_release_lease(const char *interface)
+{
+    const char *ctrl_prop = "ctl.stop";
+    const char *desired_status = "stopped";
+
+    /* Stop the daemon and wait until it's reported to be stopped */
+    property_set(ctrl_prop, DAEMON_NAME);
+    if (wait_for_property(DAEMON_PROP_NAME, desired_status, 5) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
 char *dhcp_get_errmsg() {
     return errmsg;
 }
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index a8e5ee4..6edc56f 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -85,3 +85,6 @@
 LOCAL_WHOLE_STATIC_LIBRARIES := libpixelflinger_armv6
 endif
 include $(BUILD_STATIC_LIBRARY)
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
index 90c275e..1cd189c 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ b/libpixelflinger/codeflinger/GGLAssembler.cpp
@@ -151,6 +151,7 @@
         // Destination is zero (beware of logic ops)
     }
     
+    int fbComponents = 0;
     const int masking = GGL_READ_NEEDS(MASK_ARGB, needs.n);
     for (int i=0 ; i<4 ; i++) {
         const int mask = 1<<i;
@@ -176,9 +177,14 @@
 
         mBlending |= (info.blend ? mask : 0);
         mMasking |= (mCbFormat.c[i].h && info.masked) ? mask : 0;
+        fbComponents |= mCbFormat.c[i].h ? mask : 0;
     }
 
-
+    mAllMasked = (mMasking == fbComponents);
+    if (mAllMasked) {
+        mDithering = 0;
+    }
+    
     fragment_parts_t parts;
 
     // ------------------------------------------------------------------------
@@ -226,8 +232,10 @@
             build_textures(parts, regs);
         }        
 
-        if ((blending & (FACTOR_DST|BLEND_DST)) || mMasking ||
-                (mLogicOp & LOGIC_OP_DST)) {
+        if ((blending & (FACTOR_DST|BLEND_DST)) || 
+                (mMasking && !mAllMasked) ||
+                (mLogicOp & LOGIC_OP_DST)) 
+        {
             // blending / logic_op / masking need the framebuffer
             mDstPixel.setTo(regs.obtain(), &mCbFormat);
 
@@ -284,14 +292,16 @@
             pixel = mDstPixel;
         }
         
-        // logic operation
-        build_logic_op(pixel, regs);
-
-        // masking
-        build_masking(pixel, regs); 
-
-        comment("store");
-        store(parts.cbPtr, pixel, WRITE_BACK);
+        if (!mAllMasked) {
+            // logic operation
+            build_logic_op(pixel, regs);
+    
+            // masking
+            build_masking(pixel, regs); 
+    
+            comment("store");
+            store(parts.cbPtr, pixel, WRITE_BACK);
+        }
     }
 
     if (registerFile().status())
@@ -322,7 +332,9 @@
         build_smooth_shade(parts);
         build_iterate_z(parts);
         build_iterate_f(parts);
-        ADD(AL, 0, parts.cbPtr.reg, parts.cbPtr.reg, imm(parts.cbPtr.size>>3));
+        if (!mAllMasked) {
+            ADD(AL, 0, parts.cbPtr.reg, parts.cbPtr.reg, imm(parts.cbPtr.size>>3));
+        }
         SUB(AL, S, parts.count.reg, parts.count.reg, imm(1<<16));
         B(PL, "fragment_loop");
         epilog(registerFile().touched());
@@ -370,16 +382,18 @@
         MOV(AL, 0, parts.count.reg, reg_imm(parts.count.reg, LSL, 16));
     }
 
-    // compute dst ptr
-    comment("compute color-buffer pointer");
-    const int cb_bits = mCbFormat.size*8;
-    int Rs = scratches.obtain();
-    parts.cbPtr.setTo(obtainReg(), cb_bits);
-    CONTEXT_LOAD(Rs, state.buffers.color.stride);
-    CONTEXT_LOAD(parts.cbPtr.reg, state.buffers.color.data);
-    SMLABB(AL, Rs, Ry, Rs, Rx);  // Rs = Rx + Ry*Rs
-    base_offset(parts.cbPtr, parts.cbPtr, Rs);
-    scratches.recycle(Rs);
+    if (!mAllMasked) {
+        // compute dst ptr
+        comment("compute color-buffer pointer");
+        const int cb_bits = mCbFormat.size*8;
+        int Rs = scratches.obtain();
+        parts.cbPtr.setTo(obtainReg(), cb_bits);
+        CONTEXT_LOAD(Rs, state.buffers.color.stride);
+        CONTEXT_LOAD(parts.cbPtr.reg, state.buffers.color.data);
+        SMLABB(AL, Rs, Ry, Rs, Rx);  // Rs = Rx + Ry*Rs
+        base_offset(parts.cbPtr, parts.cbPtr, Rs);
+        scratches.recycle(Rs);
+    }
     
     // init fog
     const int need_fog = GGL_READ_NEEDS(P_FOG, needs.p);
@@ -904,8 +918,9 @@
 
 void GGLAssembler::build_masking(pixel_t& pixel, Scratch& regs)
 {
-    if (!mMasking)
+    if (!mMasking || mAllMasked) {
         return;
+    }
 
     comment("color mask");
 
@@ -928,7 +943,7 @@
 
     // There is no need to clear the masked components of the source
     // (unless we applied a logic op), because they're already zeroed 
-    // by contruction (masked components are not computed)
+    // by construction (masked components are not computed)
 
     if (mLogicOp) {
         const needs_t& needs = mBuilderContext.needs;
diff --git a/libpixelflinger/codeflinger/GGLAssembler.h b/libpixelflinger/codeflinger/GGLAssembler.h
index ccaf43d..d1d29f0 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.h
+++ b/libpixelflinger/codeflinger/GGLAssembler.h
@@ -363,6 +363,10 @@
                     const component_t& incoming,
                     const pixel_t& texel, int component, int tmu);
 
+    void    add(  component_t& dest,
+                    const component_t& incoming,
+                    const pixel_t& texel, int component);
+
     // load/store stuff
     void    store(const pointer_t& addr, const pixel_t& src, uint32_t flags=0);
     void    load(const pointer_t& addr, const pixel_t& dest, uint32_t flags=0);
@@ -517,6 +521,7 @@
     component_info_t    mInfo[4];
     int                 mBlending;
     int                 mMasking;
+    int                 mAllMasked;
     int                 mLogicOp;
     int                 mAlphaTest;
     int                 mAA;
diff --git a/libpixelflinger/codeflinger/blending.cpp b/libpixelflinger/codeflinger/blending.cpp
index 6d3b282..f10217b 100644
--- a/libpixelflinger/codeflinger/blending.cpp
+++ b/libpixelflinger/codeflinger/blending.cpp
@@ -50,6 +50,12 @@
         integer_t factor(scratches.obtain(), 16, CORRUPTIBLE);
         CONTEXT_LOAD(factor.reg, generated_vars.f);
 
+        // clamp fog factor (TODO: see if there is a way to guarantee
+        // we won't overflow, when setting the iterators)
+        BIC(AL, 0, factor.reg, factor.reg, reg_imm(factor.reg, ASR, 31));
+        CMP(AL, factor.reg, imm( 0x10000 ));
+        MOV(HS, 0, factor.reg, imm( 0x10000 ));
+
         build_blendFOneMinusF(temp, factor, fragment, fogColor);
     }
 }
diff --git a/libpixelflinger/codeflinger/load_store.cpp b/libpixelflinger/codeflinger/load_store.cpp
index 514ce07..93c5825 100644
--- a/libpixelflinger/codeflinger/load_store.cpp
+++ b/libpixelflinger/codeflinger/load_store.cpp
@@ -168,7 +168,7 @@
 void GGLAssembler::expand(component_t& d, const component_t& s, int dbits)
 {
     integer_t r(d.reg, 32, d.flags);
-    expand(r, d, dbits);
+    expand(r, s, dbits);
     d = component_t(r);
 }
 
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
index 269b6c0..90e6584 100644
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ b/libpixelflinger/codeflinger/texturing.cpp
@@ -1000,6 +1000,9 @@
                 case GGL_BLEND:
                     blend(fragment, incoming, texel, component, i);
                     break;
+                case GGL_ADD:
+                    add(fragment, incoming, texel, component);
+                    break;
                 }
             }
         }
@@ -1202,6 +1205,46 @@
     build_blendOneMinusFF(dest, factor, incomingNorm, color);
 }
 
+void GGLAssembler::add(
+        component_t& dest, 
+        const component_t& incoming,
+        const pixel_t& incomingTexel, int component)
+{
+    // RGBA:
+    // Cv = Cf + Ct;
+    Scratch locals(registerFile());
+    
+    component_t incomingTemp(incoming);
+
+    // use "dest" as a temporary for extracting the texel, unless "dest"
+    // overlaps "incoming".
+    integer_t texel(dest.reg, 32, CORRUPTIBLE);
+    if (dest.reg == incomingTemp.reg)
+        texel.reg = locals.obtain();
+    extract(texel, incomingTexel, component);
+
+    if (texel.s < incomingTemp.size()) {
+        expand(texel, texel, incomingTemp.size());
+    } else if (texel.s > incomingTemp.size()) {
+        if (incomingTemp.flags & CORRUPTIBLE) {
+            expand(incomingTemp, incomingTemp, texel.s);
+        } else {
+            incomingTemp.reg = locals.obtain();
+            expand(incomingTemp, incoming, texel.s);
+        }
+    }
+
+    if (incomingTemp.l) {
+        ADD(AL, 0, dest.reg, texel.reg,
+                reg_imm(incomingTemp.reg, LSR, incomingTemp.l));
+    } else {
+        ADD(AL, 0, dest.reg, texel.reg, incomingTemp.reg);
+    }
+    dest.l = 0;
+    dest.h = texel.size();
+    component_sat(dest);
+}
+
 // ----------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/libpixelflinger/format.cpp b/libpixelflinger/format.cpp
index c77eada..cbbd91a 100644
--- a/libpixelflinger/format.cpp
+++ b/libpixelflinger/format.cpp
@@ -21,13 +21,13 @@
 namespace android {
 
 static GGLFormat const gPixelFormatInfos[] =
-{
+{   //          Alpha    Red     Green   Blue
     {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
     {  4, 32, {{32,24,   8, 0,  16, 8,  24,16 }}, GGL_RGBA },   // PIXEL_FORMAT_RGBA_8888
     {  4, 24, {{ 0, 0,   8, 0,  16, 8,  24,16 }}, GGL_RGB  },   // PIXEL_FORMAT_RGBX_8888
     {  3, 24, {{ 0, 0,   8, 0,  16, 8,  24,16 }}, GGL_RGB  },   // PIXEL_FORMAT_RGB_888
     {  2, 16, {{ 0, 0,  16,11,  11, 5,   5, 0 }}, GGL_RGB  },   // PIXEL_FORMAT_RGB_565
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
+    {  4, 32, {{32,24,  24,16,  16, 8,   8, 0 }}, GGL_RGBA },   // PIXEL_FORMAT_BGRA_8888
     {  2, 16, {{ 1, 0,  16,11,  11, 6,   6, 1 }}, GGL_RGBA },   // PIXEL_FORMAT_RGBA_5551
     {  2, 16, {{ 4, 0,  16,12,  12, 8,   8, 4 }}, GGL_RGBA },   // PIXEL_FORMAT_RGBA_4444
     {  1,  8, {{ 8, 0,   0, 0,   0, 0,   0, 0 }}, GGL_ALPHA},   // PIXEL_FORMAT_A8
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index d24c988..75b668d 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -55,9 +55,11 @@
 #   define ANDROID_ARM_CODEGEN  0
 #endif
 
-
 #define DEBUG__CODEGEN_ONLY     0
 
+
+#define ASSEMBLY_SCRATCH_SIZE   2048
+
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
@@ -247,7 +249,8 @@
     sp<Assembly> assembly = gCodeCache.lookup(key);
     if (assembly == 0) {
         // create a new assembly region
-        sp<ScanlineAssembly> a = new ScanlineAssembly(c->state.needs, 1024);
+        sp<ScanlineAssembly> a = new ScanlineAssembly(c->state.needs, 
+                ASSEMBLY_SCRATCH_SIZE);
         // initialize our assembler
         GGLAssembler assembler( new ARMAssembler(a) );
         //GGLAssembler assembler(
@@ -676,6 +679,12 @@
                             Cf = ((((1<<st) - factor) * Cf) + Ct*Cc)>>st;
                         }
                         break;
+                    case GGL_ADD:
+                        if (st) {
+                            rescale(Cf, sf, Ct, st);
+                            Cf += Ct;
+                        }
+                        break;
                     }
                 }
             }
@@ -1473,7 +1482,7 @@
     needs.p = p;
     needs.t[0] = t0;
     needs.t[1] = t1;
-    sp<ScanlineAssembly> a(new ScanlineAssembly(needs, 1024));
+    sp<ScanlineAssembly> a(new ScanlineAssembly(needs, ASSEMBLY_SCRATCH_SIZE));
     GGLAssembler assembler( new ARMAssembler(a) );
     int err = assembler.scanline(needs, (context_t*)c);
     if (err != 0) {
diff --git a/libpixelflinger/tests/Android.mk b/libpixelflinger/tests/Android.mk
new file mode 100644
index 0000000..6571161
--- /dev/null
+++ b/libpixelflinger/tests/Android.mk
@@ -0,0 +1 @@
+include $(all-subdir-makefiles)
diff --git a/libpixelflinger/tests/codegen/Android.mk b/libpixelflinger/tests/codegen/Android.mk
new file mode 100644
index 0000000..1bc4214
--- /dev/null
+++ b/libpixelflinger/tests/codegen/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	codegen.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+    libpixelflinger
+
+LOCAL_MODULE:= test-opengl-codegen
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libpixelflinger/tests/codegen/codegen.cpp b/libpixelflinger/tests/codegen/codegen.cpp
new file mode 100644
index 0000000..1865888
--- /dev/null
+++ b/libpixelflinger/tests/codegen/codegen.cpp
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <stdint.h>
+
+extern "C" void ggl_test_codegen(
+        uint32_t n, uint32_t p, uint32_t t0, uint32_t t1);
+
+
+int main(int argc, char** argv)
+{
+    if (argc != 2) {
+        printf("usage: %s 00000117:03454504_00001501_00000000\n", argv[0]);
+        return 0;
+    }
+    uint32_t n;
+    uint32_t p;
+    uint32_t t0;
+    uint32_t t1;
+    sscanf(argv[1], "%08x:%08x_%08x_%08x", &p, &n, &t0, &t1);
+    ggl_test_codegen(n, p,  t0, t1);
+    return 0;
+}
diff --git a/logcat/event-log-tags b/logcat/event-log-tags
index 3ee5f8e..3d977a5 100644
--- a/logcat/event-log-tags
+++ b/logcat/event-log-tags
@@ -244,8 +244,8 @@
 50000 menu_item_selected (Menu type where 0 is options and 1 is context|1|5),(Menu item title|3)
 50001 menu_opened (Menu type where 0 is options and 1 is context|1|5)
 # Connectivity state changed:
-# [31-11] Reserved for future use
-# [10-9] Mobile network connection type (as defined by the TelephonyManager)
+# [31-13] Reserved for future use
+# [12- 9] Network subtype (for mobile network, as defined by TelephonyManager)
 # [ 8- 3] Detailed state ordinal (as defined by NetworkInfo.DetailedState)   
 # [ 2- 0] Network type (as defined by ConnectivityManager)
 50020 connectivity_state_changed (custom|1|5)
@@ -271,8 +271,9 @@
 50024 wifi_interface_configuration_state_changed (IP_configuration|1|5)
 
 # Wi-Fi supplicant connection state changed:
-# [31- 1] Reserved for future use
-# [ 0- 0] Connected to supplicant (1) or disconnected from supplicant (0)   
+# [31- 2] Reserved for future use
+# [ 1- 0] Connected to supplicant (1) or disconnected from supplicant (0),
+#         or supplicant died (2)
 50025 wifi_supplicant_connection_state_changed (connected|1|5)
 
 # PDP Context has a bad DNS address
@@ -291,6 +292,17 @@
 # Reregister to data network - timed out with no incoming packets.
 50104 pdp_reregister_network (out_packet_count|1|1)
 
+# PDP Setup failures
+50105 pdp_setup_fail (cause|1|5), (cid|1|5), (network_type|1|5)
+
+# Call drops 
+50106 call_drop (cause|1|5), (cid|1|5), (network_type|1|5)
+
+# Data network registration failed after successful voice registration
+50107 data_network_registration_fail (op_numeric|1|5), (cid|1|5)
+
+# Suspicious status of data connection while radio poweroff 
+50108 data_network_status_on_radio_off (dc_state|3), (enable|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
diff --git a/logwrapper/logwrapper.c b/logwrapper/logwrapper.c
index c7a2534..f00bfbf 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -21,7 +21,9 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
+#include <fcntl.h>
 
+#include "private/android_filesystem_config.h"
 #include "cutils/log.h"
 
 void fatal(const char *msg) {
@@ -32,48 +34,74 @@
 
 void usage() {
     fatal(
-        "Usage: logwrapper BINARY [ARGS ...]\n"
+        "Usage: logwrapper [-x] BINARY [ARGS ...]\n"
         "\n"
         "Forks and executes BINARY ARGS, redirecting stdout and stderr to\n"
         "the Android logging system. Tag is set to BINARY, priority is\n"
-        "always LOG_INFO.\n");
+        "always LOG_INFO.\n"
+        "\n"
+        "-x: Causes logwrapper to SIGSEGV when BINARY terminates\n"
+        "    fault address is set to the status of wait()\n");
 }
 
-void parent(const char *tag, int parent_read) {
+void parent(const char *tag, int seg_fault_on_exit, int parent_read) {
     int status;
-    char buffer[1024];
+    char buffer[4096];
 
     int a = 0;  // start index of unprocessed data
     int b = 0;  // end index of unprocessed data
     int sz;
-    while ((sz = read(parent_read, &buffer[b], 1023 - b)) > 0) {
+    while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
+
+        sz += b;
         // Log one line at a time
-        for (b = a; b < sz; b++) {
-            if (buffer[b] == '\n') {
+        for (b = 0; b < sz; b++) {
+            if (buffer[b] == '\r') {
+                buffer[b] = '\0';
+            } else if (buffer[b] == '\n') {
                 buffer[b] = '\0';
                 LOG(LOG_INFO, tag, &buffer[a]);
                 a = b + 1;
             }
         }
 
-        if (a == 0 && b == 1023) {
+        if (a == 0 && b == sizeof(buffer) - 1) {
             // buffer is full, flush
             buffer[b] = '\0';
             LOG(LOG_INFO, tag, &buffer[a]);
             b = 0;
-        } else {
+        } else if (a != b) {
             // Keep left-overs
-            b = sz - a;
+            b -= a;
             memmove(buffer, &buffer[a], b);
             a = 0;
+        } else {
+            a = 0;
+            b = 0;
         }
+
     }
     // Flush remaining data
     if (a != b) {
         buffer[b] = '\0';
         LOG(LOG_INFO, tag, &buffer[a]);
     }
-    wait(&status);  // Wait for child
+    status = 0xAAAA;
+    if (wait(&status) != -1) {  // Wait for child
+        if (WIFEXITED(status))
+            LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
+                    WEXITSTATUS(status));
+        else if (WIFSIGNALED(status))
+            LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
+                    WTERMSIG(status));
+        else if (WIFSTOPPED(status))
+            LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
+                    WSTOPSIG(status));
+    } else
+        LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
+                strerror(errno), errno);
+    if (seg_fault_on_exit)
+        *(int *)status = 0;  // causes SIGSEGV with fault_address = status
 }
 
 void child(int argc, char* argv[]) {
@@ -91,35 +119,62 @@
 
 int main(int argc, char* argv[]) {
     pid_t pid;
+    int seg_fault_on_exit = 0;
 
-    int pipe_fds[2];
-    int *parent_read = &pipe_fds[0];
-    int *child_write = &pipe_fds[1];
+    int parent_ptty;
+    int child_ptty;
+    char *child_devname = NULL;
 
     if (argc < 2) {
         usage();
     }
 
-    if (pipe(pipe_fds) < 0) {
-        fatal("Cannot create pipe\n");
+    if (strncmp(argv[1], "-d", 2) == 0) {
+        seg_fault_on_exit = 1;
+        argc--;
+        argv++;
+    }
+
+    if (argc < 2) {
+        usage();
+    }
+
+    /* Use ptty instead of socketpair so that STDOUT is not buffered */
+    parent_ptty = open("/dev/ptmx", O_RDWR);
+    if (parent_ptty < 0) {
+        fatal("Cannot create parent ptty\n");
+    }
+
+    if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
+            ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
+        fatal("Problem with /dev/ptmx\n");
     }
 
     pid = fork();
     if (pid < 0) {
         fatal("Failed to fork\n");
     } else if (pid == 0) {
+        child_ptty = open(child_devname, O_RDWR);
+        if (child_ptty < 0) {
+            fatal("Problem with child ptty\n");
+        }
+
         // redirect stdout and stderr
-        close(*parent_read);
-        dup2(*child_write, 1);
-        dup2(*child_write, 2);
-        close(*child_write);
+        close(parent_ptty);
+        dup2(child_ptty, 1);
+        dup2(child_ptty, 2);
+        close(child_ptty);
 
         child(argc - 1, &argv[1]);
 
     } else {
-        close(*child_write);
+        // switch user and group to "log"
+        // this may fail if we are not root, 
+        // but in that case switching user/group is unnecessary 
+        setgid(AID_LOG);
+        setuid(AID_LOG);
 
-        parent(argv[1], *parent_read);
+        parent(argv[1], seg_fault_on_exit, parent_ptty);
     }
 
     return 0;
diff --git a/mkbootimg/Android.mk b/mkbootimg/Android.mk
index e44bd99..a579de0 100644
--- a/mkbootimg/Android.mk
+++ b/mkbootimg/Android.mk
@@ -8,4 +8,4 @@
 
 include $(BUILD_HOST_EXECUTABLE)
 
-$(call dist-for-goals,user userdebug droid,$(LOCAL_BUILT_MODULE))
+$(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
diff --git a/mountd/ASEC.c b/mountd/ASEC.c
new file mode 100644
index 0000000..3d8e50e
--- /dev/null
+++ b/mountd/ASEC.c
@@ -0,0 +1,770 @@
+/*
+ * 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.
+ */
+
+/*
+** Android Secure External Cache 
+*/
+
+#include "mountd.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <poll.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <linux/loop.h>
+
+#include <cutils/properties.h>
+#include <cutils/misc.h>
+
+#include "ASEC.h"
+#include "dm-ioctl.h"
+
+extern int init_module(void *, unsigned long, const char *);
+extern int delete_module(const char *, unsigned int);
+
+struct asec_context
+{
+    char *name;           // Device mapper volume name
+    char *srcPath;        // Path to the source (original) mount
+    char *backingFile;    // Name of the image file
+    unsigned int sectors; // Number of sectors
+    char *dstPath;        // Destination mount point
+    char *crypt;          // Crypt options
+
+    boolean needs_format;
+    boolean started;
+    int cacheFd;
+    int lo_num;
+    int dm_num;
+    unsigned char key[16];
+};
+
+static const char *MODULES[] = { "dm_mod", "crypto", "crypto_algapi", "crypto_blkcipher", 
+                                 "cryptomgr", "dm_crypt", "jbd",  
+                                 "twofish_common", "twofish", "cbc",
+                                 "mbcache", "ext3",
+                                 NULL };
+static const char KEY_PATH[] = "/data/system/asec.key";
+static const char MODULE_PATH[] = "/system/lib/modules";
+static const char MKE2FS_PATH[] = "/system/bin/mke2fs";
+static const char E2FSCK_PATH[] = "/system/bin/e2fsck";
+
+boolean AsecIsStarted(void *Handle)
+{
+    struct asec_context *ctx = (struct asec_context *) Handle;
+
+    return ctx->started;
+}
+
+const char *AsecMountPoint(void *Handle)
+{
+    struct asec_context *ctx = (struct asec_context *) Handle;
+
+    return ctx->dstPath;
+}
+
+static boolean AsecIsEnabled()
+{
+    char value[PROPERTY_VALUE_MAX];
+    int  enabled;
+
+    property_get(ASEC_ENABLED, value, "0");
+
+    if (atoi(value) == 1)
+        return true;
+    return false;
+}
+
+void *AsecInit(const char *Name, const char *SrcPath, const char *BackingFile,
+               const char *Size, const char *DstPath, const char *Crypt)
+{
+    struct asec_context *ctx;
+
+    LOG_ASEC("AsecInit(%s, %s, %s, %s, %s, %s):\n",
+             Name, SrcPath, BackingFile, Size, DstPath, Crypt);
+
+    if (!AsecIsEnabled()) {
+        LOG_ERROR("AsecInit(): Disabled\n");
+        return NULL;
+    }
+
+    if (!Name || !SrcPath || !BackingFile || !Size || !DstPath || !Crypt) {
+        LOG_ERROR("AsecInit(): Invalid arguments\n");
+        return NULL;
+    }
+
+    if (!(ctx = malloc(sizeof(struct asec_context)))) {
+        LOG_ERROR("AsecInit(): Out of memory\n");
+        return NULL;
+    }
+
+    memset(ctx, 0, sizeof(struct asec_context));
+    ctx->name = strdup(Name);
+    ctx->srcPath = strdup(SrcPath);
+    ctx->backingFile = strdup(BackingFile);
+    ctx->sectors = atoi(Size);
+    ctx->dstPath = strdup(DstPath);
+    ctx->crypt = strdup(Crypt);
+    return ctx;
+}
+
+void AsecDeinit(void *Handle)
+{
+    struct asec_context *ctx = (struct asec_context *) Handle;
+
+    free(ctx->name);
+    free(ctx->srcPath);
+    free(ctx->backingFile);
+    free(ctx->dstPath);
+    free(ctx->crypt);
+
+    free(ctx);
+}
+
+static int AsecLoadModules()
+{
+    int i;
+
+    for (i = 0; MODULES[i] != NULL; i++) {
+	const char *moduleName = MODULES[i];
+        char moduleFile[255];
+        int rc = 0;
+        void *module;
+        unsigned int size;
+
+        sprintf(moduleFile, "%s/%s.ko", MODULE_PATH, moduleName);
+        module = load_file(moduleFile, &size);
+        if (!module) {
+            LOG_ERROR("Failed to load module %s\n", moduleFile);
+            return -1;
+        }
+
+        rc = init_module(module, size, "");
+        free(module);
+        if (rc && errno != EEXIST) {
+            LOG_ERROR("Failed to init module %s (%d)\n", moduleFile, errno);
+            return -errno;
+        }
+    }
+    return 0;
+}
+
+static int AsecUnloadModules()
+{
+    int i, j, rc;
+
+    for (i = 0; MODULES[i] != NULL; i++);
+
+    for (j = (i - 1); j >= 0; j--) {
+	const char *moduleName = MODULES[j];
+        int maxretry = 10;
+        while(maxretry-- > 0) {
+            rc = delete_module(moduleName, O_NONBLOCK | O_EXCL);
+            if (rc < 0 && errno == EAGAIN)
+                usleep(500000);
+            else
+                break;
+        }
+        if (rc != 0) {
+            LOG_ERROR("Failed to unload module %s\n", moduleName);
+            return -errno;
+        }
+    }
+    return 0;
+}
+
+static int AsecGenerateKey(struct asec_context *ctx)
+{
+    LOG_ASEC("AsecGenerateKey():\n");
+
+    memset((void *) ctx->key, 0x69, sizeof(ctx->key));
+    return 0;
+}
+
+static int AsecLoadGenerateKey(struct asec_context *ctx)
+{
+    int fd;
+    int rc = 0;
+
+    if ((fd = open(KEY_PATH, O_RDWR | O_CREAT, 0600)) < 0) {
+        LOG_ERROR("Error opening / creating keyfile (%d)\n", errno);
+        return -errno;
+    }
+
+    if (read(fd, ctx->key, sizeof(ctx->key)) != sizeof(ctx->key)) {
+        LOG_ASEC("Generating key\n");
+        if ((rc = AsecGenerateKey(ctx)) < 0) {
+            LOG_ERROR("Error generating key (%d)\n", rc);
+            goto out;
+        }
+        if (write(fd, ctx->key, sizeof(ctx->key)) != sizeof(ctx->key)) {
+            LOG_ERROR("Error writing keyfile (%d)\n", errno);
+            rc = -1;
+            goto out;
+        }
+    }
+    
+ out:
+    close (fd);
+    return rc;
+}
+
+static int AsecFormatFilesystem(struct asec_context *ctx)
+{
+    char cmdline[255];
+    int rc;
+
+    sprintf(cmdline,
+            "%s -b 4096 -m 1 -j -L \"%s\" /dev/block/dm-%d",
+            MKE2FS_PATH, ctx->name, ctx->dm_num);
+
+    LOG_ASEC("Formatting filesystem (%s)\n", cmdline);
+    // XXX: PROTECT FROM VIKING KILLER
+    if ((rc = system(cmdline)) < 0) {
+        LOG_ERROR("Error executing format command (%d)\n", errno);
+        return -errno;
+    }
+
+    rc = WEXITSTATUS(rc);
+
+    if (!rc) {
+        LOG_ASEC("Format completed\n");
+    } else {
+        LOG_ASEC("Format failed (%d)\n", rc);
+    }
+
+    return rc;
+}
+
+static int AsecCheckFilesystem(struct asec_context *ctx)
+{
+    char cmdline[255];
+    int rc;
+
+    sprintf(cmdline, "%s -p /dev/block/dm-%d", E2FSCK_PATH, ctx->dm_num);
+
+    LOG_ASEC("Checking filesystem (%s)\n", cmdline);
+    // XXX: PROTECT FROM VIKING KILLER
+    if ((rc = system(cmdline)) < 0) {
+        LOG_ERROR("Error executing check command (%d)\n", errno);
+        return -errno;
+    }
+
+    rc = WEXITSTATUS(rc);
+
+    if (rc == 0) {
+        LOG_ASEC("ASEC volume '%s' had no errors\n", ctx->name);
+    } else if (rc == 1) {
+        LOG_ASEC("ASEC volume '%s' had corrected errors\n", ctx->name);
+        rc = 0;
+    } else if (rc == 2) {
+        LOG_ERROR("ASEC volume '%s' had corrected errors (system should be rebooted)\n", ctx->name);
+    } else if (rc == 4) {
+        LOG_ERROR("ASEC volume '%s' had uncorrectable errors\n", ctx->name);
+    } else if (rc == 8) {
+        LOG_ERROR("Operational error while checking volume '%s'\n", ctx->name);
+    } else {
+        LOG_ERROR("Unknown e2fsck exit code (%d)\n", rc);
+    }
+    return rc;
+}
+
+static int AsecOpenCreateCache(struct asec_context *ctx)
+{
+    char filepath[255];
+
+    sprintf(filepath, "%s/%s", ctx->srcPath, ctx->backingFile);
+
+    if ((ctx->cacheFd = open(filepath, O_RDWR)) < 0) {
+        if (errno == ENOENT) {
+            int rc = 0;
+
+            LOG_ASEC("Creating cache file (%u sectors)\n", ctx->sectors);
+            if ((ctx->cacheFd = creat(filepath, 0600)) < 0) {
+                LOG_ERROR("Error creating cache (%d)\n", errno);
+                return -errno;
+            }
+            if (ftruncate(ctx->cacheFd, ctx->sectors * 512) < 0) {
+                LOG_ERROR("Error truncating cache (%d)\n", errno);
+                close(ctx->cacheFd);
+                unlink(filepath);
+                return -errno;
+            }
+            LOG_ASEC("Cache created (%u sectors) \n", ctx->sectors);
+            close(ctx->cacheFd); // creat() is WRONLY
+           
+            if ((ctx->cacheFd = open(filepath, O_RDWR)) < 0) {
+               LOG_ERROR("Error opening cache file (%d)\n", errno);
+                close(ctx->cacheFd);
+                unlink(filepath);
+                return -errno;
+            }
+
+            ctx->needs_format = 1;
+        } else
+            return -errno;
+    } else {
+        struct stat stat_buf;
+
+        if (fstat(ctx->cacheFd, &stat_buf) < 0) {
+            LOG_ERROR("Failed to fstat cache (%d)\n", errno);
+            close(ctx->cacheFd);
+            return -errno;
+        }
+        if (stat_buf.st_size != ctx->sectors * 512) {
+            LOG_ERROR("Cache size %lld != configured size %u\n",
+                      stat_buf.st_size, ctx->sectors * 512);
+        }
+
+        // XXX: Verify volume label matches ctx->name
+    }
+
+    return 0;
+}
+
+static void AsecCloseCache(struct asec_context *ctx)
+{
+    close(ctx->cacheFd);
+}
+
+static void *_align(void *ptr, unsigned int a)
+{
+        register unsigned long agn = --a;
+
+        return (void *) (((unsigned long) ptr + agn) & ~agn);
+}
+
+static struct dm_ioctl *_dm_ioctl_setup(struct asec_context *ctx, int flags)
+{
+    void *buffer;
+    void *p;
+    const size_t min_size = 16 * 1024;
+    size_t len = sizeof(struct dm_ioctl);
+    struct dm_ioctl *io;
+    struct dm_target_spec *tgt;
+    int i;
+    char params[1024];
+    char key[80];
+
+    key[0] = '\0';
+
+    for (i = 0; i < (int) sizeof(ctx->key); i++) {
+        char tmp[8];
+
+        sprintf(tmp, "%02x", ctx->key[i]);
+        strcat(key, tmp);
+    }
+
+    // XXX: Handle ctx->crypt 
+    sprintf(params, "twofish %s 0 /dev/block/loop%d 0", key, ctx->lo_num);
+ 
+    if (len < min_size)
+        len = min_size;
+
+    if (!(buffer = malloc(len))) {
+        LOG_ERROR("Unable to allocate memory\n");
+        return NULL;
+    }
+
+    memset(buffer, 0, len);
+    io = buffer;
+    tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
+    
+    io->version[0] = 4;
+    io->version[1] = 0;
+    io->version[2] = 0;
+
+    io->data_size = len;
+    io->data_start = sizeof(struct dm_ioctl);
+
+    io->flags = flags;
+    io->dev = 0; 
+
+    io->target_count = 1;
+    io->event_nr = 1;
+    strncpy(io->name, ctx->name, sizeof(io->name));
+
+    tgt->status = 0;
+    tgt->sector_start = 0;
+    tgt->length = ctx->sectors;
+    strncpy(tgt->target_type, "crypt", sizeof(tgt->target_type));
+
+    p = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
+    strcpy((char *) p, params);
+    p+= strlen(params) + 1;
+
+    p = _align(p, 8);
+    tgt->next = p - buffer;
+
+    return io;
+}
+
+static int FindNextAvailableDm()
+{
+    int i;
+
+    for (i = 0; i < 8; i++) {
+        char path[255];
+        sprintf(path, "/dev/block/dm-%d", i);
+        if ((access(path, F_OK) < 0) && (errno == ENOENT))
+            return i;
+    }
+
+    LOG_ERROR("Out of device mapper numbers\n");
+    return -1;
+}
+
+static int AsecCreateDeviceMapping(struct asec_context *ctx)
+{
+    struct dm_ioctl       *io;
+    int                   dmFd;
+    int                   rc = 0;
+
+    ctx->dm_num = FindNextAvailableDm();
+
+    if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
+        LOG_ERROR("Error opening device mapper (%d)\n", errno);
+        return -errno;
+    }
+
+    if (!(io = _dm_ioctl_setup(ctx, 0))) {
+        LOG_ERROR("Unable to setup ioctl (out of memory)\n");
+        close(dmFd);
+        return -ENOMEM;
+    }
+
+    if ((rc = ioctl(dmFd, DM_DEV_CREATE, io)) < 0) {
+        LOG_ERROR("device-mapper create ioctl failed (%d)\n", errno);
+        rc = -errno;
+        goto out_free;
+    } 
+
+    free(io);
+
+    if (!(io = _dm_ioctl_setup(ctx, DM_STATUS_TABLE_FLAG))) {
+        LOG_ERROR("Unable to setup ioctl (out of memory)\n");
+        rc = -ENOMEM;
+        goto out_nofree;
+    }
+ 
+    if ((rc = ioctl(dmFd, DM_TABLE_LOAD, io)) < 0) {
+        LOG_ERROR("device-mapper load ioctl failed (%d)\n", errno);
+        rc = -errno;
+        goto out_free;
+    }
+
+    free(io);
+ 
+    if (!(io = _dm_ioctl_setup(ctx, 0))) {
+        LOG_ERROR("Unable to setup ioctl (out of memory)\n");
+        rc = -ENOMEM;
+        goto out_nofree;
+    }
+
+    if ((rc = ioctl(dmFd, DM_DEV_SUSPEND, io)) < 0) {
+        LOG_ERROR("device-mapper resume ioctl failed (%d)\n", errno);
+        rc = -errno;
+        goto out_free;
+    }
+
+out_free:
+    free (io);
+out_nofree:
+    close (dmFd);
+    return rc;
+}
+
+static int AsecDestroyDeviceMapping(struct asec_context *ctx)
+{
+    struct dm_ioctl       *io;
+    int                   dmFd;
+    int                   rc = 0;
+
+    if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
+        LOG_ERROR("Error opening device mapper (%d)\n", errno);
+        return -errno;
+    }
+
+    if (!(io = _dm_ioctl_setup(ctx, DM_PERSISTENT_DEV_FLAG))) {
+        LOG_ERROR("Unable to setup ioctl (out of memory)\n");
+        rc = -ENOMEM;
+        goto out_nofree;
+    }
+
+    if ((rc = ioctl(dmFd, DM_DEV_REMOVE, io)) < 0) {
+        LOG_ERROR("device-mapper remove ioctl failed (%d)\n", errno);
+        rc = -errno;
+        goto out_free;
+    } 
+
+out_free:
+    free (io);
+out_nofree:
+    close (dmFd);
+    return rc;
+}
+
+static int AsecMountCache(struct asec_context *ctx)
+{
+    int flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_NOATIME | MS_NODIRATIME;
+    char devname[255];
+
+    if (access(ctx->dstPath, R_OK)) {
+        LOG_ERROR("Destination mount point '%s' unavailable (%d)\n", ctx->dstPath, errno);
+        return -errno;
+    }
+
+    sprintf(devname, "/dev/block/dm-%d", ctx->dm_num);
+
+    if (mount(devname, ctx->dstPath, "ext3", flags, NULL)) {
+        LOG_ERROR("ASEC mount failed (%d)\n", errno);
+        return -errno;
+    }
+    
+    return 0;
+}
+
+static int AsecUnmountCache(struct asec_context *ctx)
+{
+    if (umount(ctx->dstPath)) {
+        if (errno == EBUSY) {
+            LOG_ASEC("ASEC volume '%s' still busy\n", ctx->name);
+        } else {
+            LOG_ERROR("ASEC umount failed (%d)\n", errno);
+        }
+        return -errno;
+    }
+    LOG_ASEC("ASEC volume '%s' unmounted\n", ctx->name);
+    return 0;
+}
+
+static int FindNextAvailableLoop()
+{
+    int i;
+
+    for (i = 0; i < MAX_LOOP; i++) {
+        struct loop_info info;
+        char devname[255];
+        int fd;
+
+        sprintf(devname, "/dev/block/loop%d", i);
+
+        if ((fd = open(devname, O_RDONLY)) < 0) {
+            LOG_ERROR("Unable to open %s (%d)\n", devname, errno);
+            return -errno;
+        }
+
+        if (ioctl(fd, LOOP_GET_STATUS, &info) < 0) {
+            close(fd);
+
+            if (errno == ENXIO)
+                return i;
+
+            LOG_ERROR("Unable to get loop status for %s (%d)\n", devname, errno);
+            return -errno;
+        }
+        close(fd);
+    }
+    return -ENXIO;
+}
+
+static int AsecCreateLoop(struct asec_context *ctx)
+{
+    char devname[255];
+    int device_fd;
+    int rc = 0;
+
+    ctx->lo_num = FindNextAvailableLoop();
+    if (ctx->lo_num < 0) {
+        LOG_ERROR("No loop devices available\n");
+        return -ENXIO;
+    }
+
+    sprintf(devname, "/dev/block/loop%d", ctx->lo_num);
+    device_fd = open(devname, O_RDWR);
+    if (device_fd < 0) {
+        LOG_ERROR("failed to open loop device (%d)\n", errno);
+        return -errno;
+    }
+
+    if (ioctl(device_fd, LOOP_SET_FD, ctx->cacheFd) < 0) {
+        LOG_ERROR("loop_set_fd ioctl failed (%d)\n", errno);
+        rc = -errno;
+    }
+    close(device_fd);
+    return rc;
+}
+
+static int AsecDestroyLoop(struct asec_context *ctx)
+{
+    char devname[255];
+    int device_fd;
+    int rc = 0;
+
+    sprintf(devname, "/dev/block/loop%d", ctx->lo_num);
+    device_fd = open(devname, O_RDONLY);
+    if (device_fd < 0) {
+        LOG_ERROR("Failed to open loop (%d)\n", errno);
+        return -errno;
+    }
+
+    if (ioctl(device_fd, LOOP_CLR_FD, 0) < 0) {
+        LOG_ERROR("Failed to destroy loop (%d)\n", errno);
+        rc = -errno;
+    }
+
+    close(device_fd);
+    return rc;
+}
+
+int AsecStart(void *Handle)
+{
+    struct asec_context *ctx = (struct asec_context *) Handle;
+    char value[PROPERTY_VALUE_MAX];
+    int rc = 0;
+
+    if (!ctx)
+        return -EINVAL;
+
+    if (ctx->started)
+        return -EBUSY;
+
+    LOG_ASEC("AsecStart(%s):\n", ctx->name);
+
+    NotifyAsecState(ASEC_BUSY, ctx->dstPath);
+
+    if ((rc = AsecLoadModules()) < 0) {
+        LOG_ERROR("AsecStart: Failed to load kernel modules\n");
+        NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+	return rc;
+    }
+
+    if ((rc = AsecLoadGenerateKey(ctx))) {
+        LOG_ERROR("AsecStart: Failed to load / generate key\n");
+        NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+	return rc;
+    }
+    
+    if ((rc = AsecOpenCreateCache(ctx)) < 0) {
+        LOG_ERROR("AsecStart: Failed to open / create cache\n");
+        NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+	return rc;
+    }
+
+    if ((rc = AsecCreateLoop(ctx)) < 0) {
+        LOG_ERROR("AsecStart: Failed to create loop\n");
+        NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+	goto fail_closecache;
+    }
+
+    if ((rc = AsecCreateDeviceMapping(ctx)) < 0) {
+        LOG_ERROR("AsecStart: Failed to create devmapping (%d)\n", rc);
+        NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+        goto fail_destroyloop;
+    }
+    
+    if (ctx->needs_format) {
+        if ((rc = AsecFormatFilesystem(ctx))) {
+            LOG_ERROR("AsecStart: Failed to format cache (%d)\n", rc);
+            NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+            goto fail_destroydm;
+        }
+        ctx->needs_format = 0;
+    } else {
+        if ((rc = AsecCheckFilesystem(ctx))) {
+            LOG_ERROR("AsecStart: Failed to check filesystem (%d)\n", rc);
+            NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+            goto fail_destroydm;
+        }
+    }
+
+    if ((rc = AsecMountCache(ctx)) < 0) {
+        LOG_ERROR("AsecStart: Failed to mount cache (%d)\n", rc);
+        NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+        goto fail_destroydm;
+    }
+    
+    NotifyAsecState(ASEC_AVAILABLE, ctx->dstPath);
+    ctx->started = true;
+
+    return rc;
+
+ fail_destroydm:
+    AsecDestroyDeviceMapping(ctx);
+ fail_destroyloop:
+    AsecDestroyLoop(ctx);
+ fail_closecache:
+    AsecCloseCache(ctx);
+    return rc;
+}
+
+int AsecStop(void *Handle)
+{
+    struct asec_context *ctx = (struct asec_context *) Handle;
+    int rc = 0;
+
+    if (!ctx->started)
+        return -EINVAL;
+
+    LOG_ASEC("AsecStop(%s):\n", ctx->name);
+
+    NotifyAsecState(ASEC_BUSY, ctx->dstPath);
+
+    if ((rc = AsecUnmountCache(ctx)) < 0) {
+        LOG_ERROR("AsecStop: Failed to unmount cache (%d)\n", rc);
+        NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+	return rc;
+    }
+
+    if ((rc = AsecDestroyDeviceMapping(ctx)) < 0) {
+        LOG_ERROR("AsecStop: Failed to destroy devmapping (%d)\n", rc);
+        NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+	return rc;
+    }
+
+    if ((rc = AsecDestroyLoop(ctx)) < 0) {
+        LOG_ERROR("AsecStop: Failed to destroy loop device (%d)\n", rc);
+        NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+	return rc;
+    }
+
+    AsecCloseCache(ctx);
+ 
+    if ((rc = AsecUnloadModules()) < 0) {
+        if (rc == -EAGAIN) {
+            LOG_ASEC("AsecStop: Kernel modules still in use\n");
+        } else {
+            LOG_ERROR("AsecStop: Failed to unload kernel modules (%d)\n", rc);
+            NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+	    return rc;
+        }
+    }
+
+    ctx->started = false;
+    NotifyAsecState(ASEC_DISABLED, ctx->dstPath);
+    return rc;
+}
diff --git a/mountd/ASEC.h b/mountd/ASEC.h
new file mode 100644
index 0000000..c87b288
--- /dev/null
+++ b/mountd/ASEC.h
@@ -0,0 +1,66 @@
+#ifndef _ASEC_H
+#define _ASEC_H
+
+#define ASEC_STORES_MAX 4
+#define MAX_LOOP 8
+
+typedef enum AsecState {
+    // Feature disabled
+    ASEC_DISABLED,
+
+    // Feature enabled and operational
+    ASEC_AVAILABLE,
+
+    // Busy
+    ASEC_BUSY,
+
+    // Internal Error
+    ASEC_FAILED_INTERR,
+
+    // No media available
+    ASEC_FAILED_NOMEDIA,
+
+    // Media is corrupt
+    ASEC_FAILED_BADMEDIA,
+
+    // Key mismatch
+    ASEC_FAILED_BADKEY,
+} AsecState;
+
+/*
+ * ASEC commands
+ */
+#define ASEC_CMD_SEND_STATUS		"asec_send_status"
+#define ASEC_CMD_ENABLE			"asec_enable"
+#define ASEC_CMD_DISABLE		"asec_disable"
+
+/*
+ * ASEC events
+ */
+
+// These events correspond to the states in the AsecState enum.
+// A path to the ASEC mount point follows the colon
+#define ASEC_EVENT_DISABLED		"asec_disabled:"
+#define ASEC_EVENT_AVAILABLE		"asec_available:"
+#define ASEC_EVENT_BUSY			"asec_busy:"
+#define ASEC_EVENT_FAILED_INTERR	"asec_failed_interror:"
+#define ASEC_EVENT_FAILED_NOMEDIA	"asec_failed_nomedia"
+#define ASEC_EVENT_FAILED_BADMEDIA	"asec_failed_badmedia:"
+#define ASEC_EVENT_FAILED_BADKEY	"asec_failed_badkey:"
+
+/*
+ * System Properties
+ */
+
+#define ASEC_ENABLED			"asec.enabled"
+
+#define ASEC_STATUS			"ro.asec.status"
+#define ASEC_STATUS_DISABLED		"disabled"
+#define ASEC_STATUS_AVAILABLE		"available"
+#define ASEC_STATUS_BUSY			"busy"
+#define ASEC_STATUS_FAILED_INTERR	"internal_error"
+#define ASEC_STATUS_FAILED_NOMEDIA	"no_media"
+#define ASEC_STATUS_FAILED_BADMEDIA	"bad_media"
+#define ASEC_STATUS_FAILED_BADKEY	"bad_key"
+
+#endif
diff --git a/mountd/Android.mk b/mountd/Android.mk
index 87bcef3..bc128ac 100644
--- a/mountd/Android.mk
+++ b/mountd/Android.mk
@@ -6,7 +6,8 @@
     AutoMount.c          \
     ProcessKiller.c      \
     Server.c             \
-    mountd.c
+    mountd.c		 \
+    ASEC.c
 
 LOCAL_MODULE:= mountd
 
diff --git a/mountd/AutoMount.c b/mountd/AutoMount.c
index bfe8ad1..0aac871 100644
--- a/mountd/AutoMount.c
+++ b/mountd/AutoMount.c
@@ -76,17 +76,20 @@
     
     // mount point for device
     const char* mountPoint;
+
+    // path to the UMS driver file for specifying the block device path
+    const char* driverStorePath;
     
     // true if device can be shared via
     // USB mass storage
     boolean enableUms;
-    
+ 
+    // Array of ASEC handles
+    void *asecHandles[ASEC_STORES_MAX];
+
     // true if the device is being shared via USB mass storage
     boolean umsActive;
     
-    // logical unit number (for UMS)
-    int lun;
-    
     // current state of the mount point
     MountState state;
     
@@ -100,11 +103,13 @@
 
 // list of our mount points (does not change after initialization)
 static MountPoint* sMountPointList = NULL;
-static int sNextLun = 0;
 boolean gMassStorageEnabled = false;
 boolean gMassStorageConnected = false;
 
 static pthread_t sAutoMountThread = 0;
+static pid_t gExcludedPids[2] = {-1, -1};
+
+static const char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos";
 
 // number of mount points that have timeouts pending
 static int sRetriesPending = 0;
@@ -116,15 +121,18 @@
 // via USB mass storage.
 static void SetBackingStore(MountPoint* mp, boolean enable) 
 {
-    char path[PATH_MAX];
     int fd;
 
+    if (!mp->driverStorePath) {
+        LOG_ERROR("no driver_store_path specified in config file for %s", mp->device);
+        return;
+    }
+
     LOG_MOUNT("SetBackingStore enable: %s\n", (enable ? "true" : "false"));
-    snprintf(path, sizeof(path), "/sys/devices/platform/usb_mass_storage/lun%d/file", mp->lun);
-    fd = open(path, O_WRONLY);
+    fd = open(mp->driverStorePath, O_WRONLY);
     if (fd < 0)
     {
-        LOG_ERROR("could not open %s\n", path);
+        LOG_ERROR("could not open driver_store_path %s\n", mp->driverStorePath);
     }
     else
     {
@@ -192,6 +200,56 @@
     return result;
 }
 
+static int CheckFilesystem(const char *device)
+{
+    char cmdline[255];
+    int rc;
+
+    // XXX: SAN: Check for FAT signature
+    
+    int result = access(FSCK_MSDOS_PATH, X_OK);
+    if (result != 0) {
+        LOG_MOUNT("CheckFilesystem(%s): fsck_msdos not found (skipping checks)\n", device);
+        return 0;
+    }
+ 
+    sprintf(cmdline, "%s -p %s", FSCK_MSDOS_PATH, device);
+    LOG_MOUNT("Checking filesystem (%s)\n", cmdline);
+
+    // XXX: Notify framework we're disk checking
+  
+    // XXX: PROTECT FROM VIKING KILLER
+    if ((rc = system(cmdline)) < 0) {
+        LOG_ERROR("Error executing disk check command (%d)\n", errno);
+        return -errno;
+    } 
+
+    rc = WEXITSTATUS(rc);
+  
+    if (rc == 0) {
+        LOG_MOUNT("Filesystem check completed OK\n");
+        return 0;
+    } else if (rc == 1) {
+        LOG_MOUNT("Filesystem check failed (invalid usage)\n");
+        return -EINVAL;
+    } else if (rc == 2) {
+        LOG_MOUNT("Filesystem check failed (unresolved issues)\n");
+        return -EIO;
+    } else if (rc == 4) {
+        LOG_MOUNT("Filesystem check failed (root changed)\n");
+        return -EIO;
+    } else if (rc == 8) {
+        LOG_MOUNT("Filesystem check failed (general failure)\n");
+        return -EIO;
+    } else if (rc == 12) {
+        LOG_MOUNT("Filesystem check failed (exit signaled)\n");
+        return -EIO;
+    } else {
+        LOG_MOUNT("Filesystem check failed (unknown exit code %d)\n", rc);
+        return -EIO;
+    }
+}
+
 static int DoMountDevice(const char* device, const char* mountPoint)
 {
     LOG_MOUNT("mounting %s at %s\n", device, mountPoint);
@@ -237,6 +295,17 @@
     if (result != 0)
         return result;
 
+    if ((result = CheckFilesystem(device))) {
+        LOG_ERROR("Not mounting filesystem due to check failure (%d)\n", result);
+        // XXX:  Notify framework - need a new SDCARD state for the following:
+        //       - SD cards which are not present
+        //       - SD cards with no partition table
+        //       - SD cards with no filesystem
+        //       - SD cards with bad filesystem
+        return result;
+    }
+    
+
     // Extra safety measures:
     flags |= MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
     // Also, set fmask = 711 so that files cannot be marked executable,
@@ -254,6 +323,24 @@
 
     if (result == 0) {
         NotifyMediaState(mountPoint, MEDIA_MOUNTED, (flags & MS_RDONLY) != 0);
+
+        MountPoint* mp = sMountPointList;
+        while (mp) {
+            if (!strcmp(mountPoint, mp->mountPoint)) {
+                int i;
+             
+                for (i = 0; i < ASEC_STORES_MAX; i++) {
+                    if (mp->asecHandles[i] != NULL) {
+                        int a_result;
+                        if ((a_result = AsecStart(mp->asecHandles[i])) < 0) {
+                            LOG_ERROR("ASEC start failure (%d)\n", a_result);
+                        }
+                    }
+                }
+                break;
+            }
+            mp = mp -> next;
+        }
     } else if (errno == EBUSY) {
     // ignore EBUSY, since it usually means the device is already mounted
         result = 0;
@@ -267,32 +354,39 @@
     return result;
 }
 
-static int DoUnmountDevice(const char* mountPoint)
+static int DoUnmountDevice(MountPoint *mp)
 {
-    boolean loop = IsLoopMounted(mountPoint);
-    int result = umount(mountPoint);
+    boolean loop = IsLoopMounted(mp->mountPoint);
+    int i;
+
+    for (i = 0; i < ASEC_STORES_MAX; i++) {
+        if (mp->asecHandles[i] && AsecIsStarted(mp->asecHandles[i]))
+            AsecStop(mp->asecHandles[i]);
+    }
+
+    int result = umount(mp->mountPoint);
     LOG_MOUNT("umount returned %d errno: %d\n", result, errno);
 
     if (result == 0)
     {
-        if (loop)
-        {
-            // free the loop device
-            int loop_fd = open(LOOP_DEVICE, O_RDONLY);
-            if (loop_fd < -1) {
-                LOG_ERROR("open loop device failed\n");
-            }
-            if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
-                LOG_ERROR("ioctl LOOP_CLR_FD failed\n");
-            }
-
-            close(loop_fd);
-        }
-
 #if CREATE_MOUNT_POINTS
         rmdir(mountPoint);
 #endif
-        NotifyMediaState(mountPoint, MEDIA_UNMOUNTED, false);
+        NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTED, false);
+    }
+
+    if (loop)
+    {
+        // free the loop device
+        int loop_fd = open(LOOP_DEVICE, O_RDONLY);
+        if (loop_fd < -1) {
+            LOG_ERROR("open loop device failed\n");
+        }
+        if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
+            LOG_ERROR("ioctl LOOP_CLR_FD failed\n");
+        }
+
+        close(loop_fd);
     }
 
     // ignore EINVAL and ENOENT, since it usually means the device is already unmounted
@@ -408,7 +502,7 @@
         sync();
         DropSystemCaches();
 
-        if (DoUnmountDevice(mp->mountPoint) == 0) 
+        if (DoUnmountDevice(mp) == 0) 
         {
             SetState(mp, kUnmounted);
             if (retryState == kUnmountingForUms) 
@@ -502,6 +596,8 @@
 {
     MountPoint* mp = sMountPointList;
     
+    LOG_MOUNT("HandleMediaInserted(%s):\n", device);
+
     while (mp)
     {
         // see if the device matches mount point's block device
@@ -573,7 +669,7 @@
        } 
        else if (mp->state == kUnmountingForEject || mp->state == kUnmountingForUms)
        {
-            if (DoUnmountDevice(mp->mountPoint) == 0)
+            if (DoUnmountDevice(mp) == 0)
             {
                 // unmounting succeeded
                 // start mass storage, if state is kUnmountingForUms
@@ -594,8 +690,25 @@
                     // send SIGKILL instead of SIGTERM if the first attempt did not succeed
                     boolean sigkill = (mp->retryCount > MAX_UNMOUNT_RETRIES);
                     
+                    int i;
+
+                    for (i = 0; i < ASEC_STORES_MAX; i++) {
+                        if (mp->asecHandles[i] && AsecIsStarted(mp->asecHandles[i])) {
+                            LOG_MOUNT("Killing processes for ASEC path '%s'\n",
+                                      AsecMountPoint(mp->asecHandles[i]));
+                            KillProcessesWithOpenFiles(AsecMountPoint(mp->asecHandles[i]),
+                                                       sigkill,
+                                                       gExcludedPids, sizeof(gExcludedPids) / sizeof(pid_t));
+
+                            // Now that we've killed the processes, try to stop the volume again
+                            AsecStop(mp->asecHandles[i]);
+                        }
+                    }
+
                     // unmounting the device is failing, so start killing processes
-                    KillProcessesWithOpenFiles(mp->mountPoint, sigkill);
+                    KillProcessesWithOpenFiles(mp->mountPoint, sigkill, gExcludedPids, 
+                                               sizeof(gExcludedPids) / sizeof(pid_t));
+
                 }
             }
        } 
@@ -676,6 +789,8 @@
     int id;
     struct sigaction    actions;
 
+    gExcludedPids[1] = getpid();
+
     memset(&actions, 0, sizeof(actions));
     sigemptyset(&actions.sa_mask);
     actions.sa_flags = 0;
@@ -829,7 +944,9 @@
 void MountMedia(const char* mountPoint)
 {
     MountPoint* mp = sMountPointList;
-    
+ 
+    LOG_MOUNT("MountMedia(%s)\n", mountPoint);
+   
     pthread_mutex_lock(&sMutex);
     while (mp)
     {
@@ -883,27 +1000,48 @@
  * 
  ***********************************************/
  
-void AddMountPoint(const char* device, const char* mountPoint, boolean enableUms)
+void *AddMountPoint(const char* device, const char* mountPoint, const char * driverStorePath, boolean enableUms)
 {
     MountPoint* newMountPoint;
     
-    LOG_MOUNT("AddMountPoint device: %s, mountPoint: %s\n", device, mountPoint);
+    LOG_MOUNT("AddMountPoint device: %s, mountPoint: %s driverStorePath: %s\n", device, mountPoint, driverStorePath);
     // add a new MountPoint to the head of our linked list
     newMountPoint = (MountPoint *)malloc(sizeof(MountPoint));
     newMountPoint->device = device;
     newMountPoint->mountPoint = mountPoint;
+    newMountPoint->driverStorePath = driverStorePath;
     newMountPoint->enableUms = enableUms;
     newMountPoint->umsActive = false;
-    if (enableUms)
-        newMountPoint->lun = sNextLun++;
     newMountPoint->state = kUnmounted;
     newMountPoint->retryCount = 0;
 
     // add to linked list
     newMountPoint->next = sMountPointList;
     sMountPointList = newMountPoint;
+    return newMountPoint;
 }
 
+int AddAsecToMountPoint(void *Mp, const char *name, const char *backing_file, const char *size,
+                        const char *mount_point, const char *crypt)
+{
+    MountPoint *mp = (MountPoint *) Mp;
+    int i;
+
+    for (i = 0; i < ASEC_STORES_MAX; i++) {
+        if (!mp->asecHandles[i])
+            break;   
+    }
+
+    if (i == ASEC_STORES_MAX) {
+        LOG_ERROR("Maximum # of ASEC stores exceeded\n");
+        return -EINVAL;
+    }
+
+    if (!(mp->asecHandles[i] = AsecInit(name, mp->mountPoint, backing_file, size, mount_point, crypt)))
+        return -1;
+
+    return 0;
+}
 static void MountDevices()
 {
     MountPoint* mp = sMountPointList;
@@ -916,6 +1054,8 @@
 
 void StartAutoMounter()
 {
+    gExcludedPids[0] = getpid();
+
     gMassStorageConnected = ReadMassStorageState();
     LOG_MOUNT(gMassStorageConnected ? "USB online\n" : "USB offline\n");
 
diff --git a/mountd/ProcessKiller.c b/mountd/ProcessKiller.c
index 3ce7aa8..e377774 100644
--- a/mountd/ProcessKiller.c
+++ b/mountd/ProcessKiller.c
@@ -177,7 +177,7 @@
 }
 
 // hunt down and kill processes that have files open on the given mount point
-void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill)
+void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded)
 {
     DIR*    dir;
     struct dirent* de;
@@ -200,8 +200,21 @@
                 || CheckSymLink(pid, mountPoint, "exe", "executable path")      // check executable path
             ) 
         {
-            LOG_ERROR("Killing process %d\n", pid);
-            kill(pid, (sigkill ? SIGKILL : SIGTERM));
+            int i;
+            boolean hit = false;
+
+            for (i = 0; i < num_excluded; i++) {
+                if (pid == excluded[i]) {
+                    LOG_ERROR("I just need a little more TIME captain!\n");
+                    hit = true;
+                    break;
+                }
+            }
+
+            if (!hit) {
+                LOG_ERROR("Killing process %d\n", pid);
+                kill(pid, (sigkill ? SIGKILL : SIGTERM));
+            }
         }
     }
 
diff --git a/mountd/Server.c b/mountd/Server.c
index 14b3830..64459bd 100644
--- a/mountd/Server.c
+++ b/mountd/Server.c
@@ -19,6 +19,7 @@
 */
 
 #include "mountd.h"
+#include "ASEC.h"
 
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
@@ -43,6 +44,10 @@
 // path for media that failed to mount before the runtime is connected
 static char* sDeferredUnmountableMediaPath = NULL;
 
+// last asec msg before the runtime was connected
+static char* sAsecDeferredMessage = NULL;
+static char* sAsecDeferredArgument = NULL;
+
 static int Write(const char* message)
 {
     int result = -1;
@@ -107,6 +112,18 @@
     {
         const char* path = command + strlen(MOUNTD_EJECT_MEDIA);
         UnmountMedia(path);
+    } 
+    else if (strncmp(command, ASEC_CMD_ENABLE, strlen(ASEC_CMD_ENABLE)) == 0) {
+        LOG_ASEC("Got ASEC_CMD_ENABLE\n");
+	// XXX: SAN: Impliment
+    }
+    else if (strncmp(command, ASEC_CMD_DISABLE, strlen(ASEC_CMD_DISABLE)) == 0) {
+        LOG_ASEC("Got ASEC_CMD_DISABLE\n");
+	// XXX: SAN: Impliment
+    }
+    else if (strncmp(command, ASEC_CMD_SEND_STATUS, strlen(ASEC_CMD_SEND_STATUS)) == 0) {
+        LOG_ASEC("Got ASEC_CMD_SEND_STATUS\n");
+	// XXX: SAN: Impliment
     }
     else
         LOGE("unknown command %s\n", command);
@@ -145,6 +162,15 @@
             sDeferredUnmountableMediaPath = NULL;
         }
 
+        if (sAsecDeferredMessage) {
+    
+            if (Write2(sAsecDeferredMessage, sAsecDeferredArgument) < 0)
+                LOG_ERROR("Failed to deliver deferred ASEC msg to framework\n");
+            free(sAsecDeferredMessage);
+            free(sAsecDeferredArgument);
+            sAsecDeferredMessage = sAsecDeferredArgument = NULL;
+        }
+
         while (1)
         {    
             char    buffer[101];
@@ -187,6 +213,61 @@
     Write2(MOUNTD_REQUEST_EJECT, path);
 }
 
+void NotifyAsecState(AsecState state, const char *argument)
+{
+    const char *event = NULL;
+    const char *status = NULL;
+    boolean deferr = true;;
+
+    switch (state) {
+        case ASEC_DISABLED:
+            event = ASEC_EVENT_DISABLED;
+            status = ASEC_STATUS_DISABLED;
+            break;
+        case ASEC_AVAILABLE:
+            event = ASEC_EVENT_AVAILABLE;
+            status = ASEC_STATUS_AVAILABLE;
+            break;
+        case ASEC_BUSY:
+            event = ASEC_EVENT_BUSY;
+            status = ASEC_STATUS_BUSY;
+            deferr = false;
+            break;
+        case ASEC_FAILED_INTERR:
+            event = ASEC_EVENT_FAILED_INTERR;
+            status = ASEC_STATUS_FAILED_INTERR;
+            break;
+        case ASEC_FAILED_NOMEDIA:
+            event = ASEC_EVENT_FAILED_NOMEDIA;
+            status = ASEC_STATUS_FAILED_NOMEDIA;
+            break;
+        case ASEC_FAILED_BADMEDIA:
+            event = ASEC_EVENT_FAILED_BADMEDIA;
+            status = ASEC_STATUS_FAILED_BADMEDIA;
+            break;
+        case ASEC_FAILED_BADKEY:
+            event = ASEC_EVENT_FAILED_BADKEY;
+            status = ASEC_STATUS_FAILED_BADKEY;
+            break;
+        default:
+            LOG_ERROR("unknown AsecState %d in NotifyAsecState\n", state);
+            return;
+    }
+
+    property_set(ASEC_STATUS, status);
+
+    int result = Write2(event, argument);
+    if ((result < 0) && deferr) {
+        if (sAsecDeferredMessage) 
+            free(sAsecDeferredMessage);
+        sAsecDeferredMessage = strdup(event);
+        if (sAsecDeferredArgument)
+            free(sAsecDeferredArgument);
+        sAsecDeferredArgument = strdup(argument);
+        LOG_ASEC("Deferring event '%s' arg '%s' until framework connects\n", event, argument);
+    }
+}
+
 void NotifyMediaState(const char* path, MediaState state, boolean readOnly)
 {
     const char* event = NULL;
diff --git a/mountd/dm-ioctl.h b/mountd/dm-ioctl.h
new file mode 100644
index 0000000..ee5c350
--- /dev/null
+++ b/mountd/dm-ioctl.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2001 - 2003 Sistina Software (UK) Limited.
+ * Copyright (C) 2004 - 2005 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the LGPL.
+ */
+
+#ifndef _LINUX_DM_IOCTL_V4_H
+#define _LINUX_DM_IOCTL_V4_H
+
+#ifdef linux
+#  include <linux/types.h>
+#endif
+
+#define DM_DIR "mapper"		/* Slashes not supported */
+#define DM_MAX_TYPE_NAME 16
+#define DM_NAME_LEN 128
+#define DM_UUID_LEN 129
+
+/*
+ * A traditional ioctl interface for the device mapper.
+ *
+ * Each device can have two tables associated with it, an
+ * 'active' table which is the one currently used by io passing
+ * through the device, and an 'inactive' one which is a table
+ * that is being prepared as a replacement for the 'active' one.
+ *
+ * DM_VERSION:
+ * Just get the version information for the ioctl interface.
+ *
+ * DM_REMOVE_ALL:
+ * Remove all dm devices, destroy all tables.  Only really used
+ * for debug.
+ *
+ * DM_LIST_DEVICES:
+ * Get a list of all the dm device names.
+ *
+ * DM_DEV_CREATE:
+ * Create a new device, neither the 'active' or 'inactive' table
+ * slots will be filled.  The device will be in suspended state
+ * after creation, however any io to the device will get errored
+ * since it will be out-of-bounds.
+ *
+ * DM_DEV_REMOVE:
+ * Remove a device, destroy any tables.
+ *
+ * DM_DEV_RENAME:
+ * Rename a device.
+ *
+ * DM_SUSPEND:
+ * This performs both suspend and resume, depending which flag is
+ * passed in.
+ * Suspend: This command will not return until all pending io to
+ * the device has completed.  Further io will be deferred until
+ * the device is resumed.
+ * Resume: It is no longer an error to issue this command on an
+ * unsuspended device.  If a table is present in the 'inactive'
+ * slot, it will be moved to the active slot, then the old table
+ * from the active slot will be _destroyed_.  Finally the device
+ * is resumed.
+ *
+ * DM_DEV_STATUS:
+ * Retrieves the status for the table in the 'active' slot.
+ *
+ * DM_DEV_WAIT:
+ * Wait for a significant event to occur to the device.  This
+ * could either be caused by an event triggered by one of the
+ * targets of the table in the 'active' slot, or a table change.
+ *
+ * DM_TABLE_LOAD:
+ * Load a table into the 'inactive' slot for the device.  The
+ * device does _not_ need to be suspended prior to this command.
+ *
+ * DM_TABLE_CLEAR:
+ * Destroy any table in the 'inactive' slot (ie. abort).
+ *
+ * DM_TABLE_DEPS:
+ * Return a set of device dependencies for the 'active' table.
+ *
+ * DM_TABLE_STATUS:
+ * Return the targets status for the 'active' table.
+ *
+ * DM_TARGET_MSG:
+ * Pass a message string to the target at a specific offset of a device.
+ *
+ * DM_DEV_SET_GEOMETRY:
+ * Set the geometry of a device by passing in a string in this format:
+ *
+ * "cylinders heads sectors_per_track start_sector"
+ *
+ * Beware that CHS geometry is nearly obsolete and only provided
+ * for compatibility with dm devices that can be booted by a PC
+ * BIOS.  See struct hd_geometry for range limits.  Also note that
+ * the geometry is erased if the device size changes.
+ */
+
+/*
+ * All ioctl arguments consist of a single chunk of memory, with
+ * this structure at the start.  If a uuid is specified any
+ * lookup (eg. for a DM_INFO) will be done on that, *not* the
+ * name.
+ */
+struct dm_ioctl {
+	/*
+	 * The version number is made up of three parts:
+	 * major - no backward or forward compatibility,
+	 * minor - only backwards compatible,
+	 * patch - both backwards and forwards compatible.
+	 *
+	 * All clients of the ioctl interface should fill in the
+	 * version number of the interface that they were
+	 * compiled with.
+	 *
+	 * All recognised ioctl commands (ie. those that don't
+	 * return -ENOTTY) fill out this field, even if the
+	 * command failed.
+	 */
+	uint32_t version[3];	/* in/out */
+	uint32_t data_size;	/* total size of data passed in
+				 * including this struct */
+
+	uint32_t data_start;	/* offset to start of data
+				 * relative to start of this struct */
+
+	uint32_t target_count;	/* in/out */
+	int32_t open_count;	/* out */
+	uint32_t flags;		/* in/out */
+	uint32_t event_nr;      	/* in/out */
+	uint32_t padding;
+
+	uint64_t dev;		/* in/out */
+
+	char name[DM_NAME_LEN];	/* device name */
+	char uuid[DM_UUID_LEN];	/* unique identifier for
+				 * the block device */
+	char data[7];		/* padding or data */
+};
+
+/*
+ * Used to specify tables.  These structures appear after the
+ * dm_ioctl.
+ */
+struct dm_target_spec {
+	uint64_t sector_start;
+	uint64_t length;
+	int32_t status;		/* used when reading from kernel only */
+
+	/*
+	 * Location of the next dm_target_spec.
+	 * - When specifying targets on a DM_TABLE_LOAD command, this value is
+	 *   the number of bytes from the start of the "current" dm_target_spec
+	 *   to the start of the "next" dm_target_spec.
+	 * - When retrieving targets on a DM_TABLE_STATUS command, this value
+	 *   is the number of bytes from the start of the first dm_target_spec
+	 *   (that follows the dm_ioctl struct) to the start of the "next"
+	 *   dm_target_spec.
+	 */
+	uint32_t next;
+
+	char target_type[DM_MAX_TYPE_NAME];
+
+	/*
+	 * Parameter string starts immediately after this object.
+	 * Be careful to add padding after string to ensure correct
+	 * alignment of subsequent dm_target_spec.
+	 */
+};
+
+/*
+ * Used to retrieve the target dependencies.
+ */
+struct dm_target_deps {
+	uint32_t count;	/* Array size */
+	uint32_t padding;	/* unused */
+	uint64_t dev[0];	/* out */
+};
+
+/*
+ * Used to get a list of all dm devices.
+ */
+struct dm_name_list {
+	uint64_t dev;
+	uint32_t next;		/* offset to the next record from
+				   the _start_ of this */
+	char name[0];
+};
+
+/*
+ * Used to retrieve the target versions
+ */
+struct dm_target_versions {
+        uint32_t next;
+        uint32_t version[3];
+
+        char name[0];
+};
+
+/*
+ * Used to pass message to a target
+ */
+struct dm_target_msg {
+	uint64_t sector;	/* Device sector */
+
+	char message[0];
+};
+
+/*
+ * If you change this make sure you make the corresponding change
+ * to dm-ioctl.c:lookup_ioctl()
+ */
+enum {
+	/* Top level cmds */
+	DM_VERSION_CMD = 0,
+	DM_REMOVE_ALL_CMD,
+	DM_LIST_DEVICES_CMD,
+
+	/* device level cmds */
+	DM_DEV_CREATE_CMD,
+	DM_DEV_REMOVE_CMD,
+	DM_DEV_RENAME_CMD,
+	DM_DEV_SUSPEND_CMD,
+	DM_DEV_STATUS_CMD,
+	DM_DEV_WAIT_CMD,
+
+	/* Table level cmds */
+	DM_TABLE_LOAD_CMD,
+	DM_TABLE_CLEAR_CMD,
+	DM_TABLE_DEPS_CMD,
+	DM_TABLE_STATUS_CMD,
+
+	/* Added later */
+	DM_LIST_VERSIONS_CMD,
+	DM_TARGET_MSG_CMD,
+	DM_DEV_SET_GEOMETRY_CMD
+};
+
+#define DM_IOCTL 0xfd
+
+#define DM_VERSION       _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl)
+#define DM_REMOVE_ALL    _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl)
+#define DM_LIST_DEVICES  _IOWR(DM_IOCTL, DM_LIST_DEVICES_CMD, struct dm_ioctl)
+
+#define DM_DEV_CREATE    _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl)
+#define DM_DEV_REMOVE    _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl)
+#define DM_DEV_RENAME    _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl)
+#define DM_DEV_SUSPEND   _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl)
+#define DM_DEV_STATUS    _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl)
+#define DM_DEV_WAIT      _IOWR(DM_IOCTL, DM_DEV_WAIT_CMD, struct dm_ioctl)
+
+#define DM_TABLE_LOAD    _IOWR(DM_IOCTL, DM_TABLE_LOAD_CMD, struct dm_ioctl)
+#define DM_TABLE_CLEAR   _IOWR(DM_IOCTL, DM_TABLE_CLEAR_CMD, struct dm_ioctl)
+#define DM_TABLE_DEPS    _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, struct dm_ioctl)
+#define DM_TABLE_STATUS  _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, struct dm_ioctl)
+
+#define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl)
+
+#define DM_TARGET_MSG	 _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl)
+#define DM_DEV_SET_GEOMETRY	_IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
+
+#define DM_VERSION_MAJOR	4
+#define DM_VERSION_MINOR	13
+#define DM_VERSION_PATCHLEVEL	0
+#define DM_VERSION_EXTRA	"-ioctl (2007-10-18)"
+
+/* Status bits */
+#define DM_READONLY_FLAG	(1 << 0) /* In/Out */
+#define DM_SUSPEND_FLAG		(1 << 1) /* In/Out */
+#define DM_PERSISTENT_DEV_FLAG	(1 << 3) /* In */
+
+/*
+ * Flag passed into ioctl STATUS command to get table information
+ * rather than current status.
+ */
+#define DM_STATUS_TABLE_FLAG	(1 << 4) /* In */
+
+/*
+ * Flags that indicate whether a table is present in either of
+ * the two table slots that a device has.
+ */
+#define DM_ACTIVE_PRESENT_FLAG   (1 << 5) /* Out */
+#define DM_INACTIVE_PRESENT_FLAG (1 << 6) /* Out */
+
+/*
+ * Indicates that the buffer passed in wasn't big enough for the
+ * results.
+ */
+#define DM_BUFFER_FULL_FLAG	(1 << 8) /* Out */
+
+/*
+ * This flag is now ignored.
+ */
+#define DM_SKIP_BDGET_FLAG	(1 << 9) /* In */
+
+/*
+ * Set this to avoid attempting to freeze any filesystem when suspending.
+ */
+#define DM_SKIP_LOCKFS_FLAG	(1 << 10) /* In */
+
+/*
+ * Set this to suspend without flushing queued ios.
+ */
+#define DM_NOFLUSH_FLAG		(1 << 11) /* In */
+
+#endif				/* _LINUX_DM_IOCTL_H */
diff --git a/mountd/mountd.c b/mountd/mountd.c
index fb54fe6..27ec8de 100644
--- a/mountd/mountd.c
+++ b/mountd/mountd.c
@@ -39,6 +39,54 @@
 FILE*    logFile;
 #endif
 
+struct asec_cfg {
+    const char *name;
+    const char *backing_file;
+    const char *size;
+    const char *mount_point;
+    const char *crypt;
+};
+
+static int ProcessAsecData(cnode *node, struct asec_cfg *stores, int idx)
+{
+    cnode *child = node->first_child;
+    const char *name = NULL;
+    const char *file = NULL;
+    const char *size = NULL;
+    const char *mp = NULL;
+    const char *crypt = NULL;
+
+    LOG_ASEC("ProcessAsecData(%s, %p, %d)\n", node->name, stores, idx);
+
+    while (child) {
+        if (!strcmp(child->name, "name"))
+            name = child->value;
+        else if (!strcmp(child->name, "backing_file"))
+            file = child->value;
+        else if (!strcmp(child->name, "size"))
+            size = child->value;
+        else if (!strcmp(child->name, "mount_point"))
+            mp = child->value;
+        else if (!strcmp(child->name, "crypt"))
+            crypt = child->value;
+        child = child->next;
+    }
+
+    if (!name || !file || !size || !mp || !crypt) {
+        LOG_ERROR("Missing required token from config. Skipping ASEC volume\n");
+        return -1;
+    } else if (idx == ASEC_STORES_MAX) {
+        LOG_ERROR("Maximum # of ASEC stores already defined\n");
+        return -1;
+    }
+
+    stores[idx].name = name;
+    stores[idx].backing_file = file;
+    stores[idx].size = size;
+    stores[idx].mount_point = mp;
+    stores[idx].crypt = crypt;
+    return ++idx;
+}
 
 static void ReadConfigFile(const char* path)
 {
@@ -54,18 +102,31 @@
         {
             const char* block_device = NULL;
             const char* mount_point = NULL;
+            const char* driver_store_path = NULL;
             boolean enable_ums = false;
             cnode* child = node->first_child;
-            
+            struct asec_cfg asec_stores[ASEC_STORES_MAX];
+            int    asec_idx = 0;
+
+            memset(asec_stores, 0, sizeof(asec_stores));
+
             while (child)
             {
                 const char* name = child->name;
                 const char* value = child->value;
-                
-                if (strcmp(name, "block_device") == 0)
+
+                if (!strncmp(name, "asec_", 5)) {
+                     int rc = ProcessAsecData(child, asec_stores, asec_idx);
+                     if (rc < 0) {
+                         LOG_ERROR("Error processing ASEC cfg data\n");
+                     } else
+                         asec_idx = rc;
+                } else if (strcmp(name, "block_device") == 0)
                     block_device = value;
                 else if (strcmp(name, "mount_point") == 0)
                     mount_point = value;
+                else if (strcmp(name, "driver_store_path") == 0)
+                    driver_store_path = value;
                 else if (strcmp(name, "enable_ums") == 0 &&
                         strcmp(value, "true") == 0)
                     enable_ums = true;
@@ -76,7 +137,14 @@
             // mount point and removable fields are optional
             if (block_device && mount_point)
             {
-                AddMountPoint(block_device, mount_point, enable_ums);
+                void *mp = AddMountPoint(block_device, mount_point, driver_store_path, enable_ums);
+                int i;
+
+                for (i = 0; i < asec_idx; i++) {
+                    AddAsecToMountPoint(mp, asec_stores[i].name, asec_stores[i].backing_file,
+                                        asec_stores[i].size, asec_stores[i].mount_point,
+                                        asec_stores[i].crypt);
+                }
             }
         }
             
diff --git a/mountd/mountd.h b/mountd/mountd.h
index 746a414..9b62484 100644
--- a/mountd/mountd.h
+++ b/mountd/mountd.h
@@ -20,21 +20,28 @@
 #define LOG_TAG "mountd"
 #include "cutils/log.h"
 
+#include "ASEC.h"
+
 typedef int boolean;
 enum {
     false = 0,
     true = 1
 };
 
+#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
+
 // Set this for logging error messages
 #define ENABLE_LOG_ERROR
 
 // set this to log automounter events
-//#define ENABLE_LOG_MOUNT
+#define ENABLE_LOG_MOUNT
 
 // set this to log server events
 //#define ENABLE_LOG_SERVER
 
+// set this to log ASEC events
+#define ENABLE_LOG_ASEC
+
 #ifdef ENABLE_LOG_ERROR
 #define LOG_ERROR(fmt, args...) \
     { LOGE(fmt , ## args); }
@@ -59,6 +66,14 @@
     do { } while (0)
 #endif /* ENABLE_LOG_SERVER */
 
+#ifdef ENABLE_LOG_ASEC
+#define LOG_ASEC(fmt, args...) \
+    { LOGD(fmt , ## args); }
+#else
+#define LOG_ASEC(fmt, args...) \
+    do { } while (0)
+#endif /* ENABLE_LOG_ASEC */
+
 
 typedef enum MediaState {
     // no media in SD card slot
@@ -135,7 +150,11 @@
 void EnableMassStorage(boolean enable);
 
 // call this before StartAutoMounter() to add a mount point to monitor
-void AddMountPoint(const char* device, const char* mountPoint, boolean enableUms);
+void *AddMountPoint(const char* device, const char* mountPoint, const char* driverStorePath,
+                    boolean enableUms);
+
+int AddAsecToMountPoint(void *Mp, const char *name, const char *backing_file,
+                        const char *size, const char *mount_point, const char *crypt);
 
 // start automounter thread
 void StartAutoMounter();
@@ -144,9 +163,19 @@
 void NotifyExistingMounts();
 
 
+// ASEC.c
+
+void *AsecInit(const char *Name, const char *SrcPath, const char *BackingFile,
+               const char *Size, const char *DstPath, const char *Crypt);
+int AsecStart(void *Handle);
+int AsecStop(void *Handle);
+void AsecDeinit(void *Handle);
+boolean AsecIsStarted(void *Handle);
+const char *AsecMountPoint(void *Handle);
+
 // ProcessKiller.c
 
-void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill);
+void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, pid_t *excluded, int num_excluded);
 
 
 // Server.c
@@ -155,5 +184,5 @@
 void SendMassStorageConnected(boolean connected); 
 void SendUnmountRequest(const char* path);
 void NotifyMediaState(const char* path, MediaState state, boolean readOnly);
-
+void NotifyAsecState(AsecState state, const char *argument);
 #endif // MOUNTD_H__
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 756005b..7ff1a74 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -7,8 +7,7 @@
 	etc/mountd.conf \
 	etc/dbus.conf \
 	etc/init.goldfish.sh \
-	etc/hosts \
-	etc/hcid.conf 
+	etc/hosts
 
 dont_copy := \
 	etc/init.gprs-pppd \
@@ -28,10 +27,13 @@
 
 # files that live under /...
 
+# Only copy init.rc if the target doesn't have its own.
+ifneq ($(TARGET_PROVIDES_INIT_RC),true)
 file := $(TARGET_ROOT_OUT)/init.rc
 $(file) : $(LOCAL_PATH)/init.rc | $(ACP)
 	$(transform-prebuilt-to-target)
 ALL_PREBUILT += $(file)
+endif
 
 file := $(TARGET_ROOT_OUT)/init.goldfish.rc
 $(file) : $(LOCAL_PATH)/etc/init.goldfish.rc | $(ACP)
diff --git a/rootdir/etc/dbus.conf b/rootdir/etc/dbus.conf
index 8742345..75586b9 100644
--- a/rootdir/etc/dbus.conf
+++ b/rootdir/etc/dbus.conf
@@ -5,9 +5,6 @@
   <!-- Our well-known bus type, do not change this -->
   <type>system</type>
 
-  <!-- Fork into daemon mode -->
-  <fork/>
-
   <!-- Only allow socket-credentials-based authentication -->
   <auth>EXTERNAL</auth>
 
@@ -17,51 +14,14 @@
        systems.) -->
   <listen>unix:path=/dev/socket/dbus</listen>
 
+  <!-- Allow everything, D-Bus socket is protected by unix filesystem
+       permissions -->
   <policy context="default">
-    <!-- Deny everything then punch holes -->
-    <deny send_interface="*"/>
-    <deny receive_interface="*"/>
-    <deny own="*"/>
-    <!-- But allow all users to connect -->
+    <allow send_interface="*"/>
+    <allow receive_interface="*"/>
+    <allow own="*"/>
     <allow user="*"/>
-    <!-- Allow anyone to talk to the message bus -->
-    <!-- FIXME I think currently these allow rules are always implicit 
-         even if they aren't in here -->
-    <allow send_destination="org.freedesktop.DBus"/>
-    <allow receive_sender="org.freedesktop.DBus"/>
-    <!-- valid replies are always allowed -->
     <allow send_requested_reply="true"/>
     <allow receive_requested_reply="true"/>
   </policy>
-
-
-  <!-- Now punch holes for bluetooth -->
-
-  <policy context="default">
-    <allow own="*"/>
-    <allow user="*"/>
-    <allow send_destination="org.bluez.PasskeyAgent"/>
-    <allow receive_sender="org.bluez.PasskeyAgent"/>
-    <allow send_path="/org/bluez/PasskeyAgent"/>
-  </policy>
-
-  <policy user="root">
-    <allow own="org.bluez"/>
-  </policy>
-
-  <policy at_console="true">
-    <allow send_destination="org.bluez.Adapter"/>
-    <allow receive_sender="org.bluez.Adapter"/>
-
-    <allow send_path="/org/bluez/Adapter"/>
-
-    <allow send_destination="org.bluez.Manager"/>
-    <allow receive_sender="org.bluez.Manager"/>
-
-    <allow send_path="/org/bluez/Manager"/>
-
-    <allow send_destination="org.bluez.Security"/>
-    <allow receive_sender="org.bluez.Security"/>
-  </policy>
-
 </busconfig>
diff --git a/rootdir/etc/hcid.conf b/rootdir/etc/hcid.conf
deleted file mode 100644
index 56df63a..0000000
--- a/rootdir/etc/hcid.conf
+++ /dev/null
@@ -1,64 +0,0 @@
-#
-# HCI daemon configuration file.
-#
-
-# HCId options
-options {
-	# Automatically initialize new devices
-	autoinit yes;
-
-	# Security Manager mode
-	#   none - Security manager disabled
-	#   auto - Use local PIN for incoming connections
-	#   user - Always ask user for a PIN
-	#
-	security user;
-
-	# Pairing mode
-	#   none  - Pairing disabled
-	#   multi - Allow pairing with already paired devices
-	#   once  - Pair once and deny successive attempts
-	pairing multi;
-}
-
-# Default settings for HCI devices
-device {
-	# Local device name
-	#   %d - device id
-	#   %h - host name
-	#   %b - ro.product.brand
-	#   %m - ro.product.model
-	#   %n - ro.product.name
-	name "%m";
-
-	# Local device class
-	#     0x400000  - Service class: Telephony
-	#     0x000200  - Major class: Phone
-	#     0x00000C  - Minor class: Smart phone
-	class 0x40020C;
-
-	# Default packet type
-	#pkt_type DH1,DM1,HV1;
-
-	# Inquiry and Page scan
-	iscan disable;
-	pscan enable;
-
-	# Page timeout (in 0.625ms slots): 10 seconds
-	pageto 16384;
-
-	# Default link mode
-	#   none   - no specific policy
-	#   accept - always accept incoming connections
-	#   master - become master on incoming connections,
-	#            deny role switch on outgoing connections
-	lm accept;
-
-	# Default link policy
-	#   none    - no specific policy
-	#   rswitch - allow role switch
-	#   hold    - allow hold mode
-	#   sniff   - allow sniff mode
-	#   park    - allow park mode
-	lp rswitch,hold,sniff,park;
-}
diff --git a/rootdir/etc/init.goldfish.rc b/rootdir/etc/init.goldfish.rc
index 5975974..96480f3 100644
--- a/rootdir/etc/init.goldfish.rc
+++ b/rootdir/etc/init.goldfish.rc
@@ -16,11 +16,11 @@
     stop dund
     stop akmd
 
-    setprop app.setupwizard.disable 1
+    setprop ro.setupwizard.mode EMULATOR
 
 # enable Google-specific location features,
 # like NetworkLocationProvider and LocationCollector
-    setprop ro.com.google.enable_google_location_features 1
+    setprop ro.com.google.locationfeatures 1
 
 # For the emulator, which bypasses Setup Wizard, you can specify
 # account info for the device via these two properties.  Google
@@ -39,8 +39,9 @@
     oneshot
 
 service qemud /system/bin/qemud
-    socket qemud_gsm stream 666
-    socket qemud_gps stream 666
+    socket qemud_gsm     stream 666
+    socket qemud_gps     stream 666
+    socket qemud_control stream 666
     oneshot
 
 # -Q is a special logcat option that forces the
diff --git a/rootdir/etc/mountd.conf b/rootdir/etc/mountd.conf
index d9dfded..094a2c7 100644
--- a/rootdir/etc/mountd.conf
+++ b/rootdir/etc/mountd.conf
@@ -10,4 +10,10 @@
     
     ## true if this mount point can be shared via USB mass storage
     enable_ums      true
+    
+    ## path to the UMS driver file for specifying the block device path  
+    ## use this for the mass_storage function driver
+    driver_store_path   /sys/devices/platform/usb_mass_storage/lun0/file
+    ## use this for android_usb composite gadget driver
+    ##driver_store_path   /sys/devices/platform/msm_hsusb/gadget/lun0/file
 }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 23daa0b..3f8c6a0 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -1,6 +1,8 @@
 
 on init
 
+sysclktz 0
+
 loglevel 3
 
 # setup the global environment
@@ -118,6 +120,12 @@
     chown radio system /sys/android_power/acquire_full_wake_lock
     chown radio system /sys/android_power/acquire_partial_wake_lock
     chown radio system /sys/android_power/release_wake_lock
+    chown radio system /sys/power/state
+    chown radio system /sys/power/wake_lock
+    chown radio system /sys/power/wake_unlock
+    chmod 0660 /sys/power/state
+    chmod 0660 /sys/power/wake_lock
+    chmod 0660 /sys/power/wake_unlock
     chown system system /sys/class/timed_output/vibrator/enable
     chown system system /sys/class/leds/keyboard-backlight/brightness
     chown system system /sys/class/leds/lcd-backlight/brightness
@@ -193,6 +201,7 @@
 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
     socket zygote stream 666
     onrestart write /sys/android_power/request_state wake
+    onrestart write /sys/power/state on
 
 service media /system/bin/mediaserver
     user media
@@ -208,7 +217,8 @@
     user bluetooth
     group bluetooth net_bt_admin
 
-service hcid /system/bin/hcid -s -n -f /etc/hcid.conf
+#STOPSHIP: disable the verbose logging
+service hcid /system/bin/logwrapper /system/bin/hcid -d -s -n -f /etc/bluez/hcid.conf
     socket bluetooth stream 660 bluetooth bluetooth
     socket dbus_bluetooth stream 660 bluetooth bluetooth
     # init.rc does not yet support applying capabilities, so run as root and
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index df8ba9f..b0c241e 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -83,3 +83,8 @@
 	$(hide) ln -sf $(TOOLBOX_BINARY) $@
 
 ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)
+
+# We need this so that the installed files could be picked up based on the
+# local module name
+ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \
+    $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(SYMLINKS)