am 8ab9ece2: am 162c9a24: Merge "Switch MIPS over to <sys/user.h>."

* commit '8ab9ece2e9c6e246f66357c800d6d1ba61becc00':
  Switch MIPS over to <sys/user.h>.
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 8611d3b..74ec29d 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -50,3 +50,4 @@
 
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/init.rc)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/init.rc)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/reboot)
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..152be20
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,324 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Android-specific code.                        ==
+   =========================================================================
+
+Android Code
+Copyright 2005-2008 The Android Open Source Project
+
+This product includes software developed as part of
+The Android Open Source Project (http://source.android.com).
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for Apache Commons code.                              ==
+   =========================================================================
+
+Apache Commons
+Copyright 1999-2006 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for Jakarta Commons Logging.                          ==
+   =========================================================================
+
+Jakarta Commons Logging (JCL)
+Copyright 2005,2006 The Apache Software Foundation.
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Nuance code.                                  ==
+   =========================================================================
+
+These files are Copyright 2007 Nuance Communications, but released under
+the Apache2 License.
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Media Codecs code.                            ==
+   =========================================================================
+
+Media Codecs
+These files are Copyright 1998 - 2009 PacketVideo, but released under
+the Apache2 License.
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the TagSoup code.                                 ==
+   =========================================================================
+
+This file is part of TagSoup and is Copyright 2002-2008 by John Cowan.
+
+TagSoup is licensed under the Apache License,
+Version 2.0.  You may obtain a copy of this license at
+http://www.apache.org/licenses/LICENSE-2.0 .  You may also have
+additional legal rights not granted by this license.
+
+TagSoup is distributed in the hope that it will be useful, but
+unless required by applicable law or agreed to in writing, TagSoup
+is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+OF ANY KIND, either express or implied; not even the implied warranty
+of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for Additional Codecs code.                           ==
+   =========================================================================
+
+Additional Codecs
+These files are Copyright 2003-2010 VisualOn, but released under
+the Apache2 License.
+
+  =========================================================================
+  ==  NOTICE file corresponding to the section 4 d of                    ==
+  ==  the Apache License, Version 2.0,                                   ==
+  ==  in this case for the Audio Effects code.                           ==
+  =========================================================================
+
+Audio Effects
+These files are Copyright (C) 2004-2010 NXP Software and
+Copyright (C) 2010 The Android Open Source Project, but released under
+the Apache2 License.
+
+
+                               Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+
+
+UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
+
+Unicode Data Files include all data files under the directories
+http://www.unicode.org/Public/, http://www.unicode.org/reports/,
+and http://www.unicode.org/cldr/data/ . Unicode Software includes any
+source code published in the Unicode Standard or under the directories
+http://www.unicode.org/Public/, http://www.unicode.org/reports/, and
+http://www.unicode.org/cldr/data/.
+
+NOTICE TO USER: Carefully read the following legal agreement. BY
+DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA
+FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY
+ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF
+THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY,
+DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright © 1991-2008 Unicode, Inc. All rights reserved. Distributed
+under the Terms of Use in http://www.unicode.org/copyright.html.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Unicode data files and any associated documentation (the
+"Data Files") or Unicode software and any associated documentation (the
+"Software") to deal in the Data Files or Software without restriction,
+including without limitation the rights to use, copy, modify, merge,
+publish, distribute, and/or sell copies of the Data Files or Software,
+and to permit persons to whom the Data Files or Software are furnished to
+do so, provided that (a) the above copyright notice(s) and this permission
+notice appear with all copies of the Data Files or Software, (b) both the
+above copyright notice(s) and this permission notice appear in associated
+documentation, and (c) there is clear notice in each modified Data File
+or in the Software as well as in the documentation associated with the
+Data File(s) or Software that the data or software has been modified.
+
+THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
+INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
+OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
+OR PERFORMANCE OF THE DATA FILES OR SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale, use
+or other dealings in these Data Files or Software without prior written
+authorization of the copyright holder.
diff --git a/adb/Android.mk b/adb/Android.mk
index a803978..721b48d 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -64,7 +64,6 @@
 	file_sync_client.c \
 	$(EXTRA_SRCS) \
 	$(USB_SRCS) \
-	utils.c \
 	usb_vendors.c
 
 LOCAL_C_INCLUDES += external/openssl/include
@@ -116,8 +115,7 @@
 	framebuffer_service.c \
 	remount_service.c \
 	usb_linux_client.c \
-	log_service.c \
-	utils.c
+	log_service.c
 
 LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
 LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
@@ -132,7 +130,7 @@
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
 
-LOCAL_STATIC_LIBRARIES := libcutils libc libmincrypt
+LOCAL_STATIC_LIBRARIES := liblog libcutils libc libmincrypt
 include $(BUILD_EXECUTABLE)
 
 
@@ -157,7 +155,6 @@
 	file_sync_client.c \
 	get_my_path_linux.c \
 	usb_linux.c \
-	utils.c \
 	usb_vendors.c \
 	fdevent.c
 
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
index b53bc44..5966686 100644
--- a/adb/SERVICES.TXT
+++ b/adb/SERVICES.TXT
@@ -225,27 +225,6 @@
       If the adbd daemon doesn't have sufficient privileges 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 tethering).
-
-    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 successfully, 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>.
 
diff --git a/adb/adb.c b/adb/adb.c
index ec74b49..72b7484 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -34,6 +34,7 @@
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
 #if !ADB_HOST
+#include <cutils/properties.h>
 #include <private/android_filesystem_config.h>
 #include <sys/capability.h>
 #include <linux/prctl.h>
@@ -1199,7 +1200,7 @@
 #endif
     int i;
     for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
-        if ((i == CAP_SETUID) || (i == CAP_SETGID)) {
+        if (i == CAP_SETUID || i == CAP_SETGID) {
             // CAP_SETUID CAP_SETGID needed by /system/bin/run-as
             continue;
         }
@@ -1301,13 +1302,6 @@
     /* don't listen on a port (default 5037) if running in secure mode */
     /* don't run as root if we are running in secure mode */
     if (should_drop_privileges()) {
-        struct __user_cap_header_struct header;
-        struct __user_cap_data_struct cap[2];
-
-        if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
-            exit(1);
-        }
-
         drop_capabilities_bounding_set_if_needed();
 
         /* add extra groups:
@@ -1337,16 +1331,6 @@
             exit(1);
         }
 
-        memset(&header, 0, sizeof(header));
-        memset(cap, 0, sizeof(cap));
-
-        /* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */
-        header.version = _LINUX_CAPABILITY_VERSION_3;
-        header.pid = 0;
-        cap[CAP_TO_INDEX(CAP_SYS_BOOT)].effective |= CAP_TO_MASK(CAP_SYS_BOOT);
-        cap[CAP_TO_INDEX(CAP_SYS_BOOT)].permitted |= CAP_TO_MASK(CAP_SYS_BOOT);
-        capset(&header, cap);
-
         D("Local port disabled\n");
     } else {
         char local_name[30];
@@ -1404,105 +1388,6 @@
     return 0;
 }
 
-#if ADB_HOST
-void connect_device(char* host, char* buffer, int buffer_size)
-{
-    int port, fd;
-    char* portstr = strchr(host, ':');
-    char hostbuf[100];
-    char serial[100];
-
-    strncpy(hostbuf, host, sizeof(hostbuf) - 1);
-    if (portstr) {
-        if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) {
-            snprintf(buffer, buffer_size, "bad host name %s", host);
-            return;
-        }
-        // zero terminate the host at the point we found the colon
-        hostbuf[portstr - host] = 0;
-        if (sscanf(portstr + 1, "%d", &port) == 0) {
-            snprintf(buffer, buffer_size, "bad port number %s", portstr);
-            return;
-        }
-    } else {
-        port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
-    }
-
-    snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
-    if (find_transport(serial)) {
-        snprintf(buffer, buffer_size, "already connected to %s", serial);
-        return;
-    }
-
-    fd = socket_network_client(hostbuf, port, SOCK_STREAM);
-    if (fd < 0) {
-        snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
-        return;
-    }
-
-    D("client: connected on remote on fd %d\n", fd);
-    close_on_exec(fd);
-    disable_tcp_nagle(fd);
-    register_socket_transport(fd, serial, port, 0);
-    snprintf(buffer, buffer_size, "connected to %s", serial);
-}
-
-void connect_emulator(char* port_spec, char* buffer, int buffer_size)
-{
-    char* port_separator = strchr(port_spec, ',');
-    if (!port_separator) {
-        snprintf(buffer, buffer_size,
-                "unable to parse '%s' as <console port>,<adb port>",
-                port_spec);
-        return;
-    }
-
-    // Zero-terminate console port and make port_separator point to 2nd port.
-    *port_separator++ = 0;
-    int console_port = strtol(port_spec, NULL, 0);
-    int adb_port = strtol(port_separator, NULL, 0);
-    if (!(console_port > 0 && adb_port > 0)) {
-        *(port_separator - 1) = ',';
-        snprintf(buffer, buffer_size,
-                "Invalid port numbers: Expected positive numbers, got '%s'",
-                port_spec);
-        return;
-    }
-
-    /* Check if the emulator is already known.
-     * Note: There's a small but harmless race condition here: An emulator not
-     * present just yet could be registered by another invocation right
-     * after doing this check here. However, local_connect protects
-     * against double-registration too. From here, a better error message
-     * can be produced. In the case of the race condition, the very specific
-     * error message won't be shown, but the data doesn't get corrupted. */
-    atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
-    if (known_emulator != NULL) {
-        snprintf(buffer, buffer_size,
-                "Emulator on port %d already registered.", adb_port);
-        return;
-    }
-
-    /* Check if more emulators can be registered. Similar unproblematic
-     * race condition as above. */
-    int candidate_slot = get_available_local_transport_index();
-    if (candidate_slot < 0) {
-        snprintf(buffer, buffer_size, "Cannot accept more emulators.");
-        return;
-    }
-
-    /* Preconditions met, try to connect to the emulator. */
-    if (!local_connect_arbitrary_ports(console_port, adb_port)) {
-        snprintf(buffer, buffer_size,
-                "Connected to emulator on ports %d,%d", console_port, adb_port);
-    } else {
-        snprintf(buffer, buffer_size,
-                "Could not connect to emulator on ports %d,%d",
-                console_port, adb_port);
-    }
-}
-#endif
-
 int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
 {
     atransport *transport = NULL;
@@ -1563,21 +1448,6 @@
         }
     }
 
-    // add a new TCP transport, device or emulator
-    if (!strncmp(service, "connect:", 8)) {
-        char buffer[4096];
-        char* host = service + 8;
-        if (!strncmp(host, "emu:", 4)) {
-            connect_emulator(host + 4, buffer, sizeof(buffer));
-        } else {
-            connect_device(host, buffer, sizeof(buffer));
-        }
-        // Send response for emulator and device
-        snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
-        writex(reply_fd, buf, strlen(buf));
-        return 0;
-    }
-
     // remove TCP transport
     if (!strncmp(service, "disconnect:", 11)) {
         char buffer[4096];
diff --git a/adb/adb.h b/adb/adb.h
index a01d460..622ca70 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -128,10 +128,7 @@
         */
     void (*close)(asocket *s);
 
-        /* socket-type-specific extradata */
-    void *extra;
-
-    	/* A socket is bound to atransport */
+        /* A socket is bound to atransport */
     atransport *transport;
 };
 
@@ -292,7 +289,7 @@
 void close_usb_devices();
 
 /* cause new transports to be init'd and added to the list */
-void register_socket_transport(int s, const char *serial, int port, int local);
+int register_socket_transport(int s, const char *serial, int port, int local);
 
 /* these should only be used for the "adb disconnect" command */
 void unregister_transport(atransport *t);
diff --git a/adb/log_service.c b/adb/log_service.c
index 6e9bdee..af24356 100644
--- a/adb/log_service.c
+++ b/adb/log_service.c
@@ -22,7 +22,7 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <sys/socket.h>
-#include <cutils/logger.h>
+#include <log/logger.h>
 #include "sysdeps.h"
 #include "adb.h"
 
diff --git a/adb/mutex_list.h b/adb/mutex_list.h
index 652dd73..ff72751 100644
--- a/adb/mutex_list.h
+++ b/adb/mutex_list.h
@@ -6,7 +6,6 @@
 #ifndef ADB_MUTEX
 #error ADB_MUTEX not defined when including this file
 #endif
-ADB_MUTEX(dns_lock)
 ADB_MUTEX(socket_list_lock)
 ADB_MUTEX(transport_lock)
 #if ADB_HOST
diff --git a/adb/remount_service.c b/adb/remount_service.c
index 4cb41e7..ad61284 100644
--- a/adb/remount_service.c
+++ b/adb/remount_service.c
@@ -72,6 +72,8 @@
 static int remount_system()
 {
     char *dev;
+    int fd;
+    int OFF = 0;
 
     if (system_ro == 0) {
         return 0;
@@ -82,6 +84,13 @@
     if (!dev)
         return -1;
 
+    fd = unix_open(dev, O_RDONLY);
+    if (fd < 0)
+        return -1;
+
+    ioctl(fd, BLKROSET, &OFF);
+    adb_close(fd);
+
     system_ro = mount(dev, "/system", "none", MS_REMOUNT, NULL);
 
     free(dev);
diff --git a/adb/services.c b/adb/services.c
index 54d21a8..951048e 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <stddef.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -34,6 +35,7 @@
 #  endif
 #else
 #  include <cutils/android_reboot.h>
+#  include <cutils/properties.h>
 #endif
 
 typedef struct stinfo stinfo;
@@ -53,59 +55,7 @@
     return 0;
 }
 
-#if ADB_HOST
-ADB_MUTEX_DEFINE( dns_lock );
-
-static void dns_service(int fd, void *cookie)
-{
-    char *hostname = cookie;
-    struct hostent *hp;
-    unsigned zero = 0;
-
-    adb_mutex_lock(&dns_lock);
-    hp = gethostbyname(hostname);
-    free(cookie);
-    if(hp == 0) {
-        writex(fd, &zero, 4);
-    } else {
-        writex(fd, hp->h_addr, 4);
-    }
-    adb_mutex_unlock(&dns_lock);
-    adb_close(fd);
-}
-#else
-extern int recovery_mode;
-
-static void recover_service(int s, void *cookie)
-{
-    unsigned char buf[4096];
-    unsigned count = (unsigned) cookie;
-    int fd;
-
-    fd = adb_creat("/tmp/update", 0644);
-    if(fd < 0) {
-        adb_close(s);
-        return;
-    }
-
-    while(count > 0) {
-        unsigned xfer = (count > 4096) ? 4096 : count;
-        if(readx(s, buf, xfer)) break;
-        if(writex(fd, buf, xfer)) break;
-        count -= xfer;
-    }
-
-    if(count == 0) {
-        writex(s, "OKAY", 4);
-    } else {
-        writex(s, "FAIL", 4);
-    }
-    adb_close(fd);
-    adb_close(s);
-
-    fd = adb_creat("/tmp/update.begin", 0644);
-    adb_close(fd);
-}
+#if !ADB_HOST
 
 void restart_root_service(int fd, void *cookie)
 {
@@ -165,6 +115,7 @@
 void reboot_service(int fd, void *arg)
 {
     char buf[100];
+    char property_val[PROPERTY_VALUE_MAX];
     int pid, ret;
 
     sync();
@@ -182,51 +133,29 @@
         waitpid(pid, &ret, 0);
     }
 
-    ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
-    if (ret < 0) {
-        snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
+    ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg);
+    if (ret >= (int) sizeof(property_val)) {
+        snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret);
         writex(fd, buf, strlen(buf));
+        goto cleanup;
     }
+
+    ret = property_set(ANDROID_RB_PROPERTY, property_val);
+    if (ret < 0) {
+        snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret);
+        writex(fd, buf, strlen(buf));
+        goto cleanup;
+    }
+    // Don't return early. Give the reboot command time to take effect
+    // to avoid messing up scripts which do "adb reboot && adb wait-for-device"
+    while(1) { pause(); }
+cleanup:
     free(arg);
     adb_close(fd);
 }
 
 #endif
 
-#if 0
-static void echo_service(int fd, void *cookie)
-{
-    char buf[4096];
-    int r;
-    char *p;
-    int c;
-
-    for(;;) {
-        r = adb_read(fd, buf, 4096);
-        if(r == 0) goto done;
-        if(r < 0) {
-            if(errno == EINTR) continue;
-            else goto done;
-        }
-
-        c = r;
-        p = buf;
-        while(c > 0) {
-            r = write(fd, p, c);
-            if(r > 0) {
-                c -= r;
-                p += r;
-                continue;
-            }
-            if((r < 0) && (errno == EINTR)) continue;
-            goto done;
-        }
-    }
-done:
-    close(fd);
-}
-#endif
-
 static int create_service_thread(void (*func)(int, void *), void *cookie)
 {
     stinfo *sti;
@@ -413,9 +342,7 @@
                 disable_tcp_nagle(ret);
         } else {
 #if ADB_HOST
-            adb_mutex_lock(&dns_lock);
             ret = socket_network_client(name + 1, port, SOCK_STREAM);
-            adb_mutex_unlock(&dns_lock);
 #else
             return -1;
 #endif
@@ -434,18 +361,11 @@
         ret = socket_local_client(name + 16,
                 ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
 #endif
-#if ADB_HOST
-    } else if(!strncmp("dns:", name, 4)){
-        char *n = strdup(name + 4);
-        if(n == 0) return -1;
-        ret = create_service_thread(dns_service, n);
-#else /* !ADB_HOST */
+#if !ADB_HOST
     } else if(!strncmp("dev:", name, 4)) {
         ret = unix_open(name + 4, O_RDWR);
     } else if(!strncmp(name, "framebuffer:", 12)) {
         ret = create_service_thread(framebuffer_service, 0);
-    } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
-        ret = create_service_thread(recover_service, (void*) atoi(name + 8));
     } else if (!strncmp(name, "jdwp:", 5)) {
         ret = create_jdwp_connection_fd(atoi(name+5));
     } else if (!strncmp(name, "log:", 4)) {
@@ -481,10 +401,6 @@
     } else if(!strncmp(name, "usb:", 4)) {
         ret = create_service_thread(restart_usb_service, NULL);
 #endif
-#if 0
-    } else if(!strncmp(name, "echo:", 5)){
-        ret = create_service_thread(echo_service, 0);
-#endif
     }
     if (ret >= 0) {
         close_on_exec(ret);
@@ -519,6 +435,124 @@
     adb_close(fd);
     D("wait_for_state is done\n");
 }
+
+static void connect_device(char* host, char* buffer, int buffer_size)
+{
+    int port, fd;
+    char* portstr = strchr(host, ':');
+    char hostbuf[100];
+    char serial[100];
+    int ret;
+
+    strncpy(hostbuf, host, sizeof(hostbuf) - 1);
+    if (portstr) {
+        if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) {
+            snprintf(buffer, buffer_size, "bad host name %s", host);
+            return;
+        }
+        // zero terminate the host at the point we found the colon
+        hostbuf[portstr - host] = 0;
+        if (sscanf(portstr + 1, "%d", &port) == 0) {
+            snprintf(buffer, buffer_size, "bad port number %s", portstr);
+            return;
+        }
+    } else {
+        port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+    }
+
+    snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
+
+    fd = socket_network_client(hostbuf, port, SOCK_STREAM);
+    if (fd < 0) {
+        snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
+        return;
+    }
+
+    D("client: connected on remote on fd %d\n", fd);
+    close_on_exec(fd);
+    disable_tcp_nagle(fd);
+
+    ret = register_socket_transport(fd, serial, port, 0);
+    if (ret < 0) {
+        adb_close(fd);
+        snprintf(buffer, buffer_size, "already connected to %s", serial);
+    } else {
+        snprintf(buffer, buffer_size, "connected to %s", serial);
+    }
+}
+
+void connect_emulator(char* port_spec, char* buffer, int buffer_size)
+{
+    char* port_separator = strchr(port_spec, ',');
+    if (!port_separator) {
+        snprintf(buffer, buffer_size,
+                "unable to parse '%s' as <console port>,<adb port>",
+                port_spec);
+        return;
+    }
+
+    // Zero-terminate console port and make port_separator point to 2nd port.
+    *port_separator++ = 0;
+    int console_port = strtol(port_spec, NULL, 0);
+    int adb_port = strtol(port_separator, NULL, 0);
+    if (!(console_port > 0 && adb_port > 0)) {
+        *(port_separator - 1) = ',';
+        snprintf(buffer, buffer_size,
+                "Invalid port numbers: Expected positive numbers, got '%s'",
+                port_spec);
+        return;
+    }
+
+    /* Check if the emulator is already known.
+     * Note: There's a small but harmless race condition here: An emulator not
+     * present just yet could be registered by another invocation right
+     * after doing this check here. However, local_connect protects
+     * against double-registration too. From here, a better error message
+     * can be produced. In the case of the race condition, the very specific
+     * error message won't be shown, but the data doesn't get corrupted. */
+    atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
+    if (known_emulator != NULL) {
+        snprintf(buffer, buffer_size,
+                "Emulator on port %d already registered.", adb_port);
+        return;
+    }
+
+    /* Check if more emulators can be registered. Similar unproblematic
+     * race condition as above. */
+    int candidate_slot = get_available_local_transport_index();
+    if (candidate_slot < 0) {
+        snprintf(buffer, buffer_size, "Cannot accept more emulators.");
+        return;
+    }
+
+    /* Preconditions met, try to connect to the emulator. */
+    if (!local_connect_arbitrary_ports(console_port, adb_port)) {
+        snprintf(buffer, buffer_size,
+                "Connected to emulator on ports %d,%d", console_port, adb_port);
+    } else {
+        snprintf(buffer, buffer_size,
+                "Could not connect to emulator on ports %d,%d",
+                console_port, adb_port);
+    }
+}
+
+static void connect_service(int fd, void* cookie)
+{
+    char buf[4096];
+    char resp[4096];
+    char *host = cookie;
+
+    if (!strncmp(host, "emu:", 4)) {
+        connect_emulator(host + 4, buf, sizeof(buf));
+    } else {
+        connect_device(host, buf, sizeof(buf));
+    }
+
+    // Send response for emulator and device
+    snprintf(resp, sizeof(resp), "%04x%s",(unsigned)strlen(buf), buf);
+    writex(fd, resp, strlen(resp));
+    adb_close(fd);
+}
 #endif
 
 #if ADB_HOST
@@ -552,6 +586,10 @@
 
         int fd = create_service_thread(wait_for_state, sinfo);
         return create_local_socket(fd);
+    } else if (!strncmp(name, "connect:", 8)) {
+        const char *host = name + 8;
+        int fd = create_service_thread(connect_service, (void *)host);
+        return create_local_socket(fd);
     }
     return NULL;
 }
diff --git a/adb/sockets.c b/adb/sockets.c
index 305cb44..f17608b 100644
--- a/adb/sockets.c
+++ b/adb/sockets.c
@@ -844,7 +844,7 @@
     free(s);
 }
 
-asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act))
+static asocket *create_smart_socket(void)
 {
     D("Creating smart socket \n");
     asocket *s = calloc(1, sizeof(asocket));
@@ -852,21 +852,15 @@
     s->enqueue = smart_socket_enqueue;
     s->ready = smart_socket_ready;
     s->close = smart_socket_close;
-    s->extra = action_cb;
 
-    D("SS(%d): created %p\n", s->id, action_cb);
+    D("SS(%d)\n", s->id);
     return s;
 }
 
-void smart_socket_action(asocket *s, const char *act)
-{
-
-}
-
 void connect_to_smartsocket(asocket *s)
 {
     D("Connecting to smart socket \n");
-    asocket *ss = create_smart_socket(smart_socket_action);
+    asocket *ss = create_smart_socket();
     s->peer = ss;
     ss->peer = s;
     s->ready(s);
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 0252ef3..4033b72 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -261,7 +261,6 @@
 
 #include "fdevent.h"
 #include <cutils/sockets.h>
-#include <cutils/properties.h>
 #include <cutils/misc.h>
 #include <signal.h>
 #include <sys/wait.h>
diff --git a/adb/transport.c b/adb/transport.c
index b4abb66..224fe55 100644
--- a/adb/transport.c
+++ b/adb/transport.c
@@ -32,6 +32,11 @@
     .prev = &transport_list,
 };
 
+static atransport pending_list = {
+    .next = &pending_list,
+    .prev = &pending_list,
+};
+
 ADB_MUTEX_DEFINE( transport_lock );
 
 #if ADB_TRACE
@@ -645,8 +650,11 @@
         }
     }
 
-        /* put us on the master device list */
     adb_mutex_lock(&transport_lock);
+    /* remove from pending list */
+    t->next->prev = t->prev;
+    t->prev->next = t->next;
+    /* put us on the master device list */
     t->next = &transport_list;
     t->prev = transport_list.prev;
     t->next->prev = t;
@@ -989,9 +997,10 @@
 }
 #endif // ADB_HOST
 
-void register_socket_transport(int s, const char *serial, int port, int local)
+int register_socket_transport(int s, const char *serial, int port, int local)
 {
     atransport *t = calloc(1, sizeof(atransport));
+    atransport *n;
     char buff[32];
 
     if (!serial) {
@@ -999,15 +1008,37 @@
         serial = buff;
     }
     D("transport: %s init'ing for socket %d, on port %d\n", serial, s, port);
-    if ( init_socket_transport(t, s, port, local) < 0 ) {
-        adb_close(s);
+    if (init_socket_transport(t, s, port, local) < 0) {
         free(t);
-        return;
+        return -1;
     }
-    if(serial) {
-        t->serial = strdup(serial);
+
+    adb_mutex_lock(&transport_lock);
+    for (n = pending_list.next; n != &pending_list; n = n->next) {
+        if (n->serial && !strcmp(serial, n->serial)) {
+            adb_mutex_unlock(&transport_lock);
+            free(t);
+            return -1;
+        }
     }
+
+    for (n = transport_list.next; n != &transport_list; n = n->next) {
+        if (n->serial && !strcmp(serial, n->serial)) {
+            adb_mutex_unlock(&transport_lock);
+            free(t);
+            return -1;
+        }
+    }
+
+    t->next = &pending_list;
+    t->prev = pending_list.prev;
+    t->next->prev = t;
+    t->prev->next = t;
+    t->serial = strdup(serial);
+    adb_mutex_unlock(&transport_lock);
+
     register_transport(t);
+    return 0;
 }
 
 #if ADB_HOST
@@ -1077,6 +1108,14 @@
     if(devpath) {
         t->devpath = strdup(devpath);
     }
+
+    adb_mutex_lock(&transport_lock);
+    t->next = &pending_list;
+    t->prev = pending_list.prev;
+    t->next->prev = t;
+    t->prev->next = t;
+    adb_mutex_unlock(&transport_lock);
+
     register_transport(t);
 }
 
diff --git a/adb/transport_local.c b/adb/transport_local.c
index 96a24ba..1cfa24d 100644
--- a/adb/transport_local.c
+++ b/adb/transport_local.c
@@ -21,6 +21,9 @@
 
 #include "sysdeps.h"
 #include <sys/types.h>
+#if !ADB_HOST
+#include <cutils/properties.h>
+#endif
 
 #define  TRACE_TAG  TRACE_TRANSPORT
 #include "adb.h"
diff --git a/adb/utils.c b/adb/utils.c
deleted file mode 100644
index 91518ba..0000000
--- a/adb/utils.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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
deleted file mode 100644
index f70ecd2..0000000
--- a/adb/utils.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
index da2e9b0..756f7bb 100644
--- a/debuggerd/debuggerd.c
+++ b/debuggerd/debuggerd.c
@@ -31,9 +31,10 @@
 #include <sys/stat.h>
 #include <sys/poll.h>
 
+#include <log/logd.h>
+#include <log/logger.h>
+
 #include <cutils/sockets.h>
-#include <cutils/logd.h>
-#include <cutils/logger.h>
 #include <cutils/properties.h>
 #include <cutils/debugger.h>
 
@@ -435,11 +436,13 @@
     signal(SIGBUS, SIG_DFL);
     signal(SIGFPE, SIG_DFL);
     signal(SIGSEGV, SIG_DFL);
-    signal(SIGPIPE, SIG_DFL);
 #ifdef SIGSTKFLT
     signal(SIGSTKFLT, SIG_DFL);
 #endif
 
+    // Ignore failed writes to closed sockets
+    signal(SIGPIPE, SIG_IGN);
+
     logsocket = socket_local_client("logd",
             ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);
     if(logsocket < 0) {
diff --git a/debuggerd/tombstone.c b/debuggerd/tombstone.c
index 48d7aa9..aa63547 100644
--- a/debuggerd/tombstone.c
+++ b/debuggerd/tombstone.c
@@ -29,7 +29,7 @@
 
 #include <private/android_filesystem_config.h>
 
-#include <cutils/logger.h>
+#include <log/logger.h>
 #include <cutils/properties.h>
 
 #include <backtrace/backtrace.h>
diff --git a/debuggerd/utility.c b/debuggerd/utility.c
index 9bf3c18..41be982 100644
--- a/debuggerd/utility.c
+++ b/debuggerd/utility.c
@@ -22,7 +22,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include <signal.h>
-#include <cutils/logd.h>
+#include <log/logd.h>
 #include <sys/ptrace.h>
 #include <sys/wait.h>
 #include <arpa/inet.h>
diff --git a/fastboot/engine.c b/fastboot/engine.c
index 84ea984..972c4ed 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -264,21 +264,7 @@
     int fd;
     struct stat st;
 
-#ifdef USE_MINGW
-    /* Ideally we should use tmpfile() here, the same as with unix version.
-     * But unfortunately it is not portable as it is not clear whether this
-     * function opens file in TEXT or BINARY mode.
-     *
-     * There are also some reports it is buggy:
-     *    http://pdplab.it.uom.gr/teaching/gcc_manuals/gnulib.html#tmpfile
-     *    http://www.mega-nerd.com/erikd/Blog/Windiots/tmpfile.html
-     */
-    char *filename = tempnam(getenv("TEMP"), "fastboot-format.img");
-    fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0644);
-    unlink(filename);
-#else
     fd = fileno(tmpfile());
-#endif
     make_ext4fs_sparse_fd(fd, image->partition_size, NULL, NULL);
 
     fstat(fd, &st);
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index da2af41..73a6e56 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -42,6 +42,7 @@
 
 #include <sys/time.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 
 #include <bootimg.h>
 #include <sparse/sparse.h>
@@ -53,6 +54,8 @@
 #define O_BINARY 0
 #endif
 
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
+
 char cur_product[FB_RESPONSE_SZ + 1];
 
 void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
@@ -80,6 +83,27 @@
 unsigned second_offset  = 0x00f00000;
 unsigned tags_offset    = 0x00000100;
 
+enum fb_buffer_type {
+    FB_BUFFER,
+    FB_BUFFER_SPARSE,
+};
+
+struct fastboot_buffer {
+    enum fb_buffer_type type;
+    void *data;
+    unsigned int sz;
+};
+
+static struct {
+    char img_name[13];
+    char sig_name[13];
+    char part_name[9];
+    bool is_optional;
+} images[3] = {
+    {"boot.img", "boot.sig", "boot", false},
+    {"recovery.img", "recovery.sig", "recovery", true},
+    {"system.img", "system.sig", "system", false},
+};
 
 void get_my_path(char *path);
 
@@ -123,44 +147,28 @@
     return strdup(path);
 }
 
-#ifdef _WIN32
-void *load_file(const char *fn, unsigned *_sz);
-int64_t file_size(const char *fn);
-#else
-#if defined(__APPLE__) && defined(__MACH__)
-#define lseek64 lseek
-#define off64_t off_t
-#endif
-
-int64_t file_size(const char *fn)
+static int64_t file_size(int fd)
 {
-    off64_t off;
-    int fd;
+    struct stat st;
+    int ret;
 
-    fd = open(fn, O_RDONLY);
-    if (fd < 0) return -1;
+    ret = fstat(fd, &st);
 
-    off = lseek64(fd, 0, SEEK_END);
-    close(fd);
-
-    return off;
+    return ret ? -1 : st.st_size;
 }
 
-void *load_file(const char *fn, unsigned *_sz)
+static void *load_fd(int fd, unsigned *_sz)
 {
     char *data;
     int sz;
-    int fd;
     int errno_tmp;
 
     data = 0;
-    fd = open(fn, O_RDONLY);
-    if(fd < 0) return 0;
 
-    sz = lseek(fd, 0, SEEK_END);
-    if(sz < 0) goto oops;
-
-    if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
+    sz = file_size(fd);
+    if (sz < 0) {
+        goto oops;
+    }
 
     data = (char*) malloc(sz);
     if(data == 0) goto oops;
@@ -178,7 +186,16 @@
     errno = errno_tmp;
     return 0;
 }
-#endif
+
+static void *load_file(const char *fn, unsigned *_sz)
+{
+    int fd;
+
+    fd = open(fn, O_RDONLY | O_BINARY);
+    if(fd < 0) return 0;
+
+    return load_fd(fd, _sz);
+}
 
 int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial)
 {
@@ -385,6 +402,31 @@
     return data;
 }
 
+static int unzip_to_file(zipfile_t zip, char *name)
+{
+    int fd;
+    char *data;
+    unsigned sz;
+
+    fd = fileno(tmpfile());
+    if (fd < 0) {
+        return -1;
+    }
+
+    data = unzip_file(zip, name, &sz);
+    if (data == 0) {
+        return -1;
+    }
+
+    if (write(fd, data, sz) != sz) {
+        fd = -1;
+    }
+
+    free(data);
+    lseek(fd, 0, SEEK_SET);
+    return fd;
+}
+
 static char *strip(char *s)
 {
     int n;
@@ -489,27 +531,20 @@
     fb_queue_notice("--------------------------------------------");
 }
 
-
-struct sparse_file **load_sparse_files(const char *fname, int max_size)
+static struct sparse_file **load_sparse_files(int fd, int max_size)
 {
-    int fd;
     struct sparse_file *s;
     int files;
     struct sparse_file **out_s;
 
-    fd = open(fname, O_RDONLY | O_BINARY);
-    if (fd < 0) {
-        die("cannot open '%s'\n", fname);
-    }
-
     s = sparse_file_import_auto(fd, false);
     if (!s) {
-        die("cannot sparse read file '%s'\n", fname);
+        die("cannot sparse read file\n");
     }
 
     files = sparse_file_resparse(s, max_size, NULL, 0);
     if (files < 0) {
-        die("Failed to resparse '%s'\n", fname);
+        die("Failed to resparse\n");
     }
 
     out_s = calloc(sizeof(struct sparse_file *), files + 1);
@@ -519,7 +554,7 @@
 
     files = sparse_file_resparse(s, max_size, out_s, files);
     if (files < 0) {
-        die("Failed to resparse '%s'\n", fname);
+        die("Failed to resparse\n");
     }
 
     return out_s;
@@ -580,29 +615,78 @@
      return fb_format_supported(usb, part);
 }
 
-void do_flash(usb_handle *usb, const char *pname, const char *fname)
+static int load_buf_fd(usb_handle *usb, int fd,
+        struct fastboot_buffer *buf)
 {
     int64_t sz64;
     void *data;
     int64_t limit;
 
-    sz64 = file_size(fname);
+    sz64 = file_size(fd);
+    if (sz64 < 0) {
+        return -1;
+    }
     limit = get_sparse_limit(usb, sz64);
     if (limit) {
-        struct sparse_file **s = load_sparse_files(fname, limit);
+        struct sparse_file **s = load_sparse_files(fd, limit);
         if (s == NULL) {
-            die("cannot sparse load '%s'\n", fname);
+            return -1;
         }
-        while (*s) {
-            sz64 = sparse_file_len(*s, true, false);
-            fb_queue_flash_sparse(pname, *s++, sz64);
-        }
+        buf->type = FB_BUFFER_SPARSE;
+        buf->data = s;
     } else {
         unsigned int sz;
-        data = load_file(fname, &sz);
-        if (data == 0) die("cannot load '%s': %s\n", fname, strerror(errno));
-        fb_queue_flash(pname, data, sz);
+        data = load_fd(fd, &sz);
+        if (data == 0) return -1;
+        buf->type = FB_BUFFER;
+        buf->data = data;
+        buf->sz = sz;
     }
+
+    return 0;
+}
+
+static int load_buf(usb_handle *usb, const char *fname,
+        struct fastboot_buffer *buf)
+{
+    int fd;
+
+    fd = open(fname, O_RDONLY | O_BINARY);
+    if (fd < 0) {
+        die("cannot open '%s'\n", fname);
+    }
+
+    return load_buf_fd(usb, fd, buf);
+}
+
+static void flash_buf(const char *pname, struct fastboot_buffer *buf)
+{
+    struct sparse_file **s;
+
+    switch (buf->type) {
+        case FB_BUFFER_SPARSE:
+            s = buf->data;
+            while (*s) {
+                int64_t sz64 = sparse_file_len(*s, true, false);
+                fb_queue_flash_sparse(pname, *s++, sz64);
+            }
+            break;
+        case FB_BUFFER:
+            fb_queue_flash(pname, buf->data, buf->sz);
+            break;
+        default:
+            die("unknown buffer type: %d", buf->type);
+    }
+}
+
+void do_flash(usb_handle *usb, const char *pname, const char *fname)
+{
+    struct fastboot_buffer buf;
+
+    if (load_buf(usb, fname, &buf)) {
+        die("cannot load '%s'", fname);
+    }
+    flash_buf(pname, &buf);
 }
 
 void do_update_signature(zipfile_t zip, char *fn)
@@ -615,13 +699,17 @@
     fb_queue_command("signature", "installing signature");
 }
 
-void do_update(char *fn, int erase_first)
+void do_update(usb_handle *usb, char *fn, int erase_first)
 {
     void *zdata;
     unsigned zsize;
     void *data;
     unsigned sz;
     zipfile_t zip;
+    int fd;
+    int rc;
+    struct fastboot_buffer buf;
+    int i;
 
     queue_info_dump();
 
@@ -650,30 +738,25 @@
 
     setup_requirements(data, sz);
 
-    data = unzip_file(zip, "boot.img", &sz);
-    if (data == 0) die("update package missing boot.img");
-    do_update_signature(zip, "boot.sig");
-    if (erase_first && needs_erase("boot")) {
-        fb_queue_erase("boot");
-    }
-    fb_queue_flash("boot", data, sz);
-
-    data = unzip_file(zip, "recovery.img", &sz);
-    if (data != 0) {
-        do_update_signature(zip, "recovery.sig");
-        if (erase_first && needs_erase("recovery")) {
-            fb_queue_erase("recovery");
+    for (i = 0; i < ARRAY_SIZE(images); i++) {
+        fd = unzip_to_file(zip, images[i].img_name);
+        if (fd < 0) {
+            if (images[i].is_optional)
+                continue;
+            die("update package missing %s", images[i].img_name);
         }
-        fb_queue_flash("recovery", data, sz);
+        rc = load_buf_fd(usb, fd, &buf);
+        if (rc) die("cannot load %s from flash", images[i].img_name);
+        do_update_signature(zip, images[i].sig_name);
+        if (erase_first && needs_erase(images[i].part_name)) {
+            fb_queue_erase(images[i].part_name);
+        }
+        flash_buf(images[i].part_name, &buf);
+        /* not closing the fd here since the sparse code keeps the fd around
+         * but hasn't mmaped data yet. The tmpfile will get cleaned up when the
+         * program exits.
+         */
     }
-
-    data = unzip_file(zip, "system.img", &sz);
-    if (data == 0) die("update package missing system.img");
-    do_update_signature(zip, "system.sig");
-    if (erase_first && needs_erase("system")) {
-        fb_queue_erase("system");
-    }
-    fb_queue_flash("system", data, sz);
 }
 
 void do_send_signature(char *fn)
@@ -694,11 +777,13 @@
     fb_queue_command("signature", "installing signature");
 }
 
-void do_flashall(int erase_first)
+void do_flashall(usb_handle *usb, int erase_first)
 {
     char *fname;
     void *data;
     unsigned sz;
+    struct fastboot_buffer buf;
+    int i;
 
     queue_info_dump();
 
@@ -710,33 +795,19 @@
     if (data == 0) die("could not load android-info.txt: %s", strerror(errno));
     setup_requirements(data, sz);
 
-    fname = find_item("boot", product);
-    data = load_file(fname, &sz);
-    if (data == 0) die("could not load boot.img: %s", strerror(errno));
-    do_send_signature(fname);
-    if (erase_first && needs_erase("boot")) {
-        fb_queue_erase("boot");
-    }
-    fb_queue_flash("boot", data, sz);
-
-    fname = find_item("recovery", product);
-    data = load_file(fname, &sz);
-    if (data != 0) {
-        do_send_signature(fname);
-        if (erase_first && needs_erase("recovery")) {
-            fb_queue_erase("recovery");
+    for (i = 0; i < ARRAY_SIZE(images); i++) {
+        fname = find_item(images[i].part_name, product);
+        if (load_buf(usb, fname, &buf)) {
+            if (images[i].is_optional)
+                continue;
+            die("could not load %s\n", images[i].img_name);
         }
-        fb_queue_flash("recovery", data, sz);
+        do_send_signature(fname);
+        if (erase_first && needs_erase(images[i].part_name)) {
+            fb_queue_erase(images[i].part_name);
+        }
+        flash_buf(images[i].part_name, &buf);
     }
-
-    fname = find_item("system", product);
-    data = load_file(fname, &sz);
-    if (data == 0) die("could not load system.img: %s", strerror(errno));
-    do_send_signature(fname);
-    if (erase_first && needs_erase("system")) {
-        fb_queue_erase("system");
-    }
-    fb_queue_flash("system", data, sz);
 }
 
 #define skip(n) do { argc -= (n); argv += (n); } while (0)
@@ -996,14 +1067,14 @@
             fb_queue_flash(pname, data, sz);
         } else if(!strcmp(*argv, "flashall")) {
             skip(1);
-            do_flashall(erase_first);
+            do_flashall(usb, erase_first);
             wants_reboot = 1;
         } else if(!strcmp(*argv, "update")) {
             if (argc > 1) {
-                do_update(argv[1], erase_first);
+                do_update(usb, argv[1], erase_first);
                 skip(2);
             } else {
-                do_update("update.zip", erase_first);
+                do_update(usb, "update.zip", erase_first);
                 skip(1);
             }
             wants_reboot = 1;
diff --git a/fastboot/util_windows.c b/fastboot/util_windows.c
index 9e029fd..74a5c27 100644
--- a/fastboot/util_windows.c
+++ b/fastboot/util_windows.c
@@ -36,29 +36,6 @@
 
 #include <windows.h>
 
-int64_t file_size(const char *fn)
-{
-    HANDLE    file;
-    char     *data;
-    DWORD     sz;
-
-    file = CreateFile( fn,
-                       GENERIC_READ,
-                       FILE_SHARE_READ,
-                       NULL,
-                       OPEN_EXISTING,
-                       0,
-                       NULL );
-
-    if (file == INVALID_HANDLE_VALUE)
-        return -1;
-
-    sz = GetFileSize( file, NULL );
-    CloseHandle( file );
-
-    return sz;
-}
-
 void get_my_path(char exe[PATH_MAX])
 {
 	char*  r;
@@ -70,47 +47,3 @@
 		*r = 0;
 }
 
-
-void *load_file(const char *fn, unsigned *_sz)
-{
-    HANDLE    file;
-    char     *data;
-    DWORD     sz;
-
-    file = CreateFile( fn,
-                       GENERIC_READ,
-                       FILE_SHARE_READ,
-                       NULL,
-                       OPEN_EXISTING,
-                       0,
-                       NULL );
-
-    if (file == INVALID_HANDLE_VALUE)
-        return NULL;
-
-    sz = GetFileSize( file, NULL );
-    data      = NULL;
-
-    if (sz > 0) {
-        data = (char*) malloc( sz );
-        if (data == NULL) {
-            fprintf(stderr, "load_file: could not allocate %ld bytes\n", sz );
-            sz = 0;
-        } else {
-            DWORD  out_bytes;
-
-            if ( !ReadFile( file, data, sz, &out_bytes, NULL ) ||
-                 out_bytes != sz )
-            {
-                fprintf(stderr, "load_file: could not read %ld bytes from '%s'\n", sz, fn);
-                free(data);
-                data      = NULL;
-                sz = 0;
-            }
-        }
-    }
-    CloseHandle( file );
-
-    *_sz = (unsigned) sz;
-    return  data;
-}
diff --git a/fastbootd/Android.mk b/fastbootd/Android.mk
new file mode 100644
index 0000000..76b28e2
--- /dev/null
+++ b/fastbootd/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2013 Google Inc.
+#
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    config.c \
+    commands.c \
+    fastbootd.c \
+    protocol.c \
+    transport.c \
+    usb_linux_client.c
+
+LOCAL_MODULE := fastbootd
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
+
+LOCAL_STATIC_LIBRARIES := \
+    libsparse_static \
+    libc \
+    libcutils
+
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+
+include $(BUILD_EXECUTABLE)
diff --git a/fastbootd/bootimg.h b/fastbootd/bootimg.h
new file mode 100644
index 0000000..44fde92
--- /dev/null
+++ b/fastbootd/bootimg.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BOOT_IMAGE_H_
+#define _BOOT_IMAGE_H_
+
+typedef struct boot_img_hdr boot_img_hdr;
+
+#define BOOT_MAGIC "ANDROID!"
+#define BOOT_MAGIC_SIZE 8
+#define BOOT_NAME_SIZE 16
+#define BOOT_ARGS_SIZE 512
+
+struct boot_img_hdr
+{
+    unsigned char magic[BOOT_MAGIC_SIZE];
+
+    unsigned kernel_size;  /* size in bytes */
+    unsigned kernel_addr;  /* physical load addr */
+
+    unsigned ramdisk_size; /* size in bytes */
+    unsigned ramdisk_addr; /* physical load addr */
+
+    unsigned second_size;  /* size in bytes */
+    unsigned second_addr;  /* physical load addr */
+
+    unsigned tags_addr;    /* physical addr for kernel tags */
+    unsigned page_size;    /* flash page size we assume */
+    unsigned unused[2];    /* future expansion: should be 0 */
+
+    unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
+    
+    unsigned char cmdline[BOOT_ARGS_SIZE];
+
+    unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+};
+
+/*
+** +-----------------+ 
+** | boot header     | 1 page
+** +-----------------+
+** | kernel          | n pages  
+** +-----------------+
+** | ramdisk         | m pages  
+** +-----------------+
+** | second stage    | o pages
+** +-----------------+
+**
+** n = (kernel_size + page_size - 1) / page_size
+** m = (ramdisk_size + page_size - 1) / page_size
+** o = (second_size + page_size - 1) / page_size
+**
+** 0. all entities are page_size aligned in flash
+** 1. kernel and ramdisk are required (size != 0)
+** 2. second is optional (second_size == 0 -> no second)
+** 3. load each element (kernel, ramdisk, second) at
+**    the specified physical address (kernel_addr, etc)
+** 4. prepare tags at tag_addr.  kernel_args[] is
+**    appended to the kernel commandline in the tags.
+** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
+** 6. if second_size != 0: jump to second_addr
+**    else: jump to kernel_addr
+*/
+
+boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
+                        void *ramdisk, unsigned ramdisk_size,
+                        void *second, unsigned second_size,
+                        unsigned page_size,
+                        unsigned *bootimg_size);
+
+void bootimg_set_cmdline(boot_img_hdr *hdr, const char *cmdline);                
+#endif
diff --git a/fastbootd/commands.c b/fastbootd/commands.c
new file mode 100644
index 0000000..252f655
--- /dev/null
+++ b/fastbootd/commands.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "bootimg.h"
+#include "debug.h"
+#include "protocol.h"
+
+static void cmd_boot(struct protocol_handle *phandle, const char *arg)
+{
+#if 0
+    unsigned kernel_actual;
+    unsigned ramdisk_actual;
+    static struct boot_img_hdr hdr;
+    char *ptr = ((char*) data);
+
+    if (sz < sizeof(hdr)) {
+        fastboot_fail(phandle, "invalid bootimage header");
+        return;
+    }
+
+    memcpy(&hdr, data, sizeof(hdr));
+
+    /* ensure commandline is terminated */
+    hdr.cmdline[BOOT_ARGS_SIZE-1] = 0;
+
+    kernel_actual = ROUND_TO_PAGE(hdr.kernel_size);
+    ramdisk_actual = ROUND_TO_PAGE(hdr.ramdisk_size);
+
+    if (2048 + kernel_actual + ramdisk_actual < sz) {
+        fastboot_fail(phandle, "incomplete bootimage");
+        return;
+    }
+
+    /*memmove((void*) KERNEL_ADDR, ptr + 2048, hdr.kernel_size);
+    memmove((void*) RAMDISK_ADDR, ptr + 2048 + kernel_actual, hdr.ramdisk_size);*/
+
+    fastboot_okay(phandle, "");
+    udc_stop();
+
+
+    /*boot_linux((void*) KERNEL_ADDR, (void*) TAGS_ADDR,
+           (const char*) hdr.cmdline, LINUX_MACHTYPE,
+           (void*) RAMDISK_ADDR, hdr.ramdisk_size);*/
+#endif
+}
+
+static void cmd_erase(struct protocol_handle *phandle, const char *arg)
+{
+#if 0
+    struct ptentry *ptn;
+    struct ptable *ptable;
+
+    ptable = flash_get_ptable();
+    if (ptable == NULL) {
+        fastboot_fail(phandle, "partition table doesn't exist");
+        return;
+    }
+
+    ptn = ptable_find(ptable, arg);
+    if (ptn == NULL) {
+        fastboot_fail(phandle, "unknown partition name");
+        return;
+    }
+
+    if (flash_erase(ptn)) {
+        fastboot_fail(phandle, "failed to erase partition");
+        return;
+    }
+    fastboot_okay(phandle, "");
+#endif
+}
+
+static void cmd_flash(struct protocol_handle *phandle, const char *arg)
+{
+#if 0
+    struct ptentry *ptn;
+    struct ptable *ptable;
+    unsigned extra = 0;
+
+    ptable = flash_get_ptable();
+    if (ptable == NULL) {
+        fastboot_fail(phandle, "partition table doesn't exist");
+        return;
+    }
+
+    ptn = ptable_find(ptable, arg);
+    if (ptn == NULL) {
+        fastboot_fail(phandle, "unknown partition name");
+        return;
+    }
+
+    if (!strcmp(ptn->name, "boot") || !strcmp(ptn->name, "recovery")) {
+        if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
+            fastboot_fail(phandle, "image is not a boot image");
+            return;
+        }
+    }
+
+    if (!strcmp(ptn->name, "system") || !strcmp(ptn->name, "userdata"))
+        extra = 64;
+    else
+        sz = ROUND_TO_PAGE(sz);
+
+    D(INFO, "writing %d bytes to '%s'\n", sz, ptn->name);
+    if (flash_write(ptn, extra, data, sz)) {
+        fastboot_fail(phandle, "flash write failure");
+        return;
+    }
+    D(INFO, "partition '%s' updated\n", ptn->name);
+#endif
+    fastboot_okay(phandle, "");
+}
+
+static void cmd_continue(struct protocol_handle *phandle, const char *arg)
+{
+    fastboot_okay(phandle, "");
+#if 0
+    udc_stop();
+
+    boot_linux_from_flash();
+#endif
+}
+
+static void cmd_getvar(struct protocol_handle *phandle, const char *arg)
+{
+    const char *value;
+    D(DEBUG, "cmd_getvar %s\n", arg);
+
+    value = fastboot_getvar(arg);
+
+    fastboot_okay(phandle, value);
+}
+
+static void cmd_download(struct protocol_handle *phandle, const char *arg)
+{
+    unsigned len = strtoul(arg, NULL, 16);
+    int old_fd;
+
+    if (len > 256 * 1024 * 1024) {
+        fastboot_fail(phandle, "data too large");
+        return;
+    }
+
+    fastboot_data(phandle, len);
+
+    old_fd = protocol_get_download(phandle);
+    if (old_fd >= 0) {
+        off_t len = lseek(old_fd, 0, SEEK_END);
+        D(INFO, "disposing of unused fd %d, size %ld", old_fd, len);
+        close(old_fd);
+    }
+
+    phandle->download_fd = protocol_handle_download(phandle, len);
+    if (phandle->download_fd < 0) {
+        //handle->state = STATE_ERROR;
+        fastboot_fail(phandle, "download failed");
+        return;
+    }
+
+    fastboot_okay(phandle, "");
+}
+
+void commands_init()
+{
+    fastboot_register("boot", cmd_boot);
+    fastboot_register("erase:", cmd_erase);
+    fastboot_register("flash:", cmd_flash);
+    fastboot_register("continue", cmd_continue);
+    fastboot_register("getvar:", cmd_getvar);
+    fastboot_register("download:", cmd_download);
+    //fastboot_publish("version", "0.5");
+    //fastboot_publish("product", "swordfish");
+    //fastboot_publish("kernel", "lk");
+}
diff --git a/fastbootd/config.c b/fastbootd/config.c
new file mode 100644
index 0000000..b8503fd
--- /dev/null
+++ b/fastbootd/config.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "protocol.h"
+
+#include "debug.h"
+
+// TODO: change config path
+#define CONFIG_PATH "/data/fastboot.cfg"
+
+static char *strip(char *str)
+{
+    int n;
+
+    n = strspn(str, " \t");
+    str += n;
+
+    for (n = strlen(str) - 1; n >= 0; n--) {
+        if (str[n] == ' ' || str[n] == '\t')
+            str[n] = '\0';
+        else
+            break;
+    }
+
+    return str;
+}
+
+static int config_parse_line(char *line)
+{
+    char *c;
+    char *key;
+    char *value;
+
+    c = strchr(line, '#');
+    if (c)
+        *c = '\0';
+
+    if (strspn(line, " \t") == strlen(line))
+        return 0;
+
+    c = strchr(line, '=');
+    if (c == NULL)
+        return -1;
+
+    key = line;
+    *c = '\0';
+    value = c + 1;
+
+    key = strip(key);
+    value = strip(value);
+
+    key = strdup(key);
+    value = strdup(value);
+
+    fastboot_publish(key, value);
+
+    return 0;
+}
+
+static void config_parse(char *buffer)
+{
+    char *saveptr;
+    char *str = buffer;
+    char *line = buffer;
+    int c;
+    int ret;
+
+    for (c = 1; line != NULL; c++) {
+        line = strtok_r(str, "\r\n", &saveptr);
+        if (line != NULL) {
+            D(VERBOSE, "'%s'", line);
+            ret = config_parse_line(line);
+            if (ret < 0) {
+                D(WARN, "error parsing " CONFIG_PATH " line %d", c);
+            }
+        }
+        str = NULL;
+    }
+}
+
+void config_init()
+{
+    int fd;
+    off_t len;
+    ssize_t ret;
+    size_t count = 0;
+    char *buffer;
+
+    fd = open(CONFIG_PATH, O_RDONLY);
+    if (fd < 0) {
+        D(ERR, "failed to open " CONFIG_PATH);
+        return;
+    }
+
+    len = lseek(fd, 0, SEEK_END);
+    if (len < 0) {
+        D(ERR, "failed to seek to end of " CONFIG_PATH);
+        return;
+    }
+
+    lseek(fd, 0, SEEK_SET);
+
+    buffer = malloc(len + 1);
+    if (buffer == NULL) {
+        D(ERR, "failed to allocate %ld bytes", len);
+        return;
+    }
+
+    while (count < (size_t)len) {
+        ret = read(fd, buffer + count, len - count);
+        if (ret < 0 && errno != EINTR) {
+            D(ERR, "failed to read " CONFIG_PATH ": %d %s", errno, strerror(errno));
+            return;
+        }
+        if (ret == 0) {
+            D(ERR, "early EOF reading " CONFIG_PATH);
+            return;
+        }
+
+        count += ret;
+    }
+
+    buffer[len] = '\0';
+
+    config_parse(buffer);
+
+    free(buffer);
+}
diff --git a/fastbootd/debug.h b/fastbootd/debug.h
new file mode 100644
index 0000000..74620b8
--- /dev/null
+++ b/fastbootd/debug.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 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 _FASTBOOTD_DEBUG_H_
+#define _FASTBOOTD_DEBUG_H_
+
+#include <stdio.h>
+
+#include <cutils/klog.h>
+
+#define ERR 0
+#define WARN 1
+#define INFO 2
+#define VERBOSE 3
+#define DEBUG 4
+
+extern unsigned int debug_level;
+
+//#define DLOG(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#define DLOG(fmt, ...) KLOG_INFO("fastbootd", fmt, ##__VA_ARGS__)
+
+#define D(level, fmt, ...) \
+    do { \
+        if (debug_level == level || debug_level > level) { \
+            DLOG("%s:%d " fmt "\n", __BASE_FILE__, __LINE__, ##__VA_ARGS__); \
+        } \
+    } while (0)
+
+#endif
diff --git a/fastbootd/fastbootd.c b/fastbootd/fastbootd.c
new file mode 100644
index 0000000..98df0db
--- /dev/null
+++ b/fastbootd/fastbootd.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 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 <stdio.h>
+#include <unistd.h>
+
+#include <cutils/klog.h>
+
+#include "debug.h"
+
+unsigned int debug_level = DEBUG;
+
+void commands_init();
+void usb_init();
+void config_init();
+
+int main(int argc, char **argv)
+{
+    (void)argc;
+    (void)argv;
+
+    klog_init();
+    klog_set_level(6);
+
+    config_init();
+    commands_init();
+    usb_init();
+    while (1) {
+        sleep(1);
+    }
+    return 0;
+}
diff --git a/fastbootd/protocol.c b/fastbootd/protocol.c
new file mode 100644
index 0000000..0086b4a
--- /dev/null
+++ b/fastbootd/protocol.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "debug.h"
+#include "protocol.h"
+#include "transport.h"
+
+#define STATE_OFFLINE   0
+#define STATE_COMMAND   1
+#define STATE_COMPLETE  2
+#define STATE_ERROR     3
+
+struct fastboot_cmd {
+    struct fastboot_cmd *next;
+    const char *prefix;
+    unsigned prefix_len;
+    void (*execute)(struct protocol_handle *phandle, const char *arg);
+};
+
+struct fastboot_var {
+    struct fastboot_var *next;
+    const char *name;
+    const char *value;
+};
+
+static struct fastboot_cmd *cmdlist;
+
+void fastboot_register(const char *prefix,
+        void (*phandle)(struct protocol_handle *phandle, const char *arg))
+{
+    struct fastboot_cmd *cmd;
+    cmd = malloc(sizeof(*cmd));
+    if (cmd) {
+        cmd->prefix = prefix;
+        cmd->prefix_len = strlen(prefix);
+        cmd->execute = phandle;
+        cmd->next = cmdlist;
+        cmdlist = cmd;
+    }
+}
+
+static struct fastboot_var *varlist;
+
+void fastboot_publish(const char *name, const char *value)
+{
+    struct fastboot_var *var;
+    var = malloc(sizeof(*var));
+    if (var) {
+        var->name = name;
+        var->value = value;
+        var->next = varlist;
+        varlist = var;
+    }
+}
+
+const char *fastboot_getvar(const char *name)
+{
+    struct fastboot_var *var;
+
+    for (var = varlist; var; var = var->next) {
+        if (!strcmp(var->name, name)) {
+            return var->value;
+        }
+    }
+
+    return "";
+}
+
+int protocol_handle_download(struct protocol_handle *phandle, size_t len)
+{
+    return transport_handle_download(phandle->transport_handle, len);
+}
+
+static ssize_t protocol_handle_write(struct protocol_handle *phandle,
+        char *buffer, size_t len)
+{
+    return transport_handle_write(phandle->transport_handle, buffer, len);
+}
+
+static void fastboot_ack(struct protocol_handle *phandle, const char *code,
+        const char *reason)
+{
+    char response[64];
+
+    if (phandle->state != STATE_COMMAND)
+        return;
+
+    if (reason == 0)
+        reason = "";
+
+    snprintf(response, 64, "%s%s", code, reason);
+    phandle->state = STATE_COMPLETE;
+
+    protocol_handle_write(phandle, response, strlen(response));
+}
+
+void fastboot_fail(struct protocol_handle *phandle, const char *reason)
+{
+    fastboot_ack(phandle, "FAIL", reason);
+}
+
+void fastboot_okay(struct protocol_handle *phandle, const char *info)
+{
+    fastboot_ack(phandle, "OKAY", info);
+}
+
+void fastboot_data(struct protocol_handle *phandle, size_t len)
+{
+    char response[64];
+    ssize_t ret;
+
+    snprintf(response, 64, "DATA%08x", len);
+    ret = protocol_handle_write(phandle, response, strlen(response));
+    if (ret < 0)
+        return;
+}
+
+void protocol_handle_command(struct protocol_handle *phandle, char *buffer)
+{
+    D(INFO,"fastboot: %s\n", buffer);
+
+    struct fastboot_cmd *cmd;
+
+    for (cmd = cmdlist; cmd; cmd = cmd->next) {
+        if (memcmp(buffer, cmd->prefix, cmd->prefix_len))
+            continue;
+        phandle->state = STATE_COMMAND;
+        cmd->execute(phandle, buffer + cmd->prefix_len);
+        if (phandle->state == STATE_COMMAND)
+            fastboot_fail(phandle, "unknown reason");
+        return;
+    }
+
+    fastboot_fail(phandle, "unknown command");
+}
+
+struct protocol_handle *create_protocol_handle(struct transport_handle *thandle)
+{
+    struct protocol_handle *phandle;
+
+    phandle = calloc(sizeof(struct protocol_handle), 1);
+
+    phandle->transport_handle = thandle;
+    phandle->state = STATE_OFFLINE;
+    phandle->download_fd = -1;
+
+    pthread_mutex_init(&phandle->lock, NULL);
+
+    return phandle;
+}
+
+int protocol_get_download(struct protocol_handle *phandle)
+{
+    int fd;
+
+    pthread_mutex_lock(&phandle->lock);
+    fd = phandle->download_fd;
+    phandle->download_fd = -1;
+    pthread_mutex_unlock(&phandle->lock);
+
+    return fd;
+}
diff --git a/fastbootd/protocol.h b/fastbootd/protocol.h
new file mode 100644
index 0000000..ea2a8df
--- /dev/null
+++ b/fastbootd/protocol.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _FASTBOOTD_PROTOCOL_H_
+#define _FASTBOOTD_PROTOCOL_H_
+
+#include <pthread.h>
+#include <stddef.h>
+
+struct protocol_handle {
+    struct transport_handle *transport_handle;
+    unsigned int state;
+    int download_fd;
+
+    pthread_mutex_t lock;
+};
+
+void fastboot_register(const char *prefix,
+               void (*handle)(struct protocol_handle *handle, const char *arg));
+
+void fastboot_publish(const char *name, const char *value);
+const char *fastboot_getvar(const char *name);
+
+struct protocol_handle *create_protocol_handle(struct transport_handle *t);
+void protocol_handle_command(struct protocol_handle *handle, char *buffer);
+int protocol_handle_download(struct protocol_handle *phandle, size_t len);
+int protocol_get_download(struct protocol_handle *phandle);
+
+void fastboot_fail(struct protocol_handle *handle, const char *reason);
+void fastboot_okay(struct protocol_handle *handle, const char *reason);
+void fastboot_data(struct protocol_handle *handle, size_t len);
+
+#endif
diff --git a/fastbootd/transport.c b/fastbootd/transport.c
new file mode 100644
index 0000000..01a5a8a
--- /dev/null
+++ b/fastbootd/transport.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2013 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 <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "debug.h"
+#include "protocol.h"
+#include "transport.h"
+
+#define COMMAND_BUF_SIZE 64
+
+ssize_t transport_handle_write(struct transport_handle *thandle, char *buffer, size_t len)
+{
+    return thandle->transport->write(thandle, buffer, len);
+}
+
+void transport_handle_close(struct transport_handle *thandle)
+{
+    thandle->transport->close(thandle);
+}
+
+int transport_handle_download(struct transport_handle *thandle, size_t len)
+{
+    ssize_t ret;
+    size_t n = 0;
+    int fd;
+    // TODO: move out of /dev
+    char tempname[] = "/dev/fastboot_download_XXXXXX";
+    char *buffer;
+
+    fd = mkstemp(tempname);
+    if (fd < 0)
+        return -1;
+
+    unlink(tempname);
+
+    ftruncate(fd, len);
+
+    buffer = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    if (buffer == NULL) {
+        D(ERR, "mmap(%u) failed: %d %s", len, errno, strerror(errno));
+        goto err;
+    }
+
+    while (n < len) {
+        ret = thandle->transport->read(thandle, buffer + n, len - n);
+        if (ret <= 0) {
+            D(WARN, "transport read failed, ret=%d %s", ret, strerror(-ret));
+            break;
+        }
+        n += ret;
+    }
+
+    munmap(buffer, len);
+
+    if (n != len)
+        goto err;
+
+    return fd;
+
+err:
+    close(fd);
+    transport_handle_close(thandle);
+    return -1;
+}
+
+static void *transport_data_thread(void *arg)
+{
+    struct transport_handle *thandle = arg;
+    struct protocol_handle *phandle = create_protocol_handle(thandle);
+
+    while (!thandle->stopped) {
+        int ret;
+        char buffer[COMMAND_BUF_SIZE + 1];
+        D(VERBOSE, "transport_data_thread\n");
+
+        ret = thandle->transport->read(thandle, buffer, COMMAND_BUF_SIZE);
+        if (ret <= 0) {
+            D(DEBUG, "ret = %d\n", ret);
+            break;
+        }
+        if (ret > 0) {
+            buffer[ret] = 0;
+            protocol_handle_command(phandle, buffer);
+        }
+    }
+
+    transport_handle_close(thandle);
+    free(thandle);
+
+    return NULL;
+}
+
+static void *transport_connect_thread(void *arg)
+{
+    struct transport *transport = arg;
+    while (!transport->stopped) {
+        struct transport_handle *thandle;
+        pthread_t thread;
+        pthread_attr_t attr;
+
+        D(VERBOSE, "transport_connect_thread\n");
+        thandle = transport->connect(transport);
+        if (thandle == NULL) {
+            D(ERR, "transport connect failed\n");
+            sleep(1);
+            continue;
+        }
+        thandle->transport = transport;
+
+        pthread_attr_init(&attr);
+        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+        pthread_create(&thread, &attr, transport_data_thread, thandle);
+
+        sleep(1);
+    }
+
+    return NULL;
+}
+
+void transport_register(struct transport *transport)
+{
+    pthread_t thread;
+    pthread_attr_t attr;
+
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+    pthread_create(&thread, &attr, transport_connect_thread, transport);
+}
diff --git a/fastbootd/transport.h b/fastbootd/transport.h
new file mode 100644
index 0000000..209340d
--- /dev/null
+++ b/fastbootd/transport.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 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 _FASTBOOTD_TRANSPORT_H_
+#define _FASTBOOTD_TRANSPORT_H_
+
+#include <stdbool.h>
+
+struct transport_handle {
+    struct transport *transport;
+
+    bool stopped;
+};
+
+struct transport {
+    void (*init)();
+    void (*close)(struct transport_handle *thandle);
+    ssize_t (*read)(struct transport_handle *thandle, void *data, size_t len);
+    ssize_t (*write)(struct transport_handle *thandle, const void *data, size_t len);
+    struct transport_handle *(*connect)(struct transport *transport);
+    bool stopped;
+};
+
+void transport_register(struct transport *transport);
+ssize_t transport_handle_write(struct transport_handle *handle, char *buffer, size_t len);
+int transport_handle_download(struct transport_handle *handle, size_t len);
+
+#endif
diff --git a/fastbootd/usb_linux_client.c b/fastbootd/usb_linux_client.c
new file mode 100644
index 0000000..111cf35
--- /dev/null
+++ b/fastbootd/usb_linux_client.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2007 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 <endian.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
+
+#include "debug.h"
+#include "transport.h"
+
+#define   TRACE_TAG  TRACE_USB
+
+#define MAX_PACKET_SIZE_FS     64
+#define MAX_PACKET_SIZE_HS     512
+
+#define cpu_to_le16(x)  htole16(x)
+#define cpu_to_le32(x)  htole32(x)
+
+#define FASTBOOT_CLASS         0xff
+#define FASTBOOT_SUBCLASS      0x42
+#define FASTBOOT_PROTOCOL      0x3
+
+#define USB_FFS_FASTBOOT_PATH  "/dev/usb-ffs/adb/"
+#define USB_FFS_FASTBOOT_EP(x) USB_FFS_FASTBOOT_PATH#x
+
+#define USB_FFS_FASTBOOT_EP0   USB_FFS_FASTBOOT_EP(ep0)
+#define USB_FFS_FASTBOOT_OUT   USB_FFS_FASTBOOT_EP(ep1)
+#define USB_FFS_FASTBOOT_IN    USB_FFS_FASTBOOT_EP(ep2)
+
+#define READ_BUF_SIZE (16*1024)
+
+#define container_of(ptr, type, member) \
+    ((type*)((char*)(ptr) - offsetof(type, member)))
+
+struct usb_transport {
+    struct transport transport;
+
+    pthread_cond_t notify;
+    pthread_mutex_t lock;
+
+    int control;
+    int bulk_out; /* "out" from the host's perspective => source for fastbootd */
+    int bulk_in;  /* "in" from the host's perspective => sink for fastbootd */
+};
+
+struct usb_handle {
+    struct transport_handle handle;
+};
+
+static const struct {
+    struct usb_functionfs_descs_head header;
+    struct {
+        struct usb_interface_descriptor intf;
+        struct usb_endpoint_descriptor_no_audio source;
+        struct usb_endpoint_descriptor_no_audio sink;
+    } __attribute__((packed)) fs_descs, hs_descs;
+} __attribute__((packed)) descriptors = {
+    .header = {
+        .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+        .length = cpu_to_le32(sizeof(descriptors)),
+        .fs_count = 3,
+        .hs_count = 3,
+    },
+    .fs_descs = {
+        .intf = {
+            .bLength = sizeof(descriptors.fs_descs.intf),
+            .bDescriptorType = USB_DT_INTERFACE,
+            .bInterfaceNumber = 0,
+            .bNumEndpoints = 2,
+            .bInterfaceClass = FASTBOOT_CLASS,
+            .bInterfaceSubClass = FASTBOOT_SUBCLASS,
+            .bInterfaceProtocol = FASTBOOT_PROTOCOL,
+            .iInterface = 1, /* first string from the provided table */
+        },
+        .source = {
+            .bLength = sizeof(descriptors.fs_descs.source),
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 1 | USB_DIR_OUT,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+        },
+        .sink = {
+            .bLength = sizeof(descriptors.fs_descs.sink),
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 2 | USB_DIR_IN,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+        },
+    },
+    .hs_descs = {
+        .intf = {
+            .bLength = sizeof(descriptors.hs_descs.intf),
+            .bDescriptorType = USB_DT_INTERFACE,
+            .bInterfaceNumber = 0,
+            .bNumEndpoints = 2,
+            .bInterfaceClass = FASTBOOT_CLASS,
+            .bInterfaceSubClass = FASTBOOT_SUBCLASS,
+            .bInterfaceProtocol = FASTBOOT_PROTOCOL,
+            .iInterface = 1, /* first string from the provided table */
+        },
+        .source = {
+            .bLength = sizeof(descriptors.hs_descs.source),
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 1 | USB_DIR_OUT,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+        },
+        .sink = {
+            .bLength = sizeof(descriptors.hs_descs.sink),
+            .bDescriptorType = USB_DT_ENDPOINT,
+            .bEndpointAddress = 2 | USB_DIR_IN,
+            .bmAttributes = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+        },
+    },
+};
+
+#define STR_INTERFACE_ "Fastboot Interface"
+
+static const struct {
+    struct usb_functionfs_strings_head header;
+    struct {
+        __le16 code;
+        const char str1[sizeof(STR_INTERFACE_)];
+    } __attribute__((packed)) lang0;
+} __attribute__((packed)) strings = {
+    .header = {
+        .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
+        .length = cpu_to_le32(sizeof(strings)),
+        .str_count = cpu_to_le32(1),
+        .lang_count = cpu_to_le32(1),
+    },
+    .lang0 = {
+        cpu_to_le16(0x0409), /* en-us */
+        STR_INTERFACE_,
+    },
+};
+
+static int init_functionfs(struct usb_transport *usb_transport)
+{
+    ssize_t ret;
+
+    D(VERBOSE, "OPENING %s", USB_FFS_FASTBOOT_EP0);
+    usb_transport->control = open(USB_FFS_FASTBOOT_EP0, O_RDWR);
+    if (usb_transport->control < 0) {
+        D(ERR, "[ %s: cannot open control endpoint: errno=%d]", USB_FFS_FASTBOOT_EP0, errno);
+        goto err;
+    }
+
+    ret = write(usb_transport->control, &descriptors, sizeof(descriptors));
+    if (ret < 0) {
+        D(ERR, "[ %s: write descriptors failed: errno=%d ]", USB_FFS_FASTBOOT_EP0, errno);
+        goto err;
+    }
+
+    ret = write(usb_transport->control, &strings, sizeof(strings));
+    if (ret < 0) {
+        D(ERR, "[ %s: writing strings failed: errno=%d]", USB_FFS_FASTBOOT_EP0, errno);
+        goto err;
+    }
+
+    usb_transport->bulk_out = open(USB_FFS_FASTBOOT_OUT, O_RDWR);
+    if (usb_transport->bulk_out < 0) {
+        D(ERR, "[ %s: cannot open bulk-out ep: errno=%d ]", USB_FFS_FASTBOOT_OUT, errno);
+        goto err;
+    }
+
+    usb_transport->bulk_in = open(USB_FFS_FASTBOOT_IN, O_RDWR);
+    if (usb_transport->bulk_in < 0) {
+        D(ERR, "[ %s: cannot open bulk-in ep: errno=%d ]", USB_FFS_FASTBOOT_IN, errno);
+        goto err;
+    }
+
+    return 0;
+
+err:
+    if (usb_transport->bulk_in > 0) {
+        close(usb_transport->bulk_in);
+        usb_transport->bulk_in = -1;
+    }
+    if (usb_transport->bulk_out > 0) {
+        close(usb_transport->bulk_out);
+        usb_transport->bulk_out = -1;
+    }
+    if (usb_transport->control > 0) {
+        close(usb_transport->control);
+        usb_transport->control = -1;
+    }
+    return -1;
+}
+
+static ssize_t bulk_write(int bulk_in, const char *buf, size_t length)
+{
+    size_t count = 0;
+    ssize_t ret;
+
+    do {
+        ret = TEMP_FAILURE_RETRY(write(bulk_in, buf + count, length - count));
+        if (ret < 0) {
+            D(WARN, "[ bulk_read failed fd=%d length=%d errno=%d %s ]",
+                    bulk_in, length, errno, strerror(errno));
+            return -1;
+        } else {
+            count += ret;
+        }
+    } while (count < length);
+
+    D(VERBOSE, "[ bulk_write done fd=%d ]", bulk_in);
+    return count;
+}
+
+static ssize_t usb_write(struct transport_handle *thandle, const void *data, size_t len)
+{
+    ssize_t ret;
+    struct transport *t = thandle->transport;
+    struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
+
+    D(DEBUG, "about to write (fd=%d, len=%d)", usb_transport->bulk_in, len);
+    ret = bulk_write(usb_transport->bulk_in, data, len);
+    if (ret < 0) {
+        D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_in, ret);
+        return -1;
+    }
+    D(DEBUG, "[ usb_write done fd=%d ]", usb_transport->bulk_in);
+    return ret;
+}
+
+static ssize_t bulk_read(int bulk_out, char *buf, size_t length)
+{
+    ssize_t ret;
+    size_t n = 0;
+
+    while (n < length) {
+        size_t to_read = (length - n > READ_BUF_SIZE) ? READ_BUF_SIZE : length - n;
+        ret = TEMP_FAILURE_RETRY(read(bulk_out, buf + n, to_read));
+        if (ret < 0) {
+            D(WARN, "[ bulk_read failed fd=%d length=%d errno=%d %s ]",
+                    bulk_out, length, errno, strerror(errno));
+            return ret;
+        }
+        n += ret;
+        if (ret < (ssize_t)to_read) {
+            D(VERBOSE, "bulk_read short read, ret=%zd to_read=%u n=%u length=%u",
+                    ret, to_read, n, length);
+            break;
+        }
+    }
+
+    return n;
+}
+
+ssize_t usb_read(struct transport_handle *thandle, void *data, size_t len)
+{
+    ssize_t ret;
+    struct transport *t = thandle->transport;
+    struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
+
+    D(DEBUG, "about to read (fd=%d, len=%d)", usb_transport->bulk_out, len);
+    ret = bulk_read(usb_transport->bulk_out, data, len);
+    if (ret < 0) {
+        D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_out, ret);
+        return -1;
+    }
+    D(DEBUG, "[ usb_read done fd=%d ret=%zd]", usb_transport->bulk_out, ret);
+    return ret;
+}
+
+void usb_close(struct transport_handle *thandle)
+{
+    int err;
+    struct transport *t = thandle->transport;
+    struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
+
+    err = ioctl(usb_transport->bulk_in, FUNCTIONFS_CLEAR_HALT);
+    if (err < 0)
+        D(WARN, "[ kick: source (fd=%d) clear halt failed (%d) ]", usb_transport->bulk_in, errno);
+
+    err = ioctl(usb_transport->bulk_out, FUNCTIONFS_CLEAR_HALT);
+    if (err < 0)
+        D(WARN, "[ kick: sink (fd=%d) clear halt failed (%d) ]", usb_transport->bulk_out, errno);
+
+    pthread_mutex_lock(&usb_transport->lock);
+    close(usb_transport->control);
+    close(usb_transport->bulk_out);
+    close(usb_transport->bulk_in);
+    usb_transport->control = usb_transport->bulk_out = usb_transport->bulk_in = -1;
+
+    pthread_cond_signal(&usb_transport->notify);
+    pthread_mutex_unlock(&usb_transport->lock);
+}
+
+struct transport_handle *usb_connect(struct transport *transport)
+{
+    int ret;
+    struct usb_handle *usb_handle = calloc(sizeof(struct usb_handle), 1);
+    struct usb_transport *usb_transport = container_of(transport, struct usb_transport, transport);
+
+    pthread_mutex_lock(&usb_transport->lock);
+    while (usb_transport->control != -1)
+        pthread_cond_wait(&usb_transport->notify, &usb_transport->lock);
+    pthread_mutex_unlock(&usb_transport->lock);
+
+    ret = init_functionfs(usb_transport);
+    if (ret < 0) {
+        D(ERR, "usb connect: failed to initialize usb transport");
+        return NULL;
+    }
+
+    D(DEBUG, "[ usb_thread - registering device ]");
+    return &usb_handle->handle;
+}
+
+void usb_init()
+{
+    struct usb_transport *usb_transport = calloc(1, sizeof(struct usb_transport));
+
+    usb_transport->transport.connect = usb_connect;
+    usb_transport->transport.close = usb_close;
+    usb_transport->transport.read = usb_read;
+    usb_transport->transport.write = usb_write;
+    usb_transport->control  = -1;
+    usb_transport->bulk_out = -1;
+    usb_transport->bulk_out = -1;
+
+    pthread_cond_init(&usb_transport->notify, NULL);
+    pthread_mutex_init(&usb_transport->lock, NULL);
+
+    transport_register(&usb_transport->transport);
+}
+
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 782ae99..790598a 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -3,12 +3,13 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= fs_mgr.c
+LOCAL_SRC_FILES:= fs_mgr.c fs_mgr_verity.c
 
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 
 LOCAL_MODULE:= libfs_mgr
-LOCAL_STATIC_LIBRARIES := liblogwrap
+LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static
+LOCAL_C_INCLUDES += system/extras/ext4_utils
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 
 include $(BUILD_STATIC_LIBRARY)
@@ -28,7 +29,7 @@
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
 
-LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc
+LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 4f11fbb..13b71ee 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -27,18 +27,35 @@
 #include <sys/wait.h>
 #include <libgen.h>
 #include <time.h>
+#include <sys/swap.h>
+/* XXX These need to be obtained from kernel headers. See b/9336527 */
+#define SWAP_FLAG_PREFER        0x8000
+#define SWAP_FLAG_PRIO_MASK     0x7fff
+#define SWAP_FLAG_PRIO_SHIFT    0
+#define SWAP_FLAG_DISCARD       0x10000
 
+#include <linux/loop.h>
 #include <private/android_filesystem_config.h>
 #include <cutils/partition_utils.h>
 #include <cutils/properties.h>
 #include <logwrap/logwrap.h>
 
+#include "mincrypt/rsa.h"
+#include "mincrypt/sha.h"
+#include "mincrypt/sha256.h"
+
 #include "fs_mgr_priv.h"
+#include "fs_mgr_priv_verity.h"
 
 #define KEY_LOC_PROP   "ro.crypto.keyfile.userdata"
 #define KEY_IN_FOOTER  "footer"
 
 #define E2FSCK_BIN      "/system/bin/e2fsck"
+#define MKSWAP_BIN      "/system/bin/mkswap"
+
+#define FSCK_LOG_FILE   "/dev/fscklogs/log"
+
+#define ZRAM_CONF_DEV   "/sys/block/zram0/disksize"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
@@ -74,10 +91,23 @@
     { "voldmanaged=",MF_VOLDMANAGED},
     { "length=",     MF_LENGTH },
     { "recoveryonly",MF_RECOVERYONLY },
+    { "swapprio=",   MF_SWAPPRIO },
+    { "zramsize=",   MF_ZRAMSIZE },
+    { "verify",      MF_VERIFY },
+    { "noemulatedsd", MF_NOEMULATEDSD },
     { "defaults",    0 },
     { 0,             0 },
 };
 
+struct fs_mgr_flag_values {
+    char *key_loc;
+    long long part_length;
+    char *label;
+    int partnum;
+    int swap_prio;
+    unsigned int zram_size;
+};
+
 /*
  * gettime() - returns the time in seconds of the system's monotonic clock or
  * zero on error.
@@ -109,7 +139,7 @@
 }
 
 static int parse_flags(char *flags, struct flag_list *fl,
-                       char **key_loc, long long *part_length, char **label, int *partnum,
+                       struct fs_mgr_flag_values *flag_vals,
                        char *fs_options, int fs_options_len)
 {
     int f = 0;
@@ -117,21 +147,12 @@
     char *p;
     char *savep;
 
-    /* initialize key_loc to null, if we find an MF_CRYPT flag,
-     * then we'll set key_loc to the proper value */
-    if (key_loc) {
-        *key_loc = NULL;
-    }
-    /* initialize part_length to 0, if we find an MF_LENGTH flag,
-     * then we'll set part_length to the proper value */
-    if (part_length) {
-        *part_length = 0;
-    }
-    if (partnum) {
-        *partnum = -1;
-    }
-    if (label) {
-        *label = NULL;
+    /* initialize flag values.  If we find a relevant flag, we'll
+     * update the value */
+    if (flag_vals) {
+        memset(flag_vals, 0, sizeof(*flag_vals));
+        flag_vals->partnum = -1;
+        flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
     }
 
     /* initialize fs_options to the null string */
@@ -147,17 +168,17 @@
         for (i = 0; fl[i].name; i++) {
             if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
                 f |= fl[i].flag;
-                if ((fl[i].flag == MF_CRYPT) && key_loc) {
+                if ((fl[i].flag == MF_CRYPT) && flag_vals) {
                     /* The encryptable flag is followed by an = and the
                      * location of the keys.  Get it and return it.
                      */
-                    *key_loc = strdup(strchr(p, '=') + 1);
-                } else if ((fl[i].flag == MF_LENGTH) && part_length) {
+                    flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+                } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
                     /* The length flag is followed by an = and the
                      * size of the partition.  Get it and return it.
                      */
-                    *part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
-                } else if ((fl[i].flag == MF_VOLDMANAGED) && label && partnum) {
+                    flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
+                } else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
                     /* The voldmanaged flag is followed by an = and the
                      * label, a colon and the partition number or the
                      * word "auto", e.g.
@@ -171,17 +192,21 @@
                     label_start = strchr(p, '=') + 1;
                     label_end = strchr(p, ':');
                     if (label_end) {
-                        *label = strndup(label_start,
-                                         (int) (label_end - label_start));
+                        flag_vals->label = strndup(label_start,
+                                                   (int) (label_end - label_start));
                         part_start = strchr(p, ':') + 1;
                         if (!strcmp(part_start, "auto")) {
-                            *partnum = -1;
+                            flag_vals->partnum = -1;
                         } else {
-                            *partnum = strtol(part_start, NULL, 0);
+                            flag_vals->partnum = strtol(part_start, NULL, 0);
                         }
                     } else {
                         ERROR("Warning: voldmanaged= flag malformed\n");
                     }
+                } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
+                    flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
+                } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
+                    flag_vals->zram_size = strtoll(strchr(p, '=') + 1, NULL, 0);
                 }
                 break;
             }
@@ -224,10 +249,7 @@
     char *save_ptr, *p;
     struct fstab *fstab = NULL;
     struct fstab_rec *recs;
-    char *key_loc;
-    long long part_length;
-    char *label;
-    int partnum;
+    struct fs_mgr_flag_values flag_vals;
 #define FS_OPTIONS_LEN 1024
     char tmp_fs_options[FS_OPTIONS_LEN];
 
@@ -315,8 +337,7 @@
             goto err;
         }
         tmp_fs_options[0] = '\0';
-        fstab->recs[cnt].flags = parse_flags(p, mount_flags,
-                                       NULL, NULL, NULL, NULL,
+        fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
                                        tmp_fs_options, FS_OPTIONS_LEN);
 
         /* fs_options are optional */
@@ -331,13 +352,13 @@
             goto err;
         }
         fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
-                                              &key_loc, &part_length,
-                                              &label, &partnum,
-                                              NULL, 0);
-        fstab->recs[cnt].key_loc = key_loc;
-        fstab->recs[cnt].length = part_length;
-        fstab->recs[cnt].label = label;
-        fstab->recs[cnt].partnum = partnum;
+                                                    &flag_vals, NULL, 0);
+        fstab->recs[cnt].key_loc = flag_vals.key_loc;
+        fstab->recs[cnt].length = flag_vals.part_length;
+        fstab->recs[cnt].label = flag_vals.label;
+        fstab->recs[cnt].partnum = flag_vals.partnum;
+        fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
+        fstab->recs[cnt].zram_size = flag_vals.zram_size;
         cnt++;
     }
     fclose(fstab_file);
@@ -356,6 +377,10 @@
 {
     int i;
 
+    if (!fstab) {
+        return;
+    }
+
     for (i = 0; i < fstab->num_entries; i++) {
         /* Free the pointers return by strdup(3) */
         free(fstab->recs[i].blk_device);
@@ -411,7 +436,8 @@
         INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
 
         ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
-                                      &status, true, LOG_KLOG, true);
+                                      &status, true, LOG_KLOG | LOG_FILE,
+                                      true, FSCK_LOG_FILE);
 
         if (ret < 0) {
             /* No need to check for error in fork, we can't really handle it now */
@@ -433,6 +459,43 @@
     }
 }
 
+/*
+ * Mark the given block device as read-only, using the BLKROSET ioctl.
+ * Return 0 on success, and -1 on error.
+ */
+static void fs_set_blk_ro(const char *blockdev)
+{
+    int fd;
+    int ON = 1;
+
+    fd = open(blockdev, O_RDONLY);
+    if (fd < 0) {
+        // should never happen
+        return;
+    }
+
+    ioctl(fd, BLKROSET, &ON);
+    close(fd);
+}
+
+/*
+ * __mount(): wrapper around the mount() system call which also
+ * sets the underlying block device to read-only if the mount is read-only.
+ * See "man 2 mount" for return values.
+ */
+static int __mount(const char *source, const char *target,
+                   const char *filesystemtype, unsigned long mountflags,
+                   const void *data)
+{
+    int ret = mount(source, target, filesystemtype, mountflags, data);
+
+    if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
+        fs_set_blk_ro(source);
+    }
+
+    return ret;
+}
+
 static int fs_match(char *in1, char *in2)
 {
     char *n1;
@@ -470,8 +533,9 @@
             continue;
         }
 
-        /* Skip raw partition entries such as boot, recovery, etc */
-        if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
+        /* Skip swap and raw partition entries such as boot, recovery, etc */
+        if (!strcmp(fstab->recs[i].fs_type, "swap") ||
+            !strcmp(fstab->recs[i].fs_type, "emmc") ||
             !strcmp(fstab->recs[i].fs_type, "mtd")) {
             continue;
         }
@@ -485,9 +549,17 @@
                      fstab->recs[i].mount_point);
         }
 
-        mret = mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
+        if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
+            if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
+                ERROR("Could not set up verified partition, skipping!");
+                continue;
+            }
+        }
+
+        mret = __mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
                      fstab->recs[i].fs_type, fstab->recs[i].flags,
                      fstab->recs[i].fs_options);
+
         if (!mret) {
             /* Success!  Go get the next one */
             continue;
@@ -543,8 +615,9 @@
         }
 
         /* We found our match */
-        /* If this is a raw partition, report an error */
-        if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
+        /* If this swap or a raw partition, report an error */
+        if (!strcmp(fstab->recs[i].fs_type, "swap") ||
+            !strcmp(fstab->recs[i].fs_type, "emmc") ||
             !strcmp(fstab->recs[i].fs_type, "mtd")) {
             ERROR("Cannot mount filesystem of type %s on %s\n",
                   fstab->recs[i].fs_type, n_blk_device);
@@ -561,14 +634,21 @@
                      fstab->recs[i].mount_point);
         }
 
+        if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
+            if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
+                ERROR("Could not set up verified partition, skipping!");
+                continue;
+            }
+        }
+
         /* Now mount it where requested */
         if (tmp_mount_point) {
             m = tmp_mount_point;
         } else {
             m = fstab->recs[i].mount_point;
         }
-        if (mount(n_blk_device, m, fstab->recs[i].fs_type,
-                  fstab->recs[i].flags, fstab->recs[i].fs_options)) {
+        if (__mount(n_blk_device, m, fstab->recs[i].fs_type,
+                    fstab->recs[i].flags, fstab->recs[i].fs_options)) {
             ERROR("Cannot mount filesystem on %s at %s\n",
                     n_blk_device, m);
             goto out;
@@ -623,6 +703,83 @@
 
     return ret;
 }
+
+/* This must be called after mount_all, because the mkswap command needs to be
+ * available.
+ */
+int fs_mgr_swapon_all(struct fstab *fstab)
+{
+    int i = 0;
+    int flags = 0;
+    int err = 0;
+    int ret = 0;
+    int status;
+    char *mkswap_argv[2] = {
+        MKSWAP_BIN,
+        NULL
+    };
+
+    if (!fstab) {
+        return -1;
+    }
+
+    for (i = 0; i < fstab->num_entries; i++) {
+        /* Skip non-swap entries */
+        if (strcmp(fstab->recs[i].fs_type, "swap")) {
+            continue;
+        }
+
+        if (fstab->recs[i].zram_size > 0) {
+            /* A zram_size was specified, so we need to configure the
+             * device.  There is no point in having multiple zram devices
+             * on a system (all the memory comes from the same pool) so
+             * we can assume the device number is 0.
+             */
+            FILE *zram_fp;
+
+            zram_fp = fopen(ZRAM_CONF_DEV, "r+");
+            if (zram_fp == NULL) {
+                ERROR("Unable to open zram conf device " ZRAM_CONF_DEV);
+                ret = -1;
+                continue;
+            }
+            fprintf(zram_fp, "%d\n", fstab->recs[i].zram_size);
+            fclose(zram_fp);
+        }
+
+        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
+            wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
+        }
+
+        /* Initialize the swap area */
+        mkswap_argv[1] = fstab->recs[i].blk_device;
+        err = android_fork_execvp_ext(ARRAY_SIZE(mkswap_argv), mkswap_argv,
+                                      &status, true, LOG_KLOG, false, NULL);
+        if (err) {
+            ERROR("mkswap failed for %s\n", fstab->recs[i].blk_device);
+            ret = -1;
+            continue;
+        }
+
+        /* If -1, then no priority was specified in fstab, so don't set
+         * SWAP_FLAG_PREFER or encode the priority */
+        if (fstab->recs[i].swap_prio >= 0) {
+            flags = (fstab->recs[i].swap_prio << SWAP_FLAG_PRIO_SHIFT) &
+                    SWAP_FLAG_PRIO_MASK;
+            flags |= SWAP_FLAG_PREFER;
+        } else {
+            flags = 0;
+        }
+        err = swapon(fstab->recs[i].blk_device, flags);
+        if (err) {
+            ERROR("swapon failed for %s\n", fstab->recs[i].blk_device);
+            ret = -1;
+        }
+    }
+
+    return ret;
+}
+
 /*
  * key_loc must be at least PROPERTY_VALUE_MAX bytes long
  *
@@ -729,3 +886,7 @@
     return fstab->fs_mgr_flags & MF_CRYPT;
 }
 
+int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index f961b39..59ffd78 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -69,6 +69,17 @@
 #define MF_VOLDMANAGED  0x10
 #define MF_LENGTH       0x20
 #define MF_RECOVERYONLY 0x40
+#define MF_SWAPPRIO     0x80
+#define MF_ZRAMSIZE     0x100
+#define MF_VERIFY       0x200
+/*
+ * There is no emulated sdcard daemon running on /data/media on this device,
+ * so treat the physical SD card as the only external storage device,
+ * a la the Nexus One.
+ */
+#define MF_NOEMULATEDSD 0x400
+
+#define DM_BUF_SIZE 4096
 
 #endif /* __CORE_FS_MGR_PRIV_H */
 
diff --git a/include/cutils/zygote.h b/fs_mgr/fs_mgr_priv_verity.h
similarity index 63%
copy from include/cutils/zygote.h
copy to fs_mgr/fs_mgr_priv_verity.h
index a7480d3..6193784 100644
--- a/include/cutils/zygote.h
+++ b/fs_mgr/fs_mgr_priv_verity.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -14,18 +14,4 @@
  * limitations under the License.
  */
 
-#ifndef __CUTILS_ZYGOTE_H
-#define __CUTILS_ZYGOTE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int zygote_run_oneshot(int sendStdio, int argc, const char **argv);
-int zygote_run(int argc, const char **argv);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __CUTILS_ZYGOTE_H */
+int fs_mgr_setup_verity(struct fstab_rec *fstab);
\ No newline at end of file
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
new file mode 100644
index 0000000..969eab2
--- /dev/null
+++ b/fs_mgr/fs_mgr_verity.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2013 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <libgen.h>
+#include <time.h>
+
+#include <private/android_filesystem_config.h>
+#include <logwrap/logwrap.h>
+
+#include "mincrypt/rsa.h"
+#include "mincrypt/sha.h"
+#include "mincrypt/sha256.h"
+
+#include "ext4_utils.h"
+#include "ext4.h"
+
+#include "fs_mgr_priv.h"
+#include "fs_mgr_priv_verity.h"
+
+#define VERITY_METADATA_SIZE 32768
+#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001
+#define VERITY_TABLE_RSA_KEY "/verity_key"
+
+extern struct fs_info info;
+
+static RSAPublicKey *load_key(char *path)
+{
+    FILE *f;
+    RSAPublicKey *key;
+
+    key = malloc(sizeof(RSAPublicKey));
+    if (!key) {
+        ERROR("Can't malloc key\n");
+        return NULL;
+    }
+
+    f = fopen(path, "r");
+    if (!f) {
+        ERROR("Can't open '%s'\n", path);
+        free(key);
+        return NULL;
+    }
+
+    if (!fread(key, sizeof(*key), 1, f)) {
+        ERROR("Could not read key!");
+        fclose(f);
+        free(key);
+        return NULL;
+    }
+
+    if (key->len != RSANUMWORDS) {
+        ERROR("Invalid key length %d\n", key->len);
+        fclose(f);
+        free(key);
+        return NULL;
+    }
+
+    fclose(f);
+    return key;
+}
+
+static int verify_table(char *signature, char *table, int table_length)
+{
+    int fd;
+    RSAPublicKey *key;
+    uint8_t hash_buf[SHA_DIGEST_SIZE];
+    int retval = -1;
+
+    // Hash the table
+    SHA_hash((uint8_t*)table, table_length, hash_buf);
+
+    // Now get the public key from the keyfile
+    key = load_key(VERITY_TABLE_RSA_KEY);
+    if (!key) {
+        ERROR("Couldn't load verity keys");
+        goto out;
+    }
+
+    // verify the result
+    if (!RSA_verify(key,
+                    (uint8_t*) signature,
+                    RSANUMBYTES,
+                    (uint8_t*) hash_buf,
+                    SHA_DIGEST_SIZE)) {
+        ERROR("Couldn't verify table.");
+        goto out;
+    }
+
+    retval = 0;
+
+out:
+    free(key);
+    return retval;
+}
+
+static int get_target_device_size(char *blk_device, uint64_t *device_size)
+{
+    int data_device;
+    struct ext4_super_block sb;
+
+    data_device = open(blk_device, O_RDONLY);
+    if (data_device < 0) {
+        ERROR("Error opening block device (%s)", strerror(errno));
+        return -1;
+    }
+
+    if (lseek64(data_device, 1024, SEEK_SET) < 0) {
+        ERROR("Error seeking to superblock");
+        close(data_device);
+        return -1;
+    }
+
+    if (read(data_device, &sb, sizeof(sb)) != sizeof(sb)) {
+        ERROR("Error reading superblock");
+        close(data_device);
+        return -1;
+    }
+
+    ext4_parse_sb(&sb);
+    *device_size = info.len;
+
+    close(data_device);
+    return 0;
+}
+
+static int read_verity_metadata(char *block_device, char **signature, char **table)
+{
+    unsigned magic_number;
+    unsigned table_length;
+    uint64_t device_length;
+    int protocol_version;
+    FILE *device;
+    int retval = -1;
+
+    device = fopen(block_device, "r");
+    if (!device) {
+        ERROR("Could not open block device %s (%s).\n", block_device, strerror(errno));
+        goto out;
+    }
+
+    // find the start of the verity metadata
+    if (get_target_device_size(block_device, &device_length) < 0) {
+        ERROR("Could not get target device size.\n");
+        goto out;
+    }
+    if (fseek(device, device_length, SEEK_SET) < 0) {
+        ERROR("Could not seek to start of verity metadata block.\n");
+        goto out;
+    }
+
+    // check the magic number
+    if (!fread(&magic_number, sizeof(int), 1, device)) {
+        ERROR("Couldn't read magic number!\n");
+        goto out;
+    }
+    if (magic_number != VERITY_METADATA_MAGIC_NUMBER) {
+        ERROR("Couldn't find verity metadata at offset %llu!\n", device_length);
+        goto out;
+    }
+
+    // check the protocol version
+    if (!fread(&protocol_version, sizeof(int), 1, device)) {
+        ERROR("Couldn't read verity metadata protocol version!\n");
+        goto out;
+    }
+    if (protocol_version != 0) {
+        ERROR("Got unknown verity metadata protocol version %d!\n", protocol_version);
+        goto out;
+    }
+
+    // get the signature
+    *signature = (char*) malloc(RSANUMBYTES * sizeof(char));
+    if (!*signature) {
+        ERROR("Couldn't allocate memory for signature!\n");
+        goto out;
+    }
+    if (!fread(*signature, RSANUMBYTES, 1, device)) {
+        ERROR("Couldn't read signature from verity metadata!\n");
+        free(*signature);
+        goto out;
+    }
+
+    // get the size of the table
+    if (!fread(&table_length, sizeof(int), 1, device)) {
+        ERROR("Couldn't get the size of the verity table from metadata!\n");
+        free(*signature);
+        goto out;
+    }
+
+    // get the table + null terminator
+    table_length += 1;
+    *table = malloc(table_length);
+    if(!*table) {
+        ERROR("Couldn't allocate memory for verity table!\n");
+        goto out;
+    }
+    if (!fgets(*table, table_length, device)) {
+        ERROR("Couldn't read the verity table from metadata!\n");
+        free(*table);
+        free(*signature);
+        goto out;
+    }
+
+    retval = 0;
+
+out:
+    if (device)
+        fclose(device);
+    return retval;
+}
+
+static void verity_ioctl_init(struct dm_ioctl *io, char *name, unsigned flags)
+{
+    memset(io, 0, DM_BUF_SIZE);
+    io->data_size = DM_BUF_SIZE;
+    io->data_start = sizeof(struct dm_ioctl);
+    io->version[0] = 4;
+    io->version[1] = 0;
+    io->version[2] = 0;
+    io->flags = flags | DM_READONLY_FLAG;
+    if (name) {
+        strlcpy(io->name, name, sizeof(io->name));
+    }
+}
+
+static int create_verity_device(struct dm_ioctl *io, char *name, int fd)
+{
+    verity_ioctl_init(io, name, 1);
+    if (ioctl(fd, DM_DEV_CREATE, io)) {
+        ERROR("Error creating device mapping (%s)", strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+static int get_verity_device_name(struct dm_ioctl *io, char *name, int fd, char **dev_name)
+{
+    verity_ioctl_init(io, name, 0);
+    if (ioctl(fd, DM_DEV_STATUS, io)) {
+        ERROR("Error fetching verity device number (%s)", strerror(errno));
+        return -1;
+    }
+    int dev_num = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
+    if (asprintf(dev_name, "/dev/block/dm-%u", dev_num) < 0) {
+        ERROR("Error getting verity block device name (%s)", strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+static int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, int fd, char *table)
+{
+    char *verity_params;
+    char *buffer = (char*) io;
+    uint64_t device_size = 0;
+
+    if (get_target_device_size(blockdev, &device_size) < 0) {
+        return -1;
+    }
+
+    verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG);
+
+    struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
+
+    // set tgt arguments here
+    io->target_count = 1;
+    tgt->status=0;
+    tgt->sector_start=0;
+    tgt->length=device_size/512;
+    strcpy(tgt->target_type, "verity");
+
+    // build the verity params here
+    verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
+    if (sprintf(verity_params, "%s", table) < 0) {
+        return -1;
+    }
+
+    // set next target boundary
+    verity_params += strlen(verity_params) + 1;
+    verity_params = (char*) (((unsigned long)verity_params + 7) & ~8);
+    tgt->next = verity_params - buffer;
+
+    // send the ioctl to load the verity table
+    if (ioctl(fd, DM_TABLE_LOAD, io)) {
+        ERROR("Error loading verity table (%s)", strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int resume_verity_table(struct dm_ioctl *io, char *name, int fd)
+{
+    verity_ioctl_init(io, name, 0);
+    if (ioctl(fd, DM_DEV_SUSPEND, io)) {
+        ERROR("Error activating verity device (%s)", strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+static int test_access(char *device) {
+    int tries = 25;
+    while (tries--) {
+        if (!access(device, F_OK) || errno != ENOENT) {
+            return 0;
+        }
+        usleep(40 * 1000);
+    }
+    return -1;
+}
+
+int fs_mgr_setup_verity(struct fstab_rec *fstab) {
+
+    int retval = -1;
+
+    char *verity_blk_name;
+    char *verity_table;
+    char *verity_table_signature;
+
+    char buffer[DM_BUF_SIZE];
+    struct dm_ioctl *io = (struct dm_ioctl *) buffer;
+    char *mount_point = basename(fstab->mount_point);
+
+    // set the dm_ioctl flags
+    io->flags |= 1;
+    io->target_count = 1;
+
+    // get the device mapper fd
+    int fd;
+    if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
+        ERROR("Error opening device mapper (%s)", strerror(errno));
+        return retval;
+    }
+
+    // create the device
+    if (create_verity_device(io, mount_point, fd) < 0) {
+        ERROR("Couldn't create verity device!");
+        goto out;
+    }
+
+    // get the name of the device file
+    if (get_verity_device_name(io, mount_point, fd, &verity_blk_name) < 0) {
+        ERROR("Couldn't get verity device number!");
+        goto out;
+    }
+
+    // read the verity block at the end of the block device
+    if (read_verity_metadata(fstab->blk_device,
+                                    &verity_table_signature,
+                                    &verity_table) < 0) {
+        goto out;
+    }
+
+    // verify the signature on the table
+    if (verify_table(verity_table_signature,
+                            verity_table,
+                            strlen(verity_table)) < 0) {
+        goto out;
+    }
+
+    // load the verity mapping table
+    if (load_verity_table(io, mount_point, fstab->blk_device, fd, verity_table) < 0) {
+        goto out;
+    }
+
+    // activate the device
+    if (resume_verity_table(io, mount_point, fd) < 0) {
+        goto out;
+    }
+
+    // assign the new verity block device as the block device
+    free(fstab->blk_device);
+    fstab->blk_device = verity_blk_name;
+
+    // make sure we've set everything up properly
+    if (test_access(fstab->blk_device) < 0) {
+        goto out;
+    }
+
+    retval = 0;
+
+out:
+    close(fd);
+    return retval;
+}
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 05bcc1b..0f90c32 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -17,6 +17,9 @@
 #ifndef __CORE_FS_MGR_H
 #define __CORE_FS_MGR_H
 
+#include <stdint.h>
+#include <linux/dm-ioctl.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -35,9 +38,12 @@
     char *fs_options;
     int fs_mgr_flags;
     char *key_loc;
+    char *verity_loc;
     long long length;
     char *label;
     int partnum;
+    int swap_prio;
+    unsigned int zram_size;
 };
 
 struct fstab *fs_mgr_read_fstab(const char *fstab_path);
@@ -56,6 +62,8 @@
 int fs_mgr_is_voldmanaged(struct fstab_rec *fstab);
 int fs_mgr_is_nonremovable(struct fstab_rec *fstab);
 int fs_mgr_is_encryptable(struct fstab_rec *fstab);
+int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab);
+int fs_mgr_swapon_all(struct fstab *fstab);
 #ifdef __cplusplus
 }
 #endif
diff --git a/healthd/Android.mk b/healthd/Android.mk
new file mode 100644
index 0000000..473d375
--- /dev/null
+++ b/healthd/Android.mk
@@ -0,0 +1,30 @@
+# Copyright 2013 The Android Open Source Project
+
+ifneq ($(BUILD_TINY_ANDROID),true)
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := healthd_board_default.cpp
+LOCAL_MODULE := libhealthd.default
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	healthd.cpp \
+	BatteryMonitor.cpp \
+	BatteryPropertiesRegistrar.cpp
+
+LOCAL_MODULE := healthd
+LOCAL_MODULE_TAGS := optional
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
+LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
+
+LOCAL_STATIC_LIBRARIES :=  libbatteryservice libbinder libz libutils libstdc++ libcutils liblog libm libc
+LOCAL_HAL_STATIC_LIBRARIES := libhealthd
+
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
new file mode 100644
index 0000000..688c7ff
--- /dev/null
+++ b/healthd/BatteryMonitor.cpp
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#define LOG_TAG "healthd"
+
+#include "healthd.h"
+#include "BatteryMonitor.h"
+#include "BatteryPropertiesRegistrar.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <batteryservice/BatteryService.h>
+#include <cutils/klog.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#define POWER_SUPPLY_SUBSYSTEM "power_supply"
+#define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
+
+namespace android {
+
+struct sysfsStringEnumMap {
+    char* s;
+    int val;
+};
+
+static int mapSysfsString(const char* str,
+                          struct sysfsStringEnumMap map[]) {
+    for (int i = 0; map[i].s; i++)
+        if (!strcmp(str, map[i].s))
+            return map[i].val;
+
+    return -1;
+}
+
+int BatteryMonitor::getBatteryStatus(const char* status) {
+    int ret;
+    struct sysfsStringEnumMap batteryStatusMap[] = {
+        { "Unknown", BATTERY_STATUS_UNKNOWN },
+        { "Charging", BATTERY_STATUS_CHARGING },
+        { "Discharging", BATTERY_STATUS_DISCHARGING },
+        { "Not charging", BATTERY_STATUS_NOT_CHARGING },
+        { "Full", BATTERY_STATUS_FULL },
+        { NULL, 0 },
+    };
+
+    ret = mapSysfsString(status, batteryStatusMap);
+    if (ret < 0) {
+        KLOG_WARNING(LOG_TAG, "Unknown battery status '%s'\n", status);
+        ret = BATTERY_STATUS_UNKNOWN;
+    }
+
+    return ret;
+}
+
+int BatteryMonitor::getBatteryHealth(const char* status) {
+    int ret;
+    struct sysfsStringEnumMap batteryHealthMap[] = {
+        { "Unknown", BATTERY_HEALTH_UNKNOWN },
+        { "Good", BATTERY_HEALTH_GOOD },
+        { "Overheat", BATTERY_HEALTH_OVERHEAT },
+        { "Dead", BATTERY_HEALTH_DEAD },
+        { "Over voltage", BATTERY_HEALTH_OVER_VOLTAGE },
+        { "Unspecified failure", BATTERY_HEALTH_UNSPECIFIED_FAILURE },
+        { "Cold", BATTERY_HEALTH_COLD },
+        { NULL, 0 },
+    };
+
+    ret = mapSysfsString(status, batteryHealthMap);
+    if (ret < 0) {
+        KLOG_WARNING(LOG_TAG, "Unknown battery health '%s'\n", status);
+        ret = BATTERY_HEALTH_UNKNOWN;
+    }
+
+    return ret;
+}
+
+int BatteryMonitor::readFromFile(const String8& path, char* buf, size_t size) {
+    char *cp = NULL;
+
+    if (path.isEmpty())
+        return -1;
+    int fd = open(path.string(), O_RDONLY, 0);
+    if (fd == -1) {
+        KLOG_ERROR(LOG_TAG, "Could not open '%s'\n", path.string());
+        return -1;
+    }
+
+    ssize_t count = TEMP_FAILURE_RETRY(read(fd, buf, size));
+    if (count > 0)
+            cp = (char *)memrchr(buf, '\n', count);
+
+    if (cp)
+        *cp = '\0';
+    else
+        buf[0] = '\0';
+
+    close(fd);
+    return count;
+}
+
+BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String8& path) {
+    const int SIZE = 128;
+    char buf[SIZE];
+    int length = readFromFile(path, buf, SIZE);
+    BatteryMonitor::PowerSupplyType ret;
+    struct sysfsStringEnumMap supplyTypeMap[] = {
+            { "Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN },
+            { "Battery", ANDROID_POWER_SUPPLY_TYPE_BATTERY },
+            { "UPS", ANDROID_POWER_SUPPLY_TYPE_AC },
+            { "Mains", ANDROID_POWER_SUPPLY_TYPE_AC },
+            { "USB", ANDROID_POWER_SUPPLY_TYPE_USB },
+            { "USB_DCP", ANDROID_POWER_SUPPLY_TYPE_AC },
+            { "USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC },
+            { "USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC },
+            { "Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS },
+            { NULL, 0 },
+    };
+
+    if (length <= 0)
+        return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
+
+    ret = (BatteryMonitor::PowerSupplyType)mapSysfsString(buf, supplyTypeMap);
+    if (ret < 0)
+        ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
+
+    return ret;
+}
+
+bool BatteryMonitor::getBooleanField(const String8& path) {
+    const int SIZE = 16;
+    char buf[SIZE];
+
+    bool value = false;
+    if (readFromFile(path, buf, SIZE) > 0) {
+        if (buf[0] != '0') {
+            value = true;
+        }
+    }
+
+    return value;
+}
+
+int BatteryMonitor::getIntField(const String8& path) {
+    const int SIZE = 128;
+    char buf[SIZE];
+
+    int value = 0;
+    if (readFromFile(path, buf, SIZE) > 0) {
+        value = strtol(buf, NULL, 0);
+    }
+    return value;
+}
+
+bool BatteryMonitor::update(void) {
+    struct BatteryProperties props;
+    bool logthis;
+
+    props.chargerAcOnline = false;
+    props.chargerUsbOnline = false;
+    props.chargerWirelessOnline = false;
+    props.batteryStatus = BATTERY_STATUS_UNKNOWN;
+    props.batteryHealth = BATTERY_HEALTH_UNKNOWN;
+    props.batteryCurrentNow = INT_MIN;
+    props.batteryChargeCounter = INT_MIN;
+
+    if (!mHealthdConfig->batteryPresentPath.isEmpty())
+        props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
+    else
+        props.batteryPresent = true;
+
+    props.batteryLevel = getIntField(mHealthdConfig->batteryCapacityPath);
+    props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
+
+    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
+        props.batteryCurrentNow = getIntField(mHealthdConfig->batteryCurrentNowPath);
+
+    if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
+        props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);
+
+    props.batteryTemperature = getIntField(mHealthdConfig->batteryTemperaturePath);
+
+    const int SIZE = 128;
+    char buf[SIZE];
+    String8 btech;
+
+    if (readFromFile(mHealthdConfig->batteryStatusPath, buf, SIZE) > 0)
+        props.batteryStatus = getBatteryStatus(buf);
+
+    if (readFromFile(mHealthdConfig->batteryHealthPath, buf, SIZE) > 0)
+        props.batteryHealth = getBatteryHealth(buf);
+
+    if (readFromFile(mHealthdConfig->batteryTechnologyPath, buf, SIZE) > 0)
+        props.batteryTechnology = String8(buf);
+
+    unsigned int i;
+
+    for (i = 0; i < mChargerNames.size(); i++) {
+        String8 path;
+        path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
+                          mChargerNames[i].string());
+
+        if (readFromFile(path, buf, SIZE) > 0) {
+            if (buf[0] != '0') {
+                path.clear();
+                path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
+                                  mChargerNames[i].string());
+                switch(readPowerSupplyType(path)) {
+                case ANDROID_POWER_SUPPLY_TYPE_AC:
+                    props.chargerAcOnline = true;
+                    break;
+                case ANDROID_POWER_SUPPLY_TYPE_USB:
+                    props.chargerUsbOnline = true;
+                    break;
+                case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
+                    props.chargerWirelessOnline = true;
+                    break;
+                default:
+                    KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
+                                 mChargerNames[i].string());
+                }
+            }
+        }
+    }
+
+    logthis = !healthd_board_battery_update(&props);
+
+    if (logthis) {
+        char dmesgline[256];
+        snprintf(dmesgline, sizeof(dmesgline),
+                 "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
+                 props.batteryLevel, props.batteryVoltage,
+                 props.batteryTemperature < 0 ? "-" : "",
+                 abs(props.batteryTemperature / 10),
+                 abs(props.batteryTemperature % 10), props.batteryHealth,
+                 props.batteryStatus);
+
+        if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+            char b[20];
+
+            snprintf(b, sizeof(b), " c=%d", props.batteryCurrentNow / 1000);
+            strlcat(dmesgline, b, sizeof(dmesgline));
+        }
+
+        KLOG_INFO(LOG_TAG, "%s chg=%s%s%s\n", dmesgline,
+                  props.chargerAcOnline ? "a" : "",
+                  props.chargerUsbOnline ? "u" : "",
+                  props.chargerWirelessOnline ? "w" : "");
+    }
+
+    if (mBatteryPropertiesRegistrar != NULL)
+        mBatteryPropertiesRegistrar->notifyListeners(props);
+
+    return props.chargerAcOnline | props.chargerUsbOnline |
+            props.chargerWirelessOnline;
+}
+
+void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) {
+    String8 path;
+
+    mHealthdConfig = hc;
+    DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);
+    if (dir == NULL) {
+        KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
+    } else {
+        struct dirent* entry;
+
+        while ((entry = readdir(dir))) {
+            const char* name = entry->d_name;
+
+            if (!strcmp(name, ".") || !strcmp(name, ".."))
+                continue;
+
+            char buf[20];
+            // Look for "type" file in each subdirectory
+            path.clear();
+            path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
+            switch(readPowerSupplyType(path)) {
+            case ANDROID_POWER_SUPPLY_TYPE_AC:
+            case ANDROID_POWER_SUPPLY_TYPE_USB:
+            case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
+                path.clear();
+                path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
+                if (access(path.string(), R_OK) == 0)
+                    mChargerNames.add(String8(name));
+                break;
+
+            case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
+                if (mHealthdConfig->batteryStatusPath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
+                                      name);
+                    if (access(path, R_OK) == 0)
+                        mHealthdConfig->batteryStatusPath = path;
+                }
+
+                if (mHealthdConfig->batteryHealthPath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
+                                      name);
+                    if (access(path, R_OK) == 0)
+                        mHealthdConfig->batteryHealthPath = path;
+                }
+
+                if (mHealthdConfig->batteryPresentPath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
+                                      name);
+                    if (access(path, R_OK) == 0)
+                        mHealthdConfig->batteryPresentPath = path;
+                }
+
+                if (mHealthdConfig->batteryCapacityPath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
+                                      name);
+                    if (access(path, R_OK) == 0)
+                        mHealthdConfig->batteryCapacityPath = path;
+                }
+
+                if (mHealthdConfig->batteryVoltagePath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/voltage_now",
+                                      POWER_SUPPLY_SYSFS_PATH, name);
+                    if (access(path, R_OK) == 0) {
+                        mHealthdConfig->batteryVoltagePath = path;
+                    } else {
+                        path.clear();
+                        path.appendFormat("%s/%s/batt_vol",
+                                          POWER_SUPPLY_SYSFS_PATH, name);
+                        if (access(path, R_OK) == 0)
+                            mHealthdConfig->batteryVoltagePath = path;
+                    }
+                }
+
+                if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/current_now",
+                                      POWER_SUPPLY_SYSFS_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        mHealthdConfig->batteryCurrentNowPath = path;
+                }
+
+                if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/charge_counter",
+                                      POWER_SUPPLY_SYSFS_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        mHealthdConfig->batteryChargeCounterPath = path;
+                }
+
+                if (mHealthdConfig->batteryTemperaturePath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,
+                                      name);
+                    if (access(path, R_OK) == 0) {
+                        mHealthdConfig->batteryTemperaturePath = path;
+                    } else {
+                        path.clear();
+                        path.appendFormat("%s/%s/batt_temp",
+                                          POWER_SUPPLY_SYSFS_PATH, name);
+                        if (access(path, R_OK) == 0)
+                            mHealthdConfig->batteryTemperaturePath = path;
+                    }
+                }
+
+                if (mHealthdConfig->batteryTechnologyPath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/technology",
+                                      POWER_SUPPLY_SYSFS_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        mHealthdConfig->batteryTechnologyPath = path;
+                }
+
+                break;
+
+            case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
+                break;
+            }
+        }
+        closedir(dir);
+    }
+
+    if (!mChargerNames.size())
+        KLOG_ERROR(LOG_TAG, "No charger supplies found\n");
+    if (mHealthdConfig->batteryStatusPath.isEmpty())
+        KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
+    if (mHealthdConfig->batteryHealthPath.isEmpty())
+        KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
+    if (mHealthdConfig->batteryPresentPath.isEmpty())
+        KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
+    if (mHealthdConfig->batteryCapacityPath.isEmpty())
+        KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
+    if (mHealthdConfig->batteryVoltagePath.isEmpty())
+        KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
+    if (mHealthdConfig->batteryTemperaturePath.isEmpty())
+        KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
+    if (mHealthdConfig->batteryTechnologyPath.isEmpty())
+        KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
+
+    if (nosvcmgr == false) {
+            mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(this);
+            mBatteryPropertiesRegistrar->publish();
+    }
+}
+
+}; // namespace android
diff --git a/healthd/BatteryMonitor.h b/healthd/BatteryMonitor.h
new file mode 100644
index 0000000..ba291af
--- /dev/null
+++ b/healthd/BatteryMonitor.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2013 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 HEALTHD_BATTERYMONITOR_H
+#define HEALTHD_BATTERYMONITOR_H
+
+#include <binder/IInterface.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include "healthd.h"
+#include "BatteryPropertiesRegistrar.h"
+
+namespace android {
+
+class BatteryPropertiesRegistrar;
+
+class BatteryMonitor {
+  public:
+
+    enum PowerSupplyType {
+        ANDROID_POWER_SUPPLY_TYPE_UNKNOWN = 0,
+        ANDROID_POWER_SUPPLY_TYPE_AC,
+        ANDROID_POWER_SUPPLY_TYPE_USB,
+        ANDROID_POWER_SUPPLY_TYPE_WIRELESS,
+        ANDROID_POWER_SUPPLY_TYPE_BATTERY
+    };
+
+    void init(struct healthd_config *hc, bool nosvcmgr);
+    bool update(void);
+
+  private:
+    struct healthd_config *mHealthdConfig;
+    Vector<String8> mChargerNames;
+
+    sp<BatteryPropertiesRegistrar> mBatteryPropertiesRegistrar;
+
+    int getBatteryStatus(const char* status);
+    int getBatteryHealth(const char* status);
+    int readFromFile(const String8& path, char* buf, size_t size);
+    PowerSupplyType readPowerSupplyType(const String8& path);
+    bool getBooleanField(const String8& path);
+    int getIntField(const String8& path);
+};
+
+}; // namespace android
+
+#endif // HEALTHD_BATTERY_MONTIOR_H
diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp
new file mode 100644
index 0000000..6a33ad8
--- /dev/null
+++ b/healthd/BatteryPropertiesRegistrar.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 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 "BatteryPropertiesRegistrar.h"
+#include <batteryservice/BatteryService.h>
+#include <batteryservice/IBatteryPropertiesListener.h>
+#include <batteryservice/IBatteryPropertiesRegistrar.h>
+#include <binder/IServiceManager.h>
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
+#include <utils/String16.h>
+
+namespace android {
+
+BatteryPropertiesRegistrar::BatteryPropertiesRegistrar(BatteryMonitor* monitor) {
+    mBatteryMonitor = monitor;
+}
+
+void BatteryPropertiesRegistrar::publish() {
+    defaultServiceManager()->addService(String16("batterypropreg"), this);
+}
+
+void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) {
+    Mutex::Autolock _l(mRegistrationLock);
+    for (size_t i = 0; i < mListeners.size(); i++) {
+        mListeners[i]->batteryPropertiesChanged(props);
+    }
+}
+
+void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesListener>& listener) {
+    {
+        Mutex::Autolock _l(mRegistrationLock);
+        // check whether this is a duplicate
+        for (size_t i = 0; i < mListeners.size(); i++) {
+            if (mListeners[i]->asBinder() == listener->asBinder()) {
+                return;
+            }
+        }
+
+        mListeners.add(listener);
+        listener->asBinder()->linkToDeath(this);
+    }
+    mBatteryMonitor->update();
+}
+
+void BatteryPropertiesRegistrar::unregisterListener(const sp<IBatteryPropertiesListener>& listener) {
+    Mutex::Autolock _l(mRegistrationLock);
+    for (size_t i = 0; i < mListeners.size(); i++) {
+        if (mListeners[i]->asBinder() == listener->asBinder()) {
+            mListeners[i]->asBinder()->unlinkToDeath(this);
+            mListeners.removeAt(i);
+            break;
+        }
+    }
+}
+
+void BatteryPropertiesRegistrar::binderDied(const wp<IBinder>& who) {
+    Mutex::Autolock _l(mRegistrationLock);
+
+    for (size_t i = 0; i < mListeners.size(); i++) {
+        if (mListeners[i]->asBinder() == who) {
+            mListeners.removeAt(i);
+            break;
+        }
+    }
+}
+
+}  // namespace android
diff --git a/healthd/BatteryPropertiesRegistrar.h b/healthd/BatteryPropertiesRegistrar.h
new file mode 100644
index 0000000..793ddad
--- /dev/null
+++ b/healthd/BatteryPropertiesRegistrar.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013 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 HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
+#define HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
+
+#include "BatteryMonitor.h"
+
+#include <binder/IBinder.h>
+#include <utils/Mutex.h>
+#include <utils/Vector.h>
+#include <batteryservice/BatteryService.h>
+#include <batteryservice/IBatteryPropertiesListener.h>
+#include <batteryservice/IBatteryPropertiesRegistrar.h>
+
+namespace android {
+
+class BatteryMonitor;
+
+class BatteryPropertiesRegistrar : public BnBatteryPropertiesRegistrar,
+                                   public IBinder::DeathRecipient {
+public:
+    BatteryPropertiesRegistrar(BatteryMonitor* monitor);
+    void publish();
+    void notifyListeners(struct BatteryProperties props);
+
+private:
+    BatteryMonitor* mBatteryMonitor;
+    Mutex mRegistrationLock;
+    Vector<sp<IBatteryPropertiesListener> > mListeners;
+
+    void registerListener(const sp<IBatteryPropertiesListener>& listener);
+    void unregisterListener(const sp<IBatteryPropertiesListener>& listener);
+    void binderDied(const wp<IBinder>& who);
+};
+
+};  // namespace android
+
+#endif // HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
new file mode 100644
index 0000000..9b84c3e
--- /dev/null
+++ b/healthd/healthd.cpp
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#define LOG_TAG "healthd"
+#define KLOG_LEVEL 6
+
+#include "healthd.h"
+#include "BatteryMonitor.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <batteryservice/BatteryService.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <cutils/klog.h>
+#include <cutils/uevent.h>
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+
+using namespace android;
+
+// Periodic chores intervals in seconds
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
+
+static struct healthd_config healthd_config = {
+    .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
+    .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
+    .batteryStatusPath = String8(String8::kEmptyString),
+    .batteryHealthPath = String8(String8::kEmptyString),
+    .batteryPresentPath = String8(String8::kEmptyString),
+    .batteryCapacityPath = String8(String8::kEmptyString),
+    .batteryVoltagePath = String8(String8::kEmptyString),
+    .batteryTemperaturePath = String8(String8::kEmptyString),
+    .batteryTechnologyPath = String8(String8::kEmptyString),
+    .batteryCurrentNowPath = String8(String8::kEmptyString),
+    .batteryChargeCounterPath = String8(String8::kEmptyString),
+};
+
+#define POWER_SUPPLY_SUBSYSTEM "power_supply"
+
+// epoll events: uevent, wakealarm, binder
+#define MAX_EPOLL_EVENTS 3
+static int uevent_fd;
+static int wakealarm_fd;
+static int binder_fd;
+
+// -1 for no epoll timeout
+static int awake_poll_interval = -1;
+
+static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
+
+static BatteryMonitor* gBatteryMonitor;
+
+static bool nosvcmgr;
+
+static void wakealarm_set_interval(int interval) {
+    struct itimerspec itval;
+
+    if (wakealarm_fd == -1)
+            return;
+
+    wakealarm_wake_interval = interval;
+
+    if (interval == -1)
+        interval = 0;
+
+    itval.it_interval.tv_sec = interval;
+    itval.it_interval.tv_nsec = 0;
+    itval.it_value.tv_sec = interval;
+    itval.it_value.tv_nsec = 0;
+
+    if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
+        KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
+}
+
+static void battery_update(void) {
+    // Fast wake interval when on charger (watch for overheat);
+    // slow wake interval when on battery (watch for drained battery).
+
+   int new_wake_interval = gBatteryMonitor->update() ?
+       healthd_config.periodic_chores_interval_fast :
+           healthd_config.periodic_chores_interval_slow;
+
+    if (new_wake_interval != wakealarm_wake_interval)
+            wakealarm_set_interval(new_wake_interval);
+
+    // During awake periods poll at fast rate.  If wake alarm is set at fast
+    // rate then just use the alarm; if wake alarm is set at slow rate then
+    // poll at fast rate while awake and let alarm wake up at slow rate when
+    // asleep.
+
+    if (healthd_config.periodic_chores_interval_fast == -1)
+        awake_poll_interval = -1;
+    else
+        awake_poll_interval =
+            new_wake_interval == healthd_config.periodic_chores_interval_fast ?
+                -1 : healthd_config.periodic_chores_interval_fast * 1000;
+}
+
+static void periodic_chores() {
+    battery_update();
+}
+
+static void uevent_init(void) {
+    uevent_fd = uevent_open_socket(64*1024, true);
+
+    if (uevent_fd >= 0)
+        fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
+    else
+        KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+}
+
+#define UEVENT_MSG_LEN 1024
+static void uevent_event(void) {
+    char msg[UEVENT_MSG_LEN+2];
+    char *cp;
+    int n;
+
+    n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
+    if (n <= 0)
+        return;
+    if (n >= UEVENT_MSG_LEN)   /* overflow -- discard */
+        return;
+
+    msg[n] = '\0';
+    msg[n+1] = '\0';
+    cp = msg;
+
+    while (*cp) {
+        if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
+            battery_update();
+            break;
+        }
+
+        /* advance to after the next \0 */
+        while (*cp++)
+            ;
+    }
+}
+
+static void wakealarm_init(void) {
+    wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
+    if (wakealarm_fd == -1) {
+        KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
+        return;
+    }
+
+    wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
+}
+
+static void wakealarm_event(void) {
+    unsigned long long wakeups;
+
+    if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
+        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm_fd failed\n");
+        return;
+    }
+
+    periodic_chores();
+}
+
+static void binder_init(void) {
+    ProcessState::self()->setThreadPoolMaxThreadCount(0);
+    IPCThreadState::self()->disableBackgroundScheduling(true);
+    IPCThreadState::self()->setupPolling(&binder_fd);
+}
+
+static void binder_event(void) {
+    IPCThreadState::self()->handlePolledCommands();
+}
+
+static void healthd_mainloop(void) {
+    struct epoll_event ev;
+    int epollfd;
+    int maxevents = 0;
+
+    epollfd = epoll_create(MAX_EPOLL_EVENTS);
+    if (epollfd == -1) {
+        KLOG_ERROR(LOG_TAG,
+                   "healthd_mainloop: epoll_create failed; errno=%d\n",
+                   errno);
+        return;
+    }
+
+    if (uevent_fd >= 0) {
+        ev.events = EPOLLIN | EPOLLWAKEUP;
+        ev.data.ptr = (void *)uevent_event;
+        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1)
+            KLOG_ERROR(LOG_TAG,
+                       "healthd_mainloop: epoll_ctl for uevent_fd failed; errno=%d\n",
+                       errno);
+        else
+            maxevents++;
+    }
+
+    if (wakealarm_fd >= 0) {
+        ev.events = EPOLLIN | EPOLLWAKEUP;
+        ev.data.ptr = (void *)wakealarm_event;
+        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, wakealarm_fd, &ev) == -1)
+            KLOG_ERROR(LOG_TAG,
+                       "healthd_mainloop: epoll_ctl for wakealarm_fd failed; errno=%d\n",
+                       errno);
+        else
+            maxevents++;
+   }
+
+    if (binder_fd >= 0) {
+        ev.events = EPOLLIN | EPOLLWAKEUP;
+        ev.data.ptr= (void *)binder_event;
+        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, binder_fd, &ev) == -1)
+            KLOG_ERROR(LOG_TAG,
+                       "healthd_mainloop: epoll_ctl for binder_fd failed; errno=%d\n",
+                       errno);
+        else
+            maxevents++;
+   }
+
+    while (1) {
+        struct epoll_event events[maxevents];
+        int nevents;
+
+        IPCThreadState::self()->flushCommands();
+        nevents = epoll_wait(epollfd, events, maxevents, awake_poll_interval);
+
+        if (nevents == -1) {
+            if (errno == EINTR)
+                continue;
+            KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
+            break;
+        }
+
+        for (int n = 0; n < nevents; ++n) {
+            if (events[n].data.ptr)
+                (*(void (*)())events[n].data.ptr)();
+        }
+
+        if (!nevents)
+            periodic_chores();
+    }
+
+    return;
+}
+
+int main(int argc, char **argv) {
+    int ch;
+
+    klog_set_level(KLOG_LEVEL);
+
+    while ((ch = getopt(argc, argv, "n")) != -1) {
+        switch (ch) {
+        case 'n':
+            nosvcmgr = true;
+            break;
+        case '?':
+        default:
+            KLOG_WARNING(LOG_TAG, "Unrecognized healthd option: %c\n", ch);
+        }
+    }
+
+    healthd_board_init(&healthd_config);
+    wakealarm_init();
+    uevent_init();
+    binder_init();
+    gBatteryMonitor = new BatteryMonitor();
+    gBatteryMonitor->init(&healthd_config, nosvcmgr);
+
+    healthd_mainloop();
+    return 0;
+}
diff --git a/healthd/healthd.h b/healthd/healthd.h
new file mode 100644
index 0000000..5374fb1
--- /dev/null
+++ b/healthd/healthd.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2013 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 _HEALTHD_H_
+#define _HEALTHD_H_
+
+#include <batteryservice/BatteryService.h>
+#include <utils/String8.h>
+
+// periodic_chores_interval_fast, periodic_chores_interval_slow: intervals at
+// which healthd wakes up to poll health state and perform periodic chores,
+// in units of seconds:
+//
+//    periodic_chores_interval_fast is used while the device is not in
+//    suspend, or in suspend and connected to a charger (to watch for battery
+//    overheat due to charging).  The default value is 60 (1 minute).  Value
+//    -1 turns off periodic chores (and wakeups) in these conditions.
+//
+//    periodic_chores_interval_slow is used when the device is in suspend and
+//    not connected to a charger (to watch for a battery drained to zero
+//    remaining capacity).  The default value is 600 (10 minutes).  Value -1
+//    tuns off periodic chores (and wakeups) in these conditions.
+//
+// power_supply sysfs attribute file paths.  Set these to specific paths
+// to use for the associated battery parameters.  healthd will search for
+// appropriate power_supply attribute files to use for any paths left empty:
+//
+//    batteryStatusPath: charging status (POWER_SUPPLY_PROP_STATUS)
+//    batteryHealthPath: battery health (POWER_SUPPLY_PROP_HEALTH)
+//    batteryPresentPath: battery present (POWER_SUPPLY_PROP_PRESENT)
+//    batteryCapacityPath: remaining capacity (POWER_SUPPLY_PROP_CAPACITY)
+//    batteryVoltagePath: battery voltage (POWER_SUPPLY_PROP_VOLTAGE_NOW)
+//    batteryTemperaturePath: battery temperature (POWER_SUPPLY_PROP_TEMP)
+//    batteryTechnologyPath: battery technology (POWER_SUPPLY_PROP_TECHNOLOGY)
+//    batteryCurrentNowPath: battery current (POWER_SUPPLY_PROP_CURRENT_NOW)
+//    batteryChargeCounterPath: battery accumulated charge
+//                                         (POWER_SUPPLY_PROP_CHARGE_COUNTER)
+
+struct healthd_config {
+    int periodic_chores_interval_fast;
+    int periodic_chores_interval_slow;
+
+    android::String8 batteryStatusPath;
+    android::String8 batteryHealthPath;
+    android::String8 batteryPresentPath;
+    android::String8 batteryCapacityPath;
+    android::String8 batteryVoltagePath;
+    android::String8 batteryTemperaturePath;
+    android::String8 batteryTechnologyPath;
+    android::String8 batteryCurrentNowPath;
+    android::String8 batteryChargeCounterPath;
+};
+
+// The following are implemented in libhealthd_board to handle board-specific
+// behavior.
+//
+// healthd_board_init() is called at startup time to modify healthd's
+// configuration according to board-specific requirements.  config
+// points to the healthd configuration values described above.  To use default
+// values, this function can simply return without modifying the fields of the
+// config parameter.
+
+void healthd_board_init(struct healthd_config *config);
+
+// Process updated battery property values.  This function is called when
+// the kernel sends updated battery status via a uevent from the power_supply
+// subsystem, or when updated values are polled by healthd, as for periodic
+// poll of battery state.
+//
+// props are the battery properties read from the kernel.  These values may
+// be modified in this call, prior to sending the modified values to the
+// Android runtime.
+//
+// Return 0 to indicate the usual kernel log battery status heartbeat message
+// is to be logged, or non-zero to prevent logging this information.
+
+int healthd_board_battery_update(struct android::BatteryProperties *props);
+
+#endif /* _HEALTHD_H_ */
diff --git a/include/cutils/zygote.h b/healthd/healthd_board_default.cpp
similarity index 63%
copy from include/cutils/zygote.h
copy to healthd/healthd_board_default.cpp
index a7480d3..b2bb516 100644
--- a/include/cutils/zygote.h
+++ b/healthd/healthd_board_default.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -14,18 +14,16 @@
  * limitations under the License.
  */
 
-#ifndef __CUTILS_ZYGOTE_H
-#define __CUTILS_ZYGOTE_H
+#include <healthd.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int zygote_run_oneshot(int sendStdio, int argc, const char **argv);
-int zygote_run(int argc, const char **argv);
-
-#ifdef __cplusplus
+void healthd_board_init(struct healthd_config *config)
+{
+    // use defaults
 }
-#endif
 
-#endif /* __CUTILS_ZYGOTE_H */
+
+int healthd_board_battery_update(struct android::BatteryProperties *props)
+{
+    // return 0 to log periodic polled battery status to kernel log
+    return 0;
+}
diff --git a/include/cutils/abort_socket.h b/include/cutils/abort_socket.h
deleted file mode 100644
index fbb1112..0000000
--- a/include/cutils/abort_socket.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2009, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Helper to perform abortable blocking operations on a socket:
- *   asocket_connect()
- *   asocket_accept()
- *   asocket_read()
- *   asocket_write()
- * These calls are similar to the regular syscalls, but can be aborted with:
- *   asocket_abort()
- *
- * Calling close() on a regular POSIX socket does not abort blocked syscalls on
- * that socket in other threads.
- *
- * After calling asocket_abort() the socket cannot be reused.
- *
- * Call asocket_destory() *after* all threads have finished with the socket to
- * finish closing the socket and free the asocket structure.
- *
- * The helper is implemented by setting the socket non-blocking to initiate
- * syscalls connect(), accept(), read(), write(), then using a blocking poll()
- * on both the primary socket and a local pipe. This makes the poll() abortable
- * by writing a byte to the local pipe in asocket_abort().
- *
- * asocket_create() sets the fd to non-blocking mode. It must not be changed to
- * blocking mode.
- *
- * Using asocket will triple the number of file descriptors required per
- * socket, due to the local pipe. It may be possible to use a global pipe per
- * process rather than per socket, but we have not been able to come up with a
- * race-free implementation yet.
- *
- * All functions except asocket_init() and asocket_destroy() are thread safe.
- */
-
-#include <stdlib.h>
-#include <sys/socket.h>
-
-#ifndef __CUTILS_ABORT_SOCKET_H__
-#define __CUTILS_ABORT_SOCKET_H__
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct asocket {
-    int fd;           /* primary socket fd */
-    int abort_fd[2];  /* pipe used to abort */
-};
-
-/* Create an asocket from fd.
- * Sets the socket to non-blocking mode.
- * Returns NULL on error with errno set.
- */
-struct asocket *asocket_init(int fd);
-
-/* Blocking socket I/O with timeout.
- * Calling asocket_abort() from another thread will cause each of these
- * functions to immediately return with value -1 and errno ECANCELED.
- * timeout is in ms, use -1 to indicate no timeout. On timeout -1 is returned
- * with errno ETIMEDOUT.
- * EINTR is handled in-call.
- * Other semantics are identical to the regular syscalls.
- */
-int asocket_connect(struct asocket *s, const struct sockaddr *addr,
-        socklen_t addrlen, int timeout);
-
-int asocket_accept(struct asocket *s, struct sockaddr *addr,
-        socklen_t *addrlen, int timeout);
-
-int asocket_read(struct asocket *s, void *buf, size_t count, int timeout);
-
-int asocket_write(struct asocket *s, const void *buf, size_t count,
-        int timeout);
-
-/* Abort above calls and shutdown socket.
- * Further I/O operations on this socket will immediately fail after this call.
- * asocket_destroy() should be used to release resources once all threads
- * have returned from blocking calls on the socket.
- */
-void asocket_abort(struct asocket *s);
-
-/* Close socket and free asocket structure.
- * Must not be called until all calls on this structure have completed.
- */
-void asocket_destroy(struct asocket *s);
-
-#ifdef __cplusplus
-}
-#endif
-#endif //__CUTILS_ABORT_SOCKET__H__
diff --git a/include/cutils/android_reboot.h b/include/cutils/android_reboot.h
index 0c79be7..8c30e8e 100644
--- a/include/cutils/android_reboot.h
+++ b/include/cutils/android_reboot.h
@@ -24,9 +24,8 @@
 #define ANDROID_RB_POWEROFF 0xDEAD0002
 #define ANDROID_RB_RESTART2 0xDEAD0003
 
-/* Flags */
-#define ANDROID_RB_FLAG_NO_SYNC       0x1
-#define ANDROID_RB_FLAG_NO_REMOUNT_RO 0x2
+/* Properties */
+#define ANDROID_RB_PROPERTY "sys.powerctl"
 
 int android_reboot(int cmd, int flags, char *arg);
 
diff --git a/include/cutils/array.h b/include/cutils/array.h
deleted file mode 100644
index c97ff34..0000000
--- a/include/cutils/array.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-/**
- * A pointer array which intelligently expands its capacity ad needed.
- */
-
-#ifndef __ARRAY_H
-#define __ARRAY_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdlib.h>
-
-/** An array. */
-typedef struct Array Array;
-
-/** Constructs a new array. Returns NULL if we ran out of memory. */
-Array* arrayCreate();
-
-/** Frees an array. Does not free elements themselves. */
-void arrayFree(Array* array);
-
-/** Adds a pointer. Returns 0 is successful, < 0 otherwise. */
-int arrayAdd(Array* array, void* pointer);
-
-/** Gets the pointer at the specified index. */
-void* arrayGet(Array* array, int index);
-
-/** Removes the pointer at the given index and returns it. */
-void* arrayRemove(Array* array, int index);
-
-/** Sets pointer at the given index. Returns old pointer. */
-void* arraySet(Array* array, int index, void* pointer);
-
-/** Sets the array size. Sets new pointers to NULL. Returns 0 if successful, < 0 otherwise . */
-int arraySetSize(Array* array, int size);
-
-/** Returns the size of the given array. */
-int arraySize(Array* array);
-
-/** 
- * Returns a pointer to a C-style array which will be valid until this array 
- * changes.
- */
-const void** arrayUnwrap(Array* array);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __ARRAY_H */ 
diff --git a/include/cutils/bitops.h b/include/cutils/bitops.h
index eb44236..c26dc54 100644
--- a/include/cutils/bitops.h
+++ b/include/cutils/bitops.h
@@ -75,6 +75,16 @@
     return -1;
 }
 
+static inline int bitmask_weight(unsigned int *bitmask, int num_bits)
+{
+    int i;
+    int weight = 0;
+
+    for (i = 0; i < BITS_TO_WORDS(num_bits); i++)
+        weight += __builtin_popcount(bitmask[i]);
+    return weight;
+}
+
 static inline void bitmask_set(unsigned int *bitmask, int bit)
 {
     bitmask[BIT_WORD(bit)] |= BIT_MASK(bit);
diff --git a/include/cutils/fs.h b/include/cutils/fs.h
index fd5296b..d1d4cf2 100644
--- a/include/cutils/fs.h
+++ b/include/cutils/fs.h
@@ -55,6 +55,14 @@
  */
 extern int fs_write_atomic_int(const char* path, int value);
 
+/*
+ * Ensure that all directories along given path exist, creating parent
+ * directories as needed.  Validates that given path is absolute and that
+ * it contains no relative "." or ".." paths or symlinks.  Last path segment
+ * is treated as filename and ignored, unless the path ends with "/".
+ */
+extern int fs_mkdirs(const char* path, mode_t mode);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/cutils/log.h b/include/cutils/log.h
index 8b045c7..0e0248e 100644
--- a/include/cutils/log.h
+++ b/include/cutils/log.h
@@ -1,563 +1 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//
-// C/C++ logging functions.  See the logging documentation for API details.
-//
-// We'd like these to be available from C code (in case we import some from
-// somewhere), so this has a C interface.
-//
-// The output will be correct when the log file is shared between multiple
-// threads and/or multiple processes so long as the operating system
-// supports O_APPEND.  These calls have mutex-protected data structures
-// and so are NOT reentrant.  Do not use LOG in a signal handler.
-//
-#ifndef _LIBS_CUTILS_LOG_H
-#define _LIBS_CUTILS_LOG_H
-
-#include <stdio.h>
-#include <time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#ifdef HAVE_PTHREADS
-#include <pthread.h>
-#endif
-#include <stdarg.h>
-
-#include <cutils/uio.h>
-#include <cutils/logd.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// ---------------------------------------------------------------------
-
-/*
- * Normally we strip ALOGV (VERBOSE messages) from release builds.
- * You can modify this (for example with "#define LOG_NDEBUG 0"
- * at the top of your source file) to change that behavior.
- */
-#ifndef LOG_NDEBUG
-#ifdef NDEBUG
-#define LOG_NDEBUG 1
-#else
-#define LOG_NDEBUG 0
-#endif
-#endif
-
-/*
- * This is the local tag used for the following simplified
- * logging macros.  You can change this preprocessor definition
- * before using the other macros to change the tag.
- */
-#ifndef LOG_TAG
-#define LOG_TAG NULL
-#endif
-
-// ---------------------------------------------------------------------
-
-/*
- * Simplified macro to send a verbose log message using the current LOG_TAG.
- */
-#ifndef ALOGV
-#if LOG_NDEBUG
-#define ALOGV(...)   ((void)0)
-#else
-#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
-#endif
-#endif
-
-#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
-
-#ifndef ALOGV_IF
-#if LOG_NDEBUG
-#define ALOGV_IF(cond, ...)   ((void)0)
-#else
-#define ALOGV_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug log message using the current LOG_TAG.
- */
-#ifndef ALOGD
-#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGD_IF
-#define ALOGD_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an info log message using the current LOG_TAG.
- */
-#ifndef ALOGI
-#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGI_IF
-#define ALOGI_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send a warning log message using the current LOG_TAG.
- */
-#ifndef ALOGW
-#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGW_IF
-#define ALOGW_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an error log message using the current LOG_TAG.
- */
-#ifndef ALOGE
-#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGE_IF
-#define ALOGE_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-// ---------------------------------------------------------------------
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * verbose priority.
- */
-#ifndef IF_ALOGV
-#if LOG_NDEBUG
-#define IF_ALOGV() if (false)
-#else
-#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG)
-#endif
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * debug priority.
- */
-#ifndef IF_ALOGD
-#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * info priority.
- */
-#ifndef IF_ALOGI
-#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * warn priority.
- */
-#ifndef IF_ALOGW
-#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * error priority.
- */
-#ifndef IF_ALOGE
-#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
-#endif
-
-
-// ---------------------------------------------------------------------
-
-/*
- * Simplified macro to send a verbose system log message using the current LOG_TAG.
- */
-#ifndef SLOGV
-#if LOG_NDEBUG
-#define SLOGV(...)   ((void)0)
-#else
-#define SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
-#endif
-#endif
-
-#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
-
-#ifndef SLOGV_IF
-#if LOG_NDEBUG
-#define SLOGV_IF(cond, ...)   ((void)0)
-#else
-#define SLOGV_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug system log message using the current LOG_TAG.
- */
-#ifndef SLOGD
-#define SLOGD(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef SLOGD_IF
-#define SLOGD_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an info system log message using the current LOG_TAG.
- */
-#ifndef SLOGI
-#define SLOGI(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef SLOGI_IF
-#define SLOGI_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send a warning system log message using the current LOG_TAG.
- */
-#ifndef SLOGW
-#define SLOGW(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef SLOGW_IF
-#define SLOGW_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an error system log message using the current LOG_TAG.
- */
-#ifndef SLOGE
-#define SLOGE(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef SLOGE_IF
-#define SLOGE_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-// ---------------------------------------------------------------------
-
-/*
- * Simplified macro to send a verbose radio log message using the current LOG_TAG.
- */
-#ifndef RLOGV
-#if LOG_NDEBUG
-#define RLOGV(...)   ((void)0)
-#else
-#define RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
-#endif
-#endif
-
-#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
-
-#ifndef RLOGV_IF
-#if LOG_NDEBUG
-#define RLOGV_IF(cond, ...)   ((void)0)
-#else
-#define RLOGV_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug radio log message using the current LOG_TAG.
- */
-#ifndef RLOGD
-#define RLOGD(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGD_IF
-#define RLOGD_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an info radio log message using the current LOG_TAG.
- */
-#ifndef RLOGI
-#define RLOGI(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGI_IF
-#define RLOGI_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send a warning radio log message using the current LOG_TAG.
- */
-#ifndef RLOGW
-#define RLOGW(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGW_IF
-#define RLOGW_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an error radio log message using the current LOG_TAG.
- */
-#ifndef RLOGE
-#define RLOGE(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGE_IF
-#define RLOGE_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-
-// ---------------------------------------------------------------------
-
-/*
- * Log a fatal error.  If the given condition fails, this stops program
- * execution like a normal assertion, but also generating the given message.
- * It is NOT stripped from release builds.  Note that the condition test
- * is -inverted- from the normal assert() semantics.
- */
-#ifndef LOG_ALWAYS_FATAL_IF
-#define LOG_ALWAYS_FATAL_IF(cond, ...) \
-    ( (CONDITION(cond)) \
-    ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
-    : (void)0 )
-#endif
-
-#ifndef LOG_ALWAYS_FATAL
-#define LOG_ALWAYS_FATAL(...) \
-    ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
-#endif
-
-/*
- * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
- * are stripped out of release builds.
- */
-#if LOG_NDEBUG
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) ((void)0)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) ((void)0)
-#endif
-
-#else
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
-#endif
-
-#endif
-
-/*
- * Assertion that generates a log message when the assertion fails.
- * Stripped out of release builds.  Uses the current LOG_TAG.
- */
-#ifndef ALOG_ASSERT
-#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
-//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond)
-#endif
-
-// ---------------------------------------------------------------------
-
-/*
- * Basic log message macro.
- *
- * Example:
- *  ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
- *
- * The second argument may be NULL or "" to indicate the "global" tag.
- */
-#ifndef ALOG
-#define ALOG(priority, tag, ...) \
-    LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
-#endif
-
-/*
- * Log macro that allows you to specify a number for the priority.
- */
-#ifndef LOG_PRI
-#define LOG_PRI(priority, tag, ...) \
-    android_printLog(priority, tag, __VA_ARGS__)
-#endif
-
-/*
- * Log macro that allows you to pass in a varargs ("args" is a va_list).
- */
-#ifndef LOG_PRI_VA
-#define LOG_PRI_VA(priority, tag, fmt, args) \
-    android_vprintLog(priority, NULL, tag, fmt, args)
-#endif
-
-/*
- * Conditional given a desired logging priority and tag.
- */
-#ifndef IF_ALOG
-#define IF_ALOG(priority, tag) \
-    if (android_testLog(ANDROID_##priority, tag))
-#endif
-
-// ---------------------------------------------------------------------
-
-/*
- * Event logging.
- */
-
-/*
- * Event log entry types.  These must match up with the declarations in
- * java/android/android/util/EventLog.java.
- */
-typedef enum {
-    EVENT_TYPE_INT      = 0,
-    EVENT_TYPE_LONG     = 1,
-    EVENT_TYPE_STRING   = 2,
-    EVENT_TYPE_LIST     = 3,
-} AndroidEventLogType;
-
-
-#ifndef LOG_EVENT_INT
-#define LOG_EVENT_INT(_tag, _value) {                                       \
-        int intBuf = _value;                                                \
-        (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf,            \
-            sizeof(intBuf));                                                \
-    }
-#endif
-#ifndef LOG_EVENT_LONG
-#define LOG_EVENT_LONG(_tag, _value) {                                      \
-        long long longBuf = _value;                                         \
-        (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf,          \
-            sizeof(longBuf));                                               \
-    }
-#endif
-#ifndef LOG_EVENT_STRING
-#define LOG_EVENT_STRING(_tag, _value)                                      \
-    ((void) 0)  /* not implemented -- must combine len with string */
-#endif
-/* TODO: something for LIST */
-
-/*
- * ===========================================================================
- *
- * The stuff in the rest of this file should not be used directly.
- */
-
-#define android_printLog(prio, tag, fmt...) \
-    __android_log_print(prio, tag, fmt)
-
-#define android_vprintLog(prio, cond, tag, fmt...) \
-    __android_log_vprint(prio, tag, fmt)
-
-/* XXX Macros to work around syntax errors in places where format string
- * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
- * (happens only in debug builds).
- */
-
-/* Returns 2nd arg.  Used to substitute default value if caller's vararg list
- * is empty.
- */
-#define __android_second(dummy, second, ...)     second
-
-/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
- * returns nothing.
- */
-#define __android_rest(first, ...)               , ## __VA_ARGS__
-
-#define android_printAssert(cond, tag, fmt...) \
-    __android_log_assert(cond, tag, \
-        __android_second(0, ## fmt, NULL) __android_rest(fmt))
-
-#define android_writeLog(prio, tag, text) \
-    __android_log_write(prio, tag, text)
-
-#define android_bWriteLog(tag, payload, len) \
-    __android_log_bwrite(tag, payload, len)
-#define android_btWriteLog(tag, type, payload, len) \
-    __android_log_btwrite(tag, type, payload, len)
-
-// TODO: remove these prototypes and their users
-#define android_testLog(prio, tag) (1)
-#define android_writevLog(vec,num) do{}while(0)
-#define android_write1Log(str,len) do{}while (0)
-#define android_setMinPriority(tag, prio) do{}while(0)
-//#define android_logToCallback(func) do{}while(0)
-#define android_logToFile(tag, file) (0)
-#define android_logToFd(tag, fd) (0)
-
-typedef enum {
-    LOG_ID_MAIN = 0,
-    LOG_ID_RADIO = 1,
-    LOG_ID_EVENTS = 2,
-    LOG_ID_SYSTEM = 3,
-
-    LOG_ID_MAX
-} log_id_t;
-
-/*
- * Send a simple string to the log.
- */
-int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
-int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _LIBS_CUTILS_LOG_H
+#include <log/log.h>
diff --git a/include/cutils/mq.h b/include/cutils/mq.h
deleted file mode 100644
index b27456d..0000000
--- a/include/cutils/mq.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-/**
- * IPC messaging library.
- */
-
-#ifndef __MQ_H
-#define __MQ_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** A message. */
-typedef struct MqMessage MqMessage;
-
-/** A destination to which messages can be sent. */
-typedef struct MqDestination MqDestination;
-
-/* Array of bytes. */
-typedef struct MqBytes MqBytes;
-
-/** 
- * Hears messages. 
- * 
- * @param destination to which the message was sent
- * @param message the message to hear
- */
-typedef void MqMessageListener(MqDestination* destination, MqMessage* message);
-
-/** 
- * Hears a destination close.
- * 
- * @param destination that closed
- */
-typedef void MqCloseListener(MqDestination* destination);
-
-/** Message functions. */
-
-/** 
- * Creates a new Message.
- * 
- * @param header as defined by user
- * @param body as defined by user
- * @param replyTo destination to which replies should be sent, NULL if none
- */
-MqMessage* mqCreateMessage(MqBytes header, MqBytes body, 
-        MqDestination* replyTo);
-
-/** Sends a message to a destination. */
-void mqSendMessage(MqMessage* message, MqDestination* destination);
-
-/** Destination functions. */
-
-/** 
- * Creates a new destination. Acquires a reference implicitly.
- *
- * @param messageListener function to call when a message is recieved
- * @param closeListener function to call when the destination closes
- * @param userData user-specific data to associate with the destination.
- *  Retrieve using mqGetDestinationUserData().
- */
-MqDestination* mqCreateDestination(MqMessageListener* messageListener, 
-        MqCloseListener* closeListener, void* userData);
-
-/**
- * Gets user data which was associated with the given destination at 
- * construction time. 
- * 
- * It is only valid to call this function in the same process that the 
- * given destination was created in.
- * This function returns a null pointer if you call it on a destination
- * created in a remote process.
- */
-void* mqGetUserData(MqDestination* destination);
-
-/**
- * Returns 1 if the destination was created in this process, or 0 if
- * the destination was created in a different process, in which case you have
- * a remote stub.
- */
-int mqIsDestinationLocal(MqDestination* destination);
-
-/**
- * Increments the destination's reference count.
- */
-void mqKeepDestination(MqDesintation* destination);
-
-/**
- * Decrements the destination's reference count. 
- */
-void mqFreeDestination(MqDestination* desintation);
-
-/** Registry API. */
-
-/**
- * Gets the destination bound to a name.
- */
-MqDestination* mqGetDestination(char* name);
-
-/**
- * Binds a destination to a name.
- */
-void mqPutDestination(char* name, MqDestination* desintation);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __MQ_H */ 
diff --git a/include/cutils/properties.h b/include/cutils/properties.h
index 25fd67a..2c70165 100644
--- a/include/cutils/properties.h
+++ b/include/cutils/properties.h
@@ -17,6 +17,10 @@
 #ifndef __CUTILS_PROPERTIES_H
 #define __CUTILS_PROPERTIES_H
 
+#include <sys/cdefs.h>
+#include <stddef.h>
+#include <sys/system_properties.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -28,8 +32,8 @@
 ** WARNING: system/bionic/include/sys/system_properties.h also defines
 **          these, but with different names.  (TODO: fix that)
 */
-#define PROPERTY_KEY_MAX   32
-#define PROPERTY_VALUE_MAX  92
+#define PROPERTY_KEY_MAX   PROP_NAME_MAX
+#define PROPERTY_VALUE_MAX  PROP_VALUE_MAX
 
 /* property_get: returns the length of the value which will never be
 ** greater than PROPERTY_VALUE_MAX - 1 and will always be zero terminated.
@@ -46,6 +50,22 @@
     
 int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);    
 
+#if defined(__BIONIC_FORTIFY)
+
+extern int __property_get_real(const char *, char *, const char *)
+    __asm__(__USER_LABEL_PREFIX__ "property_get");
+__errordecl(__property_get_too_small_error, "property_get() called with too small of a buffer");
+
+__BIONIC_FORTIFY_INLINE
+int property_get(const char *key, char *value, const char *default_value) {
+    size_t bos = __bos(value);
+    if (bos < PROPERTY_VALUE_MAX) {
+        __property_get_too_small_error();
+    }
+    return __property_get_real(key, value, default_value);
+}
+
+#endif
 
 #ifdef HAVE_SYSTEM_PROPERTY_SERVER
 /*
diff --git a/include/cutils/qsort_r_compat.h b/include/cutils/qsort_r_compat.h
deleted file mode 100644
index 479a1ab..0000000
--- a/include/cutils/qsort_r_compat.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-/*
- * Provides a portable version of qsort_r, called qsort_r_compat, which is a
- * reentrant variant of qsort that passes a user data pointer to its comparator.
- * This implementation follows the BSD parameter convention.
- */
-
-#ifndef _LIBS_CUTILS_QSORT_R_COMPAT_H
-#define _LIBS_CUTILS_QSORT_R_COMPAT_H
-
-#include <stdlib.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
-        int (*compar)(void*, const void* , const void* ));
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _LIBS_CUTILS_QSORT_R_COMPAT_H
diff --git a/include/cutils/selector.h b/include/cutils/selector.h
deleted file mode 100644
index dfc2a9d..0000000
--- a/include/cutils/selector.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-/**
- * Framework for multiplexing I/O. A selector manages a set of file
- * descriptors and calls out to user-provided callback functions to read and
- * write data and handle errors.
- */
-
-#ifndef __SELECTOR_H
-#define __SELECTOR_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdbool.h>
-    
-/** 
- * Manages SelectableFds and invokes their callbacks at appropriate times. 
- */
-typedef struct Selector Selector;
-
-/** 
- * A selectable descriptor. Contains callbacks which the selector can invoke
- * before calling select(), when the descriptor is readable or writable, and 
- * when the descriptor contains out-of-band data. Simply set a callback to 
- * NULL if you're not interested in that particular event.
- *
- * A selectable descriptor can indicate that it needs to be removed from the
- * selector by setting the 'remove' flag. The selector will remove the
- * descriptor at a later time and invoke the onRemove() callback.
- * 
- * SelectableFd fields should only be modified from the selector loop.
- */
-typedef struct SelectableFd SelectableFd;
-struct SelectableFd {
-
-    /** The file descriptor itself. */
-    int fd;
-    
-    /** Pointer to user-specific data. Can be NULL. */
-    void* data;
-    
-    /** 
-     * Set this flag when you no longer wish to be selected. The selector
-     * will invoke onRemove() when the descriptor is actually removed.
-     */
-    bool remove;
-
-    /** 
-     * Invoked by the selector before calling select. You can set up other
-     * callbacks from here as necessary.
-     */
-    void (*beforeSelect)(SelectableFd* self);
-
-    /** 
-     * Invoked by the selector when the descriptor has data available. Set to
-     * NULL to indicate that you're not interested in reading.
-     */
-    void (*onReadable)(SelectableFd* self);
-
-    /** 
-     * Invoked by the selector when the descriptor can accept data. Set to
-     * NULL to indicate that you're not interested in writing.
-     */
-    void (*onWritable)(SelectableFd* self);
-
-    /** 
-     * Invoked by the selector when out-of-band (OOB) data is available. Set to
-     * NULL to indicate that you're not interested in OOB data.
-     */
-    void (*onExcept)(SelectableFd* self);
-
-    /**
-     * Invoked by the selector after the descriptor is removed from the
-     * selector but before the selector frees the SelectableFd memory.
-     */
-    void (*onRemove)(SelectableFd* self);
-
-    /**
-     * The selector which selected this fd. Set by the selector itself.
-     */
-    Selector* selector;
-};
-
-/** 
- * Creates a new selector. 
- */
-Selector* selectorCreate(void);
-
-/** 
- * Creates a new selectable fd, adds it to the given selector and returns a 
- * pointer. Outside of 'selector' and 'fd', all fields are set to 0 or NULL 
- * by default.
- * 
- * The selectable fd should only be modified from the selector loop thread.
- */
-SelectableFd* selectorAdd(Selector* selector, int fd);
-
-/**
- * Wakes up the selector even though no I/O events occurred. Use this
- * to indicate that you're ready to write to a descriptor.
- */
-void selectorWakeUp(Selector* selector);
-    
-/** 
- * Loops continuously selecting file descriptors and firing events. 
- * Does not return. 
- */
-void selectorLoop(Selector* selector);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __SELECTOR_H */ 
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index 29034ca..1c8f107 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -66,7 +66,8 @@
 #define ATRACE_TAG_APP              (1<<12)
 #define ATRACE_TAG_RESOURCES        (1<<13)
 #define ATRACE_TAG_DALVIK           (1<<14)
-#define ATRACE_TAG_LAST             ATRACE_TAG_DALVIK
+#define ATRACE_TAG_RS               (1<<15)
+#define ATRACE_TAG_LAST             ATRACE_TAG_RS
 
 // Reserved for initialization.
 #define ATRACE_TAG_NOT_READY        (1LL<<63)
@@ -258,11 +259,28 @@
     }
 }
 
+/**
+ * Traces a 64-bit integer counter value.  name is used to identify the
+ * counter. This can be used to track how a value changes over time.
+ */
+#define ATRACE_INT64(name, value) atrace_int64(ATRACE_TAG, name, value)
+static inline void atrace_int64(uint64_t tag, const char* name, int64_t value)
+{
+    if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
+        char buf[ATRACE_MESSAGE_LENGTH];
+        size_t len;
+
+        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%lld",
+                getpid(), name, value);
+        write(atrace_marker_fd, buf, len);
+    }
+}
+
 #else // not HAVE_ANDROID_OS
 
 #define ATRACE_INIT()
 #define ATRACE_GET_ENABLED_TAGS()
-#define ATRACE_ENABLED()
+#define ATRACE_ENABLED() 0
 #define ATRACE_BEGIN(name)
 #define ATRACE_END()
 #define ATRACE_ASYNC_BEGIN(name, cookie)
diff --git a/include/cutils/event_tag_map.h b/include/log/event_tag_map.h
similarity index 100%
rename from include/cutils/event_tag_map.h
rename to include/log/event_tag_map.h
diff --git a/include/log/log.h b/include/log/log.h
new file mode 100644
index 0000000..7faddea
--- /dev/null
+++ b/include/log/log.h
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// C/C++ logging functions.  See the logging documentation for API details.
+//
+// We'd like these to be available from C code (in case we import some from
+// somewhere), so this has a C interface.
+//
+// The output will be correct when the log file is shared between multiple
+// threads and/or multiple processes so long as the operating system
+// supports O_APPEND.  These calls have mutex-protected data structures
+// and so are NOT reentrant.  Do not use LOG in a signal handler.
+//
+#ifndef _LIBS_LOG_LOG_H
+#define _LIBS_LOG_LOG_H
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#endif
+#include <stdarg.h>
+
+#include <log/uio.h>
+#include <log/logd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Normally we strip ALOGV (VERBOSE messages) from release builds.
+ * You can modify this (for example with "#define LOG_NDEBUG 0"
+ * at the top of your source file) to change that behavior.
+ */
+#ifndef LOG_NDEBUG
+#ifdef NDEBUG
+#define LOG_NDEBUG 1
+#else
+#define LOG_NDEBUG 0
+#endif
+#endif
+
+/*
+ * This is the local tag used for the following simplified
+ * logging macros.  You can change this preprocessor definition
+ * before using the other macros to change the tag.
+ */
+#ifndef LOG_TAG
+#define LOG_TAG NULL
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Simplified macro to send a verbose log message using the current LOG_TAG.
+ */
+#ifndef ALOGV
+#if LOG_NDEBUG
+#define ALOGV(...)   ((void)0)
+#else
+#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#endif
+#endif
+
+#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
+
+#ifndef ALOGV_IF
+#if LOG_NDEBUG
+#define ALOGV_IF(cond, ...)   ((void)0)
+#else
+#define ALOGV_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug log message using the current LOG_TAG.
+ */
+#ifndef ALOGD
+#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGD_IF
+#define ALOGD_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info log message using the current LOG_TAG.
+ */
+#ifndef ALOGI
+#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGI_IF
+#define ALOGI_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning log message using the current LOG_TAG.
+ */
+#ifndef ALOGW
+#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGW_IF
+#define ALOGW_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error log message using the current LOG_TAG.
+ */
+#ifndef ALOGE
+#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef ALOGE_IF
+#define ALOGE_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * verbose priority.
+ */
+#ifndef IF_ALOGV
+#if LOG_NDEBUG
+#define IF_ALOGV() if (false)
+#else
+#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG)
+#endif
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * debug priority.
+ */
+#ifndef IF_ALOGD
+#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG)
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * info priority.
+ */
+#ifndef IF_ALOGI
+#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG)
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * warn priority.
+ */
+#ifndef IF_ALOGW
+#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
+#endif
+
+/*
+ * Conditional based on whether the current LOG_TAG is enabled at
+ * error priority.
+ */
+#ifndef IF_ALOGE
+#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
+#endif
+
+
+// ---------------------------------------------------------------------
+
+/*
+ * Simplified macro to send a verbose system log message using the current LOG_TAG.
+ */
+#ifndef SLOGV
+#if LOG_NDEBUG
+#define SLOGV(...)   ((void)0)
+#else
+#define SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#endif
+#endif
+
+#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
+
+#ifndef SLOGV_IF
+#if LOG_NDEBUG
+#define SLOGV_IF(cond, ...)   ((void)0)
+#else
+#define SLOGV_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug system log message using the current LOG_TAG.
+ */
+#ifndef SLOGD
+#define SLOGD(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGD_IF
+#define SLOGD_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info system log message using the current LOG_TAG.
+ */
+#ifndef SLOGI
+#define SLOGI(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGI_IF
+#define SLOGI_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning system log message using the current LOG_TAG.
+ */
+#ifndef SLOGW
+#define SLOGW(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGW_IF
+#define SLOGW_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error system log message using the current LOG_TAG.
+ */
+#ifndef SLOGE
+#define SLOGE(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGE_IF
+#define SLOGE_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Simplified macro to send a verbose radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGV
+#if LOG_NDEBUG
+#define RLOGV(...)   ((void)0)
+#else
+#define RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#endif
+#endif
+
+#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
+
+#ifndef RLOGV_IF
+#if LOG_NDEBUG
+#define RLOGV_IF(cond, ...)   ((void)0)
+#else
+#define RLOGV_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGD
+#define RLOGD(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGD_IF
+#define RLOGD_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGI
+#define RLOGI(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGI_IF
+#define RLOGI_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGW
+#define RLOGW(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGW_IF
+#define RLOGW_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGE
+#define RLOGE(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGE_IF
+#define RLOGE_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+
+// ---------------------------------------------------------------------
+
+/*
+ * Log a fatal error.  If the given condition fails, this stops program
+ * execution like a normal assertion, but also generating the given message.
+ * It is NOT stripped from release builds.  Note that the condition test
+ * is -inverted- from the normal assert() semantics.
+ */
+#ifndef LOG_ALWAYS_FATAL_IF
+#define LOG_ALWAYS_FATAL_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+#ifndef LOG_ALWAYS_FATAL
+#define LOG_ALWAYS_FATAL(...) \
+    ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
+#endif
+
+/*
+ * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
+ * are stripped out of release builds.
+ */
+#if LOG_NDEBUG
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) ((void)0)
+#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) ((void)0)
+#endif
+
+#else
+
+#ifndef LOG_FATAL_IF
+#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
+#endif
+#ifndef LOG_FATAL
+#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
+#endif
+
+#endif
+
+/*
+ * Assertion that generates a log message when the assertion fails.
+ * Stripped out of release builds.  Uses the current LOG_TAG.
+ */
+#ifndef ALOG_ASSERT
+#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
+//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond)
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Basic log message macro.
+ *
+ * Example:
+ *  ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
+ *
+ * The second argument may be NULL or "" to indicate the "global" tag.
+ */
+#ifndef ALOG
+#define ALOG(priority, tag, ...) \
+    LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
+#endif
+
+/*
+ * Log macro that allows you to specify a number for the priority.
+ */
+#ifndef LOG_PRI
+#define LOG_PRI(priority, tag, ...) \
+    android_printLog(priority, tag, __VA_ARGS__)
+#endif
+
+/*
+ * Log macro that allows you to pass in a varargs ("args" is a va_list).
+ */
+#ifndef LOG_PRI_VA
+#define LOG_PRI_VA(priority, tag, fmt, args) \
+    android_vprintLog(priority, NULL, tag, fmt, args)
+#endif
+
+/*
+ * Conditional given a desired logging priority and tag.
+ */
+#ifndef IF_ALOG
+#define IF_ALOG(priority, tag) \
+    if (android_testLog(ANDROID_##priority, tag))
+#endif
+
+// ---------------------------------------------------------------------
+
+/*
+ * Event logging.
+ */
+
+/*
+ * Event log entry types.  These must match up with the declarations in
+ * java/android/android/util/EventLog.java.
+ */
+typedef enum {
+    EVENT_TYPE_INT      = 0,
+    EVENT_TYPE_LONG     = 1,
+    EVENT_TYPE_STRING   = 2,
+    EVENT_TYPE_LIST     = 3,
+} AndroidEventLogType;
+
+
+#ifndef LOG_EVENT_INT
+#define LOG_EVENT_INT(_tag, _value) {                                       \
+        int intBuf = _value;                                                \
+        (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf,            \
+            sizeof(intBuf));                                                \
+    }
+#endif
+#ifndef LOG_EVENT_LONG
+#define LOG_EVENT_LONG(_tag, _value) {                                      \
+        long long longBuf = _value;                                         \
+        (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf,          \
+            sizeof(longBuf));                                               \
+    }
+#endif
+#ifndef LOG_EVENT_STRING
+#define LOG_EVENT_STRING(_tag, _value)                                      \
+    ((void) 0)  /* not implemented -- must combine len with string */
+#endif
+/* TODO: something for LIST */
+
+/*
+ * ===========================================================================
+ *
+ * The stuff in the rest of this file should not be used directly.
+ */
+
+#define android_printLog(prio, tag, fmt...) \
+    __android_log_print(prio, tag, fmt)
+
+#define android_vprintLog(prio, cond, tag, fmt...) \
+    __android_log_vprint(prio, tag, fmt)
+
+/* XXX Macros to work around syntax errors in places where format string
+ * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
+ * (happens only in debug builds).
+ */
+
+/* Returns 2nd arg.  Used to substitute default value if caller's vararg list
+ * is empty.
+ */
+#define __android_second(dummy, second, ...)     second
+
+/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
+ * returns nothing.
+ */
+#define __android_rest(first, ...)               , ## __VA_ARGS__
+
+#define android_printAssert(cond, tag, fmt...) \
+    __android_log_assert(cond, tag, \
+        __android_second(0, ## fmt, NULL) __android_rest(fmt))
+
+#define android_writeLog(prio, tag, text) \
+    __android_log_write(prio, tag, text)
+
+#define android_bWriteLog(tag, payload, len) \
+    __android_log_bwrite(tag, payload, len)
+#define android_btWriteLog(tag, type, payload, len) \
+    __android_log_btwrite(tag, type, payload, len)
+
+// TODO: remove these prototypes and their users
+#define android_testLog(prio, tag) (1)
+#define android_writevLog(vec,num) do{}while(0)
+#define android_write1Log(str,len) do{}while (0)
+#define android_setMinPriority(tag, prio) do{}while(0)
+//#define android_logToCallback(func) do{}while(0)
+#define android_logToFile(tag, file) (0)
+#define android_logToFd(tag, fd) (0)
+
+typedef enum {
+    LOG_ID_MAIN = 0,
+    LOG_ID_RADIO = 1,
+    LOG_ID_EVENTS = 2,
+    LOG_ID_SYSTEM = 3,
+
+    LOG_ID_MAX
+} log_id_t;
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
+int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _LIBS_CUTILS_LOG_H
diff --git a/include/cutils/logd.h b/include/log/logd.h
similarity index 97%
rename from include/cutils/logd.h
rename to include/log/logd.h
index 8737639..379c373 100644
--- a/include/cutils/logd.h
+++ b/include/log/logd.h
@@ -31,7 +31,7 @@
 #ifdef HAVE_PTHREADS
 #include <pthread.h>
 #endif
-#include <cutils/uio.h>
+#include <log/uio.h>
 #include <stdarg.h>
 
 #ifdef __cplusplus
diff --git a/include/cutils/logger.h b/include/log/logger.h
similarity index 100%
rename from include/cutils/logger.h
rename to include/log/logger.h
diff --git a/include/cutils/logprint.h b/include/log/logprint.h
similarity index 97%
rename from include/cutils/logprint.h
rename to include/log/logprint.h
index 2b1e1c5..481c96e 100644
--- a/include/cutils/logprint.h
+++ b/include/log/logprint.h
@@ -17,9 +17,9 @@
 #ifndef _LOGPRINT_H
 #define _LOGPRINT_H
 
-#include <cutils/log.h>
-#include <cutils/logger.h>
-#include <cutils/event_tag_map.h>
+#include <log/log.h>
+#include <log/logger.h>
+#include <log/event_tag_map.h>
 #include <pthread.h>
 
 #ifdef __cplusplus
diff --git a/include/cutils/uio.h b/include/log/uio.h
similarity index 100%
rename from include/cutils/uio.h
rename to include/log/uio.h
diff --git a/include/memtrack/memtrack.h b/include/memtrack/memtrack.h
new file mode 100644
index 0000000..0f1f85e
--- /dev/null
+++ b/include/memtrack/memtrack.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2013 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 _LIBMEMTRACK_MEMTRACK_H_
+#define _LIBMEMTRACK_MEMTRACK_H_
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <cutils/compiler.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * struct memtrack_proc
+ *
+ * an opaque handle to the memory stats on a process.
+ * Created with memtrack_proc_new, destroyed by
+ * memtrack_proc_destroy.  Can be reused multiple times with
+ * memtrack_proc_get.
+ */
+struct memtrack_proc;
+
+/**
+ * memtrack_init
+ *
+ * Must be called once before calling any other functions.  After this function
+ * is called, everything else is thread-safe.
+ *
+ * Returns 0 on success, -errno on error.
+ */
+int memtrack_init(void);
+
+/**
+ * memtrack_proc_new
+ *
+ * Return a new handle to hold process memory stats.
+ *
+ * Returns NULL on error.
+ */
+struct memtrack_proc *memtrack_proc_new(void);
+
+/**
+ * memtrack_proc_destroy
+ *
+ * Free all memory associated with a process memory stats handle.
+ */
+void memtrack_proc_destroy(struct memtrack_proc *p);
+
+/**
+ * memtrack_proc_get
+ *
+ * Fill a process memory stats handle with data about the given pid.  Can be
+ * called on a handle that was just allocated with memtrack_proc_new,
+ * or on a handle that has been previously passed to memtrack_proc_get
+ * to replace the data with new data on the same or another process.  It is
+ * expected that the second call on the same handle should not require
+ * allocating any new memory.
+ *
+ * Returns 0 on success, -errno on error.
+ */
+int memtrack_proc_get(struct memtrack_proc *p, pid_t pid);
+
+/**
+ * memtrack_proc_graphics_total
+ *
+ * Return total amount of memory that has been allocated for use as window
+ * buffers.  Does not differentiate between memory that has already been
+ * accounted for by reading /proc/pid/smaps and memory that has not been
+ * accounted for.
+ *
+ * Returns non-negative size in bytes on success, -errno on error.
+ */
+ssize_t memtrack_proc_graphics_total(struct memtrack_proc *p);
+
+/**
+ * memtrack_proc_graphics_pss
+ *
+ * Return total amount of memory that has been allocated for use as window
+ * buffers, but has not already been accounted for by reading /proc/pid/smaps.
+ * Memory that is shared across processes may already be divided by the
+ * number of processes that share it (preferred), or may be charged in full to
+ * every process that shares it, depending on the capabilities of the driver.
+ *
+ * Returns non-negative size in bytes on success, -errno on error.
+ */
+ssize_t memtrack_proc_graphics_pss(struct memtrack_proc *p);
+
+/**
+ * memtrack_proc_gl_total
+ *
+ * Same as memtrack_proc_graphics_total, but counts GL memory (which
+ * should not overlap with graphics memory) instead of graphics memory.
+ *
+ * Returns non-negative size in bytes on success, -errno on error.
+ */
+ssize_t memtrack_proc_gl_total(struct memtrack_proc *p);
+
+/**
+ * memtrack_proc_gl_pss
+ *
+ * Same as memtrack_proc_graphics_total, but counts GL memory (which
+ * should not overlap with graphics memory) instead of graphics memory.
+ *
+ * Returns non-negative size in bytes on success, -errno on error.
+ */
+ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p);
+
+/**
+ * memtrack_proc_gl_total
+ *
+ * Same as memtrack_proc_graphics_total, but counts miscellaneous memory
+ * not tracked by gl or graphics calls above.
+ *
+ * Returns non-negative size in bytes on success, -errno on error.
+ */
+ssize_t memtrack_proc_other_total(struct memtrack_proc *p);
+
+/**
+ * memtrack_proc_gl_pss
+ *
+ * Same as memtrack_proc_graphics_total, but counts miscellaneous memory
+ * not tracked by gl or graphics calls above.
+ *
+ * Returns non-negative size in bytes on success, -errno on error.
+ */
+ssize_t memtrack_proc_other_pss(struct memtrack_proc *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netutils/dhcp.h b/include/netutils/dhcp.h
index bd2c957..de6bc82 100644
--- a/include/netutils/dhcp.h
+++ b/include/netutils/dhcp.h
@@ -30,7 +30,9 @@
                           char *dns[],
                           char *server,
                           uint32_t *lease,
-                          char *vendorInfo);
+                          char *vendorInfo,
+                          char *domain,
+                          char *mtu);
 extern int dhcp_do_request_renew(const char *ifname,
                                 char *ipaddr,
                                 char *gateway,
@@ -38,7 +40,9 @@
                                 char *dns[],
                                 char *server,
                                 uint32_t *lease,
-                                char *vendorInfo);
+                                char *vendorInfo,
+                                char *domain,
+                                char *mtu);
 extern int dhcp_stop(const char *ifname);
 extern int dhcp_release_lease(const char *ifname);
 extern char *dhcp_get_errmsg();
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 5d363a7..0ed0d78 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -34,8 +34,8 @@
 #endif
 
 /* This is the master Users and Groups config for the platform.
-** DO NOT EVER RENUMBER.
-*/
+ * DO NOT EVER RENUMBER
+ */
 
 #define AID_ROOT             0  /* traditional unix root user */
 
@@ -72,6 +72,10 @@
 #define AID_CLAT          1029  /* clat part of nat464 */
 #define AID_LOOP_RADIO    1030  /* loop radio devices */
 #define AID_MEDIA_DRM     1031  /* MediaDrm plugins */
+#define AID_PACKAGE_INFO  1032  /* access to installed package details */
+#define AID_SDCARD_PICS   1033  /* external storage photos access */
+#define AID_SDCARD_AV     1034  /* external storage audio/video access */
+#define AID_SDCARD_ALL    1035  /* access all users external storage */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
 #define AID_CACHE         2001  /* cache access */
@@ -108,50 +112,61 @@
 };
 
 static const struct android_id_info android_ids[] = {
-    { "root",      AID_ROOT, },
-    { "system",    AID_SYSTEM, },
-    { "radio",     AID_RADIO, },
-    { "bluetooth", AID_BLUETOOTH, },
-    { "graphics",  AID_GRAPHICS, },
-    { "input",     AID_INPUT, },
-    { "audio",     AID_AUDIO, },
-    { "camera",    AID_CAMERA, },
-    { "log",       AID_LOG, },
-    { "compass",   AID_COMPASS, },
-    { "mount",     AID_MOUNT, },
-    { "wifi",      AID_WIFI, },
-    { "dhcp",      AID_DHCP, },
-    { "adb",       AID_ADB, },
-    { "install",   AID_INSTALL, },
-    { "media",     AID_MEDIA, },
-    { "drm",       AID_DRM, },
-    { "mdnsr",     AID_MDNSR, },
-    { "nfc",       AID_NFC, },
-    { "drmrpc",    AID_DRMRPC, },
-    { "shell",     AID_SHELL, },
-    { "cache",     AID_CACHE, },
-    { "diag",      AID_DIAG, },
-    { "net_bt_admin", AID_NET_BT_ADMIN, },
-    { "net_bt",    AID_NET_BT, },
-    { "net_bt_stack",    AID_NET_BT_STACK, },
-    { "sdcard_r",  AID_SDCARD_R, },
-    { "sdcard_rw", AID_SDCARD_RW, },
-    { "media_rw",  AID_MEDIA_RW, },
-    { "vpn",       AID_VPN, },
-    { "keystore",  AID_KEYSTORE, },
-    { "usb",       AID_USB, },
-    { "mtp",       AID_MTP, },
-    { "gps",       AID_GPS, },
-    { "inet",      AID_INET, },
-    { "net_raw",   AID_NET_RAW, },
-    { "net_admin", AID_NET_ADMIN, },
-    { "net_bw_stats", AID_NET_BW_STATS, },
-    { "net_bw_acct", AID_NET_BW_ACCT, },
-    { "loop_radio", AID_LOOP_RADIO, },
-    { "misc",      AID_MISC, },
-    { "nobody",    AID_NOBODY, },
-    { "clat",      AID_CLAT, },
-    { "mediadrm",  AID_MEDIA_DRM, },
+    { "root",          AID_ROOT, },
+
+    { "system",        AID_SYSTEM, },
+
+    { "radio",         AID_RADIO, },
+    { "bluetooth",     AID_BLUETOOTH, },
+    { "graphics",      AID_GRAPHICS, },
+    { "input",         AID_INPUT, },
+    { "audio",         AID_AUDIO, },
+    { "camera",        AID_CAMERA, },
+    { "log",           AID_LOG, },
+    { "compass",       AID_COMPASS, },
+    { "mount",         AID_MOUNT, },
+    { "wifi",          AID_WIFI, },
+    { "adb",           AID_ADB, },
+    { "install",       AID_INSTALL, },
+    { "media",         AID_MEDIA, },
+    { "dhcp",          AID_DHCP, },
+    { "sdcard_rw",     AID_SDCARD_RW, },
+    { "vpn",           AID_VPN, },
+    { "keystore",      AID_KEYSTORE, },
+    { "usb",           AID_USB, },
+    { "drm",           AID_DRM, },
+    { "mdnsr",         AID_MDNSR, },
+    { "gps",           AID_GPS, },
+    // AID_UNUSED1
+    { "media_rw",      AID_MEDIA_RW, },
+    { "mtp",           AID_MTP, },
+    // AID_UNUSED2
+    { "drmrpc",        AID_DRMRPC, },
+    { "nfc",           AID_NFC, },
+    { "sdcard_r",      AID_SDCARD_R, },
+    { "clat",          AID_CLAT, },
+    { "loop_radio",    AID_LOOP_RADIO, },
+    { "mediadrm",      AID_MEDIA_DRM, },
+    { "package_info",  AID_PACKAGE_INFO, },
+    { "sdcard_pics",   AID_SDCARD_PICS, },
+    { "sdcard_av",     AID_SDCARD_AV, },
+    { "sdcard_all",    AID_SDCARD_ALL, },
+
+    { "shell",         AID_SHELL, },
+    { "cache",         AID_CACHE, },
+    { "diag",          AID_DIAG, },
+
+    { "net_bt_admin",  AID_NET_BT_ADMIN, },
+    { "net_bt",        AID_NET_BT, },
+    { "inet",          AID_INET, },
+    { "net_raw",       AID_NET_RAW, },
+    { "net_admin",     AID_NET_ADMIN, },
+    { "net_bw_stats",  AID_NET_BW_STATS, },
+    { "net_bw_acct",   AID_NET_BW_ACCT, },
+    { "net_bt_stack",  AID_NET_BT_STACK, },
+
+    { "misc",          AID_MISC, },
+    { "nobody",        AID_NOBODY, },
 };
 
 #define android_id_count \
@@ -229,7 +244,7 @@
     { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/tcpdump" },
     { 04770, AID_ROOT,      AID_RADIO,     0, "system/bin/pppd-ril" },
 
-    /* the following file has enhanced capabilities and IS included in user builds. */
+    /* the following files have enhanced capabilities and ARE included in user builds. */
     { 00750, AID_ROOT,      AID_SHELL,     (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" },
 
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
diff --git a/include/system/audio.h b/include/system/audio.h
index da235dd..aa7ac02 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -31,6 +31,9 @@
  * frameworks/base/include/media/AudioSystem.h
  */
 
+/* device address used to refer to the standard remote submix */
+#define AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS "0"
+
 typedef int audio_io_handle_t;
 
 /* Audio stream types */
@@ -69,6 +72,11 @@
                                           /*  play the mix captured by this audio source.      */
     AUDIO_SOURCE_CNT,
     AUDIO_SOURCE_MAX                 = AUDIO_SOURCE_CNT - 1,
+    AUDIO_SOURCE_HOTWORD             = 1999, /* A low-priority, preemptible audio source for
+                                                for background software hotword detection.
+                                                Same tuning as AUDIO_SOURCE_VOICE_RECOGNITION.
+                                                Used only internally to the framework. Not exposed
+                                                at the audio HAL. */
 } audio_source_t;
 
 /* special audio session values
@@ -383,9 +391,51 @@
                                         // controls related to voice calls.
     AUDIO_OUTPUT_FLAG_FAST = 0x4,       // output supports "fast tracks",
                                         // defined elsewhere
-    AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 0x8 // use deep audio buffers
+    AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 0x8, // use deep audio buffers
+    AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD = 0x10,  // offload playback of compressed
+                                                // streams to hardware codec
+    AUDIO_OUTPUT_FLAG_NON_BLOCKING = 0x20 // use non-blocking write
 } audio_output_flags_t;
 
+/* The audio input flags are analogous to audio output flags.
+ * Currently they are used only when an AudioRecord is created,
+ * to indicate a preference to be connected to an input stream with
+ * attributes corresponding to the specified flags.
+ */
+typedef enum {
+    AUDIO_INPUT_FLAG_NONE = 0x0,        // no attributes
+    AUDIO_INPUT_FLAG_FAST = 0x1,        // prefer an input that supports "fast tracks"
+} audio_input_flags_t;
+
+/* Additional information about compressed streams offloaded to
+ * hardware playback
+ * The version and size fields must be initialized by the caller by using
+ * one of the constants defined here.
+ */
+typedef struct {
+    uint16_t version;                   // version of the info structure
+    uint16_t size;                      // total size of the structure including version and size
+    uint32_t sample_rate;               // sample rate in Hz
+    audio_channel_mask_t channel_mask;  // channel mask
+    audio_format_t format;              // audio format
+    audio_stream_type_t stream_type;    // stream type
+    uint32_t bit_rate;                  // bit rate in bits per second
+    int64_t duration_us;                // duration in microseconds, -1 if unknown
+    bool has_video;                     // true if stream is tied to a video stream
+    bool is_streaming;                  // true if streaming, false if local playback
+} audio_offload_info_t;
+
+#define AUDIO_MAKE_OFFLOAD_INFO_VERSION(maj,min) \
+            ((((maj) & 0xff) << 8) | ((min) & 0xff))
+
+#define AUDIO_OFFLOAD_INFO_VERSION_0_1 AUDIO_MAKE_OFFLOAD_INFO_VERSION(0, 1)
+#define AUDIO_OFFLOAD_INFO_VERSION_CURRENT AUDIO_OFFLOAD_INFO_VERSION_0_1
+
+static const audio_offload_info_t AUDIO_INFO_INITIALIZER = {
+    version: AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
+    size: sizeof(audio_offload_info_t),
+};
+
 static inline bool audio_is_output_device(audio_devices_t device)
 {
     if (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
@@ -439,24 +489,25 @@
 
 static inline bool audio_is_remote_submix_device(audio_devices_t device)
 {
-    if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX))
+    if ((device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) == AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+            || (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX)
         return true;
     else
         return false;
 }
 
-static inline bool audio_is_input_channel(uint32_t channel)
+static inline bool audio_is_input_channel(audio_channel_mask_t channel)
 {
     if ((channel & ~AUDIO_CHANNEL_IN_ALL) == 0)
-        return true;
+        return channel != 0;
     else
         return false;
 }
 
-static inline bool audio_is_output_channel(uint32_t channel)
+static inline bool audio_is_output_channel(audio_channel_mask_t channel)
 {
     if ((channel & ~AUDIO_CHANNEL_OUT_ALL) == 0)
-        return true;
+        return channel != 0;
     else
         return false;
 }
diff --git a/include/system/graphics.h b/include/system/graphics.h
index ed493f5..be86ae4 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -42,15 +42,40 @@
  */
 
 enum {
+    /*
+     * "linear" color pixel formats:
+     *
+     * The pixel formats below contain sRGB data but are otherwise treated
+     * as linear formats, i.e.: no special operation is performed when
+     * reading or writing into a buffer in one of these formats
+     */
     HAL_PIXEL_FORMAT_RGBA_8888          = 1,
     HAL_PIXEL_FORMAT_RGBX_8888          = 2,
     HAL_PIXEL_FORMAT_RGB_888            = 3,
     HAL_PIXEL_FORMAT_RGB_565            = 4,
     HAL_PIXEL_FORMAT_BGRA_8888          = 5,
-    HAL_PIXEL_FORMAT_RGBA_5551          = 6,
-    HAL_PIXEL_FORMAT_RGBA_4444          = 7,
 
-    /* 0x8 - 0xFF range unavailable */
+    /*
+     * sRGB color pixel formats:
+     *
+     * The red, green and blue components are stored in sRGB space, and converted
+     * to linear space when read, using the standard sRGB to linear equation:
+     *
+     * Clinear = Csrgb / 12.92                  for Csrgb <= 0.04045
+     *         = (Csrgb + 0.055 / 1.055)^2.4    for Csrgb >  0.04045
+     *
+     * When written the inverse transformation is performed:
+     *
+     * Csrgb = 12.92 * Clinear                  for Clinear <= 0.0031308
+     *       = 1.055 * Clinear^(1/2.4) - 0.055  for Clinear >  0.0031308
+     *
+     *
+     *  The alpha component, if present, is always stored in linear space and
+     *  is left unmodified when read or written.
+     *
+     */
+    HAL_PIXEL_FORMAT_sRGB_A_8888        = 0xC,
+    HAL_PIXEL_FORMAT_sRGB_X_8888        = 0xD,
 
     /*
      * 0x100 - 0x1FF
@@ -268,6 +293,8 @@
     HAL_TRANSFORM_ROT_180   = 0x03,
     /* rotate source image 270 degrees clockwise */
     HAL_TRANSFORM_ROT_270   = 0x07,
+    /* don't use. see system/window.h */
+    HAL_TRANSFORM_RESERVED  = 0x08,
 };
 
 #ifdef __cplusplus
diff --git a/include/system/thread_defs.h b/include/system/thread_defs.h
new file mode 100644
index 0000000..377a48c
--- /dev/null
+++ b/include/system/thread_defs.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2013 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 ANDROID_THREAD_DEFS_H
+#define ANDROID_THREAD_DEFS_H
+
+#include "graphics.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+enum {
+    /*
+     * ***********************************************
+     * ** Keep in sync with android.os.Process.java **
+     * ***********************************************
+     *
+     * This maps directly to the "nice" priorities we use in Android.
+     * A thread priority should be chosen inverse-proportionally to
+     * the amount of work the thread is expected to do. The more work
+     * a thread will do, the less favorable priority it should get so that
+     * it doesn't starve the system. Threads not behaving properly might
+     * be "punished" by the kernel.
+     * Use the levels below when appropriate. Intermediate values are
+     * acceptable, preferably use the {MORE|LESS}_FAVORABLE constants below.
+     */
+    ANDROID_PRIORITY_LOWEST         =  19,
+
+    /* use for background tasks */
+    ANDROID_PRIORITY_BACKGROUND     =  10,
+
+    /* most threads run at normal priority */
+    ANDROID_PRIORITY_NORMAL         =   0,
+
+    /* threads currently running a UI that the user is interacting with */
+    ANDROID_PRIORITY_FOREGROUND     =  -2,
+
+    /* the main UI thread has a slightly more favorable priority */
+    ANDROID_PRIORITY_DISPLAY        =  -4,
+
+    /* ui service treads might want to run at a urgent display (uncommon) */
+    ANDROID_PRIORITY_URGENT_DISPLAY =  HAL_PRIORITY_URGENT_DISPLAY,
+
+    /* all normal audio threads */
+    ANDROID_PRIORITY_AUDIO          = -16,
+
+    /* service audio threads (uncommon) */
+    ANDROID_PRIORITY_URGENT_AUDIO   = -19,
+
+    /* should never be used in practice. regular process might not
+     * be allowed to use this level */
+    ANDROID_PRIORITY_HIGHEST        = -20,
+
+    ANDROID_PRIORITY_DEFAULT        = ANDROID_PRIORITY_NORMAL,
+    ANDROID_PRIORITY_MORE_FAVORABLE = -1,
+    ANDROID_PRIORITY_LESS_FAVORABLE = +1,
+};
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* ANDROID_THREAD_DEFS_H */
diff --git a/include/system/window.h b/include/system/window.h
index b8a19c8..649bd71 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -230,7 +230,13 @@
      * Boolean that indicates whether the consumer is running more than
      * one buffer behind the producer.
      */
-    NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND = 9
+    NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND = 9,
+
+    /*
+     * The consumer gralloc usage bits currently set by the consumer.
+     * The values are defined in hardware/libhardware/include/gralloc.h.
+     */
+    NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10
 };
 
 /* Valid operations for the (*perform)() hook.
@@ -290,12 +296,15 @@
     NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
     /* flip source image vertically */
     NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
-    /* rotate source image 90 degrees clock-wise */
+    /* rotate source image 90 degrees clock-wise, and is applied after TRANSFORM_FLIP_{H|V} */
     NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
     /* rotate source image 180 degrees */
     NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
     /* rotate source image 270 degrees clock-wise */
     NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
+    /* transforms source by the inverse transform of the screen it is displayed onto. This
+     * transform is applied last */
+    NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY = 0x08
 };
 
 /* parameter for NATIVE_WINDOW_SET_SCALING_MODE */
diff --git a/include/utils/AndroidThreads.h b/include/utils/AndroidThreads.h
new file mode 100644
index 0000000..4eee14d
--- /dev/null
+++ b/include/utils/AndroidThreads.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2007 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 _LIBS_UTILS_ANDROID_THREADS_H
+#define _LIBS_UTILS_ANDROID_THREADS_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#if defined(HAVE_PTHREADS)
+# include <pthread.h>
+#endif
+
+#include <utils/ThreadDefs.h>
+
+// ---------------------------------------------------------------------------
+// C API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Create and run a new thread.
+extern int androidCreateThread(android_thread_func_t, void *);
+
+// Create thread with lots of parameters
+extern int androidCreateThreadEtc(android_thread_func_t entryFunction,
+                                  void *userData,
+                                  const char* threadName,
+                                  int32_t threadPriority,
+                                  size_t threadStackSize,
+                                  android_thread_id_t *threadId);
+
+// Get some sort of unique identifier for the current thread.
+extern android_thread_id_t androidGetThreadId();
+
+// Low-level thread creation -- never creates threads that can
+// interact with the Java VM.
+extern int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
+                                     void *userData,
+                                     const char* threadName,
+                                     int32_t threadPriority,
+                                     size_t threadStackSize,
+                                     android_thread_id_t *threadId);
+
+// set the same of the running thread
+extern void androidSetThreadName(const char* name);
+
+// Used by the Java Runtime to control how threads are created, so that
+// they can be proper and lovely Java threads.
+typedef int (*android_create_thread_fn)(android_thread_func_t entryFunction,
+                                        void *userData,
+                                        const char* threadName,
+                                        int32_t threadPriority,
+                                        size_t threadStackSize,
+                                        android_thread_id_t *threadId);
+
+extern void androidSetCreateThreadFunc(android_create_thread_fn func);
+
+// ------------------------------------------------------------------
+// Extra functions working with raw pids.
+
+// Get pid for the current thread.
+extern pid_t androidGetTid();
+
+#ifdef HAVE_ANDROID_OS
+// Change the priority AND scheduling group of a particular thread.  The priority
+// should be one of the ANDROID_PRIORITY constants.  Returns INVALID_OPERATION
+// if the priority set failed, else another value if just the group set failed;
+// in either case errno is set.  Thread ID zero means current thread.
+extern int androidSetThreadPriority(pid_t tid, int prio);
+
+// Get the current priority of a particular thread. Returns one of the
+// ANDROID_PRIORITY constants or a negative result in case of error.
+extern int androidGetThreadPriority(pid_t tid);
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+// ----------------------------------------------------------------------------
+// C++ API
+#ifdef __cplusplus
+namespace android {
+// ----------------------------------------------------------------------------
+
+// Create and run a new thread.
+inline bool createThread(thread_func_t f, void *a) {
+    return androidCreateThread(f, a) ? true : false;
+}
+
+// Create thread with lots of parameters
+inline bool createThreadEtc(thread_func_t entryFunction,
+                            void *userData,
+                            const char* threadName = "android:unnamed_thread",
+                            int32_t threadPriority = PRIORITY_DEFAULT,
+                            size_t threadStackSize = 0,
+                            thread_id_t *threadId = 0)
+{
+    return androidCreateThreadEtc(entryFunction, userData, threadName,
+        threadPriority, threadStackSize, threadId) ? true : false;
+}
+
+// Get some sort of unique identifier for the current thread.
+inline thread_id_t getThreadId() {
+    return androidGetThreadId();
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+#endif  // __cplusplus
+// ----------------------------------------------------------------------------
+
+#endif // _LIBS_UTILS_ANDROID_THREADS_H
diff --git a/include/cutils/zygote.h b/include/utils/Atomic.h
similarity index 63%
rename from include/cutils/zygote.h
rename to include/utils/Atomic.h
index a7480d3..7eb476c 100644
--- a/include/cutils/zygote.h
+++ b/include/utils/Atomic.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2005 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,18 +14,9 @@
  * limitations under the License.
  */
 
-#ifndef __CUTILS_ZYGOTE_H
-#define __CUTILS_ZYGOTE_H
+#ifndef ANDROID_UTILS_ATOMIC_H
+#define ANDROID_UTILS_ATOMIC_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include <cutils/atomic.h>
 
-int zygote_run_oneshot(int sendStdio, int argc, const char **argv);
-int zygote_run(int argc, const char **argv);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __CUTILS_ZYGOTE_H */
+#endif // ANDROID_UTILS_ATOMIC_H
diff --git a/include/utils/BasicHashtable.h b/include/utils/BasicHashtable.h
new file mode 100644
index 0000000..c235d62
--- /dev/null
+++ b/include/utils/BasicHashtable.h
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2011 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 ANDROID_BASIC_HASHTABLE_H
+#define ANDROID_BASIC_HASHTABLE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/SharedBuffer.h>
+#include <utils/TypeHelpers.h>
+
+namespace android {
+
+/* Implementation type.  Nothing to see here. */
+class BasicHashtableImpl {
+protected:
+    struct Bucket {
+        // The collision flag indicates that the bucket is part of a collision chain
+        // such that at least two entries both hash to this bucket.  When true, we
+        // may need to seek further along the chain to find the entry.
+        static const uint32_t COLLISION = 0x80000000UL;
+
+        // The present flag indicates that the bucket contains an initialized entry value.
+        static const uint32_t PRESENT   = 0x40000000UL;
+
+        // Mask for 30 bits worth of the hash code that are stored within the bucket to
+        // speed up lookups and rehashing by eliminating the need to recalculate the
+        // hash code of the entry's key.
+        static const uint32_t HASH_MASK = 0x3fffffffUL;
+
+        // Combined value that stores the collision and present flags as well as
+        // a 30 bit hash code.
+        uint32_t cookie;
+
+        // Storage for the entry begins here.
+        char entry[0];
+    };
+
+    BasicHashtableImpl(size_t entrySize, bool hasTrivialDestructor,
+            size_t minimumInitialCapacity, float loadFactor);
+    BasicHashtableImpl(const BasicHashtableImpl& other);
+    virtual ~BasicHashtableImpl();
+
+    void dispose();
+
+    inline void edit() {
+        if (mBuckets && !SharedBuffer::bufferFromData(mBuckets)->onlyOwner()) {
+            clone();
+        }
+    }
+
+    void setTo(const BasicHashtableImpl& other);
+    void clear();
+
+    ssize_t next(ssize_t index) const;
+    ssize_t find(ssize_t index, hash_t hash, const void* __restrict__ key) const;
+    size_t add(hash_t hash, const void* __restrict__ entry);
+    void removeAt(size_t index);
+    void rehash(size_t minimumCapacity, float loadFactor);
+
+    const size_t mBucketSize; // number of bytes per bucket including the entry
+    const bool mHasTrivialDestructor; // true if the entry type does not require destruction
+    size_t mCapacity;         // number of buckets that can be filled before exceeding load factor
+    float mLoadFactor;        // load factor
+    size_t mSize;             // number of elements actually in the table
+    size_t mFilledBuckets;    // number of buckets for which collision or present is true
+    size_t mBucketCount;      // number of slots in the mBuckets array
+    void* mBuckets;           // array of buckets, as a SharedBuffer
+
+    inline const Bucket& bucketAt(const void* __restrict__ buckets, size_t index) const {
+        return *reinterpret_cast<const Bucket*>(
+                static_cast<const uint8_t*>(buckets) + index * mBucketSize);
+    }
+
+    inline Bucket& bucketAt(void* __restrict__ buckets, size_t index) const {
+        return *reinterpret_cast<Bucket*>(static_cast<uint8_t*>(buckets) + index * mBucketSize);
+    }
+
+    virtual bool compareBucketKey(const Bucket& bucket, const void* __restrict__ key) const = 0;
+    virtual void initializeBucketEntry(Bucket& bucket, const void* __restrict__ entry) const = 0;
+    virtual void destroyBucketEntry(Bucket& bucket) const = 0;
+
+private:
+    void clone();
+
+    // Allocates a bucket array as a SharedBuffer.
+    void* allocateBuckets(size_t count) const;
+
+    // Releases a bucket array's associated SharedBuffer.
+    void releaseBuckets(void* __restrict__ buckets, size_t count) const;
+
+    // Destroys the contents of buckets (invokes destroyBucketEntry for each
+    // populated bucket if needed).
+    void destroyBuckets(void* __restrict__ buckets, size_t count) const;
+
+    // Copies the content of buckets (copies the cookie and invokes copyBucketEntry
+    // for each populated bucket if needed).
+    void copyBuckets(const void* __restrict__ fromBuckets,
+            void* __restrict__ toBuckets, size_t count) const;
+
+    // Determines the appropriate size of a bucket array to store a certain minimum
+    // number of entries and returns its effective capacity.
+    static void determineCapacity(size_t minimumCapacity, float loadFactor,
+            size_t* __restrict__ outBucketCount, size_t* __restrict__ outCapacity);
+
+    // Trim a hash code to 30 bits to match what we store in the bucket's cookie.
+    inline static hash_t trimHash(hash_t hash) {
+        return (hash & Bucket::HASH_MASK) ^ (hash >> 30);
+    }
+
+    // Returns the index of the first bucket that is in the collision chain
+    // for the specified hash code, given the total number of buckets.
+    // (Primary hash)
+    inline static size_t chainStart(hash_t hash, size_t count) {
+        return hash % count;
+    }
+
+    // Returns the increment to add to a bucket index to seek to the next bucket
+    // in the collision chain for the specified hash code, given the total number of buckets.
+    // (Secondary hash)
+    inline static size_t chainIncrement(hash_t hash, size_t count) {
+        return ((hash >> 7) | (hash << 25)) % (count - 1) + 1;
+    }
+
+    // Returns the index of the next bucket that is in the collision chain
+    // that is defined by the specified increment, given the total number of buckets.
+    inline static size_t chainSeek(size_t index, size_t increment, size_t count) {
+        return (index + increment) % count;
+    }
+};
+
+/*
+ * A BasicHashtable stores entries that are indexed by hash code in place
+ * within an array.  The basic operations are finding entries by key,
+ * adding new entries and removing existing entries.
+ *
+ * This class provides a very limited set of operations with simple semantics.
+ * It is intended to be used as a building block to construct more complex
+ * and interesting data structures such as HashMap.  Think very hard before
+ * adding anything extra to BasicHashtable, it probably belongs at a
+ * higher level of abstraction.
+ *
+ * TKey: The key type.
+ * TEntry: The entry type which is what is actually stored in the array.
+ *
+ * TKey must support the following contract:
+ *     bool operator==(const TKey& other) const;  // return true if equal
+ *     bool operator!=(const TKey& other) const;  // return true if unequal
+ *
+ * TEntry must support the following contract:
+ *     const TKey& getKey() const;  // get the key from the entry
+ *
+ * This class supports storing entries with duplicate keys.  Of course, it can't
+ * tell them apart during removal so only the first entry will be removed.
+ * We do this because it means that operations like add() can't fail.
+ */
+template <typename TKey, typename TEntry>
+class BasicHashtable : private BasicHashtableImpl {
+public:
+    /* Creates a hashtable with the specified minimum initial capacity.
+     * The underlying array will be created when the first entry is added.
+     *
+     * minimumInitialCapacity: The minimum initial capacity for the hashtable.
+     *     Default is 0.
+     * loadFactor: The desired load factor for the hashtable, between 0 and 1.
+     *     Default is 0.75.
+     */
+    BasicHashtable(size_t minimumInitialCapacity = 0, float loadFactor = 0.75f);
+
+    /* Copies a hashtable.
+     * The underlying storage is shared copy-on-write.
+     */
+    BasicHashtable(const BasicHashtable& other);
+
+    /* Clears and destroys the hashtable.
+     */
+    virtual ~BasicHashtable();
+
+    /* Making this hashtable a copy of the other hashtable.
+     * The underlying storage is shared copy-on-write.
+     *
+     * other: The hashtable to copy.
+     */
+    inline BasicHashtable<TKey, TEntry>& operator =(const BasicHashtable<TKey, TEntry> & other) {
+        setTo(other);
+        return *this;
+    }
+
+    /* Returns the number of entries in the hashtable.
+     */
+    inline size_t size() const {
+        return mSize;
+    }
+
+    /* Returns the capacity of the hashtable, which is the number of elements that can
+     * added to the hashtable without requiring it to be grown.
+     */
+    inline size_t capacity() const {
+        return mCapacity;
+    }
+
+    /* Returns the number of buckets that the hashtable has, which is the size of its
+     * underlying array.
+     */
+    inline size_t bucketCount() const {
+        return mBucketCount;
+    }
+
+    /* Returns the load factor of the hashtable. */
+    inline float loadFactor() const {
+        return mLoadFactor;
+    };
+
+    /* Returns a const reference to the entry at the specified index.
+     *
+     * index:   The index of the entry to retrieve.  Must be a valid index within
+     *          the bounds of the hashtable.
+     */
+    inline const TEntry& entryAt(size_t index) const {
+        return entryFor(bucketAt(mBuckets, index));
+    }
+
+    /* Returns a non-const reference to the entry at the specified index.
+     *
+     * index: The index of the entry to edit.  Must be a valid index within
+     *        the bounds of the hashtable.
+     */
+    inline TEntry& editEntryAt(size_t index) {
+        edit();
+        return entryFor(bucketAt(mBuckets, index));
+    }
+
+    /* Clears the hashtable.
+     * All entries in the hashtable are destroyed immediately.
+     * If you need to do something special with the entries in the hashtable then iterate
+     * over them and do what you need before clearing the hashtable.
+     */
+    inline void clear() {
+        BasicHashtableImpl::clear();
+    }
+
+    /* Returns the index of the next entry in the hashtable given the index of a previous entry.
+     * If the given index is -1, then returns the index of the first entry in the hashtable,
+     * if there is one, or -1 otherwise.
+     * If the given index is not -1, then returns the index of the next entry in the hashtable,
+     * in strictly increasing order, or -1 if there are none left.
+     *
+     * index:   The index of the previous entry that was iterated, or -1 to begin
+     *          iteration at the beginning of the hashtable.
+     */
+    inline ssize_t next(ssize_t index) const {
+        return BasicHashtableImpl::next(index);
+    }
+
+    /* Finds the index of an entry with the specified key.
+     * If the given index is -1, then returns the index of the first matching entry,
+     * otherwise returns the index of the next matching entry.
+     * If the hashtable contains multiple entries with keys that match the requested
+     * key, then the sequence of entries returned is arbitrary.
+     * Returns -1 if no entry was found.
+     *
+     * index:   The index of the previous entry with the specified key, or -1 to
+     *          find the first matching entry.
+     * hash:    The hashcode of the key.
+     * key:     The key.
+     */
+    inline ssize_t find(ssize_t index, hash_t hash, const TKey& key) const {
+        return BasicHashtableImpl::find(index, hash, &key);
+    }
+
+    /* Adds the entry to the hashtable.
+     * Returns the index of the newly added entry.
+     * If an entry with the same key already exists, then a duplicate entry is added.
+     * If the entry will not fit, then the hashtable's capacity is increased and
+     * its contents are rehashed.  See rehash().
+     *
+     * hash:    The hashcode of the key.
+     * entry:   The entry to add.
+     */
+    inline size_t add(hash_t hash, const TEntry& entry) {
+        return BasicHashtableImpl::add(hash, &entry);
+    }
+
+    /* Removes the entry with the specified index from the hashtable.
+     * The entry is destroyed immediately.
+     * The index must be valid.
+     *
+     * The hashtable is not compacted after an item is removed, so it is legal
+     * to continue iterating over the hashtable using next() or find().
+     *
+     * index:   The index of the entry to remove.  Must be a valid index within the
+     *          bounds of the hashtable, and it must refer to an existing entry.
+     */
+    inline void removeAt(size_t index) {
+        BasicHashtableImpl::removeAt(index);
+    }
+
+    /* Rehashes the contents of the hashtable.
+     * Grows the hashtable to at least the specified minimum capacity or the
+     * current number of elements, whichever is larger.
+     *
+     * Rehashing causes all entries to be copied and the entry indices may change.
+     * Although the hash codes are cached by the hashtable, rehashing can be an
+     * expensive operation and should be avoided unless the hashtable's size
+     * needs to be changed.
+     *
+     * Rehashing is the only way to change the capacity or load factor of the
+     * hashtable once it has been created.  It can be used to compact the
+     * hashtable by choosing a minimum capacity that is smaller than the current
+     * capacity (such as 0).
+     *
+     * minimumCapacity: The desired minimum capacity after rehashing.
+     * loadFactor: The desired load factor after rehashing.
+     */
+    inline void rehash(size_t minimumCapacity, float loadFactor) {
+        BasicHashtableImpl::rehash(minimumCapacity, loadFactor);
+    }
+
+    /* Determines whether there is room to add another entry without rehashing.
+     * When this returns true, a subsequent add() operation is guaranteed to
+     * complete without performing a rehash.
+     */
+    inline bool hasMoreRoom() const {
+        return mCapacity > mFilledBuckets;
+    }
+
+protected:
+    static inline const TEntry& entryFor(const Bucket& bucket) {
+        return reinterpret_cast<const TEntry&>(bucket.entry);
+    }
+
+    static inline TEntry& entryFor(Bucket& bucket) {
+        return reinterpret_cast<TEntry&>(bucket.entry);
+    }
+
+    virtual bool compareBucketKey(const Bucket& bucket, const void* __restrict__ key) const;
+    virtual void initializeBucketEntry(Bucket& bucket, const void* __restrict__ entry) const;
+    virtual void destroyBucketEntry(Bucket& bucket) const;
+
+private:
+    // For dumping the raw contents of a hashtable during testing.
+    friend class BasicHashtableTest;
+    inline uint32_t cookieAt(size_t index) const {
+        return bucketAt(mBuckets, index).cookie;
+    }
+};
+
+template <typename TKey, typename TEntry>
+BasicHashtable<TKey, TEntry>::BasicHashtable(size_t minimumInitialCapacity, float loadFactor) :
+        BasicHashtableImpl(sizeof(TEntry), traits<TEntry>::has_trivial_dtor,
+                minimumInitialCapacity, loadFactor) {
+}
+
+template <typename TKey, typename TEntry>
+BasicHashtable<TKey, TEntry>::BasicHashtable(const BasicHashtable<TKey, TEntry>& other) :
+        BasicHashtableImpl(other) {
+}
+
+template <typename TKey, typename TEntry>
+BasicHashtable<TKey, TEntry>::~BasicHashtable() {
+    dispose();
+}
+
+template <typename TKey, typename TEntry>
+bool BasicHashtable<TKey, TEntry>::compareBucketKey(const Bucket& bucket,
+        const void* __restrict__ key) const {
+    return entryFor(bucket).getKey() == *static_cast<const TKey*>(key);
+}
+
+template <typename TKey, typename TEntry>
+void BasicHashtable<TKey, TEntry>::initializeBucketEntry(Bucket& bucket,
+        const void* __restrict__ entry) const {
+    if (!traits<TEntry>::has_trivial_copy) {
+        new (&entryFor(bucket)) TEntry(*(static_cast<const TEntry*>(entry)));
+    } else {
+        memcpy(&entryFor(bucket), entry, sizeof(TEntry));
+    }
+}
+
+template <typename TKey, typename TEntry>
+void BasicHashtable<TKey, TEntry>::destroyBucketEntry(Bucket& bucket) const {
+    if (!traits<TEntry>::has_trivial_dtor) {
+        entryFor(bucket).~TEntry();
+    }
+}
+
+}; // namespace android
+
+#endif // ANDROID_BASIC_HASHTABLE_H
diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h
new file mode 100644
index 0000000..19c03d1
--- /dev/null
+++ b/include/utils/BitSet.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2010 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 UTILS_BITSET_H
+#define UTILS_BITSET_H
+
+#include <stdint.h>
+#include <utils/TypeHelpers.h>
+
+/*
+ * Contains some bit manipulation helpers.
+ */
+
+namespace android {
+
+// A simple set of 32 bits that can be individually marked or cleared.
+struct BitSet32 {
+    uint32_t value;
+
+    inline BitSet32() : value(0) { }
+    explicit inline BitSet32(uint32_t value) : value(value) { }
+
+    // Gets the value associated with a particular bit index.
+    static inline uint32_t valueForBit(uint32_t n) { return 0x80000000 >> n; }
+
+    // Clears the bit set.
+    inline void clear() { value = 0; }
+
+    // Returns the number of marked bits in the set.
+    inline uint32_t count() const { return __builtin_popcount(value); }
+
+    // Returns true if the bit set does not contain any marked bits.
+    inline bool isEmpty() const { return ! value; }
+
+    // Returns true if the bit set does not contain any unmarked bits.
+    inline bool isFull() const { return value == 0xffffffff; }
+
+    // Returns true if the specified bit is marked.
+    inline bool hasBit(uint32_t n) const { return value & valueForBit(n); }
+
+    // Marks the specified bit.
+    inline void markBit(uint32_t n) { value |= valueForBit(n); }
+
+    // Clears the specified bit.
+    inline void clearBit(uint32_t n) { value &= ~ valueForBit(n); }
+
+    // Finds the first marked bit in the set.
+    // Result is undefined if all bits are unmarked.
+    inline uint32_t firstMarkedBit() const { return __builtin_clz(value); }
+
+    // Finds the first unmarked bit in the set.
+    // Result is undefined if all bits are marked.
+    inline uint32_t firstUnmarkedBit() const { return __builtin_clz(~ value); }
+
+    // Finds the last marked bit in the set.
+    // Result is undefined if all bits are unmarked.
+    inline uint32_t lastMarkedBit() const { return 31 - __builtin_ctz(value); }
+
+    // Finds the first marked bit in the set and clears it.  Returns the bit index.
+    // Result is undefined if all bits are unmarked.
+    inline uint32_t clearFirstMarkedBit() {
+        uint32_t n = firstMarkedBit();
+        clearBit(n);
+        return n;
+    }
+
+    // Finds the first unmarked bit in the set and marks it.  Returns the bit index.
+    // Result is undefined if all bits are marked.
+    inline uint32_t markFirstUnmarkedBit() {
+        uint32_t n = firstUnmarkedBit();
+        markBit(n);
+        return n;
+    }
+
+    // Finds the last marked bit in the set and clears it.  Returns the bit index.
+    // Result is undefined if all bits are unmarked.
+    inline uint32_t clearLastMarkedBit() {
+        uint32_t n = lastMarkedBit();
+        clearBit(n);
+        return n;
+    }
+
+    // Gets the index of the specified bit in the set, which is the number of
+    // marked bits that appear before the specified bit.
+    inline uint32_t getIndexOfBit(uint32_t n) const {
+        return __builtin_popcount(value & ~(0xffffffffUL >> n));
+    }
+
+    inline bool operator== (const BitSet32& other) const { return value == other.value; }
+    inline bool operator!= (const BitSet32& other) const { return value != other.value; }
+    inline BitSet32 operator& (const BitSet32& other) const {
+        return BitSet32(value & other.value);
+    }
+    inline BitSet32& operator&= (const BitSet32& other) {
+        value &= other.value;
+        return *this;
+    }
+    inline BitSet32 operator| (const BitSet32& other) const {
+        return BitSet32(value | other.value);
+    }
+    inline BitSet32& operator|= (const BitSet32& other) {
+        value |= other.value;
+        return *this;
+    }
+};
+
+ANDROID_BASIC_TYPES_TRAITS(BitSet32)
+
+} // namespace android
+
+#endif // UTILS_BITSET_H
diff --git a/include/utils/BlobCache.h b/include/utils/BlobCache.h
new file mode 100644
index 0000000..7d621e4
--- /dev/null
+++ b/include/utils/BlobCache.h
@@ -0,0 +1,243 @@
+/*
+ ** Copyright 2011, 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 ANDROID_BLOB_CACHE_H
+#define ANDROID_BLOB_CACHE_H
+
+#include <stddef.h>
+
+#include <utils/Flattenable.h>
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+#include <utils/threads.h>
+
+namespace android {
+
+// A BlobCache is an in-memory cache for binary key/value pairs.  A BlobCache
+// does NOT provide any thread-safety guarantees.
+//
+// The cache contents can be serialized to an in-memory buffer or mmap'd file
+// and then reloaded in a subsequent execution of the program.  This
+// serialization is non-portable and the data should only be used by the device
+// that generated it.
+class BlobCache : public RefBase {
+
+public:
+
+    // Create an empty blob cache. The blob cache will cache key/value pairs
+    // with key and value sizes less than or equal to maxKeySize and
+    // maxValueSize, respectively. The total combined size of ALL cache entries
+    // (key sizes plus value sizes) will not exceed maxTotalSize.
+    BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize);
+
+    // set inserts a new binary value into the cache and associates it with the
+    // given binary key.  If the key or value are too large for the cache then
+    // the cache remains unchanged.  This includes the case where a different
+    // value was previously associated with the given key - the old value will
+    // remain in the cache.  If the given key and value are small enough to be
+    // put in the cache (based on the maxKeySize, maxValueSize, and maxTotalSize
+    // values specified to the BlobCache constructor), then the key/value pair
+    // will be in the cache after set returns.  Note, however, that a subsequent
+    // call to set may evict old key/value pairs from the cache.
+    //
+    // Preconditions:
+    //   key != NULL
+    //   0 < keySize
+    //   value != NULL
+    //   0 < valueSize
+    void set(const void* key, size_t keySize, const void* value,
+            size_t valueSize);
+
+    // get retrieves from the cache the binary value associated with a given
+    // binary key.  If the key is present in the cache then the length of the
+    // binary value associated with that key is returned.  If the value argument
+    // is non-NULL and the size of the cached value is less than valueSize bytes
+    // then the cached value is copied into the buffer pointed to by the value
+    // argument.  If the key is not present in the cache then 0 is returned and
+    // the buffer pointed to by the value argument is not modified.
+    //
+    // Note that when calling get multiple times with the same key, the later
+    // calls may fail, returning 0, even if earlier calls succeeded.  The return
+    // value must be checked for each call.
+    //
+    // Preconditions:
+    //   key != NULL
+    //   0 < keySize
+    //   0 <= valueSize
+    size_t get(const void* key, size_t keySize, void* value, size_t valueSize);
+
+
+    // getFlattenedSize returns the number of bytes needed to store the entire
+    // serialized cache.
+    size_t getFlattenedSize() const;
+
+    // flatten serializes the current contents of the cache into the memory
+    // pointed to by 'buffer'.  The serialized cache contents can later be
+    // loaded into a BlobCache object using the unflatten method.  The contents
+    // of the BlobCache object will not be modified.
+    //
+    // Preconditions:
+    //   size >= this.getFlattenedSize()
+    status_t flatten(void* buffer, size_t size) const;
+
+    // unflatten replaces the contents of the cache with the serialized cache
+    // contents in the memory pointed to by 'buffer'.  The previous contents of
+    // the BlobCache will be evicted from the cache.  If an error occurs while
+    // unflattening the serialized cache contents then the BlobCache will be
+    // left in an empty state.
+    //
+    status_t unflatten(void const* buffer, size_t size);
+
+private:
+    // Copying is disallowed.
+    BlobCache(const BlobCache&);
+    void operator=(const BlobCache&);
+
+    // A random function helper to get around MinGW not having nrand48()
+    long int blob_random();
+
+    // clean evicts a randomly chosen set of entries from the cache such that
+    // the total size of all remaining entries is less than mMaxTotalSize/2.
+    void clean();
+
+    // isCleanable returns true if the cache is full enough for the clean method
+    // to have some effect, and false otherwise.
+    bool isCleanable() const;
+
+    // A Blob is an immutable sized unstructured data blob.
+    class Blob : public RefBase {
+    public:
+        Blob(const void* data, size_t size, bool copyData);
+        ~Blob();
+
+        bool operator<(const Blob& rhs) const;
+
+        const void* getData() const;
+        size_t getSize() const;
+
+    private:
+        // Copying is not allowed.
+        Blob(const Blob&);
+        void operator=(const Blob&);
+
+        // mData points to the buffer containing the blob data.
+        const void* mData;
+
+        // mSize is the size of the blob data in bytes.
+        size_t mSize;
+
+        // mOwnsData indicates whether or not this Blob object should free the
+        // memory pointed to by mData when the Blob gets destructed.
+        bool mOwnsData;
+    };
+
+    // A CacheEntry is a single key/value pair in the cache.
+    class CacheEntry {
+    public:
+        CacheEntry();
+        CacheEntry(const sp<Blob>& key, const sp<Blob>& value);
+        CacheEntry(const CacheEntry& ce);
+
+        bool operator<(const CacheEntry& rhs) const;
+        const CacheEntry& operator=(const CacheEntry&);
+
+        sp<Blob> getKey() const;
+        sp<Blob> getValue() const;
+
+        void setValue(const sp<Blob>& value);
+
+    private:
+
+        // mKey is the key that identifies the cache entry.
+        sp<Blob> mKey;
+
+        // mValue is the cached data associated with the key.
+        sp<Blob> mValue;
+    };
+
+    // A Header is the header for the entire BlobCache serialization format. No
+    // need to make this portable, so we simply write the struct out.
+    struct Header {
+        // mMagicNumber is the magic number that identifies the data as
+        // serialized BlobCache contents.  It must always contain 'Blb$'.
+        uint32_t mMagicNumber;
+
+        // mBlobCacheVersion is the serialization format version.
+        uint32_t mBlobCacheVersion;
+
+        // mDeviceVersion is the device-specific version of the cache.  This can
+        // be used to invalidate the cache.
+        uint32_t mDeviceVersion;
+
+        // mNumEntries is number of cache entries following the header in the
+        // data.
+        size_t mNumEntries;
+    };
+
+    // An EntryHeader is the header for a serialized cache entry.  No need to
+    // make this portable, so we simply write the struct out.  Each EntryHeader
+    // is followed imediately by the key data and then the value data.
+    //
+    // The beginning of each serialized EntryHeader is 4-byte aligned, so the
+    // number of bytes that a serialized cache entry will occupy is:
+    //
+    //   ((sizeof(EntryHeader) + keySize + valueSize) + 3) & ~3
+    //
+    struct EntryHeader {
+        // mKeySize is the size of the entry key in bytes.
+        size_t mKeySize;
+
+        // mValueSize is the size of the entry value in bytes.
+        size_t mValueSize;
+
+        // mData contains both the key and value data for the cache entry.  The
+        // key comes first followed immediately by the value.
+        uint8_t mData[];
+    };
+
+    // mMaxKeySize is the maximum key size that will be cached. Calls to
+    // BlobCache::set with a keySize parameter larger than mMaxKeySize will
+    // simply not add the key/value pair to the cache.
+    const size_t mMaxKeySize;
+
+    // mMaxValueSize is the maximum value size that will be cached. Calls to
+    // BlobCache::set with a valueSize parameter larger than mMaxValueSize will
+    // simply not add the key/value pair to the cache.
+    const size_t mMaxValueSize;
+
+    // mMaxTotalSize is the maximum size that all cache entries can occupy. This
+    // includes space for both keys and values. When a call to BlobCache::set
+    // would otherwise cause this limit to be exceeded, either the key/value
+    // pair passed to BlobCache::set will not be cached or other cache entries
+    // will be evicted from the cache to make room for the new entry.
+    const size_t mMaxTotalSize;
+
+    // mTotalSize is the total combined size of all keys and values currently in
+    // the cache.
+    size_t mTotalSize;
+
+    // mRandState is the pseudo-random number generator state. It is passed to
+    // nrand48 to generate random numbers when needed.
+    unsigned short mRandState[3];
+
+    // mCacheEntries stores all the cache entries that are resident in memory.
+    // Cache entries are added to it by the 'set' method.
+    SortedVector<CacheEntry> mCacheEntries;
+};
+
+}
+
+#endif // ANDROID_BLOB_CACHE_H
diff --git a/include/utils/ByteOrder.h b/include/utils/ByteOrder.h
new file mode 100644
index 0000000..baa3a83
--- /dev/null
+++ b/include/utils/ByteOrder.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2006 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 _LIBS_UTILS_BYTE_ORDER_H
+#define _LIBS_UTILS_BYTE_ORDER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#ifdef HAVE_WINSOCK
+#include <winsock2.h>
+#else
+#include <netinet/in.h>
+#endif
+
+/*
+ * These macros are like the hton/ntoh byte swapping macros,
+ * except they allow you to swap to and from the "device" byte
+ * order.  The device byte order is the endianness of the target
+ * device -- for the ARM CPUs we use today, this is little endian.
+ *
+ * Note that the byte swapping functions have not been optimized
+ * much; performance is currently not an issue for them since the
+ * intent is to allow us to avoid byte swapping on the device.
+ */
+
+static inline uint32_t android_swap_long(uint32_t v)
+{
+    return (v<<24) | ((v<<8)&0x00FF0000) | ((v>>8)&0x0000FF00) | (v>>24);
+}
+
+static inline uint16_t android_swap_short(uint16_t v)
+{
+    return (v<<8) | (v>>8);
+}
+
+#define DEVICE_BYTE_ORDER LITTLE_ENDIAN
+
+#if BYTE_ORDER == DEVICE_BYTE_ORDER
+
+#define	dtohl(x)	(x)
+#define	dtohs(x)	(x)
+#define	htodl(x)	(x)
+#define	htods(x)	(x)
+
+#else
+
+#define	dtohl(x)	(android_swap_long(x))
+#define	dtohs(x)	(android_swap_short(x))
+#define	htodl(x)	(android_swap_long(x))
+#define	htods(x)	(android_swap_short(x))
+
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define fromlel(x) (x)
+#define fromles(x) (x)
+#define tolel(x) (x)
+#define toles(x) (x)
+#else
+#define fromlel(x) (android_swap_long(x))
+#define fromles(x) (android_swap_short(x))
+#define tolel(x) (android_swap_long(x))
+#define toles(x) (android_swap_short(x))
+#endif
+
+#endif // _LIBS_UTILS_BYTE_ORDER_H
diff --git a/include/utils/CallStack.h b/include/utils/CallStack.h
new file mode 100644
index 0000000..2056751
--- /dev/null
+++ b/include/utils/CallStack.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2007 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 ANDROID_CALLSTACK_H
+#define ANDROID_CALLSTACK_H
+
+#include <android/log.h>
+#include <utils/String8.h>
+#include <corkscrew/backtrace.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+
+class Printer;
+
+// Collect/print the call stack (function, file, line) traces for a single thread.
+class CallStack {
+public:
+    enum {
+        // Prune the lowest-most stack frames until we have at most MAX_DEPTH.
+        MAX_DEPTH = 31,
+        // Placeholder for specifying the current thread when updating the stack.
+        CURRENT_THREAD = -1,
+    };
+
+    // Create an empty call stack. No-op.
+    CallStack();
+    // Create a callstack with the current thread's stack trace.
+    // Immediately dump it to logcat using the given logtag.
+    CallStack(const char* logtag, int32_t ignoreDepth=1,
+            int32_t maxDepth=MAX_DEPTH);
+    // Copy the existing callstack (no other side effects).
+    CallStack(const CallStack& rhs);
+    ~CallStack();
+
+    // Copy the existing callstack (no other side effects).
+    CallStack& operator = (const CallStack& rhs);
+
+    // Compare call stacks by their backtrace frame memory.
+    bool operator == (const CallStack& rhs) const;
+    bool operator != (const CallStack& rhs) const;
+    bool operator < (const CallStack& rhs) const;
+    bool operator >= (const CallStack& rhs) const;
+    bool operator > (const CallStack& rhs) const;
+    bool operator <= (const CallStack& rhs) const;
+
+    // Get the PC address for the stack frame specified by index.
+    const void* operator [] (int index) const;
+
+    // Reset the stack frames (same as creating an empty call stack).
+    void clear();
+
+    // Immediately collect the stack traces for the specified thread.
+    void update(int32_t ignoreDepth=1, int32_t maxDepth=MAX_DEPTH, pid_t tid=CURRENT_THREAD);
+
+    // Dump a stack trace to the log using the supplied logtag.
+    void log(const char* logtag,
+             android_LogPriority priority = ANDROID_LOG_DEBUG,
+             const char* prefix = 0) const;
+
+    // Dump a stack trace to the specified file descriptor.
+    void dump(int fd, int indent = 0, const char* prefix = 0) const;
+
+    // Return a string (possibly very long) containing the complete stack trace.
+    String8 toString(const char* prefix = 0) const;
+
+    // Dump a serialized representation of the stack trace to the specified printer.
+    void print(Printer& printer) const;
+
+    // Get the count of stack frames that are in this call stack.
+    size_t size() const { return mCount; }
+
+private:
+    size_t mCount;
+    backtrace_frame_t mStack[MAX_DEPTH];
+};
+
+}; // namespace android
+
+#endif // ANDROID_CALLSTACK_H
diff --git a/include/utils/Compat.h b/include/utils/Compat.h
new file mode 100644
index 0000000..fb7748e
--- /dev/null
+++ b/include/utils/Compat.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 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 __LIB_UTILS_COMPAT_H
+#define __LIB_UTILS_COMPAT_H
+
+#include <unistd.h>
+
+/* Compatibility definitions for non-Linux (i.e., BSD-based) hosts. */
+#ifndef HAVE_OFF64_T
+#if _FILE_OFFSET_BITS < 64
+#error "_FILE_OFFSET_BITS < 64; large files are not supported on this platform"
+#endif /* _FILE_OFFSET_BITS < 64 */
+
+typedef off_t off64_t;
+
+static inline off64_t lseek64(int fd, off64_t offset, int whence) {
+    return lseek(fd, offset, whence);
+}
+
+#ifdef HAVE_PREAD
+static inline ssize_t pread64(int fd, void* buf, size_t nbytes, off64_t offset) {
+    return pread(fd, buf, nbytes, offset);
+}
+#endif
+
+#endif /* !HAVE_OFF64_T */
+
+#if HAVE_PRINTF_ZD
+#  define ZD "%zd"
+#  define ZD_TYPE ssize_t
+#else
+#  define ZD "%ld"
+#  define ZD_TYPE long
+#endif
+
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
+
+#endif /* __LIB_UTILS_COMPAT_H */
diff --git a/include/utils/Condition.h b/include/utils/Condition.h
new file mode 100644
index 0000000..e63ba7e
--- /dev/null
+++ b/include/utils/Condition.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2007 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 _LIBS_UTILS_CONDITION_H
+#define _LIBS_UTILS_CONDITION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <time.h>
+
+#if defined(HAVE_PTHREADS)
+# include <pthread.h>
+#endif
+
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
+#include <utils/Timers.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+/*
+ * Condition variable class.  The implementation is system-dependent.
+ *
+ * Condition variables are paired up with mutexes.  Lock the mutex,
+ * call wait(), then either re-wait() if things aren't quite what you want,
+ * or unlock the mutex and continue.  All threads calling wait() must
+ * use the same mutex for a given Condition.
+ */
+class Condition {
+public:
+    enum {
+        PRIVATE = 0,
+        SHARED = 1
+    };
+
+    enum WakeUpType {
+        WAKE_UP_ONE = 0,
+        WAKE_UP_ALL = 1
+    };
+
+    Condition();
+    Condition(int type);
+    ~Condition();
+    // Wait on the condition variable.  Lock the mutex before calling.
+    status_t wait(Mutex& mutex);
+    // same with relative timeout
+    status_t waitRelative(Mutex& mutex, nsecs_t reltime);
+    // Signal the condition variable, allowing one thread to continue.
+    void signal();
+    // Signal the condition variable, allowing one or all threads to continue.
+    void signal(WakeUpType type) {
+        if (type == WAKE_UP_ONE) {
+            signal();
+        } else {
+            broadcast();
+        }
+    }
+    // Signal the condition variable, allowing all threads to continue.
+    void broadcast();
+
+private:
+#if defined(HAVE_PTHREADS)
+    pthread_cond_t mCond;
+#else
+    void*   mState;
+#endif
+};
+
+// ---------------------------------------------------------------------------
+
+#if defined(HAVE_PTHREADS)
+
+inline Condition::Condition() {
+    pthread_cond_init(&mCond, NULL);
+}
+inline Condition::Condition(int type) {
+    if (type == SHARED) {
+        pthread_condattr_t attr;
+        pthread_condattr_init(&attr);
+        pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+        pthread_cond_init(&mCond, &attr);
+        pthread_condattr_destroy(&attr);
+    } else {
+        pthread_cond_init(&mCond, NULL);
+    }
+}
+inline Condition::~Condition() {
+    pthread_cond_destroy(&mCond);
+}
+inline status_t Condition::wait(Mutex& mutex) {
+    return -pthread_cond_wait(&mCond, &mutex.mMutex);
+}
+inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
+#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
+    struct timespec ts;
+    ts.tv_sec  = reltime/1000000000;
+    ts.tv_nsec = reltime%1000000000;
+    return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts);
+#else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
+    struct timespec ts;
+#if defined(HAVE_POSIX_CLOCKS)
+    clock_gettime(CLOCK_REALTIME, &ts);
+#else // HAVE_POSIX_CLOCKS
+    // we don't support the clocks here.
+    struct timeval t;
+    gettimeofday(&t, NULL);
+    ts.tv_sec = t.tv_sec;
+    ts.tv_nsec= t.tv_usec*1000;
+#endif // HAVE_POSIX_CLOCKS
+    ts.tv_sec += reltime/1000000000;
+    ts.tv_nsec+= reltime%1000000000;
+    if (ts.tv_nsec >= 1000000000) {
+        ts.tv_nsec -= 1000000000;
+        ts.tv_sec  += 1;
+    }
+    return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
+#endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
+}
+inline void Condition::signal() {
+    pthread_cond_signal(&mCond);
+}
+inline void Condition::broadcast() {
+    pthread_cond_broadcast(&mCond);
+}
+
+#endif // HAVE_PTHREADS
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // _LIBS_UTILS_CONDITON_H
diff --git a/include/utils/Debug.h b/include/utils/Debug.h
new file mode 100644
index 0000000..08893bd
--- /dev/null
+++ b/include/utils/Debug.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UTILS_DEBUG_H
+#define ANDROID_UTILS_DEBUG_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+#ifdef __cplusplus
+template<bool> struct CompileTimeAssert;
+template<> struct CompileTimeAssert<true> {};
+#define COMPILE_TIME_ASSERT(_exp) \
+    template class CompileTimeAssert< (_exp) >;
+#endif
+#define COMPILE_TIME_ASSERT_FUNCTION_SCOPE(_exp) \
+    CompileTimeAssert<( _exp )>();
+
+// ---------------------------------------------------------------------------
+
+#ifdef __cplusplus
+template<bool C, typename LSH, typename RHS> struct CompileTimeIfElse;
+template<typename LHS, typename RHS> 
+struct CompileTimeIfElse<true,  LHS, RHS> { typedef LHS TYPE; };
+template<typename LHS, typename RHS> 
+struct CompileTimeIfElse<false, LHS, RHS> { typedef RHS TYPE; };
+#endif
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_UTILS_DEBUG_H
diff --git a/include/utils/Endian.h b/include/utils/Endian.h
new file mode 100644
index 0000000..19f2504
--- /dev/null
+++ b/include/utils/Endian.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Android endian-ness defines.
+//
+#ifndef _LIBS_UTILS_ENDIAN_H
+#define _LIBS_UTILS_ENDIAN_H
+
+#if defined(HAVE_ENDIAN_H)
+
+#include <endian.h>
+
+#else /*not HAVE_ENDIAN_H*/
+
+#define __BIG_ENDIAN 0x1000
+#define __LITTLE_ENDIAN 0x0001
+
+#if defined(HAVE_LITTLE_ENDIAN)
+# define __BYTE_ORDER __LITTLE_ENDIAN
+#else
+# define __BYTE_ORDER __BIG_ENDIAN
+#endif
+
+#endif /*not HAVE_ENDIAN_H*/
+
+#endif /*_LIBS_UTILS_ENDIAN_H*/
diff --git a/include/utils/Errors.h b/include/utils/Errors.h
new file mode 100644
index 0000000..0b75b19
--- /dev/null
+++ b/include/utils/Errors.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007 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 ANDROID_ERRORS_H
+#define ANDROID_ERRORS_H
+
+#include <sys/types.h>
+#include <errno.h>
+
+namespace android {
+
+// use this type to return error codes
+#ifdef HAVE_MS_C_RUNTIME
+typedef int         status_t;
+#else
+typedef int32_t     status_t;
+#endif
+
+/* the MS C runtime lacks a few error codes */
+
+/*
+ * Error codes. 
+ * All error codes are negative values.
+ */
+
+// Win32 #defines NO_ERROR as well.  It has the same value, so there's no
+// real conflict, though it's a bit awkward.
+#ifdef _WIN32
+# undef NO_ERROR
+#endif
+ 
+enum {
+    OK                = 0,    // Everything's swell.
+    NO_ERROR          = 0,    // No errors.
+    
+    UNKNOWN_ERROR       = 0x80000000,
+
+    NO_MEMORY           = -ENOMEM,
+    INVALID_OPERATION   = -ENOSYS,
+    BAD_VALUE           = -EINVAL,
+    BAD_TYPE            = 0x80000001,
+    NAME_NOT_FOUND      = -ENOENT,
+    PERMISSION_DENIED   = -EPERM,
+    NO_INIT             = -ENODEV,
+    ALREADY_EXISTS      = -EEXIST,
+    DEAD_OBJECT         = -EPIPE,
+    FAILED_TRANSACTION  = 0x80000002,
+    JPARKS_BROKE_IT     = -EPIPE,
+#if !defined(HAVE_MS_C_RUNTIME)
+    BAD_INDEX           = -EOVERFLOW,
+    NOT_ENOUGH_DATA     = -ENODATA,
+    WOULD_BLOCK         = -EWOULDBLOCK, 
+    TIMED_OUT           = -ETIMEDOUT,
+    UNKNOWN_TRANSACTION = -EBADMSG,
+#else    
+    BAD_INDEX           = -E2BIG,
+    NOT_ENOUGH_DATA     = 0x80000003,
+    WOULD_BLOCK         = 0x80000004,
+    TIMED_OUT           = 0x80000005,
+    UNKNOWN_TRANSACTION = 0x80000006,
+#endif    
+    FDS_NOT_ALLOWED     = 0x80000007,
+};
+
+// Restore define; enumeration is in "android" namespace, so the value defined
+// there won't work for Win32 code in a different namespace.
+#ifdef _WIN32
+# define NO_ERROR 0L
+#endif
+
+}; // namespace android
+    
+// ---------------------------------------------------------------------------
+    
+#endif // ANDROID_ERRORS_H
diff --git a/include/utils/FileMap.h b/include/utils/FileMap.h
new file mode 100644
index 0000000..dfe6d51
--- /dev/null
+++ b/include/utils/FileMap.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+//
+// Encapsulate a shared file mapping.
+//
+#ifndef __LIBS_FILE_MAP_H
+#define __LIBS_FILE_MAP_H
+
+#include <sys/types.h>
+
+#include <utils/Compat.h>
+
+#ifdef HAVE_WIN32_FILEMAP
+#include <windows.h>
+#endif
+
+namespace android {
+
+/*
+ * This represents a memory-mapped file.  It might be the entire file or
+ * only part of it.  This requires a little bookkeeping because the mapping
+ * needs to be aligned on page boundaries, and in some cases we'd like to
+ * have multiple references to the mapped area without creating additional
+ * maps.
+ *
+ * This always uses MAP_SHARED.
+ *
+ * TODO: we should be able to create a new FileMap that is a subset of
+ * an existing FileMap and shares the underlying mapped pages.  Requires
+ * completing the refcounting stuff and possibly introducing the notion
+ * of a FileMap hierarchy.
+ */
+class FileMap {
+public:
+    FileMap(void);
+
+    /*
+     * Create a new mapping on an open file.
+     *
+     * Closing the file descriptor does not unmap the pages, so we don't
+     * claim ownership of the fd.
+     *
+     * Returns "false" on failure.
+     */
+    bool create(const char* origFileName, int fd,
+                off64_t offset, size_t length, bool readOnly);
+
+    /*
+     * Return the name of the file this map came from, if known.
+     */
+    const char* getFileName(void) const { return mFileName; }
+    
+    /*
+     * Get a pointer to the piece of the file we requested.
+     */
+    void* getDataPtr(void) const { return mDataPtr; }
+
+    /*
+     * Get the length we requested.
+     */
+    size_t getDataLength(void) const { return mDataLength; }
+
+    /*
+     * Get the data offset used to create this map.
+     */
+    off64_t getDataOffset(void) const { return mDataOffset; }
+
+    /*
+     * Get a "copy" of the object.
+     */
+    FileMap* acquire(void) { mRefCount++; return this; }
+
+    /*
+     * Call this when mapping is no longer needed.
+     */
+    void release(void) {
+        if (--mRefCount <= 0)
+            delete this;
+    }
+
+    /*
+     * This maps directly to madvise() values, but allows us to avoid
+     * including <sys/mman.h> everywhere.
+     */
+    enum MapAdvice {
+        NORMAL, RANDOM, SEQUENTIAL, WILLNEED, DONTNEED
+    };
+
+    /*
+     * Apply an madvise() call to the entire file.
+     *
+     * Returns 0 on success, -1 on failure.
+     */
+    int advise(MapAdvice advice);
+
+protected:
+    // don't delete objects; call release()
+    ~FileMap(void);
+
+private:
+    // these are not implemented
+    FileMap(const FileMap& src);
+    const FileMap& operator=(const FileMap& src);
+
+    int         mRefCount;      // reference count
+    char*       mFileName;      // original file name, if known
+    void*       mBasePtr;       // base of mmap area; page aligned
+    size_t      mBaseLength;    // length, measured from "mBasePtr"
+    off64_t     mDataOffset;    // offset used when map was created
+    void*       mDataPtr;       // start of requested data, offset from base
+    size_t      mDataLength;    // length, measured from "mDataPtr"
+#ifdef HAVE_WIN32_FILEMAP
+    HANDLE      mFileHandle;    // Win32 file handle
+    HANDLE      mFileMapping;   // Win32 file mapping handle
+#endif
+
+    static long mPageSize;
+};
+
+}; // namespace android
+
+#endif // __LIBS_FILE_MAP_H
diff --git a/include/utils/Flattenable.h b/include/utils/Flattenable.h
new file mode 100644
index 0000000..882a8b2
--- /dev/null
+++ b/include/utils/Flattenable.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2010 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 ANDROID_UTILS_FLATTENABLE_H
+#define ANDROID_UTILS_FLATTENABLE_H
+
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/Debug.h>
+
+namespace android {
+
+
+class FlattenableUtils {
+public:
+    template<int N>
+    static size_t align(size_t size) {
+        COMPILE_TIME_ASSERT_FUNCTION_SCOPE( !(N & (N-1)) );
+        return (size + (N-1)) & ~(N-1);
+    }
+
+    template<int N>
+    static size_t align(void const*& buffer) {
+        COMPILE_TIME_ASSERT_FUNCTION_SCOPE( !(N & (N-1)) );
+        intptr_t b = intptr_t(buffer);
+        buffer = (void*)((intptr_t(buffer) + (N-1)) & ~(N-1));
+        return size_t(intptr_t(buffer) - b);
+    }
+
+    template<int N>
+    static size_t align(void*& buffer) {
+        return align<N>( const_cast<void const*&>(buffer) );
+    }
+
+    static void advance(void*& buffer, size_t& size, size_t offset) {
+        buffer = reinterpret_cast<void*>( intptr_t(buffer) + offset );
+        size -= offset;
+    }
+
+    static void advance(void const*& buffer, size_t& size, size_t offset) {
+        buffer = reinterpret_cast<void const*>( intptr_t(buffer) + offset );
+        size -= offset;
+    }
+
+    // write a POD structure
+    template<typename T>
+    static void write(void*& buffer, size_t& size, const T& value) {
+        *static_cast<T*>(buffer) = value;
+        advance(buffer, size, sizeof(T));
+    }
+
+    // read a POD structure
+    template<typename T>
+    static void read(void const*& buffer, size_t& size, T& value) {
+        value = *static_cast<T const*>(buffer);
+        advance(buffer, size, sizeof(T));
+    }
+};
+
+
+/*
+ * The Flattenable protocol allows an object to serialize itself out
+ * to a byte-buffer and an array of file descriptors.
+ * Flattenable objects must implement this protocol.
+ */
+
+template <typename T>
+class Flattenable {
+public:
+    // size in bytes of the flattened object
+    inline size_t getFlattenedSize() const;
+
+    // number of file descriptors to flatten
+    inline size_t getFdCount() const;
+
+    // flattens the object into buffer.
+    // size should be at least of getFlattenedSize()
+    // file descriptors are written in the fds[] array but ownership is
+    // not transfered (ie: they must be dupped by the caller of
+    // flatten() if needed).
+    inline status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
+
+    // unflattens the object from buffer.
+    // size should be equal to the value of getFlattenedSize() when the
+    // object was flattened.
+    // unflattened file descriptors are found in the fds[] array and
+    // don't need to be dupped(). ie: the caller of unflatten doesn't
+    // keep ownership. If a fd is not retained by unflatten() it must be
+    // explicitly closed.
+    inline status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
+};
+
+template<typename T>
+inline size_t Flattenable<T>::getFlattenedSize() const {
+    return static_cast<T const*>(this)->T::getFlattenedSize();
+}
+template<typename T>
+inline size_t Flattenable<T>::getFdCount() const {
+    return static_cast<T const*>(this)->T::getFdCount();
+}
+template<typename T>
+inline status_t Flattenable<T>::flatten(
+        void*& buffer, size_t& size, int*& fds, size_t& count) const {
+    return static_cast<T const*>(this)->T::flatten(buffer, size, fds, count);
+}
+template<typename T>
+inline status_t Flattenable<T>::unflatten(
+        void const*& buffer, size_t& size, int const*& fds, size_t& count) {
+    return static_cast<T*>(this)->T::unflatten(buffer, size, fds, count);
+}
+
+/*
+ * LightFlattenable is a protocol allowing object to serialize themselves out
+ * to a byte-buffer. Because it doesn't handle file-descriptors,
+ * LightFlattenable is usually more size efficient than Flattenable.
+ * LightFlattenable objects must implement this protocol.
+ */
+template <typename T>
+class LightFlattenable {
+public:
+    // returns whether this object always flatten into the same size.
+    // for efficiency, this should always be inline.
+    inline bool isFixedSize() const;
+
+    // returns size in bytes of the flattened object. must be a constant.
+    inline size_t getFlattenedSize() const;
+
+    // flattens the object into buffer.
+    inline status_t flatten(void* buffer, size_t size) const;
+
+    // unflattens the object from buffer of given size.
+    inline status_t unflatten(void const* buffer, size_t size);
+};
+
+template <typename T>
+inline bool LightFlattenable<T>::isFixedSize() const {
+    return static_cast<T const*>(this)->T::isFixedSize();
+}
+template <typename T>
+inline size_t LightFlattenable<T>::getFlattenedSize() const {
+    return static_cast<T const*>(this)->T::getFlattenedSize();
+}
+template <typename T>
+inline status_t LightFlattenable<T>::flatten(void* buffer, size_t size) const {
+    return static_cast<T const*>(this)->T::flatten(buffer, size);
+}
+template <typename T>
+inline status_t LightFlattenable<T>::unflatten(void const* buffer, size_t size) {
+    return static_cast<T*>(this)->T::unflatten(buffer, size);
+}
+
+/*
+ * LightFlattenablePod is an implementation of the LightFlattenable protocol
+ * for POD (plain-old-data) objects.
+ * Simply derive from LightFlattenablePod<Foo> to make Foo flattenable; no
+ * need to implement any methods; obviously Foo must be a POD structure.
+ */
+template <typename T>
+class LightFlattenablePod : public LightFlattenable<T> {
+public:
+    inline bool isFixedSize() const {
+        return true;
+    }
+
+    inline size_t getFlattenedSize() const {
+        return sizeof(T);
+    }
+    inline status_t flatten(void* buffer, size_t size) const {
+        if (size < sizeof(T)) return NO_MEMORY;
+        *reinterpret_cast<T*>(buffer) = *static_cast<T const*>(this);
+        return NO_ERROR;
+    }
+    inline status_t unflatten(void const* buffer, size_t) {
+        *static_cast<T*>(this) = *reinterpret_cast<T const*>(buffer);
+        return NO_ERROR;
+    }
+};
+
+
+}; // namespace android
+
+
+#endif /* ANDROID_UTILS_FLATTENABLE_H */
diff --git a/include/cutils/zygote.h b/include/utils/Functor.h
similarity index 61%
copy from include/cutils/zygote.h
copy to include/utils/Functor.h
index a7480d3..e24ded4 100644
--- a/include/cutils/zygote.h
+++ b/include/utils/Functor.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -14,18 +14,20 @@
  * limitations under the License.
  */
 
-#ifndef __CUTILS_ZYGOTE_H
-#define __CUTILS_ZYGOTE_H
+#ifndef ANDROID_FUNCTOR_H
+#define ANDROID_FUNCTOR_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include <utils/Errors.h>
 
-int zygote_run_oneshot(int sendStdio, int argc, const char **argv);
-int zygote_run(int argc, const char **argv);
+namespace  android {
 
-#ifdef __cplusplus
-}
-#endif
+class Functor {
+public:
+    Functor() {}
+    virtual ~Functor() {}
+    virtual status_t operator ()(int what, void* data) { return NO_ERROR; }
+};
 
-#endif /* __CUTILS_ZYGOTE_H */
+}; // namespace android
+
+#endif // ANDROID_FUNCTOR_H
diff --git a/include/utils/JenkinsHash.h b/include/utils/JenkinsHash.h
new file mode 100644
index 0000000..7da5dbd
--- /dev/null
+++ b/include/utils/JenkinsHash.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/* Implementation of Jenkins one-at-a-time hash function. These choices are
+ * optimized for code size and portability, rather than raw speed. But speed
+ * should still be quite good.
+ **/
+
+#ifndef ANDROID_JENKINS_HASH_H
+#define ANDROID_JENKINS_HASH_H
+
+#include <utils/TypeHelpers.h>
+
+namespace android {
+
+/* The Jenkins hash of a sequence of 32 bit words A, B, C is:
+ * Whiten(Mix(Mix(Mix(0, A), B), C)) */
+
+inline uint32_t JenkinsHashMix(uint32_t hash, uint32_t data) {
+    hash += data;
+    hash += (hash << 10);
+    hash ^= (hash >> 6);
+    return hash;
+}
+
+hash_t JenkinsHashWhiten(uint32_t hash);
+
+/* Helpful utility functions for hashing data in 32 bit chunks */
+uint32_t JenkinsHashMixBytes(uint32_t hash, const uint8_t* bytes, size_t size);
+
+uint32_t JenkinsHashMixShorts(uint32_t hash, const uint16_t* shorts, size_t size);
+
+}
+
+#endif // ANDROID_JENKINS_HASH_H
diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h
new file mode 100644
index 0000000..c4faae0
--- /dev/null
+++ b/include/utils/KeyedVector.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_KEYED_VECTOR_H
+#define ANDROID_KEYED_VECTOR_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/log.h>
+
+#include <utils/SortedVector.h>
+#include <utils/TypeHelpers.h>
+#include <utils/Errors.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+template <typename KEY, typename VALUE>
+class KeyedVector
+{
+public:
+    typedef KEY    key_type;
+    typedef VALUE  value_type;
+
+    inline                  KeyedVector();
+
+    /*
+     * empty the vector
+     */
+
+    inline  void            clear()                     { mVector.clear(); }
+
+    /*! 
+     * vector stats
+     */
+
+    //! returns number of items in the vector
+    inline  size_t          size() const                { return mVector.size(); }
+    //! returns whether or not the vector is empty
+    inline  bool            isEmpty() const             { return mVector.isEmpty(); }
+    //! returns how many items can be stored without reallocating the backing store
+    inline  size_t          capacity() const            { return mVector.capacity(); }
+    //! sets the capacity. capacity can never be reduced less than size()
+    inline ssize_t          setCapacity(size_t size)    { return mVector.setCapacity(size); }
+
+    // returns true if the arguments is known to be identical to this vector
+    inline bool isIdenticalTo(const KeyedVector& rhs) const;
+
+    /*! 
+     * accessors
+     */
+            const VALUE&    valueFor(const KEY& key) const;
+            const VALUE&    valueAt(size_t index) const;
+            const KEY&      keyAt(size_t index) const;
+            ssize_t         indexOfKey(const KEY& key) const;
+            const VALUE&    operator[] (size_t index) const;
+
+    /*!
+     * modifying the array
+     */
+
+            VALUE&          editValueFor(const KEY& key);
+            VALUE&          editValueAt(size_t index);
+
+            /*! 
+             * add/insert/replace items
+             */
+             
+            ssize_t         add(const KEY& key, const VALUE& item);
+            ssize_t         replaceValueFor(const KEY& key, const VALUE& item);
+            ssize_t         replaceValueAt(size_t index, const VALUE& item);
+
+    /*!
+     * remove items
+     */
+
+            ssize_t         removeItem(const KEY& key);
+            ssize_t         removeItemsAt(size_t index, size_t count = 1);
+            
+private:
+            SortedVector< key_value_pair_t<KEY, VALUE> >    mVector;
+};
+
+// KeyedVector<KEY, VALUE> can be trivially moved using memcpy() because its
+// underlying SortedVector can be trivially moved.
+template<typename KEY, typename VALUE> struct trait_trivial_move<KeyedVector<KEY, VALUE> > {
+    enum { value = trait_trivial_move<SortedVector< key_value_pair_t<KEY, VALUE> > >::value };
+};
+
+
+// ---------------------------------------------------------------------------
+
+/**
+ * Variation of KeyedVector that holds a default value to return when
+ * valueFor() is called with a key that doesn't exist.
+ */
+template <typename KEY, typename VALUE>
+class DefaultKeyedVector : public KeyedVector<KEY, VALUE>
+{
+public:
+    inline                  DefaultKeyedVector(const VALUE& defValue = VALUE());
+            const VALUE&    valueFor(const KEY& key) const;
+
+private:
+            VALUE                                           mDefault;
+};
+
+// ---------------------------------------------------------------------------
+
+template<typename KEY, typename VALUE> inline
+KeyedVector<KEY,VALUE>::KeyedVector()
+{
+}
+
+template<typename KEY, typename VALUE> inline
+bool KeyedVector<KEY,VALUE>::isIdenticalTo(const KeyedVector<KEY,VALUE>& rhs) const {
+    return mVector.array() == rhs.mVector.array();
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::indexOfKey(const KEY& key) const {
+    return mVector.indexOf( key_value_pair_t<KEY,VALUE>(key) );
+}
+
+template<typename KEY, typename VALUE> inline
+const VALUE& KeyedVector<KEY,VALUE>::valueFor(const KEY& key) const {
+    ssize_t i = this->indexOfKey(key);
+    LOG_ALWAYS_FATAL_IF(i<0, "%s: key not found", __PRETTY_FUNCTION__);
+    return mVector.itemAt(i).value;
+}
+
+template<typename KEY, typename VALUE> inline
+const VALUE& KeyedVector<KEY,VALUE>::valueAt(size_t index) const {
+    return mVector.itemAt(index).value;
+}
+
+template<typename KEY, typename VALUE> inline
+const VALUE& KeyedVector<KEY,VALUE>::operator[] (size_t index) const {
+    return valueAt(index);
+}
+
+template<typename KEY, typename VALUE> inline
+const KEY& KeyedVector<KEY,VALUE>::keyAt(size_t index) const {
+    return mVector.itemAt(index).key;
+}
+
+template<typename KEY, typename VALUE> inline
+VALUE& KeyedVector<KEY,VALUE>::editValueFor(const KEY& key) {
+    ssize_t i = this->indexOfKey(key);
+    LOG_ALWAYS_FATAL_IF(i<0, "%s: key not found", __PRETTY_FUNCTION__);
+    return mVector.editItemAt(i).value;
+}
+
+template<typename KEY, typename VALUE> inline
+VALUE& KeyedVector<KEY,VALUE>::editValueAt(size_t index) {
+    return mVector.editItemAt(index).value;
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::add(const KEY& key, const VALUE& value) {
+    return mVector.add( key_value_pair_t<KEY,VALUE>(key, value) );
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::replaceValueFor(const KEY& key, const VALUE& value) {
+    key_value_pair_t<KEY,VALUE> pair(key, value);
+    mVector.remove(pair);
+    return mVector.add(pair);
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::replaceValueAt(size_t index, const VALUE& item) {
+    if (index<size()) {
+        mVector.editItemAt(index).value = item;
+        return index;
+    }
+    return BAD_INDEX;
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY,VALUE>::removeItem(const KEY& key) {
+    return mVector.remove(key_value_pair_t<KEY,VALUE>(key));
+}
+
+template<typename KEY, typename VALUE> inline
+ssize_t KeyedVector<KEY, VALUE>::removeItemsAt(size_t index, size_t count) {
+    return mVector.removeItemsAt(index, count);
+}
+
+// ---------------------------------------------------------------------------
+
+template<typename KEY, typename VALUE> inline
+DefaultKeyedVector<KEY,VALUE>::DefaultKeyedVector(const VALUE& defValue)
+    : mDefault(defValue)
+{
+}
+
+template<typename KEY, typename VALUE> inline
+const VALUE& DefaultKeyedVector<KEY,VALUE>::valueFor(const KEY& key) const {
+    ssize_t i = this->indexOfKey(key);
+    return i >= 0 ? KeyedVector<KEY,VALUE>::valueAt(i) : mDefault;
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_KEYED_VECTOR_H
diff --git a/include/utils/LinearAllocator.h b/include/utils/LinearAllocator.h
new file mode 100644
index 0000000..4772bc8
--- /dev/null
+++ b/include/utils/LinearAllocator.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_LINEARALLOCATOR_H
+#define ANDROID_LINEARALLOCATOR_H
+
+#include <stddef.h>
+
+namespace android {
+
+/**
+ * A memory manager that internally allocates multi-kbyte buffers for placing objects in. It avoids
+ * the overhead of malloc when many objects are allocated. It is most useful when creating many
+ * small objects with a similar lifetime, and doesn't add significant overhead for large
+ * allocations.
+ */
+class LinearAllocator {
+public:
+    LinearAllocator();
+    ~LinearAllocator();
+
+    /**
+     * Reserves and returns a region of memory of at least size 'size', aligning as needed.
+     * Typically this is used in an object's overridden new() method or as a replacement for malloc.
+     *
+     * The lifetime of the returned buffers is tied to that of the LinearAllocator. If calling
+     * delete() on an object stored in a buffer is needed, it should be overridden to use
+     * rewindIfLastAlloc()
+     */
+    void* alloc(size_t size);
+
+    /**
+     * Attempt to deallocate the given buffer, with the LinearAllocator attempting to rewind its
+     * state if possible. No destructors are called.
+     */
+    void rewindIfLastAlloc(void* ptr, size_t allocSize);
+
+    /**
+     * Dump memory usage statistics to the log (allocated and wasted space)
+     */
+    void dumpMemoryStats(const char* prefix = "");
+
+    /**
+     * The number of bytes used for buffers allocated in the LinearAllocator (does not count space
+     * wasted)
+     */
+    size_t usedSize() const { return mTotalAllocated - mWastedSpace; }
+
+private:
+    LinearAllocator(const LinearAllocator& other);
+
+    class Page;
+
+    Page* newPage(size_t pageSize);
+    bool fitsInCurrentPage(size_t size);
+    void ensureNext(size_t size);
+    void* start(Page *p);
+    void* end(Page* p);
+
+    size_t mPageSize;
+    size_t mMaxAllocSize;
+    void* mNext;
+    Page* mCurrentPage;
+    Page* mPages;
+
+    // Memory usage tracking
+    size_t mTotalAllocated;
+    size_t mWastedSpace;
+    size_t mPageCount;
+    size_t mDedicatedPageCount;
+};
+
+}; // namespace android
+
+#endif // ANDROID_LINEARALLOCATOR_H
diff --git a/include/utils/LinearTransform.h b/include/utils/LinearTransform.h
new file mode 100644
index 0000000..04cb355
--- /dev/null
+++ b/include/utils/LinearTransform.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 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 _LIBS_UTILS_LINEAR_TRANSFORM_H
+#define _LIBS_UTILS_LINEAR_TRANSFORM_H
+
+#include <stdint.h>
+
+namespace android {
+
+// LinearTransform defines a structure which hold the definition of a
+// transformation from single dimensional coordinate system A into coordinate
+// system B (and back again).  Values in A and in B are 64 bit, the linear
+// scale factor is expressed as a rational number using two 32 bit values.
+//
+// Specifically, let
+// f(a) = b
+// F(b) = f^-1(b) = a
+// then
+//
+// f(a) = (((a - a_zero) * a_to_b_numer) / a_to_b_denom) + b_zero;
+//
+// and
+//
+// F(b) = (((b - b_zero) * a_to_b_denom) / a_to_b_numer) + a_zero;
+//
+struct LinearTransform {
+  int64_t  a_zero;
+  int64_t  b_zero;
+  int32_t  a_to_b_numer;
+  uint32_t a_to_b_denom;
+
+  // Transform from A->B
+  // Returns true on success, or false in the case of a singularity or an
+  // overflow.
+  bool doForwardTransform(int64_t a_in, int64_t* b_out) const;
+
+  // Transform from B->A
+  // Returns true on success, or false in the case of a singularity or an
+  // overflow.
+  bool doReverseTransform(int64_t b_in, int64_t* a_out) const;
+
+  // Helpers which will reduce the fraction N/D using Euclid's method.
+  template <class T> static void reduce(T* N, T* D);
+  static void reduce(int32_t* N, uint32_t* D);
+};
+
+
+}
+
+#endif  // _LIBS_UTILS_LINEAR_TRANSFORM_H
diff --git a/include/utils/List.h b/include/utils/List.h
new file mode 100644
index 0000000..403cd7f
--- /dev/null
+++ b/include/utils/List.h
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Templated list class.  Normally we'd use STL, but we don't have that.
+// This class mimics STL's interfaces.
+//
+// Objects are copied into the list with the '=' operator or with copy-
+// construction, so if the compiler's auto-generated versions won't work for
+// you, define your own.
+//
+// The only class you want to use from here is "List".
+//
+#ifndef _LIBS_UTILS_LIST_H
+#define _LIBS_UTILS_LIST_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace android {
+
+/*
+ * Doubly-linked list.  Instantiate with "List<MyClass> myList".
+ *
+ * Objects added to the list are copied using the assignment operator,
+ * so this must be defined.
+ */
+template<typename T> 
+class List 
+{
+protected:
+    /*
+     * One element in the list.
+     */
+    class _Node {
+    public:
+        explicit _Node(const T& val) : mVal(val) {}
+        ~_Node() {}
+        inline T& getRef() { return mVal; }
+        inline const T& getRef() const { return mVal; }
+        inline _Node* getPrev() const { return mpPrev; }
+        inline _Node* getNext() const { return mpNext; }
+        inline void setVal(const T& val) { mVal = val; }
+        inline void setPrev(_Node* ptr) { mpPrev = ptr; }
+        inline void setNext(_Node* ptr) { mpNext = ptr; }
+    private:
+        friend class List;
+        friend class _ListIterator;
+        T           mVal;
+        _Node*      mpPrev;
+        _Node*      mpNext;
+    };
+
+    /*
+     * Iterator for walking through the list.
+     */
+    
+    template <typename TYPE>
+    struct CONST_ITERATOR {
+        typedef _Node const * NodePtr;
+        typedef const TYPE Type;
+    };
+    
+    template <typename TYPE>
+    struct NON_CONST_ITERATOR {
+        typedef _Node* NodePtr;
+        typedef TYPE Type;
+    };
+    
+    template<
+        typename U,
+        template <class> class Constness
+    > 
+    class _ListIterator {
+        typedef _ListIterator<U, Constness>     _Iter;
+        typedef typename Constness<U>::NodePtr  _NodePtr;
+        typedef typename Constness<U>::Type     _Type;
+
+        explicit _ListIterator(_NodePtr ptr) : mpNode(ptr) {}
+
+    public:
+        _ListIterator() {}
+        _ListIterator(const _Iter& rhs) : mpNode(rhs.mpNode) {}
+        ~_ListIterator() {}
+        
+        // this will handle conversions from iterator to const_iterator
+        // (and also all convertible iterators)
+        // Here, in this implementation, the iterators can be converted
+        // if the nodes can be converted
+        template<typename V> explicit 
+        _ListIterator(const V& rhs) : mpNode(rhs.mpNode) {}
+        
+
+        /*
+         * Dereference operator.  Used to get at the juicy insides.
+         */
+        _Type& operator*() const { return mpNode->getRef(); }
+        _Type* operator->() const { return &(mpNode->getRef()); }
+
+        /*
+         * Iterator comparison.
+         */
+        inline bool operator==(const _Iter& right) const { 
+            return mpNode == right.mpNode; }
+        
+        inline bool operator!=(const _Iter& right) const { 
+            return mpNode != right.mpNode; }
+
+        /*
+         * handle comparisons between iterator and const_iterator
+         */
+        template<typename OTHER>
+        inline bool operator==(const OTHER& right) const { 
+            return mpNode == right.mpNode; }
+        
+        template<typename OTHER>
+        inline bool operator!=(const OTHER& right) const { 
+            return mpNode != right.mpNode; }
+
+        /*
+         * Incr/decr, used to move through the list.
+         */
+        inline _Iter& operator++() {     // pre-increment
+            mpNode = mpNode->getNext();
+            return *this;
+        }
+        const _Iter operator++(int) {    // post-increment
+            _Iter tmp(*this);
+            mpNode = mpNode->getNext();
+            return tmp;
+        }
+        inline _Iter& operator--() {     // pre-increment
+            mpNode = mpNode->getPrev();
+            return *this;
+        }
+        const _Iter operator--(int) {   // post-increment
+            _Iter tmp(*this);
+            mpNode = mpNode->getPrev();
+            return tmp;
+        }
+
+        inline _NodePtr getNode() const { return mpNode; }
+
+        _NodePtr mpNode;    /* should be private, but older gcc fails */
+    private:
+        friend class List;
+    };
+
+public:
+    List() {
+        prep();
+    }
+    List(const List<T>& src) {      // copy-constructor
+        prep();
+        insert(begin(), src.begin(), src.end());
+    }
+    virtual ~List() {
+        clear();
+        delete[] (unsigned char*) mpMiddle;
+    }
+
+    typedef _ListIterator<T, NON_CONST_ITERATOR> iterator;
+    typedef _ListIterator<T, CONST_ITERATOR> const_iterator;
+
+    List<T>& operator=(const List<T>& right);
+
+    /* returns true if the list is empty */
+    inline bool empty() const { return mpMiddle->getNext() == mpMiddle; }
+
+    /* return #of elements in list */
+    size_t size() const {
+        return size_t(distance(begin(), end()));
+    }
+
+    /*
+     * Return the first element or one past the last element.  The
+     * _Node* we're returning is converted to an "iterator" by a
+     * constructor in _ListIterator.
+     */
+    inline iterator begin() { 
+        return iterator(mpMiddle->getNext()); 
+    }
+    inline const_iterator begin() const { 
+        return const_iterator(const_cast<_Node const*>(mpMiddle->getNext())); 
+    }
+    inline iterator end() { 
+        return iterator(mpMiddle); 
+    }
+    inline const_iterator end() const { 
+        return const_iterator(const_cast<_Node const*>(mpMiddle)); 
+    }
+
+    /* add the object to the head or tail of the list */
+    void push_front(const T& val) { insert(begin(), val); }
+    void push_back(const T& val) { insert(end(), val); }
+
+    /* insert before the current node; returns iterator at new node */
+    iterator insert(iterator posn, const T& val) 
+    {
+        _Node* newNode = new _Node(val);        // alloc & copy-construct
+        newNode->setNext(posn.getNode());
+        newNode->setPrev(posn.getNode()->getPrev());
+        posn.getNode()->getPrev()->setNext(newNode);
+        posn.getNode()->setPrev(newNode);
+        return iterator(newNode);
+    }
+
+    /* insert a range of elements before the current node */
+    void insert(iterator posn, const_iterator first, const_iterator last) {
+        for ( ; first != last; ++first)
+            insert(posn, *first);
+    }
+
+    /* remove one entry; returns iterator at next node */
+    iterator erase(iterator posn) {
+        _Node* pNext = posn.getNode()->getNext();
+        _Node* pPrev = posn.getNode()->getPrev();
+        pPrev->setNext(pNext);
+        pNext->setPrev(pPrev);
+        delete posn.getNode();
+        return iterator(pNext);
+    }
+
+    /* remove a range of elements */
+    iterator erase(iterator first, iterator last) {
+        while (first != last)
+            erase(first++);     // don't erase than incr later!
+        return iterator(last);
+    }
+
+    /* remove all contents of the list */
+    void clear() {
+        _Node* pCurrent = mpMiddle->getNext();
+        _Node* pNext;
+
+        while (pCurrent != mpMiddle) {
+            pNext = pCurrent->getNext();
+            delete pCurrent;
+            pCurrent = pNext;
+        }
+        mpMiddle->setPrev(mpMiddle);
+        mpMiddle->setNext(mpMiddle);
+    }
+
+    /*
+     * Measure the distance between two iterators.  On exist, "first"
+     * will be equal to "last".  The iterators must refer to the same
+     * list.
+     *
+     * FIXME: This is actually a generic iterator function. It should be a 
+     * template function at the top-level with specializations for things like
+     * vector<>, which can just do pointer math). Here we limit it to
+     * _ListIterator of the same type but different constness.
+     */
+    template<
+        typename U,
+        template <class> class CL,
+        template <class> class CR
+    > 
+    ptrdiff_t distance(
+            _ListIterator<U, CL> first, _ListIterator<U, CR> last) const 
+    {
+        ptrdiff_t count = 0;
+        while (first != last) {
+            ++first;
+            ++count;
+        }
+        return count;
+    }
+
+private:
+    /*
+     * I want a _Node but don't need it to hold valid data.  More
+     * to the point, I don't want T's constructor to fire, since it
+     * might have side-effects or require arguments.  So, we do this
+     * slightly uncouth storage alloc.
+     */
+    void prep() {
+        mpMiddle = (_Node*) new unsigned char[sizeof(_Node)];
+        mpMiddle->setPrev(mpMiddle);
+        mpMiddle->setNext(mpMiddle);
+    }
+
+    /*
+     * This node plays the role of "pointer to head" and "pointer to tail".
+     * It sits in the middle of a circular list of nodes.  The iterator
+     * runs around the circle until it encounters this one.
+     */
+    _Node*      mpMiddle;
+};
+
+/*
+ * Assignment operator.
+ *
+ * The simplest way to do this would be to clear out the target list and
+ * fill it with the source.  However, we can speed things along by
+ * re-using existing elements.
+ */
+template<class T>
+List<T>& List<T>::operator=(const List<T>& right)
+{
+    if (this == &right)
+        return *this;       // self-assignment
+    iterator firstDst = begin();
+    iterator lastDst = end();
+    const_iterator firstSrc = right.begin();
+    const_iterator lastSrc = right.end();
+    while (firstSrc != lastSrc && firstDst != lastDst)
+        *firstDst++ = *firstSrc++;
+    if (firstSrc == lastSrc)        // ran out of elements in source?
+        erase(firstDst, lastDst);   // yes, erase any extras
+    else
+        insert(lastDst, firstSrc, lastSrc);     // copy remaining over
+    return *this;
+}
+
+}; // namespace android
+
+#endif // _LIBS_UTILS_LIST_H
diff --git a/include/utils/Log.h b/include/utils/Log.h
new file mode 100644
index 0000000..4259c86
--- /dev/null
+++ b/include/utils/Log.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// C/C++ logging functions.  See the logging documentation for API details.
+//
+// We'd like these to be available from C code (in case we import some from
+// somewhere), so this has a C interface.
+//
+// The output will be correct when the log file is shared between multiple
+// threads and/or multiple processes so long as the operating system
+// supports O_APPEND.  These calls have mutex-protected data structures
+// and so are NOT reentrant.  Do not use LOG in a signal handler.
+//
+#ifndef _LIBS_UTILS_LOG_H
+#define _LIBS_UTILS_LOG_H
+
+#include <cutils/log.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+
+namespace android {
+
+/*
+ * A very simple utility that yells in the log when an operation takes too long.
+ */
+class LogIfSlow {
+public:
+    LogIfSlow(const char* tag, android_LogPriority priority,
+            int timeoutMillis, const char* message);
+    ~LogIfSlow();
+
+private:
+    const char* const mTag;
+    const android_LogPriority mPriority;
+    const int mTimeoutMillis;
+    const char* const mMessage;
+    const int64_t mStart;
+};
+
+/*
+ * Writes the specified debug log message if this block takes longer than the
+ * specified number of milliseconds to run.  Includes the time actually taken.
+ *
+ * {
+ *     ALOGD_IF_SLOW(50, "Excessive delay doing something.");
+ *     doSomething();
+ * }
+ */
+#define ALOGD_IF_SLOW(timeoutMillis, message) \
+    android::LogIfSlow _logIfSlow(LOG_TAG, ANDROID_LOG_DEBUG, timeoutMillis, message);
+
+} // namespace android
+
+#endif // __cplusplus
+
+#endif // _LIBS_UTILS_LOG_H
diff --git a/include/utils/Looper.h b/include/utils/Looper.h
new file mode 100644
index 0000000..2e0651a
--- /dev/null
+++ b/include/utils/Looper.h
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2010 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 UTILS_LOOPER_H
+#define UTILS_LOOPER_H
+
+#include <utils/threads.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/Timers.h>
+
+#include <android/looper.h>
+
+#include <sys/epoll.h>
+
+/*
+ * Declare a concrete type for the NDK's looper forward declaration.
+ */
+struct ALooper {
+};
+
+namespace android {
+
+/**
+ * A message that can be posted to a Looper.
+ */
+struct Message {
+    Message() : what(0) { }
+    Message(int what) : what(what) { }
+
+    /* The message type. (interpretation is left up to the handler) */
+    int what;
+};
+
+
+/**
+ * Interface for a Looper message handler.
+ *
+ * The Looper holds a strong reference to the message handler whenever it has
+ * a message to deliver to it.  Make sure to call Looper::removeMessages
+ * to remove any pending messages destined for the handler so that the handler
+ * can be destroyed.
+ */
+class MessageHandler : public virtual RefBase {
+protected:
+    virtual ~MessageHandler() { }
+
+public:
+    /**
+     * Handles a message.
+     */
+    virtual void handleMessage(const Message& message) = 0;
+};
+
+
+/**
+ * A simple proxy that holds a weak reference to a message handler.
+ */
+class WeakMessageHandler : public MessageHandler {
+protected:
+    virtual ~WeakMessageHandler();
+
+public:
+    WeakMessageHandler(const wp<MessageHandler>& handler);
+    virtual void handleMessage(const Message& message);
+
+private:
+    wp<MessageHandler> mHandler;
+};
+
+
+/**
+ * A looper callback.
+ */
+class LooperCallback : public virtual RefBase {
+protected:
+    virtual ~LooperCallback() { }
+
+public:
+    /**
+     * Handles a poll event for the given file descriptor.
+     * It is given the file descriptor it is associated with,
+     * a bitmask of the poll events that were triggered (typically ALOOPER_EVENT_INPUT),
+     * and the data pointer that was originally supplied.
+     *
+     * Implementations should return 1 to continue receiving callbacks, or 0
+     * to have this file descriptor and callback unregistered from the looper.
+     */
+    virtual int handleEvent(int fd, int events, void* data) = 0;
+};
+
+
+/**
+ * Wraps a ALooper_callbackFunc function pointer.
+ */
+class SimpleLooperCallback : public LooperCallback {
+protected:
+    virtual ~SimpleLooperCallback();
+
+public:
+    SimpleLooperCallback(ALooper_callbackFunc callback);
+    virtual int handleEvent(int fd, int events, void* data);
+
+private:
+    ALooper_callbackFunc mCallback;
+};
+
+
+/**
+ * A polling loop that supports monitoring file descriptor events, optionally
+ * using callbacks.  The implementation uses epoll() internally.
+ *
+ * A looper can be associated with a thread although there is no requirement that it must be.
+ */
+class Looper : public ALooper, public RefBase {
+protected:
+    virtual ~Looper();
+
+public:
+    /**
+     * Creates a looper.
+     *
+     * If allowNonCallbaks is true, the looper will allow file descriptors to be
+     * registered without associated callbacks.  This assumes that the caller of
+     * pollOnce() is prepared to handle callback-less events itself.
+     */
+    Looper(bool allowNonCallbacks);
+
+    /**
+     * Returns whether this looper instance allows the registration of file descriptors
+     * using identifiers instead of callbacks.
+     */
+    bool getAllowNonCallbacks() const;
+
+    /**
+     * Waits for events to be available, with optional timeout in milliseconds.
+     * Invokes callbacks for all file descriptors on which an event occurred.
+     *
+     * If the timeout is zero, returns immediately without blocking.
+     * If the timeout is negative, waits indefinitely until an event appears.
+     *
+     * Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before
+     * the timeout expired and no callbacks were invoked and no other file
+     * descriptors were ready.
+     *
+     * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked.
+     *
+     * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
+     * timeout expired.
+     *
+     * Returns ALOOPER_POLL_ERROR if an error occurred.
+     *
+     * Returns a value >= 0 containing an identifier if its file descriptor has data
+     * and it has no callback function (requiring the caller here to handle it).
+     * In this (and only this) case outFd, outEvents and outData will contain the poll
+     * events and data associated with the fd, otherwise they will be set to NULL.
+     *
+     * This method does not return until it has finished invoking the appropriate callbacks
+     * for all file descriptors that were signalled.
+     */
+    int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
+    inline int pollOnce(int timeoutMillis) {
+        return pollOnce(timeoutMillis, NULL, NULL, NULL);
+    }
+
+    /**
+     * Like pollOnce(), but performs all pending callbacks until all
+     * data has been consumed or a file descriptor is available with no callback.
+     * This function will never return ALOOPER_POLL_CALLBACK.
+     */
+    int pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData);
+    inline int pollAll(int timeoutMillis) {
+        return pollAll(timeoutMillis, NULL, NULL, NULL);
+    }
+
+    /**
+     * Wakes the poll asynchronously.
+     *
+     * This method can be called on any thread.
+     * This method returns immediately.
+     */
+    void wake();
+
+    /**
+     * Adds a new file descriptor to be polled by the looper.
+     * If the same file descriptor was previously added, it is replaced.
+     *
+     * "fd" is the file descriptor to be added.
+     * "ident" is an identifier for this event, which is returned from pollOnce().
+     * The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback.
+     * "events" are the poll events to wake up on.  Typically this is ALOOPER_EVENT_INPUT.
+     * "callback" is the function to call when there is an event on the file descriptor.
+     * "data" is a private data pointer to supply to the callback.
+     *
+     * There are two main uses of this function:
+     *
+     * (1) If "callback" is non-NULL, then this function will be called when there is
+     * data on the file descriptor.  It should execute any events it has pending,
+     * appropriately reading from the file descriptor.  The 'ident' is ignored in this case.
+     *
+     * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce
+     * when its file descriptor has data available, requiring the caller to take
+     * care of processing it.
+     *
+     * Returns 1 if the file descriptor was added, 0 if the arguments were invalid.
+     *
+     * This method can be called on any thread.
+     * This method may block briefly if it needs to wake the poll.
+     *
+     * The callback may either be specified as a bare function pointer or as a smart
+     * pointer callback object.  The smart pointer should be preferred because it is
+     * easier to avoid races when the callback is removed from a different thread.
+     * See removeFd() for details.
+     */
+    int addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data);
+    int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data);
+
+    /**
+     * Removes a previously added file descriptor from the looper.
+     *
+     * When this method returns, it is safe to close the file descriptor since the looper
+     * will no longer have a reference to it.  However, it is possible for the callback to
+     * already be running or for it to run one last time if the file descriptor was already
+     * signalled.  Calling code is responsible for ensuring that this case is safely handled.
+     * For example, if the callback takes care of removing itself during its own execution either
+     * by returning 0 or by calling this method, then it can be guaranteed to not be invoked
+     * again at any later time unless registered anew.
+     *
+     * A simple way to avoid this problem is to use the version of addFd() that takes
+     * a sp<LooperCallback> instead of a bare function pointer.  The LooperCallback will
+     * be released at the appropriate time by the Looper.
+     *
+     * Returns 1 if the file descriptor was removed, 0 if none was previously registered.
+     *
+     * This method can be called on any thread.
+     * This method may block briefly if it needs to wake the poll.
+     */
+    int removeFd(int fd);
+
+    /**
+     * Enqueues a message to be processed by the specified handler.
+     *
+     * The handler must not be null.
+     * This method can be called on any thread.
+     */
+    void sendMessage(const sp<MessageHandler>& handler, const Message& message);
+
+    /**
+     * Enqueues a message to be processed by the specified handler after all pending messages
+     * after the specified delay.
+     *
+     * The time delay is specified in uptime nanoseconds.
+     * The handler must not be null.
+     * This method can be called on any thread.
+     */
+    void sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
+            const Message& message);
+
+    /**
+     * Enqueues a message to be processed by the specified handler after all pending messages
+     * at the specified time.
+     *
+     * The time is specified in uptime nanoseconds.
+     * The handler must not be null.
+     * This method can be called on any thread.
+     */
+    void sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
+            const Message& message);
+
+    /**
+     * Removes all messages for the specified handler from the queue.
+     *
+     * The handler must not be null.
+     * This method can be called on any thread.
+     */
+    void removeMessages(const sp<MessageHandler>& handler);
+
+    /**
+     * Removes all messages of a particular type for the specified handler from the queue.
+     *
+     * The handler must not be null.
+     * This method can be called on any thread.
+     */
+    void removeMessages(const sp<MessageHandler>& handler, int what);
+
+    /**
+     * Return whether this looper's thread is currently idling -- that is, whether it
+     * stopped waiting for more work to do.  Note that this is intrinsically racy, since
+     * its state can change before you get the result back.
+     */
+    bool isIdling() const;
+
+    /**
+     * Prepares a looper associated with the calling thread, and returns it.
+     * If the thread already has a looper, it is returned.  Otherwise, a new
+     * one is created, associated with the thread, and returned.
+     *
+     * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0.
+     */
+    static sp<Looper> prepare(int opts);
+
+    /**
+     * Sets the given looper to be associated with the calling thread.
+     * If another looper is already associated with the thread, it is replaced.
+     *
+     * If "looper" is NULL, removes the currently associated looper.
+     */
+    static void setForThread(const sp<Looper>& looper);
+
+    /**
+     * Returns the looper associated with the calling thread, or NULL if
+     * there is not one.
+     */
+    static sp<Looper> getForThread();
+
+private:
+    struct Request {
+        int fd;
+        int ident;
+        sp<LooperCallback> callback;
+        void* data;
+    };
+
+    struct Response {
+        int events;
+        Request request;
+    };
+
+    struct MessageEnvelope {
+        MessageEnvelope() : uptime(0) { }
+
+        MessageEnvelope(nsecs_t uptime, const sp<MessageHandler> handler,
+                const Message& message) : uptime(uptime), handler(handler), message(message) {
+        }
+
+        nsecs_t uptime;
+        sp<MessageHandler> handler;
+        Message message;
+    };
+
+    const bool mAllowNonCallbacks; // immutable
+
+    int mWakeReadPipeFd;  // immutable
+    int mWakeWritePipeFd; // immutable
+    Mutex mLock;
+
+    Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock
+    bool mSendingMessage; // guarded by mLock
+
+    // Whether we are currently waiting for work.  Not protected by a lock,
+    // any use of it is racy anyway.
+    volatile bool mIdling;
+
+    int mEpollFd; // immutable
+
+    // Locked list of file descriptor monitoring requests.
+    KeyedVector<int, Request> mRequests;  // guarded by mLock
+
+    // This state is only used privately by pollOnce and does not require a lock since
+    // it runs on a single thread.
+    Vector<Response> mResponses;
+    size_t mResponseIndex;
+    nsecs_t mNextMessageUptime; // set to LLONG_MAX when none
+
+    int pollInner(int timeoutMillis);
+    void awoken();
+    void pushResponse(int events, const Request& request);
+
+    static void initTLSKey();
+    static void threadDestructor(void *st);
+};
+
+} // namespace android
+
+#endif // UTILS_LOOPER_H
diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h
new file mode 100644
index 0000000..053bfaf
--- /dev/null
+++ b/include/utils/LruCache.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2012 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 ANDROID_UTILS_LRU_CACHE_H
+#define ANDROID_UTILS_LRU_CACHE_H
+
+#include <utils/BasicHashtable.h>
+#include <utils/UniquePtr.h>
+
+namespace android {
+
+/**
+ * GenerationCache callback used when an item is removed
+ */
+template<typename EntryKey, typename EntryValue>
+class OnEntryRemoved {
+public:
+    virtual ~OnEntryRemoved() { };
+    virtual void operator()(EntryKey& key, EntryValue& value) = 0;
+}; // class OnEntryRemoved
+
+template <typename TKey, typename TValue>
+class LruCache {
+public:
+    explicit LruCache(uint32_t maxCapacity);
+
+    enum Capacity {
+        kUnlimitedCapacity,
+    };
+
+    void setOnEntryRemovedListener(OnEntryRemoved<TKey, TValue>* listener);
+    size_t size() const;
+    const TValue& get(const TKey& key);
+    bool put(const TKey& key, const TValue& value);
+    bool remove(const TKey& key);
+    bool removeOldest();
+    void clear();
+
+    class Iterator {
+    public:
+        Iterator(const LruCache<TKey, TValue>& cache): mCache(cache), mIndex(-1) {
+        }
+
+        bool next() {
+            mIndex = mCache.mTable->next(mIndex);
+            return mIndex != -1;
+        }
+
+        size_t index() const {
+            return mIndex;
+        }
+
+        const TValue& value() const {
+            return mCache.mTable->entryAt(mIndex).value;
+        }
+
+        const TKey& key() const {
+            return mCache.mTable->entryAt(mIndex).key;
+        }
+    private:
+        const LruCache<TKey, TValue>& mCache;
+        size_t mIndex;
+    };
+
+private:
+    LruCache(const LruCache& that);  // disallow copy constructor
+
+    struct Entry {
+        TKey key;
+        TValue value;
+        Entry* parent;
+        Entry* child;
+
+        Entry(TKey key_, TValue value_) : key(key_), value(value_), parent(NULL), child(NULL) {
+        }
+        const TKey& getKey() const { return key; }
+    };
+
+    void attachToCache(Entry& entry);
+    void detachFromCache(Entry& entry);
+    void rehash(size_t newCapacity);
+
+    UniquePtr<BasicHashtable<TKey, Entry> > mTable;
+    OnEntryRemoved<TKey, TValue>* mListener;
+    Entry* mOldest;
+    Entry* mYoungest;
+    uint32_t mMaxCapacity;
+    TValue mNullValue;
+};
+
+// Implementation is here, because it's fully templated
+template <typename TKey, typename TValue>
+LruCache<TKey, TValue>::LruCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity),
+    mNullValue(NULL), mTable(new BasicHashtable<TKey, Entry>), mYoungest(NULL), mOldest(NULL),
+    mListener(NULL) {
+};
+
+template<typename K, typename V>
+void LruCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) {
+    mListener = listener;
+}
+
+template <typename TKey, typename TValue>
+size_t LruCache<TKey, TValue>::size() const {
+    return mTable->size();
+}
+
+template <typename TKey, typename TValue>
+const TValue& LruCache<TKey, TValue>::get(const TKey& key) {
+    hash_t hash = hash_type(key);
+    ssize_t index = mTable->find(-1, hash, key);
+    if (index == -1) {
+        return mNullValue;
+    }
+    Entry& entry = mTable->editEntryAt(index);
+    detachFromCache(entry);
+    attachToCache(entry);
+    return entry.value;
+}
+
+template <typename TKey, typename TValue>
+bool LruCache<TKey, TValue>::put(const TKey& key, const TValue& value) {
+    if (mMaxCapacity != kUnlimitedCapacity && size() >= mMaxCapacity) {
+        removeOldest();
+    }
+
+    hash_t hash = hash_type(key);
+    ssize_t index = mTable->find(-1, hash, key);
+    if (index >= 0) {
+        return false;
+    }
+    if (!mTable->hasMoreRoom()) {
+        rehash(mTable->capacity() * 2);
+    }
+
+    // Would it be better to initialize a blank entry and assign key, value?
+    Entry initEntry(key, value);
+    index = mTable->add(hash, initEntry);
+    Entry& entry = mTable->editEntryAt(index);
+    attachToCache(entry);
+    return true;
+}
+
+template <typename TKey, typename TValue>
+bool LruCache<TKey, TValue>::remove(const TKey& key) {
+    hash_t hash = hash_type(key);
+    ssize_t index = mTable->find(-1, hash, key);
+    if (index < 0) {
+        return false;
+    }
+    Entry& entry = mTable->editEntryAt(index);
+    if (mListener) {
+        (*mListener)(entry.key, entry.value);
+    }
+    detachFromCache(entry);
+    mTable->removeAt(index);
+    return true;
+}
+
+template <typename TKey, typename TValue>
+bool LruCache<TKey, TValue>::removeOldest() {
+    if (mOldest != NULL) {
+        return remove(mOldest->key);
+        // TODO: should probably abort if false
+    }
+    return false;
+}
+
+template <typename TKey, typename TValue>
+void LruCache<TKey, TValue>::clear() {
+    if (mListener) {
+        for (Entry* p = mOldest; p != NULL; p = p->child) {
+            (*mListener)(p->key, p->value);
+        }
+    }
+    mYoungest = NULL;
+    mOldest = NULL;
+    mTable->clear();
+}
+
+template <typename TKey, typename TValue>
+void LruCache<TKey, TValue>::attachToCache(Entry& entry) {
+    if (mYoungest == NULL) {
+        mYoungest = mOldest = &entry;
+    } else {
+        entry.parent = mYoungest;
+        mYoungest->child = &entry;
+        mYoungest = &entry;
+    }
+}
+
+template <typename TKey, typename TValue>
+void LruCache<TKey, TValue>::detachFromCache(Entry& entry) {
+    if (entry.parent != NULL) {
+        entry.parent->child = entry.child;
+    } else {
+        mOldest = entry.child;
+    }
+    if (entry.child != NULL) {
+        entry.child->parent = entry.parent;
+    } else {
+        mYoungest = entry.parent;
+    }
+
+    entry.parent = NULL;
+    entry.child = NULL;
+}
+
+template <typename TKey, typename TValue>
+void LruCache<TKey, TValue>::rehash(size_t newCapacity) {
+    UniquePtr<BasicHashtable<TKey, Entry> > oldTable(mTable.release());
+    Entry* oldest = mOldest;
+
+    mOldest = NULL;
+    mYoungest = NULL;
+    mTable.reset(new BasicHashtable<TKey, Entry>(newCapacity));
+    for (Entry* p = oldest; p != NULL; p = p->child) {
+        put(p->key, p->value);
+    }
+}
+
+}
+
+#endif // ANDROID_UTILS_LRU_CACHE_H
diff --git a/include/utils/Mutex.h b/include/utils/Mutex.h
new file mode 100644
index 0000000..dd201c8
--- /dev/null
+++ b/include/utils/Mutex.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007 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 _LIBS_UTILS_MUTEX_H
+#define _LIBS_UTILS_MUTEX_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <time.h>
+
+#if defined(HAVE_PTHREADS)
+# include <pthread.h>
+#endif
+
+#include <utils/Errors.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Condition;
+
+/*
+ * Simple mutex class.  The implementation is system-dependent.
+ *
+ * The mutex must be unlocked by the thread that locked it.  They are not
+ * recursive, i.e. the same thread can't lock it multiple times.
+ */
+class Mutex {
+public:
+    enum {
+        PRIVATE = 0,
+        SHARED = 1
+    };
+    
+                Mutex();
+                Mutex(const char* name);
+                Mutex(int type, const char* name = NULL);
+                ~Mutex();
+
+    // lock or unlock the mutex
+    status_t    lock();
+    void        unlock();
+
+    // lock if possible; returns 0 on success, error otherwise
+    status_t    tryLock();
+
+    // Manages the mutex automatically. It'll be locked when Autolock is
+    // constructed and released when Autolock goes out of scope.
+    class Autolock {
+    public:
+        inline Autolock(Mutex& mutex) : mLock(mutex)  { mLock.lock(); }
+        inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
+        inline ~Autolock() { mLock.unlock(); }
+    private:
+        Mutex& mLock;
+    };
+
+private:
+    friend class Condition;
+    
+    // A mutex cannot be copied
+                Mutex(const Mutex&);
+    Mutex&      operator = (const Mutex&);
+    
+#if defined(HAVE_PTHREADS)
+    pthread_mutex_t mMutex;
+#else
+    void    _init();
+    void*   mState;
+#endif
+};
+
+// ---------------------------------------------------------------------------
+
+#if defined(HAVE_PTHREADS)
+
+inline Mutex::Mutex() {
+    pthread_mutex_init(&mMutex, NULL);
+}
+inline Mutex::Mutex(__attribute__((unused)) const char* name) {
+    pthread_mutex_init(&mMutex, NULL);
+}
+inline Mutex::Mutex(int type, __attribute__((unused)) const char* name) {
+    if (type == SHARED) {
+        pthread_mutexattr_t attr;
+        pthread_mutexattr_init(&attr);
+        pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+        pthread_mutex_init(&mMutex, &attr);
+        pthread_mutexattr_destroy(&attr);
+    } else {
+        pthread_mutex_init(&mMutex, NULL);
+    }
+}
+inline Mutex::~Mutex() {
+    pthread_mutex_destroy(&mMutex);
+}
+inline status_t Mutex::lock() {
+    return -pthread_mutex_lock(&mMutex);
+}
+inline void Mutex::unlock() {
+    pthread_mutex_unlock(&mMutex);
+}
+inline status_t Mutex::tryLock() {
+    return -pthread_mutex_trylock(&mMutex);
+}
+
+#endif // HAVE_PTHREADS
+
+// ---------------------------------------------------------------------------
+
+/*
+ * Automatic mutex.  Declare one of these at the top of a function.
+ * When the function returns, it will go out of scope, and release the
+ * mutex.
+ */
+ 
+typedef Mutex::Autolock AutoMutex;
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // _LIBS_UTILS_MUTEX_H
diff --git a/include/utils/Printer.h b/include/utils/Printer.h
new file mode 100644
index 0000000..bb66287
--- /dev/null
+++ b/include/utils/Printer.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2013 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 ANDROID_PRINTER_H
+#define ANDROID_PRINTER_H
+
+#include <android/log.h>
+
+namespace android {
+
+// Interface for printing to an arbitrary data stream
+class Printer {
+public:
+    // Print a new line specified by 'string'. \n is appended automatically.
+    // -- Assumes that the string has no new line in it.
+    virtual void printLine(const char* string = "") = 0;
+
+    // Print a new line specified by the format string. \n is appended automatically.
+    // -- Assumes that the resulting string has no new line in it.
+    virtual void printFormatLine(const char* format, ...) __attribute__((format (printf, 2, 3)));
+
+protected:
+    Printer();
+    virtual ~Printer();
+}; // class Printer
+
+// Print to logcat
+class LogPrinter : public Printer {
+public:
+    // Create a printer using the specified logcat and log priority
+    // - Unless ignoreBlankLines is false, print blank lines to logcat
+    // (Note that the default ALOG behavior is to ignore blank lines)
+    LogPrinter(const char* logtag,
+               android_LogPriority priority = ANDROID_LOG_DEBUG,
+               const char* prefix = 0,
+               bool ignoreBlankLines = false);
+
+    // Print the specified line to logcat. No \n at the end is necessary.
+    virtual void printLine(const char* string);
+
+private:
+    void printRaw(const char* string);
+
+    const char* mLogTag;
+    android_LogPriority mPriority;
+    const char* mPrefix;
+    bool mIgnoreBlankLines;
+}; // class LogPrinter
+
+// Print to a file descriptor
+class FdPrinter : public Printer {
+public:
+    // Create a printer using the specified file descriptor.
+    // - Each line will be prefixed with 'indent' number of blank spaces.
+    // - In addition, each line will be prefixed with the 'prefix' string.
+    FdPrinter(int fd, unsigned int indent = 0, const char* prefix = 0);
+
+    // Print the specified line to the file descriptor. \n is appended automatically.
+    virtual void printLine(const char* string);
+
+private:
+    enum {
+        MAX_FORMAT_STRING = 20,
+    };
+
+    int mFd;
+    unsigned int mIndent;
+    const char* mPrefix;
+    char mFormatString[MAX_FORMAT_STRING];
+}; // class FdPrinter
+
+class String8;
+
+// Print to a String8
+class String8Printer : public Printer {
+public:
+    // Create a printer using the specified String8 as the target.
+    // - In addition, each line will be prefixed with the 'prefix' string.
+    // - target's memory lifetime must be a superset of this String8Printer.
+    String8Printer(String8* target, const char* prefix = 0);
+
+    // Append the specified line to the String8. \n is appended automatically.
+    virtual void printLine(const char* string);
+
+private:
+    String8* mTarget;
+    const char* mPrefix;
+}; // class String8Printer
+
+// Print to an existing Printer by adding a prefix to each line
+class PrefixPrinter : public Printer {
+public:
+    // Create a printer using the specified printer as the target.
+    PrefixPrinter(Printer& printer, const char* prefix);
+
+    // Print the line (prefixed with prefix) using the printer.
+    virtual void printLine(const char* string);
+
+private:
+    Printer& mPrinter;
+    const char* mPrefix;
+};
+
+}; // namespace android
+
+#endif // ANDROID_PRINTER_H
diff --git a/include/utils/ProcessCallStack.h b/include/utils/ProcessCallStack.h
new file mode 100644
index 0000000..4a86869
--- /dev/null
+++ b/include/utils/ProcessCallStack.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2013 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 ANDROID_PROCESS_CALLSTACK_H
+#define ANDROID_PROCESS_CALLSTACK_H
+
+#include <utils/CallStack.h>
+#include <android/log.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
+#include <time.h>
+#include <sys/types.h>
+
+namespace android {
+
+class Printer;
+
+// Collect/print the call stack (function, file, line) traces for all threads in a process.
+class ProcessCallStack {
+public:
+    // Create an empty call stack. No-op.
+    ProcessCallStack();
+    // Copy the existing process callstack (no other side effects).
+    ProcessCallStack(const ProcessCallStack& rhs);
+    ~ProcessCallStack();
+
+    // Immediately collect the stack traces for all threads.
+    void update(int32_t maxDepth = CallStack::MAX_DEPTH);
+
+    // Print all stack traces to the log using the supplied logtag.
+    void log(const char* logtag, android_LogPriority priority = ANDROID_LOG_DEBUG,
+             const char* prefix = 0) const;
+
+    // Dump all stack traces to the specified file descriptor.
+    void dump(int fd, int indent = 0, const char* prefix = 0) const;
+
+    // Return a string (possibly very long) containing all the stack traces.
+    String8 toString(const char* prefix = 0) const;
+
+    // Dump a serialized representation of all the stack traces to the specified printer.
+    void print(Printer& printer) const;
+
+    // Get the number of threads whose stack traces were collected.
+    size_t size() const;
+
+private:
+    void printInternal(Printer& printer, Printer& csPrinter) const;
+
+    // Reset the process's stack frames and metadata.
+    void clear();
+
+    struct ThreadInfo {
+        CallStack callStack;
+        String8 threadName;
+    };
+
+    // tid -> ThreadInfo
+    KeyedVector<pid_t, ThreadInfo> mThreadMap;
+    // Time that update() was last called
+    struct tm mTimeUpdated;
+};
+
+}; // namespace android
+
+#endif // ANDROID_PROCESS_CALLSTACK_H
diff --git a/include/utils/PropertyMap.h b/include/utils/PropertyMap.h
new file mode 100644
index 0000000..a9e674f
--- /dev/null
+++ b/include/utils/PropertyMap.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 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 _UTILS_PROPERTY_MAP_H
+#define _UTILS_PROPERTY_MAP_H
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/Errors.h>
+#include <utils/Tokenizer.h>
+
+namespace android {
+
+/*
+ * Provides a mechanism for passing around string-based property key / value pairs
+ * and loading them from property files.
+ *
+ * The property files have the following simple structure:
+ *
+ * # Comment
+ * key = value
+ *
+ * Keys and values are any sequence of printable ASCII characters.
+ * The '=' separates the key from the value.
+ * The key and value may not contain whitespace.
+ *
+ * The '\' character is reserved for escape sequences and is not currently supported.
+ * The '"" character is reserved for quoting and is not currently supported.
+ * Files that contain the '\' or '"' character will fail to parse.
+ *
+ * The file must not contain duplicate keys.
+ *
+ * TODO Support escape sequences and quoted values when needed.
+ */
+class PropertyMap {
+public:
+    /* Creates an empty property map. */
+    PropertyMap();
+    ~PropertyMap();
+
+    /* Clears the property map. */
+    void clear();
+
+    /* Adds a property.
+     * Replaces the property with the same key if it is already present.
+     */
+    void addProperty(const String8& key, const String8& value);
+
+    /* Returns true if the property map contains the specified key. */
+    bool hasProperty(const String8& key) const;
+
+    /* Gets the value of a property and parses it.
+     * Returns true and sets outValue if the key was found and its value was parsed successfully.
+     * Otherwise returns false and does not modify outValue.  (Also logs a warning.)
+     */
+    bool tryGetProperty(const String8& key, String8& outValue) const;
+    bool tryGetProperty(const String8& key, bool& outValue) const;
+    bool tryGetProperty(const String8& key, int32_t& outValue) const;
+    bool tryGetProperty(const String8& key, float& outValue) const;
+
+    /* Adds all values from the specified property map. */
+    void addAll(const PropertyMap* map);
+
+    /* Gets the underlying property map. */
+    inline const KeyedVector<String8, String8>& getProperties() const { return mProperties; }
+
+    /* Loads a property map from a file. */
+    static status_t load(const String8& filename, PropertyMap** outMap);
+
+private:
+    class Parser {
+        PropertyMap* mMap;
+        Tokenizer* mTokenizer;
+
+    public:
+        Parser(PropertyMap* map, Tokenizer* tokenizer);
+        ~Parser();
+        status_t parse();
+
+    private:
+        status_t parseType();
+        status_t parseKey();
+        status_t parseKeyProperty();
+        status_t parseModifier(const String8& token, int32_t* outMetaState);
+        status_t parseCharacterLiteral(char16_t* outCharacter);
+    };
+
+    KeyedVector<String8, String8> mProperties;
+};
+
+} // namespace android
+
+#endif // _UTILS_PROPERTY_MAP_H
diff --git a/include/utils/RWLock.h b/include/utils/RWLock.h
new file mode 100644
index 0000000..90beb5f
--- /dev/null
+++ b/include/utils/RWLock.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2007 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 _LIBS_UTILS_RWLOCK_H
+#define _LIBS_UTILS_RWLOCK_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#if defined(HAVE_PTHREADS)
+# include <pthread.h>
+#endif
+
+#include <utils/Errors.h>
+#include <utils/ThreadDefs.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+#if defined(HAVE_PTHREADS)
+
+/*
+ * Simple mutex class.  The implementation is system-dependent.
+ *
+ * The mutex must be unlocked by the thread that locked it.  They are not
+ * recursive, i.e. the same thread can't lock it multiple times.
+ */
+class RWLock {
+public:
+    enum {
+        PRIVATE = 0,
+        SHARED = 1
+    };
+
+                RWLock();
+                RWLock(const char* name);
+                RWLock(int type, const char* name = NULL);
+                ~RWLock();
+
+    status_t    readLock();
+    status_t    tryReadLock();
+    status_t    writeLock();
+    status_t    tryWriteLock();
+    void        unlock();
+
+    class AutoRLock {
+    public:
+        inline AutoRLock(RWLock& rwlock) : mLock(rwlock)  { mLock.readLock(); }
+        inline ~AutoRLock() { mLock.unlock(); }
+    private:
+        RWLock& mLock;
+    };
+
+    class AutoWLock {
+    public:
+        inline AutoWLock(RWLock& rwlock) : mLock(rwlock)  { mLock.writeLock(); }
+        inline ~AutoWLock() { mLock.unlock(); }
+    private:
+        RWLock& mLock;
+    };
+
+private:
+    // A RWLock cannot be copied
+                RWLock(const RWLock&);
+   RWLock&      operator = (const RWLock&);
+
+   pthread_rwlock_t mRWLock;
+};
+
+inline RWLock::RWLock() {
+    pthread_rwlock_init(&mRWLock, NULL);
+}
+inline RWLock::RWLock(__attribute__((unused)) const char* name) {
+    pthread_rwlock_init(&mRWLock, NULL);
+}
+inline RWLock::RWLock(int type, __attribute__((unused)) const char* name) {
+    if (type == SHARED) {
+        pthread_rwlockattr_t attr;
+        pthread_rwlockattr_init(&attr);
+        pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+        pthread_rwlock_init(&mRWLock, &attr);
+        pthread_rwlockattr_destroy(&attr);
+    } else {
+        pthread_rwlock_init(&mRWLock, NULL);
+    }
+}
+inline RWLock::~RWLock() {
+    pthread_rwlock_destroy(&mRWLock);
+}
+inline status_t RWLock::readLock() {
+    return -pthread_rwlock_rdlock(&mRWLock);
+}
+inline status_t RWLock::tryReadLock() {
+    return -pthread_rwlock_tryrdlock(&mRWLock);
+}
+inline status_t RWLock::writeLock() {
+    return -pthread_rwlock_wrlock(&mRWLock);
+}
+inline status_t RWLock::tryWriteLock() {
+    return -pthread_rwlock_trywrlock(&mRWLock);
+}
+inline void RWLock::unlock() {
+    pthread_rwlock_unlock(&mRWLock);
+}
+
+#endif // HAVE_PTHREADS
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // _LIBS_UTILS_RWLOCK_H
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
new file mode 100644
index 0000000..cbfe13a
--- /dev/null
+++ b/include/utils/RefBase.h
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_REF_BASE_H
+#define ANDROID_REF_BASE_H
+
+#include <cutils/atomic.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <utils/StrongPointer.h>
+#include <utils/TypeHelpers.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class TextOutput;
+TextOutput& printWeakPointer(TextOutput& to, const void* val);
+
+// ---------------------------------------------------------------------------
+
+#define COMPARE_WEAK(_op_)                                      \
+inline bool operator _op_ (const sp<T>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+inline bool operator _op_ (const T* o) const {                  \
+    return m_ptr _op_ o;                                        \
+}                                                               \
+template<typename U>                                            \
+inline bool operator _op_ (const sp<U>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+template<typename U>                                            \
+inline bool operator _op_ (const U* o) const {                  \
+    return m_ptr _op_ o;                                        \
+}
+
+// ---------------------------------------------------------------------------
+
+class ReferenceRenamer {
+protected:
+    // destructor is purposedly not virtual so we avoid code overhead from
+    // subclasses; we have to make it protected to guarantee that it
+    // cannot be called from this base class (and to make strict compilers
+    // happy).
+    ~ReferenceRenamer() { }
+public:
+    virtual void operator()(size_t i) const = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+class RefBase
+{
+public:
+            void            incStrong(const void* id) const;
+            void            decStrong(const void* id) const;
+    
+            void            forceIncStrong(const void* id) const;
+
+            //! DEBUGGING ONLY: Get current strong ref count.
+            int32_t         getStrongCount() const;
+
+    class weakref_type
+    {
+    public:
+        RefBase*            refBase() const;
+        
+        void                incWeak(const void* id);
+        void                decWeak(const void* id);
+        
+        // acquires a strong reference if there is already one.
+        bool                attemptIncStrong(const void* id);
+        
+        // acquires a weak reference if there is already one.
+        // This is not always safe. see ProcessState.cpp and BpBinder.cpp
+        // for proper use.
+        bool                attemptIncWeak(const void* id);
+
+        //! DEBUGGING ONLY: Get current weak ref count.
+        int32_t             getWeakCount() const;
+
+        //! DEBUGGING ONLY: Print references held on object.
+        void                printRefs() const;
+
+        //! DEBUGGING ONLY: Enable tracking for this object.
+        // enable -- enable/disable tracking
+        // retain -- when tracking is enable, if true, then we save a stack trace
+        //           for each reference and dereference; when retain == false, we
+        //           match up references and dereferences and keep only the 
+        //           outstanding ones.
+        
+        void                trackMe(bool enable, bool retain);
+    };
+    
+            weakref_type*   createWeak(const void* id) const;
+            
+            weakref_type*   getWeakRefs() const;
+
+            //! DEBUGGING ONLY: Print references held on object.
+    inline  void            printRefs() const { getWeakRefs()->printRefs(); }
+
+            //! DEBUGGING ONLY: Enable tracking of object.
+    inline  void            trackMe(bool enable, bool retain)
+    { 
+        getWeakRefs()->trackMe(enable, retain); 
+    }
+
+    typedef RefBase basetype;
+
+protected:
+                            RefBase();
+    virtual                 ~RefBase();
+    
+    //! Flags for extendObjectLifetime()
+    enum {
+        OBJECT_LIFETIME_STRONG  = 0x0000,
+        OBJECT_LIFETIME_WEAK    = 0x0001,
+        OBJECT_LIFETIME_MASK    = 0x0001
+    };
+    
+            void            extendObjectLifetime(int32_t mode);
+            
+    //! Flags for onIncStrongAttempted()
+    enum {
+        FIRST_INC_STRONG = 0x0001
+    };
+    
+    virtual void            onFirstRef();
+    virtual void            onLastStrongRef(const void* id);
+    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);
+    virtual void            onLastWeakRef(const void* id);
+
+private:
+    friend class weakref_type;
+    class weakref_impl;
+    
+                            RefBase(const RefBase& o);
+            RefBase&        operator=(const RefBase& o);
+
+private:
+    friend class ReferenceMover;
+
+    static void renameRefs(size_t n, const ReferenceRenamer& renamer);
+
+    static void renameRefId(weakref_type* ref,
+            const void* old_id, const void* new_id);
+
+    static void renameRefId(RefBase* ref,
+            const void* old_id, const void* new_id);
+
+        weakref_impl* const mRefs;
+};
+
+// ---------------------------------------------------------------------------
+
+template <class T>
+class LightRefBase
+{
+public:
+    inline LightRefBase() : mCount(0) { }
+    inline void incStrong(__attribute__((unused)) const void* id) const {
+        android_atomic_inc(&mCount);
+    }
+    inline void decStrong(__attribute__((unused)) const void* id) const {
+        if (android_atomic_dec(&mCount) == 1) {
+            delete static_cast<const T*>(this);
+        }
+    }
+    //! DEBUGGING ONLY: Get current strong ref count.
+    inline int32_t getStrongCount() const {
+        return mCount;
+    }
+
+    typedef LightRefBase<T> basetype;
+
+protected:
+    inline ~LightRefBase() { }
+
+private:
+    friend class ReferenceMover;
+    inline static void renameRefs(size_t n, const ReferenceRenamer& renamer) { }
+    inline static void renameRefId(T* ref,
+            const void* old_id, const void* new_id) { }
+
+private:
+    mutable volatile int32_t mCount;
+};
+
+// ---------------------------------------------------------------------------
+
+template <typename T>
+class wp
+{
+public:
+    typedef typename RefBase::weakref_type weakref_type;
+    
+    inline wp() : m_ptr(0) { }
+
+    wp(T* other);
+    wp(const wp<T>& other);
+    wp(const sp<T>& other);
+    template<typename U> wp(U* other);
+    template<typename U> wp(const sp<U>& other);
+    template<typename U> wp(const wp<U>& other);
+
+    ~wp();
+    
+    // Assignment
+
+    wp& operator = (T* other);
+    wp& operator = (const wp<T>& other);
+    wp& operator = (const sp<T>& other);
+    
+    template<typename U> wp& operator = (U* other);
+    template<typename U> wp& operator = (const wp<U>& other);
+    template<typename U> wp& operator = (const sp<U>& other);
+    
+    void set_object_and_refs(T* other, weakref_type* refs);
+
+    // promotion to sp
+    
+    sp<T> promote() const;
+
+    // Reset
+    
+    void clear();
+
+    // Accessors
+    
+    inline  weakref_type* get_refs() const { return m_refs; }
+    
+    inline  T* unsafe_get() const { return m_ptr; }
+
+    // Operators
+
+    COMPARE_WEAK(==)
+    COMPARE_WEAK(!=)
+    COMPARE_WEAK(>)
+    COMPARE_WEAK(<)
+    COMPARE_WEAK(<=)
+    COMPARE_WEAK(>=)
+
+    inline bool operator == (const wp<T>& o) const {
+        return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
+    }
+    template<typename U>
+    inline bool operator == (const wp<U>& o) const {
+        return m_ptr == o.m_ptr;
+    }
+
+    inline bool operator > (const wp<T>& o) const {
+        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
+    }
+    template<typename U>
+    inline bool operator > (const wp<U>& o) const {
+        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
+    }
+
+    inline bool operator < (const wp<T>& o) const {
+        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
+    }
+    template<typename U>
+    inline bool operator < (const wp<U>& o) const {
+        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
+    }
+                         inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
+    template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
+                         inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
+    template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
+                         inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
+    template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }
+
+private:
+    template<typename Y> friend class sp;
+    template<typename Y> friend class wp;
+
+    T*              m_ptr;
+    weakref_type*   m_refs;
+};
+
+template <typename T>
+TextOutput& operator<<(TextOutput& to, const wp<T>& val);
+
+#undef COMPARE_WEAK
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts below here.
+
+template<typename T>
+wp<T>::wp(T* other)
+    : m_ptr(other)
+{
+    if (other) m_refs = other->createWeak(this);
+}
+
+template<typename T>
+wp<T>::wp(const wp<T>& other)
+    : m_ptr(other.m_ptr), m_refs(other.m_refs)
+{
+    if (m_ptr) m_refs->incWeak(this);
+}
+
+template<typename T>
+wp<T>::wp(const sp<T>& other)
+    : m_ptr(other.m_ptr)
+{
+    if (m_ptr) {
+        m_refs = m_ptr->createWeak(this);
+    }
+}
+
+template<typename T> template<typename U>
+wp<T>::wp(U* other)
+    : m_ptr(other)
+{
+    if (other) m_refs = other->createWeak(this);
+}
+
+template<typename T> template<typename U>
+wp<T>::wp(const wp<U>& other)
+    : m_ptr(other.m_ptr)
+{
+    if (m_ptr) {
+        m_refs = other.m_refs;
+        m_refs->incWeak(this);
+    }
+}
+
+template<typename T> template<typename U>
+wp<T>::wp(const sp<U>& other)
+    : m_ptr(other.m_ptr)
+{
+    if (m_ptr) {
+        m_refs = m_ptr->createWeak(this);
+    }
+}
+
+template<typename T>
+wp<T>::~wp()
+{
+    if (m_ptr) m_refs->decWeak(this);
+}
+
+template<typename T>
+wp<T>& wp<T>::operator = (T* other)
+{
+    weakref_type* newRefs =
+        other ? other->createWeak(this) : 0;
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = other;
+    m_refs = newRefs;
+    return *this;
+}
+
+template<typename T>
+wp<T>& wp<T>::operator = (const wp<T>& other)
+{
+    weakref_type* otherRefs(other.m_refs);
+    T* otherPtr(other.m_ptr);
+    if (otherPtr) otherRefs->incWeak(this);
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = otherPtr;
+    m_refs = otherRefs;
+    return *this;
+}
+
+template<typename T>
+wp<T>& wp<T>::operator = (const sp<T>& other)
+{
+    weakref_type* newRefs =
+        other != NULL ? other->createWeak(this) : 0;
+    T* otherPtr(other.m_ptr);
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = otherPtr;
+    m_refs = newRefs;
+    return *this;
+}
+
+template<typename T> template<typename U>
+wp<T>& wp<T>::operator = (U* other)
+{
+    weakref_type* newRefs =
+        other ? other->createWeak(this) : 0;
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = other;
+    m_refs = newRefs;
+    return *this;
+}
+
+template<typename T> template<typename U>
+wp<T>& wp<T>::operator = (const wp<U>& other)
+{
+    weakref_type* otherRefs(other.m_refs);
+    U* otherPtr(other.m_ptr);
+    if (otherPtr) otherRefs->incWeak(this);
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = otherPtr;
+    m_refs = otherRefs;
+    return *this;
+}
+
+template<typename T> template<typename U>
+wp<T>& wp<T>::operator = (const sp<U>& other)
+{
+    weakref_type* newRefs =
+        other != NULL ? other->createWeak(this) : 0;
+    U* otherPtr(other.m_ptr);
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = otherPtr;
+    m_refs = newRefs;
+    return *this;
+}
+
+template<typename T>
+void wp<T>::set_object_and_refs(T* other, weakref_type* refs)
+{
+    if (other) refs->incWeak(this);
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = other;
+    m_refs = refs;
+}
+
+template<typename T>
+sp<T> wp<T>::promote() const
+{
+    sp<T> result;
+    if (m_ptr && m_refs->attemptIncStrong(&result)) {
+        result.set_pointer(m_ptr);
+    }
+    return result;
+}
+
+template<typename T>
+void wp<T>::clear()
+{
+    if (m_ptr) {
+        m_refs->decWeak(this);
+        m_ptr = 0;
+    }
+}
+
+template <typename T>
+inline TextOutput& operator<<(TextOutput& to, const wp<T>& val)
+{
+    return printWeakPointer(to, val.unsafe_get());
+}
+
+// ---------------------------------------------------------------------------
+
+// this class just serves as a namespace so TYPE::moveReferences can stay
+// private.
+class ReferenceMover {
+public:
+    // it would be nice if we could make sure no extra code is generated
+    // for sp<TYPE> or wp<TYPE> when TYPE is a descendant of RefBase:
+    // Using a sp<RefBase> override doesn't work; it's a bit like we wanted
+    // a template<typename TYPE inherits RefBase> template...
+
+    template<typename TYPE> static inline
+    void move_references(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
+
+        class Renamer : public ReferenceRenamer {
+            sp<TYPE>* d;
+            sp<TYPE> const* s;
+            virtual void operator()(size_t i) const {
+                // The id are known to be the sp<>'s this pointer
+                TYPE::renameRefId(d[i].get(), &s[i], &d[i]);
+            }
+        public:
+            Renamer(sp<TYPE>* d, sp<TYPE> const* s) : s(s), d(d) { }
+        };
+
+        memmove(d, s, n*sizeof(sp<TYPE>));
+        TYPE::renameRefs(n, Renamer(d, s));
+    }
+
+
+    template<typename TYPE> static inline
+    void move_references(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
+
+        class Renamer : public ReferenceRenamer {
+            wp<TYPE>* d;
+            wp<TYPE> const* s;
+            virtual void operator()(size_t i) const {
+                // The id are known to be the wp<>'s this pointer
+                TYPE::renameRefId(d[i].get_refs(), &s[i], &d[i]);
+            }
+        public:
+            Renamer(wp<TYPE>* d, wp<TYPE> const* s) : s(s), d(d) { }
+        };
+
+        memmove(d, s, n*sizeof(wp<TYPE>));
+        TYPE::renameRefs(n, Renamer(d, s));
+    }
+};
+
+// specialization for moving sp<> and wp<> types.
+// these are used by the [Sorted|Keyed]Vector<> implementations
+// sp<> and wp<> need to be handled specially, because they do not
+// have trivial copy operation in the general case (see RefBase.cpp
+// when DEBUG ops are enabled), but can be implemented very
+// efficiently in most cases.
+
+template<typename TYPE> inline
+void move_forward_type(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
+    ReferenceMover::move_references(d, s, n);
+}
+
+template<typename TYPE> inline
+void move_backward_type(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
+    ReferenceMover::move_references(d, s, n);
+}
+
+template<typename TYPE> inline
+void move_forward_type(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
+    ReferenceMover::move_references(d, s, n);
+}
+
+template<typename TYPE> inline
+void move_backward_type(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
+    ReferenceMover::move_references(d, s, n);
+}
+
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_REF_BASE_H
diff --git a/include/utils/SharedBuffer.h b/include/utils/SharedBuffer.h
new file mode 100644
index 0000000..b670953
--- /dev/null
+++ b/include/utils/SharedBuffer.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SHARED_BUFFER_H
+#define ANDROID_SHARED_BUFFER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class SharedBuffer
+{
+public:
+
+    /* flags to use with release() */
+    enum {
+        eKeepStorage = 0x00000001
+    };
+
+    /*! allocate a buffer of size 'size' and acquire() it.
+     *  call release() to free it.
+     */
+    static          SharedBuffer*           alloc(size_t size);
+    
+    /*! free the memory associated with the SharedBuffer.
+     * Fails if there are any users associated with this SharedBuffer.
+     * In other words, the buffer must have been release by all its
+     * users.
+     */
+    static          ssize_t                 dealloc(const SharedBuffer* released);
+
+    //! access the data for read
+    inline          const void*             data() const;
+    
+    //! access the data for read/write
+    inline          void*                   data();
+
+    //! get size of the buffer
+    inline          size_t                  size() const;
+ 
+    //! get back a SharedBuffer object from its data
+    static  inline  SharedBuffer*           bufferFromData(void* data);
+    
+    //! get back a SharedBuffer object from its data
+    static  inline  const SharedBuffer*     bufferFromData(const void* data);
+
+    //! get the size of a SharedBuffer object from its data
+    static  inline  size_t                  sizeFromData(const void* data);
+    
+    //! edit the buffer (get a writtable, or non-const, version of it)
+                    SharedBuffer*           edit() const;
+
+    //! edit the buffer, resizing if needed
+                    SharedBuffer*           editResize(size_t size) const;
+
+    //! like edit() but fails if a copy is required
+                    SharedBuffer*           attemptEdit() const;
+    
+    //! resize and edit the buffer, loose it's content.
+                    SharedBuffer*           reset(size_t size) const;
+
+    //! acquire/release a reference on this buffer
+                    void                    acquire() const;
+                    
+    /*! release a reference on this buffer, with the option of not
+     * freeing the memory associated with it if it was the last reference
+     * returns the previous reference count
+     */     
+                    int32_t                 release(uint32_t flags = 0) const;
+    
+    //! returns wether or not we're the only owner
+    inline          bool                    onlyOwner() const;
+    
+
+private:
+        inline SharedBuffer() { }
+        inline ~SharedBuffer() { }
+        SharedBuffer(const SharedBuffer&);
+        SharedBuffer& operator = (const SharedBuffer&);
+ 
+        // 16 bytes. must be sized to preserve correct alignment.
+        mutable int32_t        mRefs;
+                size_t         mSize;
+                uint32_t       mReserved[2];
+};
+
+// ---------------------------------------------------------------------------
+
+const void* SharedBuffer::data() const {
+    return this + 1;
+}
+
+void* SharedBuffer::data() {
+    return this + 1;
+}
+
+size_t SharedBuffer::size() const {
+    return mSize;
+}
+
+SharedBuffer* SharedBuffer::bufferFromData(void* data) {
+    return data ? static_cast<SharedBuffer *>(data)-1 : 0;
+}
+    
+const SharedBuffer* SharedBuffer::bufferFromData(const void* data) {
+    return data ? static_cast<const SharedBuffer *>(data)-1 : 0;
+}
+
+size_t SharedBuffer::sizeFromData(const void* data) {
+    return data ? bufferFromData(data)->mSize : 0;
+}
+
+bool SharedBuffer::onlyOwner() const {
+    return (mRefs == 1);
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_VECTOR_H
diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h
new file mode 100644
index 0000000..c60680e
--- /dev/null
+++ b/include/utils/Singleton.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 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 ANDROID_UTILS_SINGLETON_H
+#define ANDROID_UTILS_SINGLETON_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+#include <cutils/compiler.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+template <typename TYPE>
+class ANDROID_API Singleton
+{
+public:
+    static TYPE& getInstance() {
+        Mutex::Autolock _l(sLock);
+        TYPE* instance = sInstance;
+        if (instance == 0) {
+            instance = new TYPE();
+            sInstance = instance;
+        }
+        return *instance;
+    }
+
+    static bool hasInstance() {
+        Mutex::Autolock _l(sLock);
+        return sInstance != 0;
+    }
+    
+protected:
+    ~Singleton() { };
+    Singleton() { };
+
+private:
+    Singleton(const Singleton&);
+    Singleton& operator = (const Singleton&);
+    static Mutex sLock;
+    static TYPE* sInstance;
+};
+
+/*
+ * use ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) in your implementation file
+ * (eg: <TYPE>.cpp) to create the static instance of Singleton<>'s attributes,
+ * and avoid to have a copy of them in each compilation units Singleton<TYPE>
+ * is used.
+ * NOTE: we use a version of Mutex ctor that takes a parameter, because
+ * for some unknown reason using the default ctor doesn't emit the variable!
+ */
+
+#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE)                 \
+    template<> Mutex Singleton< TYPE >::sLock(Mutex::PRIVATE);  \
+    template<> TYPE* Singleton< TYPE >::sInstance(0);           \
+    template class Singleton< TYPE >;
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_UTILS_SINGLETON_H
+
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
new file mode 100644
index 0000000..2d3e82a
--- /dev/null
+++ b/include/utils/SortedVector.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SORTED_VECTOR_H
+#define ANDROID_SORTED_VECTOR_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/log.h>
+
+#include <utils/Vector.h>
+#include <utils/VectorImpl.h>
+#include <utils/TypeHelpers.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+template <class TYPE>
+class SortedVector : private SortedVectorImpl
+{
+    friend class Vector<TYPE>;
+
+public:
+            typedef TYPE    value_type;
+    
+    /*! 
+     * Constructors and destructors
+     */
+    
+                            SortedVector();
+                            SortedVector(const SortedVector<TYPE>& rhs);
+    virtual                 ~SortedVector();
+
+    /*! copy operator */
+    const SortedVector<TYPE>&   operator = (const SortedVector<TYPE>& rhs) const;    
+    SortedVector<TYPE>&         operator = (const SortedVector<TYPE>& rhs);    
+
+    /*
+     * empty the vector
+     */
+
+    inline  void            clear()             { VectorImpl::clear(); }
+
+    /*! 
+     * vector stats
+     */
+
+    //! returns number of items in the vector
+    inline  size_t          size() const                { return VectorImpl::size(); }
+    //! returns whether or not the vector is empty
+    inline  bool            isEmpty() const             { return VectorImpl::isEmpty(); }
+    //! returns how many items can be stored without reallocating the backing store
+    inline  size_t          capacity() const            { return VectorImpl::capacity(); }
+    //! sets the capacity. capacity can never be reduced less than size()
+    inline  ssize_t         setCapacity(size_t size)    { return VectorImpl::setCapacity(size); }
+
+    /*! 
+     * C-style array access
+     */
+     
+    //! read-only C-style access 
+    inline  const TYPE*     array() const;
+
+    //! read-write C-style access. BE VERY CAREFUL when modifying the array
+    //! you must keep it sorted! You usually don't use this function.
+            TYPE*           editArray();
+
+            //! finds the index of an item
+            ssize_t         indexOf(const TYPE& item) const;
+            
+            //! finds where this item should be inserted
+            size_t          orderOf(const TYPE& item) const;
+            
+    
+    /*! 
+     * accessors
+     */
+
+    //! read-only access to an item at a given index
+    inline  const TYPE&     operator [] (size_t index) const;
+    //! alternate name for operator []
+    inline  const TYPE&     itemAt(size_t index) const;
+    //! stack-usage of the vector. returns the top of the stack (last element)
+            const TYPE&     top() const;
+
+    /*!
+     * modifying the array
+     */
+
+            //! add an item in the right place (and replace the one that is there)
+            ssize_t         add(const TYPE& item);
+            
+            //! editItemAt() MUST NOT change the order of this item
+            TYPE&           editItemAt(size_t index) {
+                return *( static_cast<TYPE *>(VectorImpl::editItemLocation(index)) );
+            }
+
+            //! merges a vector into this one
+            ssize_t         merge(const Vector<TYPE>& vector);
+            ssize_t         merge(const SortedVector<TYPE>& vector);
+            
+            //! removes an item
+            ssize_t         remove(const TYPE&);
+
+    //! remove several items
+    inline  ssize_t         removeItemsAt(size_t index, size_t count = 1);
+    //! remove one item
+    inline  ssize_t         removeAt(size_t index)  { return removeItemsAt(index); }
+            
+protected:
+    virtual void    do_construct(void* storage, size_t num) const;
+    virtual void    do_destroy(void* storage, size_t num) const;
+    virtual void    do_copy(void* dest, const void* from, size_t num) const;
+    virtual void    do_splat(void* dest, const void* item, size_t num) const;
+    virtual void    do_move_forward(void* dest, const void* from, size_t num) const;
+    virtual void    do_move_backward(void* dest, const void* from, size_t num) const;
+    virtual int     do_compare(const void* lhs, const void* rhs) const;
+};
+
+// SortedVector<T> can be trivially moved using memcpy() because moving does not
+// require any change to the underlying SharedBuffer contents or reference count.
+template<typename T> struct trait_trivial_move<SortedVector<T> > { enum { value = true }; };
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts from here...
+// ---------------------------------------------------------------------------
+
+template<class TYPE> inline
+SortedVector<TYPE>::SortedVector()
+    : SortedVectorImpl(sizeof(TYPE),
+                ((traits<TYPE>::has_trivial_ctor   ? HAS_TRIVIAL_CTOR   : 0)
+                |(traits<TYPE>::has_trivial_dtor   ? HAS_TRIVIAL_DTOR   : 0)
+                |(traits<TYPE>::has_trivial_copy   ? HAS_TRIVIAL_COPY   : 0))
+                )
+{
+}
+
+template<class TYPE> inline
+SortedVector<TYPE>::SortedVector(const SortedVector<TYPE>& rhs)
+    : SortedVectorImpl(rhs) {
+}
+
+template<class TYPE> inline
+SortedVector<TYPE>::~SortedVector() {
+    finish_vector();
+}
+
+template<class TYPE> inline
+SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) {
+    SortedVectorImpl::operator = (rhs);
+    return *this; 
+}
+
+template<class TYPE> inline
+const SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const {
+    SortedVectorImpl::operator = (rhs);
+    return *this; 
+}
+
+template<class TYPE> inline
+const TYPE* SortedVector<TYPE>::array() const {
+    return static_cast<const TYPE *>(arrayImpl());
+}
+
+template<class TYPE> inline
+TYPE* SortedVector<TYPE>::editArray() {
+    return static_cast<TYPE *>(editArrayImpl());
+}
+
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::operator[](size_t index) const {
+    LOG_FATAL_IF(index>=size(),
+            "%s: index=%u out of range (%u)", __PRETTY_FUNCTION__,
+            int(index), int(size()));
+    return *(array() + index);
+}
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::itemAt(size_t index) const {
+    return operator[](index);
+}
+
+template<class TYPE> inline
+const TYPE& SortedVector<TYPE>::top() const {
+    return *(array() + size() - 1);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::add(const TYPE& item) {
+    return SortedVectorImpl::add(&item);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::indexOf(const TYPE& item) const {
+    return SortedVectorImpl::indexOf(&item);
+}
+
+template<class TYPE> inline
+size_t SortedVector<TYPE>::orderOf(const TYPE& item) const {
+    return SortedVectorImpl::orderOf(&item);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::merge(const Vector<TYPE>& vector) {
+    return SortedVectorImpl::merge(reinterpret_cast<const VectorImpl&>(vector));
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::merge(const SortedVector<TYPE>& vector) {
+    return SortedVectorImpl::merge(reinterpret_cast<const SortedVectorImpl&>(vector));
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::remove(const TYPE& item) {
+    return SortedVectorImpl::remove(&item);
+}
+
+template<class TYPE> inline
+ssize_t SortedVector<TYPE>::removeItemsAt(size_t index, size_t count) {
+    return VectorImpl::removeItemsAt(index, count);
+}
+
+// ---------------------------------------------------------------------------
+
+template<class TYPE>
+void SortedVector<TYPE>::do_construct(void* storage, size_t num) const {
+    construct_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_destroy(void* storage, size_t num) const {
+    destroy_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_copy(void* dest, const void* from, size_t num) const {
+    copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_splat(void* dest, const void* item, size_t num) const {
+    splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const {
+    move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+void SortedVector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const {
+    move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+int SortedVector<TYPE>::do_compare(const void* lhs, const void* rhs) const {
+    return compare_type( *reinterpret_cast<const TYPE*>(lhs), *reinterpret_cast<const TYPE*>(rhs) );
+}
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_SORTED_VECTOR_H
diff --git a/include/utils/StopWatch.h b/include/utils/StopWatch.h
new file mode 100644
index 0000000..693dd3c
--- /dev/null
+++ b/include/utils/StopWatch.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_STOPWATCH_H
+#define ANDROID_STOPWATCH_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Timers.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class StopWatch
+{
+public:
+        StopWatch(  const char *name,
+                    int clock = SYSTEM_TIME_MONOTONIC,
+                    uint32_t flags = 0);
+        ~StopWatch();
+        
+        const char* name() const;
+        nsecs_t     lap();
+        nsecs_t     elapsedTime() const;
+
+        void        reset();
+        
+private:
+    const char*     mName;
+    int             mClock;
+    uint32_t        mFlags;
+    
+    struct lap_t {
+        nsecs_t     soFar;
+        nsecs_t     thisLap;
+    };
+    
+    nsecs_t         mStartTime;
+    lap_t           mLaps[8];
+    int             mNumLaps;
+};
+
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_STOPWATCH_H
diff --git a/include/utils/String16.h b/include/utils/String16.h
new file mode 100644
index 0000000..d131bfc
--- /dev/null
+++ b/include/utils/String16.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_STRING16_H
+#define ANDROID_STRING16_H
+
+#include <utils/Errors.h>
+#include <utils/SharedBuffer.h>
+#include <utils/Unicode.h>
+#include <utils/TypeHelpers.h>
+
+// ---------------------------------------------------------------------------
+
+extern "C" {
+
+}
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class String8;
+class TextOutput;
+
+//! This is a string holding UTF-16 characters.
+class String16
+{
+public:
+    /* use String16(StaticLinkage) if you're statically linking against
+     * libutils and declaring an empty static String16, e.g.:
+     *
+     *   static String16 sAStaticEmptyString(String16::kEmptyString);
+     *   static String16 sAnotherStaticEmptyString(sAStaticEmptyString);
+     */
+    enum StaticLinkage { kEmptyString };
+
+                                String16();
+    explicit                    String16(StaticLinkage);
+                                String16(const String16& o);
+                                String16(const String16& o,
+                                         size_t len,
+                                         size_t begin=0);
+    explicit                    String16(const char16_t* o);
+    explicit                    String16(const char16_t* o, size_t len);
+    explicit                    String16(const String8& o);
+    explicit                    String16(const char* o);
+    explicit                    String16(const char* o, size_t len);
+
+                                ~String16();
+    
+    inline  const char16_t*     string() const;
+    inline  size_t              size() const;
+    
+    inline  const SharedBuffer* sharedBuffer() const;
+    
+            void                setTo(const String16& other);
+            status_t            setTo(const char16_t* other);
+            status_t            setTo(const char16_t* other, size_t len);
+            status_t            setTo(const String16& other,
+                                      size_t len,
+                                      size_t begin=0);
+    
+            status_t            append(const String16& other);
+            status_t            append(const char16_t* other, size_t len);
+            
+    inline  String16&           operator=(const String16& other);
+    
+    inline  String16&           operator+=(const String16& other);
+    inline  String16            operator+(const String16& other) const;
+
+            status_t            insert(size_t pos, const char16_t* chrs);
+            status_t            insert(size_t pos,
+                                       const char16_t* chrs, size_t len);
+
+            ssize_t             findFirst(char16_t c) const;
+            ssize_t             findLast(char16_t c) const;
+
+            bool                startsWith(const String16& prefix) const;
+            bool                startsWith(const char16_t* prefix) const;
+            
+            status_t            makeLower();
+
+            status_t            replaceAll(char16_t replaceThis,
+                                           char16_t withThis);
+
+            status_t            remove(size_t len, size_t begin=0);
+
+    inline  int                 compare(const String16& other) const;
+
+    inline  bool                operator<(const String16& other) const;
+    inline  bool                operator<=(const String16& other) const;
+    inline  bool                operator==(const String16& other) const;
+    inline  bool                operator!=(const String16& other) const;
+    inline  bool                operator>=(const String16& other) const;
+    inline  bool                operator>(const String16& other) const;
+    
+    inline  bool                operator<(const char16_t* other) const;
+    inline  bool                operator<=(const char16_t* other) const;
+    inline  bool                operator==(const char16_t* other) const;
+    inline  bool                operator!=(const char16_t* other) const;
+    inline  bool                operator>=(const char16_t* other) const;
+    inline  bool                operator>(const char16_t* other) const;
+    
+    inline                      operator const char16_t*() const;
+    
+private:
+            const char16_t*     mString;
+};
+
+// String16 can be trivially moved using memcpy() because moving does not
+// require any change to the underlying SharedBuffer contents or reference count.
+ANDROID_TRIVIAL_MOVE_TRAIT(String16)
+
+// ---------------------------------------------------------------------------
+// No user servicable parts below.
+
+inline int compare_type(const String16& lhs, const String16& rhs)
+{
+    return lhs.compare(rhs);
+}
+
+inline int strictly_order_type(const String16& lhs, const String16& rhs)
+{
+    return compare_type(lhs, rhs) < 0;
+}
+
+inline const char16_t* String16::string() const
+{
+    return mString;
+}
+
+inline size_t String16::size() const
+{
+    return SharedBuffer::sizeFromData(mString)/sizeof(char16_t)-1;
+}
+
+inline const SharedBuffer* String16::sharedBuffer() const
+{
+    return SharedBuffer::bufferFromData(mString);
+}
+
+inline String16& String16::operator=(const String16& other)
+{
+    setTo(other);
+    return *this;
+}
+
+inline String16& String16::operator+=(const String16& other)
+{
+    append(other);
+    return *this;
+}
+
+inline String16 String16::operator+(const String16& other) const
+{
+    String16 tmp(*this);
+    tmp += other;
+    return tmp;
+}
+
+inline int String16::compare(const String16& other) const
+{
+    return strzcmp16(mString, size(), other.mString, other.size());
+}
+
+inline bool String16::operator<(const String16& other) const
+{
+    return strzcmp16(mString, size(), other.mString, other.size()) < 0;
+}
+
+inline bool String16::operator<=(const String16& other) const
+{
+    return strzcmp16(mString, size(), other.mString, other.size()) <= 0;
+}
+
+inline bool String16::operator==(const String16& other) const
+{
+    return strzcmp16(mString, size(), other.mString, other.size()) == 0;
+}
+
+inline bool String16::operator!=(const String16& other) const
+{
+    return strzcmp16(mString, size(), other.mString, other.size()) != 0;
+}
+
+inline bool String16::operator>=(const String16& other) const
+{
+    return strzcmp16(mString, size(), other.mString, other.size()) >= 0;
+}
+
+inline bool String16::operator>(const String16& other) const
+{
+    return strzcmp16(mString, size(), other.mString, other.size()) > 0;
+}
+
+inline bool String16::operator<(const char16_t* other) const
+{
+    return strcmp16(mString, other) < 0;
+}
+
+inline bool String16::operator<=(const char16_t* other) const
+{
+    return strcmp16(mString, other) <= 0;
+}
+
+inline bool String16::operator==(const char16_t* other) const
+{
+    return strcmp16(mString, other) == 0;
+}
+
+inline bool String16::operator!=(const char16_t* other) const
+{
+    return strcmp16(mString, other) != 0;
+}
+
+inline bool String16::operator>=(const char16_t* other) const
+{
+    return strcmp16(mString, other) >= 0;
+}
+
+inline bool String16::operator>(const char16_t* other) const
+{
+    return strcmp16(mString, other) > 0;
+}
+
+inline String16::operator const char16_t*() const
+{
+    return mString;
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_STRING16_H
diff --git a/include/utils/String8.h b/include/utils/String8.h
new file mode 100644
index 0000000..ef59470
--- /dev/null
+++ b/include/utils/String8.h
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_STRING8_H
+#define ANDROID_STRING8_H
+
+#include <utils/Errors.h>
+#include <utils/SharedBuffer.h>
+#include <utils/Unicode.h>
+#include <utils/TypeHelpers.h>
+
+#include <string.h> // for strcmp
+#include <stdarg.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class String16;
+class TextOutput;
+
+//! This is a string holding UTF-8 characters. Does not allow the value more
+// than 0x10FFFF, which is not valid unicode codepoint.
+class String8
+{
+public:
+    /* use String8(StaticLinkage) if you're statically linking against
+     * libutils and declaring an empty static String8, e.g.:
+     *
+     *   static String8 sAStaticEmptyString(String8::kEmptyString);
+     *   static String8 sAnotherStaticEmptyString(sAStaticEmptyString);
+     */
+    enum StaticLinkage { kEmptyString };
+
+                                String8();
+    explicit                    String8(StaticLinkage);
+                                String8(const String8& o);
+    explicit                    String8(const char* o);
+    explicit                    String8(const char* o, size_t numChars);
+    
+    explicit                    String8(const String16& o);
+    explicit                    String8(const char16_t* o);
+    explicit                    String8(const char16_t* o, size_t numChars);
+    explicit                    String8(const char32_t* o);
+    explicit                    String8(const char32_t* o, size_t numChars);
+                                ~String8();
+
+    static inline const String8 empty();
+
+    static String8              format(const char* fmt, ...) __attribute__((format (printf, 1, 2)));
+    static String8              formatV(const char* fmt, va_list args);
+
+    inline  const char*         string() const;
+    inline  size_t              size() const;
+    inline  size_t              length() const;
+    inline  size_t              bytes() const;
+    inline  bool                isEmpty() const;
+    
+    inline  const SharedBuffer* sharedBuffer() const;
+    
+            void                clear();
+
+            void                setTo(const String8& other);
+            status_t            setTo(const char* other);
+            status_t            setTo(const char* other, size_t numChars);
+            status_t            setTo(const char16_t* other, size_t numChars);
+            status_t            setTo(const char32_t* other,
+                                      size_t length);
+
+            status_t            append(const String8& other);
+            status_t            append(const char* other);
+            status_t            append(const char* other, size_t numChars);
+
+            status_t            appendFormat(const char* fmt, ...)
+                    __attribute__((format (printf, 2, 3)));
+            status_t            appendFormatV(const char* fmt, va_list args);
+
+            // Note that this function takes O(N) time to calculate the value.
+            // No cache value is stored.
+            size_t              getUtf32Length() const;
+            int32_t             getUtf32At(size_t index,
+                                           size_t *next_index) const;
+            void                getUtf32(char32_t* dst) const;
+
+    inline  String8&            operator=(const String8& other);
+    inline  String8&            operator=(const char* other);
+    
+    inline  String8&            operator+=(const String8& other);
+    inline  String8             operator+(const String8& other) const;
+    
+    inline  String8&            operator+=(const char* other);
+    inline  String8             operator+(const char* other) const;
+
+    inline  int                 compare(const String8& other) const;
+
+    inline  bool                operator<(const String8& other) const;
+    inline  bool                operator<=(const String8& other) const;
+    inline  bool                operator==(const String8& other) const;
+    inline  bool                operator!=(const String8& other) const;
+    inline  bool                operator>=(const String8& other) const;
+    inline  bool                operator>(const String8& other) const;
+    
+    inline  bool                operator<(const char* other) const;
+    inline  bool                operator<=(const char* other) const;
+    inline  bool                operator==(const char* other) const;
+    inline  bool                operator!=(const char* other) const;
+    inline  bool                operator>=(const char* other) const;
+    inline  bool                operator>(const char* other) const;
+    
+    inline                      operator const char*() const;
+    
+            char*               lockBuffer(size_t size);
+            void                unlockBuffer();
+            status_t            unlockBuffer(size_t size);
+            
+            // return the index of the first byte of other in this at or after
+            // start, or -1 if not found
+            ssize_t             find(const char* other, size_t start = 0) const;
+
+            void                toLower();
+            void                toLower(size_t start, size_t numChars);
+            void                toUpper();
+            void                toUpper(size_t start, size_t numChars);
+
+    /*
+     * These methods operate on the string as if it were a path name.
+     */
+
+    /*
+     * Set the filename field to a specific value.
+     *
+     * Normalizes the filename, removing a trailing '/' if present.
+     */
+    void setPathName(const char* name);
+    void setPathName(const char* name, size_t numChars);
+
+    /*
+     * Get just the filename component.
+     *
+     * "/tmp/foo/bar.c" --> "bar.c"
+     */
+    String8 getPathLeaf(void) const;
+
+    /*
+     * Remove the last (file name) component, leaving just the directory
+     * name.
+     *
+     * "/tmp/foo/bar.c" --> "/tmp/foo"
+     * "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX
+     * "bar.c" --> ""
+     */
+    String8 getPathDir(void) const;
+
+    /*
+     * Retrieve the front (root dir) component.  Optionally also return the
+     * remaining components.
+     *
+     * "/tmp/foo/bar.c" --> "tmp" (remain = "foo/bar.c")
+     * "/tmp" --> "tmp" (remain = "")
+     * "bar.c" --> "bar.c" (remain = "")
+     */
+    String8 walkPath(String8* outRemains = NULL) const;
+
+    /*
+     * Return the filename extension.  This is the last '.' and any number
+     * of characters that follow it.  The '.' is included in case we
+     * decide to expand our definition of what constitutes an extension.
+     *
+     * "/tmp/foo/bar.c" --> ".c"
+     * "/tmp" --> ""
+     * "/tmp/foo.bar/baz" --> ""
+     * "foo.jpeg" --> ".jpeg"
+     * "foo." --> ""
+     */
+    String8 getPathExtension(void) const;
+
+    /*
+     * Return the path without the extension.  Rules for what constitutes
+     * an extension are described in the comment for getPathExtension().
+     *
+     * "/tmp/foo/bar.c" --> "/tmp/foo/bar"
+     */
+    String8 getBasePath(void) const;
+
+    /*
+     * Add a component to the pathname.  We guarantee that there is
+     * exactly one path separator between the old path and the new.
+     * If there is no existing name, we just copy the new name in.
+     *
+     * If leaf is a fully qualified path (i.e. starts with '/', it
+     * replaces whatever was there before.
+     */
+    String8& appendPath(const char* leaf);
+    String8& appendPath(const String8& leaf)  { return appendPath(leaf.string()); }
+
+    /*
+     * Like appendPath(), but does not affect this string.  Returns a new one instead.
+     */
+    String8 appendPathCopy(const char* leaf) const
+                                             { String8 p(*this); p.appendPath(leaf); return p; }
+    String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.string()); }
+
+    /*
+     * Converts all separators in this string to /, the default path separator.
+     *
+     * If the default OS separator is backslash, this converts all
+     * backslashes to slashes, in-place. Otherwise it does nothing.
+     * Returns self.
+     */
+    String8& convertToResPath();
+
+private:
+            status_t            real_append(const char* other, size_t numChars);
+            char*               find_extension(void) const;
+
+            const char* mString;
+};
+
+// String8 can be trivially moved using memcpy() because moving does not
+// require any change to the underlying SharedBuffer contents or reference count.
+ANDROID_TRIVIAL_MOVE_TRAIT(String8)
+
+// ---------------------------------------------------------------------------
+// No user servicable parts below.
+
+inline int compare_type(const String8& lhs, const String8& rhs)
+{
+    return lhs.compare(rhs);
+}
+
+inline int strictly_order_type(const String8& lhs, const String8& rhs)
+{
+    return compare_type(lhs, rhs) < 0;
+}
+
+inline const String8 String8::empty() {
+    return String8();
+}
+
+inline const char* String8::string() const
+{
+    return mString;
+}
+
+inline size_t String8::length() const
+{
+    return SharedBuffer::sizeFromData(mString)-1;
+}
+
+inline size_t String8::size() const
+{
+    return length();
+}
+
+inline bool String8::isEmpty() const
+{
+    return length() == 0;
+}
+
+inline size_t String8::bytes() const
+{
+    return SharedBuffer::sizeFromData(mString)-1;
+}
+
+inline const SharedBuffer* String8::sharedBuffer() const
+{
+    return SharedBuffer::bufferFromData(mString);
+}
+
+inline String8& String8::operator=(const String8& other)
+{
+    setTo(other);
+    return *this;
+}
+
+inline String8& String8::operator=(const char* other)
+{
+    setTo(other);
+    return *this;
+}
+
+inline String8& String8::operator+=(const String8& other)
+{
+    append(other);
+    return *this;
+}
+
+inline String8 String8::operator+(const String8& other) const
+{
+    String8 tmp(*this);
+    tmp += other;
+    return tmp;
+}
+
+inline String8& String8::operator+=(const char* other)
+{
+    append(other);
+    return *this;
+}
+
+inline String8 String8::operator+(const char* other) const
+{
+    String8 tmp(*this);
+    tmp += other;
+    return tmp;
+}
+
+inline int String8::compare(const String8& other) const
+{
+    return strcmp(mString, other.mString);
+}
+
+inline bool String8::operator<(const String8& other) const
+{
+    return strcmp(mString, other.mString) < 0;
+}
+
+inline bool String8::operator<=(const String8& other) const
+{
+    return strcmp(mString, other.mString) <= 0;
+}
+
+inline bool String8::operator==(const String8& other) const
+{
+    return strcmp(mString, other.mString) == 0;
+}
+
+inline bool String8::operator!=(const String8& other) const
+{
+    return strcmp(mString, other.mString) != 0;
+}
+
+inline bool String8::operator>=(const String8& other) const
+{
+    return strcmp(mString, other.mString) >= 0;
+}
+
+inline bool String8::operator>(const String8& other) const
+{
+    return strcmp(mString, other.mString) > 0;
+}
+
+inline bool String8::operator<(const char* other) const
+{
+    return strcmp(mString, other) < 0;
+}
+
+inline bool String8::operator<=(const char* other) const
+{
+    return strcmp(mString, other) <= 0;
+}
+
+inline bool String8::operator==(const char* other) const
+{
+    return strcmp(mString, other) == 0;
+}
+
+inline bool String8::operator!=(const char* other) const
+{
+    return strcmp(mString, other) != 0;
+}
+
+inline bool String8::operator>=(const char* other) const
+{
+    return strcmp(mString, other) >= 0;
+}
+
+inline bool String8::operator>(const char* other) const
+{
+    return strcmp(mString, other) > 0;
+}
+
+inline String8::operator const char*() const
+{
+    return mString;
+}
+
+}  // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_STRING8_H
diff --git a/include/utils/StrongPointer.h b/include/utils/StrongPointer.h
new file mode 100644
index 0000000..aba9577
--- /dev/null
+++ b/include/utils/StrongPointer.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_STRONG_POINTER_H
+#define ANDROID_STRONG_POINTER_H
+
+#include <cutils/atomic.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+template<typename T> class wp;
+
+// ---------------------------------------------------------------------------
+
+#define COMPARE(_op_)                                           \
+inline bool operator _op_ (const sp<T>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+inline bool operator _op_ (const T* o) const {                  \
+    return m_ptr _op_ o;                                        \
+}                                                               \
+template<typename U>                                            \
+inline bool operator _op_ (const sp<U>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+template<typename U>                                            \
+inline bool operator _op_ (const U* o) const {                  \
+    return m_ptr _op_ o;                                        \
+}                                                               \
+inline bool operator _op_ (const wp<T>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+template<typename U>                                            \
+inline bool operator _op_ (const wp<U>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}
+
+// ---------------------------------------------------------------------------
+
+template<typename T>
+class sp {
+public:
+    inline sp() : m_ptr(0) { }
+
+    sp(T* other);
+    sp(const sp<T>& other);
+    template<typename U> sp(U* other);
+    template<typename U> sp(const sp<U>& other);
+
+    ~sp();
+
+    // Assignment
+
+    sp& operator = (T* other);
+    sp& operator = (const sp<T>& other);
+
+    template<typename U> sp& operator = (const sp<U>& other);
+    template<typename U> sp& operator = (U* other);
+
+    //! Special optimization for use by ProcessState (and nobody else).
+    void force_set(T* other);
+
+    // Reset
+
+    void clear();
+
+    // Accessors
+
+    inline  T&      operator* () const  { return *m_ptr; }
+    inline  T*      operator-> () const { return m_ptr;  }
+    inline  T*      get() const         { return m_ptr; }
+
+    // Operators
+
+    COMPARE(==)
+    COMPARE(!=)
+    COMPARE(>)
+    COMPARE(<)
+    COMPARE(<=)
+    COMPARE(>=)
+
+private:    
+    template<typename Y> friend class sp;
+    template<typename Y> friend class wp;
+    void set_pointer(T* ptr);
+    T* m_ptr;
+};
+
+#undef COMPARE
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts below here.
+
+template<typename T>
+sp<T>::sp(T* other)
+        : m_ptr(other) {
+    if (other)
+        other->incStrong(this);
+}
+
+template<typename T>
+sp<T>::sp(const sp<T>& other)
+        : m_ptr(other.m_ptr) {
+    if (m_ptr)
+        m_ptr->incStrong(this);
+}
+
+template<typename T> template<typename U>
+sp<T>::sp(U* other)
+        : m_ptr(other) {
+    if (other)
+        ((T*) other)->incStrong(this);
+}
+
+template<typename T> template<typename U>
+sp<T>::sp(const sp<U>& other)
+        : m_ptr(other.m_ptr) {
+    if (m_ptr)
+        m_ptr->incStrong(this);
+}
+
+template<typename T>
+sp<T>::~sp() {
+    if (m_ptr)
+        m_ptr->decStrong(this);
+}
+
+template<typename T>
+sp<T>& sp<T>::operator =(const sp<T>& other) {
+    T* otherPtr(other.m_ptr);
+    if (otherPtr)
+        otherPtr->incStrong(this);
+    if (m_ptr)
+        m_ptr->decStrong(this);
+    m_ptr = otherPtr;
+    return *this;
+}
+
+template<typename T>
+sp<T>& sp<T>::operator =(T* other) {
+    if (other)
+        other->incStrong(this);
+    if (m_ptr)
+        m_ptr->decStrong(this);
+    m_ptr = other;
+    return *this;
+}
+
+template<typename T> template<typename U>
+sp<T>& sp<T>::operator =(const sp<U>& other) {
+    T* otherPtr(other.m_ptr);
+    if (otherPtr)
+        otherPtr->incStrong(this);
+    if (m_ptr)
+        m_ptr->decStrong(this);
+    m_ptr = otherPtr;
+    return *this;
+}
+
+template<typename T> template<typename U>
+sp<T>& sp<T>::operator =(U* other) {
+    if (other)
+        ((T*) other)->incStrong(this);
+    if (m_ptr)
+        m_ptr->decStrong(this);
+    m_ptr = other;
+    return *this;
+}
+
+template<typename T>
+void sp<T>::force_set(T* other) {
+    other->forceIncStrong(this);
+    m_ptr = other;
+}
+
+template<typename T>
+void sp<T>::clear() {
+    if (m_ptr) {
+        m_ptr->decStrong(this);
+        m_ptr = 0;
+    }
+}
+
+template<typename T>
+void sp<T>::set_pointer(T* ptr) {
+    m_ptr = ptr;
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_STRONG_POINTER_H
diff --git a/include/cutils/zygote.h b/include/utils/SystemClock.h
similarity index 62%
copy from include/cutils/zygote.h
copy to include/utils/SystemClock.h
index a7480d3..01db340 100644
--- a/include/cutils/zygote.h
+++ b/include/utils/SystemClock.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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.
@@ -14,18 +14,19 @@
  * limitations under the License.
  */
 
-#ifndef __CUTILS_ZYGOTE_H
-#define __CUTILS_ZYGOTE_H
+#ifndef ANDROID_UTILS_SYSTEMCLOCK_H
+#define ANDROID_UTILS_SYSTEMCLOCK_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include <stdint.h>
+#include <sys/types.h>
 
-int zygote_run_oneshot(int sendStdio, int argc, const char **argv);
-int zygote_run(int argc, const char **argv);
+namespace android {
 
-#ifdef __cplusplus
-}
-#endif
+int64_t uptimeMillis();
+int64_t elapsedRealtime();
+int64_t elapsedRealtimeNano();
 
-#endif /* __CUTILS_ZYGOTE_H */
+}; // namespace android
+
+#endif // ANDROID_UTILS_SYSTEMCLOCK_H
+
diff --git a/include/utils/Thread.h b/include/utils/Thread.h
new file mode 100644
index 0000000..df30611
--- /dev/null
+++ b/include/utils/Thread.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2007 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 _LIBS_UTILS_THREAD_H
+#define _LIBS_UTILS_THREAD_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <time.h>
+
+#if defined(HAVE_PTHREADS)
+# include <pthread.h>
+#endif
+
+#include <utils/Condition.h>
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+#include <utils/ThreadDefs.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Thread : virtual public RefBase
+{
+public:
+    // Create a Thread object, but doesn't create or start the associated
+    // thread. See the run() method.
+                        Thread(bool canCallJava = true);
+    virtual             ~Thread();
+
+    // Start the thread in threadLoop() which needs to be implemented.
+    virtual status_t    run(    const char* name = 0,
+                                int32_t priority = PRIORITY_DEFAULT,
+                                size_t stack = 0);
+    
+    // Ask this object's thread to exit. This function is asynchronous, when the
+    // function returns the thread might still be running. Of course, this
+    // function can be called from a different thread.
+    virtual void        requestExit();
+
+    // Good place to do one-time initializations
+    virtual status_t    readyToRun();
+    
+    // Call requestExit() and wait until this object's thread exits.
+    // BE VERY CAREFUL of deadlocks. In particular, it would be silly to call
+    // this function from this object's thread. Will return WOULD_BLOCK in
+    // that case.
+            status_t    requestExitAndWait();
+
+    // Wait until this object's thread exits. Returns immediately if not yet running.
+    // Do not call from this object's thread; will return WOULD_BLOCK in that case.
+            status_t    join();
+
+    // Indicates whether this thread is running or not.
+            bool        isRunning() const;
+
+#ifdef HAVE_ANDROID_OS
+    // Return the thread's kernel ID, same as the thread itself calling gettid() or
+    // androidGetTid(), or -1 if the thread is not running.
+            pid_t       getTid() const;
+#endif
+
+protected:
+    // exitPending() returns true if requestExit() has been called.
+            bool        exitPending() const;
+    
+private:
+    // Derived class must implement threadLoop(). The thread starts its life
+    // here. There are two ways of using the Thread object:
+    // 1) loop: if threadLoop() returns true, it will be called again if
+    //          requestExit() wasn't called.
+    // 2) once: if threadLoop() returns false, the thread will exit upon return.
+    virtual bool        threadLoop() = 0;
+
+private:
+    Thread& operator=(const Thread&);
+    static  int             _threadLoop(void* user);
+    const   bool            mCanCallJava;
+    // always hold mLock when reading or writing
+            thread_id_t     mThread;
+    mutable Mutex           mLock;
+            Condition       mThreadExitedCondition;
+            status_t        mStatus;
+    // note that all accesses of mExitPending and mRunning need to hold mLock
+    volatile bool           mExitPending;
+    volatile bool           mRunning;
+            sp<Thread>      mHoldSelf;
+#ifdef HAVE_ANDROID_OS
+    // legacy for debugging, not used by getTid() as it is set by the child thread
+    // and so is not initialized until the child reaches that point
+            pid_t           mTid;
+#endif
+};
+
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+#endif // _LIBS_UTILS_THREAD_H
+// ---------------------------------------------------------------------------
diff --git a/include/utils/ThreadDefs.h b/include/utils/ThreadDefs.h
new file mode 100644
index 0000000..9711c13
--- /dev/null
+++ b/include/utils/ThreadDefs.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 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 _LIBS_UTILS_THREAD_DEFS_H
+#define _LIBS_UTILS_THREAD_DEFS_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <system/graphics.h>
+#include <system/thread_defs.h>
+
+// ---------------------------------------------------------------------------
+// C API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void* android_thread_id_t;
+
+typedef int (*android_thread_func_t)(void*);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+// ---------------------------------------------------------------------------
+// C++ API
+#ifdef __cplusplus
+namespace android {
+// ---------------------------------------------------------------------------
+
+typedef android_thread_id_t thread_id_t;
+typedef android_thread_func_t thread_func_t;
+
+enum {
+    PRIORITY_LOWEST         = ANDROID_PRIORITY_LOWEST,
+    PRIORITY_BACKGROUND     = ANDROID_PRIORITY_BACKGROUND,
+    PRIORITY_NORMAL         = ANDROID_PRIORITY_NORMAL,
+    PRIORITY_FOREGROUND     = ANDROID_PRIORITY_FOREGROUND,
+    PRIORITY_DISPLAY        = ANDROID_PRIORITY_DISPLAY,
+    PRIORITY_URGENT_DISPLAY = ANDROID_PRIORITY_URGENT_DISPLAY,
+    PRIORITY_AUDIO          = ANDROID_PRIORITY_AUDIO,
+    PRIORITY_URGENT_AUDIO   = ANDROID_PRIORITY_URGENT_AUDIO,
+    PRIORITY_HIGHEST        = ANDROID_PRIORITY_HIGHEST,
+    PRIORITY_DEFAULT        = ANDROID_PRIORITY_DEFAULT,
+    PRIORITY_MORE_FAVORABLE = ANDROID_PRIORITY_MORE_FAVORABLE,
+    PRIORITY_LESS_FAVORABLE = ANDROID_PRIORITY_LESS_FAVORABLE,
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+#endif  // __cplusplus
+// ---------------------------------------------------------------------------
+
+
+#endif // _LIBS_UTILS_THREAD_DEFS_H
diff --git a/include/utils/Timers.h b/include/utils/Timers.h
new file mode 100644
index 0000000..d015421
--- /dev/null
+++ b/include/utils/Timers.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Timer functions.
+//
+#ifndef _LIBS_UTILS_TIMERS_H
+#define _LIBS_UTILS_TIMERS_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+// ------------------------------------------------------------------
+// C API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int64_t nsecs_t;       // nano-seconds
+
+static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs)
+{
+    return secs*1000000000;
+}
+
+static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs)
+{
+    return secs*1000000;
+}
+
+static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs)
+{
+    return secs*1000;
+}
+
+static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs)
+{
+    return secs/1000000000;
+}
+
+static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs)
+{
+    return secs/1000000;
+}
+
+static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs)
+{
+    return secs/1000;
+}
+
+static inline nsecs_t s2ns(nsecs_t v)  {return seconds_to_nanoseconds(v);}
+static inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);}
+static inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);}
+static inline nsecs_t ns2s(nsecs_t v)  {return nanoseconds_to_seconds(v);}
+static inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);}
+static inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);}
+
+static inline nsecs_t seconds(nsecs_t v)      { return s2ns(v); }
+static inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); }
+static inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); }
+
+enum {
+    SYSTEM_TIME_REALTIME = 0,  // system-wide realtime clock
+    SYSTEM_TIME_MONOTONIC = 1, // monotonic time since unspecified starting point
+    SYSTEM_TIME_PROCESS = 2,   // high-resolution per-process clock
+    SYSTEM_TIME_THREAD = 3,    // high-resolution per-thread clock
+    SYSTEM_TIME_BOOTTIME = 4   // same as SYSTEM_TIME_MONOTONIC, but including CPU suspend time
+};
+
+// return the system-time according to the specified clock
+#ifdef __cplusplus
+nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC);
+#else
+nsecs_t systemTime(int clock);
+#endif // def __cplusplus
+
+/**
+ * Returns the number of milliseconds to wait between the reference time and the timeout time.
+ * If the timeout is in the past relative to the reference time, returns 0.
+ * If the timeout is more than INT_MAX milliseconds in the future relative to the reference time,
+ * such as when timeoutTime == LLONG_MAX, returns -1 to indicate an infinite timeout delay.
+ * Otherwise, returns the difference between the reference time and timeout time
+ * rounded up to the next millisecond.
+ */
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _LIBS_UTILS_TIMERS_H
diff --git a/include/utils/Tokenizer.h b/include/utils/Tokenizer.h
new file mode 100644
index 0000000..bb25f37
--- /dev/null
+++ b/include/utils/Tokenizer.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2010 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 _UTILS_TOKENIZER_H
+#define _UTILS_TOKENIZER_H
+
+#include <assert.h>
+#include <utils/Errors.h>
+#include <utils/FileMap.h>
+#include <utils/String8.h>
+
+namespace android {
+
+/**
+ * A simple tokenizer for loading and parsing ASCII text files line by line.
+ */
+class Tokenizer {
+    Tokenizer(const String8& filename, FileMap* fileMap, char* buffer,
+            bool ownBuffer, size_t length);
+
+public:
+    ~Tokenizer();
+
+    /**
+     * Opens a file and maps it into memory.
+     *
+     * Returns NO_ERROR and a tokenizer for the file, if successful.
+     * Otherwise returns an error and sets outTokenizer to NULL.
+     */
+    static status_t open(const String8& filename, Tokenizer** outTokenizer);
+
+    /**
+     * Prepares to tokenize the contents of a string.
+     *
+     * Returns NO_ERROR and a tokenizer for the string, if successful.
+     * Otherwise returns an error and sets outTokenizer to NULL.
+     */
+    static status_t fromContents(const String8& filename,
+            const char* contents, Tokenizer** outTokenizer);
+
+    /**
+     * Returns true if at the end of the file.
+     */
+    inline bool isEof() const { return mCurrent == getEnd(); }
+
+    /**
+     * Returns true if at the end of the line or end of the file.
+     */
+    inline bool isEol() const { return isEof() || *mCurrent == '\n'; }
+
+    /**
+     * Gets the name of the file.
+     */
+    inline String8 getFilename() const { return mFilename; }
+
+    /**
+     * Gets a 1-based line number index for the current position.
+     */
+    inline int32_t getLineNumber() const { return mLineNumber; }
+
+    /**
+     * Formats a location string consisting of the filename and current line number.
+     * Returns a string like "MyFile.txt:33".
+     */
+    String8 getLocation() const;
+
+    /**
+     * Gets the character at the current position.
+     * Returns null at end of file.
+     */
+    inline char peekChar() const { return isEof() ? '\0' : *mCurrent; }
+
+    /**
+     * Gets the remainder of the current line as a string, excluding the newline character.
+     */
+    String8 peekRemainderOfLine() const;
+
+    /**
+     * Gets the character at the current position and advances past it.
+     * Returns null at end of file.
+     */
+    inline char nextChar() { return isEof() ? '\0' : *(mCurrent++); }
+
+    /**
+     * Gets the next token on this line stopping at the specified delimiters
+     * or the end of the line whichever comes first and advances past it.
+     * Also stops at embedded nulls.
+     * Returns the token or an empty string if the current character is a delimiter
+     * or is at the end of the line.
+     */
+    String8 nextToken(const char* delimiters);
+
+    /**
+     * Advances to the next line.
+     * Does nothing if already at the end of the file.
+     */
+    void nextLine();
+
+    /**
+     * Skips over the specified delimiters in the line.
+     * Also skips embedded nulls.
+     */
+    void skipDelimiters(const char* delimiters);
+
+private:
+    Tokenizer(const Tokenizer& other); // not copyable
+
+    String8 mFilename;
+    FileMap* mFileMap;
+    char* mBuffer;
+    bool mOwnBuffer;
+    size_t mLength;
+
+    const char* mCurrent;
+    int32_t mLineNumber;
+
+    inline const char* getEnd() const { return mBuffer + mLength; }
+
+};
+
+} // namespace android
+
+#endif // _UTILS_TOKENIZER_H
diff --git a/include/utils/Trace.h b/include/utils/Trace.h
new file mode 100644
index 0000000..6ee343d
--- /dev/null
+++ b/include/utils/Trace.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 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 ANDROID_TRACE_H
+#define ANDROID_TRACE_H
+
+#ifdef HAVE_ANDROID_OS
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/compiler.h>
+#include <utils/threads.h>
+#include <cutils/trace.h>
+
+// See <cutils/trace.h> for more ATRACE_* macros.
+
+// ATRACE_NAME traces the beginning and end of the current scope.  To trace
+// the correct start and end times this macro should be declared first in the
+// scope body.
+#define ATRACE_NAME(name) android::ScopedTrace ___tracer(ATRACE_TAG, name)
+// ATRACE_CALL is an ATRACE_NAME that uses the current function name.
+#define ATRACE_CALL() ATRACE_NAME(__FUNCTION__)
+
+namespace android {
+
+class ScopedTrace {
+public:
+inline ScopedTrace(uint64_t tag, const char* name)
+    : mTag(tag) {
+    atrace_begin(mTag,name);
+}
+
+inline ~ScopedTrace() {
+    atrace_end(mTag);
+}
+
+private:
+    uint64_t mTag;
+};
+
+}; // namespace android
+
+#else // HAVE_ANDROID_OS
+
+#define ATRACE_NAME(...)
+#define ATRACE_CALL()
+
+#endif // HAVE_ANDROID_OS
+
+#endif // ANDROID_TRACE_H
diff --git a/include/utils/TypeHelpers.h b/include/utils/TypeHelpers.h
new file mode 100644
index 0000000..13c9081
--- /dev/null
+++ b/include/utils/TypeHelpers.h
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_TYPE_HELPERS_H
+#define ANDROID_TYPE_HELPERS_H
+
+#include <new>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+/*
+ * Types traits
+ */
+
+template <typename T> struct trait_trivial_ctor { enum { value = false }; };
+template <typename T> struct trait_trivial_dtor { enum { value = false }; };
+template <typename T> struct trait_trivial_copy { enum { value = false }; };
+template <typename T> struct trait_trivial_move { enum { value = false }; };
+template <typename T> struct trait_pointer      { enum { value = false }; };    
+template <typename T> struct trait_pointer<T*>  { enum { value = true }; };
+
+template <typename TYPE>
+struct traits {
+    enum {
+        // whether this type is a pointer
+        is_pointer          = trait_pointer<TYPE>::value,
+        // whether this type's constructor is a no-op
+        has_trivial_ctor    = is_pointer || trait_trivial_ctor<TYPE>::value,
+        // whether this type's destructor is a no-op
+        has_trivial_dtor    = is_pointer || trait_trivial_dtor<TYPE>::value,
+        // whether this type type can be copy-constructed with memcpy
+        has_trivial_copy    = is_pointer || trait_trivial_copy<TYPE>::value,
+        // whether this type can be moved with memmove
+        has_trivial_move    = is_pointer || trait_trivial_move<TYPE>::value
+    };
+};
+
+template <typename T, typename U>
+struct aggregate_traits {
+    enum {
+        is_pointer          = false,
+        has_trivial_ctor    = 
+            traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,
+        has_trivial_dtor    = 
+            traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,
+        has_trivial_copy    = 
+            traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,
+        has_trivial_move    = 
+            traits<T>::has_trivial_move && traits<U>::has_trivial_move
+    };
+};
+
+#define ANDROID_TRIVIAL_CTOR_TRAIT( T ) \
+    template<> struct trait_trivial_ctor< T >   { enum { value = true }; };
+
+#define ANDROID_TRIVIAL_DTOR_TRAIT( T ) \
+    template<> struct trait_trivial_dtor< T >   { enum { value = true }; };
+
+#define ANDROID_TRIVIAL_COPY_TRAIT( T ) \
+    template<> struct trait_trivial_copy< T >   { enum { value = true }; };
+
+#define ANDROID_TRIVIAL_MOVE_TRAIT( T ) \
+    template<> struct trait_trivial_move< T >   { enum { value = true }; };
+
+#define ANDROID_BASIC_TYPES_TRAITS( T ) \
+    ANDROID_TRIVIAL_CTOR_TRAIT( T ) \
+    ANDROID_TRIVIAL_DTOR_TRAIT( T ) \
+    ANDROID_TRIVIAL_COPY_TRAIT( T ) \
+    ANDROID_TRIVIAL_MOVE_TRAIT( T )
+
+// ---------------------------------------------------------------------------
+
+/*
+ * basic types traits
+ */
+
+ANDROID_BASIC_TYPES_TRAITS( void )
+ANDROID_BASIC_TYPES_TRAITS( bool )
+ANDROID_BASIC_TYPES_TRAITS( char )
+ANDROID_BASIC_TYPES_TRAITS( unsigned char )
+ANDROID_BASIC_TYPES_TRAITS( short )
+ANDROID_BASIC_TYPES_TRAITS( unsigned short )
+ANDROID_BASIC_TYPES_TRAITS( int )
+ANDROID_BASIC_TYPES_TRAITS( unsigned int )
+ANDROID_BASIC_TYPES_TRAITS( long )
+ANDROID_BASIC_TYPES_TRAITS( unsigned long )
+ANDROID_BASIC_TYPES_TRAITS( long long )
+ANDROID_BASIC_TYPES_TRAITS( unsigned long long )
+ANDROID_BASIC_TYPES_TRAITS( float )
+ANDROID_BASIC_TYPES_TRAITS( double )
+
+// ---------------------------------------------------------------------------
+
+
+/*
+ * compare and order types
+ */
+
+template<typename TYPE> inline
+int strictly_order_type(const TYPE& lhs, const TYPE& rhs) {
+    return (lhs < rhs) ? 1 : 0;
+}
+
+template<typename TYPE> inline
+int compare_type(const TYPE& lhs, const TYPE& rhs) {
+    return strictly_order_type(rhs, lhs) - strictly_order_type(lhs, rhs);
+}
+
+/*
+ * create, destroy, copy and move types...
+ */
+
+template<typename TYPE> inline
+void construct_type(TYPE* p, size_t n) {
+    if (!traits<TYPE>::has_trivial_ctor) {
+        while (n--) {
+            new(p++) TYPE;
+        }
+    }
+}
+
+template<typename TYPE> inline
+void destroy_type(TYPE* p, size_t n) {
+    if (!traits<TYPE>::has_trivial_dtor) {
+        while (n--) {
+            p->~TYPE();
+            p++;
+        }
+    }
+}
+
+template<typename TYPE> inline
+void copy_type(TYPE* d, const TYPE* s, size_t n) {
+    if (!traits<TYPE>::has_trivial_copy) {
+        while (n--) {
+            new(d) TYPE(*s);
+            d++, s++;
+        }
+    } else {
+        memcpy(d,s,n*sizeof(TYPE));
+    }
+}
+
+template<typename TYPE> inline
+void splat_type(TYPE* where, const TYPE* what, size_t n) {
+    if (!traits<TYPE>::has_trivial_copy) {
+        while (n--) {
+            new(where) TYPE(*what);
+            where++;
+        }
+    } else {
+        while (n--) {
+            *where++ = *what;
+        }
+    }
+}
+
+template<typename TYPE> inline
+void move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
+    if ((traits<TYPE>::has_trivial_dtor && traits<TYPE>::has_trivial_copy) 
+            || traits<TYPE>::has_trivial_move) 
+    {
+        memmove(d,s,n*sizeof(TYPE));
+    } else {
+        d += n;
+        s += n;
+        while (n--) {
+            --d, --s;
+            if (!traits<TYPE>::has_trivial_copy) {
+                new(d) TYPE(*s);
+            } else {
+                *d = *s;   
+            }
+            if (!traits<TYPE>::has_trivial_dtor) {
+                s->~TYPE();
+            }
+        }
+    }
+}
+
+template<typename TYPE> inline
+void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
+    if ((traits<TYPE>::has_trivial_dtor && traits<TYPE>::has_trivial_copy) 
+            || traits<TYPE>::has_trivial_move) 
+    {
+        memmove(d,s,n*sizeof(TYPE));
+    } else {
+        while (n--) {
+            if (!traits<TYPE>::has_trivial_copy) {
+                new(d) TYPE(*s);
+            } else {
+                *d = *s;   
+            }
+            if (!traits<TYPE>::has_trivial_dtor) {
+                s->~TYPE();
+            }
+            d++, s++;
+        }
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+/*
+ * a key/value pair
+ */
+
+template <typename KEY, typename VALUE>
+struct key_value_pair_t {
+    typedef KEY key_t;
+    typedef VALUE value_t;
+
+    KEY     key;
+    VALUE   value;
+    key_value_pair_t() { }
+    key_value_pair_t(const key_value_pair_t& o) : key(o.key), value(o.value) { }
+    key_value_pair_t(const KEY& k, const VALUE& v) : key(k), value(v)  { }
+    key_value_pair_t(const KEY& k) : key(k) { }
+    inline bool operator < (const key_value_pair_t& o) const {
+        return strictly_order_type(key, o.key);
+    }
+    inline const KEY& getKey() const {
+        return key;
+    }
+    inline const VALUE& getValue() const {
+        return value;
+    }
+};
+
+template <typename K, typename V>
+struct trait_trivial_ctor< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_ctor }; };
+template <typename K, typename V>
+struct trait_trivial_dtor< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_dtor }; };
+template <typename K, typename V>
+struct trait_trivial_copy< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_copy }; };
+template <typename K, typename V>
+struct trait_trivial_move< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_move }; };
+
+// ---------------------------------------------------------------------------
+
+/*
+ * Hash codes.
+ */
+typedef uint32_t hash_t;
+
+template <typename TKey>
+hash_t hash_type(const TKey& key);
+
+/* Built-in hash code specializations.
+ * Assumes pointers are 32bit. */
+#define ANDROID_INT32_HASH(T) \
+        template <> inline hash_t hash_type(const T& value) { return hash_t(value); }
+#define ANDROID_INT64_HASH(T) \
+        template <> inline hash_t hash_type(const T& value) { \
+                return hash_t((value >> 32) ^ value); }
+#define ANDROID_REINTERPRET_HASH(T, R) \
+        template <> inline hash_t hash_type(const T& value) { \
+                return hash_type(*reinterpret_cast<const R*>(&value)); }
+
+ANDROID_INT32_HASH(bool)
+ANDROID_INT32_HASH(int8_t)
+ANDROID_INT32_HASH(uint8_t)
+ANDROID_INT32_HASH(int16_t)
+ANDROID_INT32_HASH(uint16_t)
+ANDROID_INT32_HASH(int32_t)
+ANDROID_INT32_HASH(uint32_t)
+ANDROID_INT64_HASH(int64_t)
+ANDROID_INT64_HASH(uint64_t)
+ANDROID_REINTERPRET_HASH(float, uint32_t)
+ANDROID_REINTERPRET_HASH(double, uint64_t)
+
+template <typename T> inline hash_t hash_type(T* const & value) {
+    return hash_type(uintptr_t(value));
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_TYPE_HELPERS_H
diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
new file mode 100644
index 0000000..c8c87c3
--- /dev/null
+++ b/include/utils/Unicode.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UNICODE_H
+#define ANDROID_UNICODE_H
+
+#include <sys/types.h>
+#include <stdint.h>
+
+extern "C" {
+
+typedef uint32_t char32_t;
+typedef uint16_t char16_t;
+
+// Standard string functions on char16_t strings.
+int strcmp16(const char16_t *, const char16_t *);
+int strncmp16(const char16_t *s1, const char16_t *s2, size_t n);
+size_t strlen16(const char16_t *);
+size_t strnlen16(const char16_t *, size_t);
+char16_t *strcpy16(char16_t *, const char16_t *);
+char16_t *strncpy16(char16_t *, const char16_t *, size_t);
+
+// Version of comparison that supports embedded nulls.
+// This is different than strncmp() because we don't stop
+// at a nul character and consider the strings to be different
+// if the lengths are different (thus we need to supply the
+// lengths of both strings).  This can also be used when
+// your string is not nul-terminated as it will have the
+// equivalent result as strcmp16 (unlike strncmp16).
+int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2);
+
+// Version of strzcmp16 for comparing strings in different endianness.
+int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2);
+
+// Standard string functions on char32_t strings.
+size_t strlen32(const char32_t *);
+size_t strnlen32(const char32_t *, size_t);
+
+/**
+ * Measure the length of a UTF-32 string in UTF-8. If the string is invalid
+ * such as containing a surrogate character, -1 will be returned.
+ */
+ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len);
+
+/**
+ * Stores a UTF-8 string converted from "src" in "dst", if "dst_length" is not
+ * large enough to store the string, the part of the "src" string is stored
+ * into "dst" as much as possible. See the examples for more detail.
+ * Returns the size actually used for storing the string.
+ * dst" is not null-terminated when dst_len is fully used (like strncpy).
+ *
+ * Example 1
+ * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84)
+ * "src_len" == 2
+ * "dst_len" >= 7
+ * ->
+ * Returned value == 6
+ * "dst" becomes \xE3\x81\x82\xE3\x81\x84\0
+ * (note that "dst" is null-terminated)
+ *
+ * Example 2
+ * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84)
+ * "src_len" == 2
+ * "dst_len" == 5
+ * ->
+ * Returned value == 3
+ * "dst" becomes \xE3\x81\x82\0
+ * (note that "dst" is null-terminated, but \u3044 is not stored in "dst"
+ * since "dst" does not have enough size to store the character)
+ *
+ * Example 3
+ * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84)
+ * "src_len" == 2
+ * "dst_len" == 6
+ * ->
+ * Returned value == 6
+ * "dst" becomes \xE3\x81\x82\xE3\x81\x84
+ * (note that "dst" is NOT null-terminated, like strncpy)
+ */
+void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst);
+
+/**
+ * Returns the unicode value at "index".
+ * Returns -1 when the index is invalid (equals to or more than "src_len").
+ * If returned value is positive, it is able to be converted to char32_t, which
+ * is unsigned. Then, if "next_index" is not NULL, the next index to be used is
+ * stored in "next_index". "next_index" can be NULL.
+ */
+int32_t utf32_from_utf8_at(const char *src, size_t src_len, size_t index, size_t *next_index);
+
+
+/**
+ * Returns the UTF-8 length of UTF-16 string "src".
+ */
+ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len);
+
+/**
+ * Converts a UTF-16 string to UTF-8. The destination buffer must be large
+ * enough to fit the UTF-16 as measured by utf16_to_utf8_length with an added
+ * NULL terminator.
+ */
+void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst);
+
+/**
+ * Returns the length of "src" when "src" is valid UTF-8 string.
+ * Returns 0 if src is NULL or 0-length string. Returns -1 when the source
+ * is an invalid string.
+ *
+ * This function should be used to determine whether "src" is valid UTF-8
+ * characters with valid unicode codepoints. "src" must be null-terminated.
+ *
+ * If you are going to use other utf8_to_... functions defined in this header
+ * with string which may not be valid UTF-8 with valid codepoint (form 0 to
+ * 0x10FFFF), you should use this function before calling others, since the
+ * other functions do not check whether the string is valid UTF-8 or not.
+ *
+ * If you do not care whether "src" is valid UTF-8 or not, you should use
+ * strlen() as usual, which should be much faster.
+ */
+ssize_t utf8_length(const char *src);
+
+/**
+ * Measure the length of a UTF-32 string.
+ */
+size_t utf8_to_utf32_length(const char *src, size_t src_len);
+
+/**
+ * Stores a UTF-32 string converted from "src" in "dst". "dst" must be large
+ * enough to store the entire converted string as measured by
+ * utf8_to_utf32_length plus space for a NULL terminator.
+ */
+void utf8_to_utf32(const char* src, size_t src_len, char32_t* dst);
+
+/**
+ * Returns the UTF-16 length of UTF-8 string "src".
+ */
+ssize_t utf8_to_utf16_length(const uint8_t* src, size_t srcLen);
+
+/**
+ * Convert UTF-8 to UTF-16 including surrogate pairs.
+ * Returns a pointer to the end of the string (where a null terminator might go
+ * if you wanted to add one).
+ */
+char16_t* utf8_to_utf16_no_null_terminator(const uint8_t* src, size_t srcLen, char16_t* dst);
+
+/**
+ * Convert UTF-8 to UTF-16 including surrogate pairs. The destination buffer
+ * must be large enough to hold the result as measured by utf8_to_utf16_length
+ * plus an added NULL terminator.
+ */
+void utf8_to_utf16(const uint8_t* src, size_t srcLen, char16_t* dst);
+
+/**
+ * Like utf8_to_utf16_no_null_terminator, but you can supply a maximum length of the
+ * decoded string.  The decoded string will fill up to that length; if it is longer
+ * the returned pointer will be to the character after dstLen.
+ */
+char16_t* utf8_to_utf16_n(const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen);
+
+}
+
+#endif
diff --git a/include/utils/UniquePtr.h b/include/utils/UniquePtr.h
new file mode 100644
index 0000000..bc62fe6
--- /dev/null
+++ b/include/utils/UniquePtr.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+/* === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE ===
+ *
+ * THIS IS A COPY OF libcore/include/UniquePtr.h AND AS SUCH THAT IS THE
+ * CANONICAL SOURCE OF THIS FILE. PLEASE KEEP THEM IN SYNC.
+ *
+ * === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE ===
+ */
+
+#ifndef UNIQUE_PTR_H_included
+#define UNIQUE_PTR_H_included
+
+#include <cstdlib> // For NULL.
+
+// Default deleter for pointer types.
+template <typename T>
+struct DefaultDelete {
+    enum { type_must_be_complete = sizeof(T) };
+    DefaultDelete() {}
+    void operator()(T* p) const {
+        delete p;
+    }
+};
+
+// Default deleter for array types.
+template <typename T>
+struct DefaultDelete<T[]> {
+    enum { type_must_be_complete = sizeof(T) };
+    void operator()(T* p) const {
+        delete[] p;
+    }
+};
+
+// A smart pointer that deletes the given pointer on destruction.
+// Equivalent to C++0x's std::unique_ptr (a combination of boost::scoped_ptr
+// and boost::scoped_array).
+// Named to be in keeping with Android style but also to avoid
+// collision with any other implementation, until we can switch over
+// to unique_ptr.
+// Use thus:
+//   UniquePtr<C> c(new C);
+template <typename T, typename D = DefaultDelete<T> >
+class UniquePtr {
+public:
+    // Construct a new UniquePtr, taking ownership of the given raw pointer.
+    explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) {
+    }
+
+    ~UniquePtr() {
+        reset();
+    }
+
+    // Accessors.
+    T& operator*() const { return *mPtr; }
+    T* operator->() const { return mPtr; }
+    T* get() const { return mPtr; }
+
+    // Returns the raw pointer and hands over ownership to the caller.
+    // The pointer will not be deleted by UniquePtr.
+    T* release() __attribute__((warn_unused_result)) {
+        T* result = mPtr;
+        mPtr = NULL;
+        return result;
+    }
+
+    // Takes ownership of the given raw pointer.
+    // If this smart pointer previously owned a different raw pointer, that
+    // raw pointer will be freed.
+    void reset(T* ptr = NULL) {
+        if (ptr != mPtr) {
+            D()(mPtr);
+            mPtr = ptr;
+        }
+    }
+
+private:
+    // The raw pointer.
+    T* mPtr;
+
+    // Comparing unique pointers is probably a mistake, since they're unique.
+    template <typename T2> bool operator==(const UniquePtr<T2>& p) const;
+    template <typename T2> bool operator!=(const UniquePtr<T2>& p) const;
+
+    // Disallow copy and assignment.
+    UniquePtr(const UniquePtr&);
+    void operator=(const UniquePtr&);
+};
+
+// Partial specialization for array types. Like std::unique_ptr, this removes
+// operator* and operator-> but adds operator[].
+template <typename T, typename D>
+class UniquePtr<T[], D> {
+public:
+    explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) {
+    }
+
+    ~UniquePtr() {
+        reset();
+    }
+
+    T& operator[](size_t i) const {
+        return mPtr[i];
+    }
+    T* get() const { return mPtr; }
+
+    T* release() __attribute__((warn_unused_result)) {
+        T* result = mPtr;
+        mPtr = NULL;
+        return result;
+    }
+
+    void reset(T* ptr = NULL) {
+        if (ptr != mPtr) {
+            D()(mPtr);
+            mPtr = ptr;
+        }
+    }
+
+private:
+    T* mPtr;
+
+    // Disallow copy and assignment.
+    UniquePtr(const UniquePtr&);
+    void operator=(const UniquePtr&);
+};
+
+#if UNIQUE_PTR_TESTS
+
+// Run these tests with:
+// g++ -g -DUNIQUE_PTR_TESTS -x c++ UniquePtr.h && ./a.out
+
+#include <stdio.h>
+
+static void assert(bool b) {
+    if (!b) {
+        fprintf(stderr, "FAIL\n");
+        abort();
+    }
+    fprintf(stderr, "OK\n");
+}
+static int cCount = 0;
+struct C {
+    C() { ++cCount; }
+    ~C() { --cCount; }
+};
+static bool freed = false;
+struct Freer {
+    void operator()(int* p) {
+        assert(*p == 123);
+        free(p);
+        freed = true;
+    }
+};
+
+int main(int argc, char* argv[]) {
+    //
+    // UniquePtr<T> tests...
+    //
+
+    // Can we free a single object?
+    {
+        UniquePtr<C> c(new C);
+        assert(cCount == 1);
+    }
+    assert(cCount == 0);
+    // Does release work?
+    C* rawC;
+    {
+        UniquePtr<C> c(new C);
+        assert(cCount == 1);
+        rawC = c.release();
+    }
+    assert(cCount == 1);
+    delete rawC;
+    // Does reset work?
+    {
+        UniquePtr<C> c(new C);
+        assert(cCount == 1);
+        c.reset(new C);
+        assert(cCount == 1);
+    }
+    assert(cCount == 0);
+
+    //
+    // UniquePtr<T[]> tests...
+    //
+
+    // Can we free an array?
+    {
+        UniquePtr<C[]> cs(new C[4]);
+        assert(cCount == 4);
+    }
+    assert(cCount == 0);
+    // Does release work?
+    {
+        UniquePtr<C[]> c(new C[4]);
+        assert(cCount == 4);
+        rawC = c.release();
+    }
+    assert(cCount == 4);
+    delete[] rawC;
+    // Does reset work?
+    {
+        UniquePtr<C[]> c(new C[4]);
+        assert(cCount == 4);
+        c.reset(new C[2]);
+        assert(cCount == 2);
+    }
+    assert(cCount == 0);
+
+    //
+    // Custom deleter tests...
+    //
+    assert(!freed);
+    {
+        UniquePtr<int, Freer> i(reinterpret_cast<int*>(malloc(sizeof(int))));
+        *i = 123;
+    }
+    assert(freed);
+    return 0;
+}
+#endif
+
+#endif  // UNIQUE_PTR_H_included
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
new file mode 100644
index 0000000..ed7b725
--- /dev/null
+++ b/include/utils/Vector.h
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VECTOR_H
+#define ANDROID_VECTOR_H
+
+#include <new>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/log.h>
+
+#include <utils/VectorImpl.h>
+#include <utils/TypeHelpers.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+template <typename TYPE>
+class SortedVector;
+
+/*!
+ * The main templated vector class ensuring type safety
+ * while making use of VectorImpl.
+ * This is the class users want to use.
+ */
+
+template <class TYPE>
+class Vector : private VectorImpl
+{
+public:
+            typedef TYPE    value_type;
+    
+    /*! 
+     * Constructors and destructors
+     */
+    
+                            Vector();
+                            Vector(const Vector<TYPE>& rhs);
+    explicit                Vector(const SortedVector<TYPE>& rhs);
+    virtual                 ~Vector();
+
+    /*! copy operator */
+            const Vector<TYPE>&     operator = (const Vector<TYPE>& rhs) const;
+            Vector<TYPE>&           operator = (const Vector<TYPE>& rhs);    
+
+            const Vector<TYPE>&     operator = (const SortedVector<TYPE>& rhs) const;
+            Vector<TYPE>&           operator = (const SortedVector<TYPE>& rhs);
+
+            /*
+     * empty the vector
+     */
+
+    inline  void            clear()             { VectorImpl::clear(); }
+
+    /*! 
+     * vector stats
+     */
+
+    //! returns number of items in the vector
+    inline  size_t          size() const                { return VectorImpl::size(); }
+    //! returns whether or not the vector is empty
+    inline  bool            isEmpty() const             { return VectorImpl::isEmpty(); }
+    //! returns how many items can be stored without reallocating the backing store
+    inline  size_t          capacity() const            { return VectorImpl::capacity(); }
+    //! sets the capacity. capacity can never be reduced less than size()
+    inline  ssize_t         setCapacity(size_t size)    { return VectorImpl::setCapacity(size); }
+
+    /*!
+     * set the size of the vector. items are appended with the default
+     * constructor, or removed from the end as needed.
+     */
+    inline  ssize_t         resize(size_t size)         { return VectorImpl::resize(size); }
+
+    /*!
+     * C-style array access
+     */
+     
+    //! read-only C-style access 
+    inline  const TYPE*     array() const;
+    //! read-write C-style access
+            TYPE*           editArray();
+    
+    /*! 
+     * accessors
+     */
+
+    //! read-only access to an item at a given index
+    inline  const TYPE&     operator [] (size_t index) const;
+    //! alternate name for operator []
+    inline  const TYPE&     itemAt(size_t index) const;
+    //! stack-usage of the vector. returns the top of the stack (last element)
+            const TYPE&     top() const;
+
+    /*!
+     * modifying the array
+     */
+
+    //! copy-on write support, grants write access to an item
+            TYPE&           editItemAt(size_t index);
+    //! grants right access to the top of the stack (last element)
+            TYPE&           editTop();
+
+            /*! 
+             * append/insert another vector
+             */
+            
+    //! insert another vector at a given index
+            ssize_t         insertVectorAt(const Vector<TYPE>& vector, size_t index);
+
+    //! append another vector at the end of this one
+            ssize_t         appendVector(const Vector<TYPE>& vector);
+
+
+    //! insert an array at a given index
+            ssize_t         insertArrayAt(const TYPE* array, size_t index, size_t length);
+
+    //! append an array at the end of this vector
+            ssize_t         appendArray(const TYPE* array, size_t length);
+
+            /*! 
+             * add/insert/replace items
+             */
+             
+    //! insert one or several items initialized with their default constructor
+    inline  ssize_t         insertAt(size_t index, size_t numItems = 1);
+    //! insert one or several items initialized from a prototype item
+            ssize_t         insertAt(const TYPE& prototype_item, size_t index, size_t numItems = 1);
+    //! pop the top of the stack (removes the last element). No-op if the stack's empty
+    inline  void            pop();
+    //! pushes an item initialized with its default constructor
+    inline  void            push();
+    //! pushes an item on the top of the stack
+            void            push(const TYPE& item);
+    //! same as push() but returns the index the item was added at (or an error)
+    inline  ssize_t         add();
+    //! same as push() but returns the index the item was added at (or an error)
+            ssize_t         add(const TYPE& item);            
+    //! replace an item with a new one initialized with its default constructor
+    inline  ssize_t         replaceAt(size_t index);
+    //! replace an item with a new one
+            ssize_t         replaceAt(const TYPE& item, size_t index);
+
+    /*!
+     * remove items
+     */
+
+    //! remove several items
+    inline  ssize_t         removeItemsAt(size_t index, size_t count = 1);
+    //! remove one item
+    inline  ssize_t         removeAt(size_t index)  { return removeItemsAt(index); }
+
+    /*!
+     * sort (stable) the array
+     */
+     
+     typedef int (*compar_t)(const TYPE* lhs, const TYPE* rhs);
+     typedef int (*compar_r_t)(const TYPE* lhs, const TYPE* rhs, void* state);
+     
+     inline status_t        sort(compar_t cmp);
+     inline status_t        sort(compar_r_t cmp, void* state);
+
+     // for debugging only
+     inline size_t getItemSize() const { return itemSize(); }
+
+
+     /*
+      * these inlines add some level of compatibility with STL. eventually
+      * we should probably turn things around.
+      */
+     typedef TYPE* iterator;
+     typedef TYPE const* const_iterator;
+
+     inline iterator begin() { return editArray(); }
+     inline iterator end()   { return editArray() + size(); }
+     inline const_iterator begin() const { return array(); }
+     inline const_iterator end() const   { return array() + size(); }
+     inline void reserve(size_t n) { setCapacity(n); }
+     inline bool empty() const{ return isEmpty(); }
+     inline void push_back(const TYPE& item)  { insertAt(item, size(), 1); }
+     inline void push_front(const TYPE& item) { insertAt(item, 0, 1); }
+     inline iterator erase(iterator pos) {
+         ssize_t index = removeItemsAt(pos-array());
+         return begin() + index;
+     }
+
+protected:
+    virtual void    do_construct(void* storage, size_t num) const;
+    virtual void    do_destroy(void* storage, size_t num) const;
+    virtual void    do_copy(void* dest, const void* from, size_t num) const;
+    virtual void    do_splat(void* dest, const void* item, size_t num) const;
+    virtual void    do_move_forward(void* dest, const void* from, size_t num) const;
+    virtual void    do_move_backward(void* dest, const void* from, size_t num) const;
+};
+
+// Vector<T> can be trivially moved using memcpy() because moving does not
+// require any change to the underlying SharedBuffer contents or reference count.
+template<typename T> struct trait_trivial_move<Vector<T> > { enum { value = true }; };
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts from here...
+// ---------------------------------------------------------------------------
+
+template<class TYPE> inline
+Vector<TYPE>::Vector()
+    : VectorImpl(sizeof(TYPE),
+                ((traits<TYPE>::has_trivial_ctor   ? HAS_TRIVIAL_CTOR   : 0)
+                |(traits<TYPE>::has_trivial_dtor   ? HAS_TRIVIAL_DTOR   : 0)
+                |(traits<TYPE>::has_trivial_copy   ? HAS_TRIVIAL_COPY   : 0))
+                )
+{
+}
+
+template<class TYPE> inline
+Vector<TYPE>::Vector(const Vector<TYPE>& rhs)
+    : VectorImpl(rhs) {
+}
+
+template<class TYPE> inline
+Vector<TYPE>::Vector(const SortedVector<TYPE>& rhs)
+    : VectorImpl(static_cast<const VectorImpl&>(rhs)) {
+}
+
+template<class TYPE> inline
+Vector<TYPE>::~Vector() {
+    finish_vector();
+}
+
+template<class TYPE> inline
+Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) {
+    VectorImpl::operator = (rhs);
+    return *this; 
+}
+
+template<class TYPE> inline
+const Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) const {
+    VectorImpl::operator = (static_cast<const VectorImpl&>(rhs));
+    return *this;
+}
+
+template<class TYPE> inline
+Vector<TYPE>& Vector<TYPE>::operator = (const SortedVector<TYPE>& rhs) {
+    VectorImpl::operator = (static_cast<const VectorImpl&>(rhs));
+    return *this;
+}
+
+template<class TYPE> inline
+const Vector<TYPE>& Vector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const {
+    VectorImpl::operator = (rhs);
+    return *this; 
+}
+
+template<class TYPE> inline
+const TYPE* Vector<TYPE>::array() const {
+    return static_cast<const TYPE *>(arrayImpl());
+}
+
+template<class TYPE> inline
+TYPE* Vector<TYPE>::editArray() {
+    return static_cast<TYPE *>(editArrayImpl());
+}
+
+
+template<class TYPE> inline
+const TYPE& Vector<TYPE>::operator[](size_t index) const {
+    LOG_FATAL_IF(index>=size(),
+            "%s: index=%u out of range (%u)", __PRETTY_FUNCTION__,
+            int(index), int(size()));
+    return *(array() + index);
+}
+
+template<class TYPE> inline
+const TYPE& Vector<TYPE>::itemAt(size_t index) const {
+    return operator[](index);
+}
+
+template<class TYPE> inline
+const TYPE& Vector<TYPE>::top() const {
+    return *(array() + size() - 1);
+}
+
+template<class TYPE> inline
+TYPE& Vector<TYPE>::editItemAt(size_t index) {
+    return *( static_cast<TYPE *>(editItemLocation(index)) );
+}
+
+template<class TYPE> inline
+TYPE& Vector<TYPE>::editTop() {
+    return *( static_cast<TYPE *>(editItemLocation(size()-1)) );
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::insertVectorAt(const Vector<TYPE>& vector, size_t index) {
+    return VectorImpl::insertVectorAt(reinterpret_cast<const VectorImpl&>(vector), index);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::appendVector(const Vector<TYPE>& vector) {
+    return VectorImpl::appendVector(reinterpret_cast<const VectorImpl&>(vector));
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::insertArrayAt(const TYPE* array, size_t index, size_t length) {
+    return VectorImpl::insertArrayAt(array, index, length);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::appendArray(const TYPE* array, size_t length) {
+    return VectorImpl::appendArray(array, length);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::insertAt(const TYPE& item, size_t index, size_t numItems) {
+    return VectorImpl::insertAt(&item, index, numItems);
+}
+
+template<class TYPE> inline
+void Vector<TYPE>::push(const TYPE& item) {
+    return VectorImpl::push(&item);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::add(const TYPE& item) {
+    return VectorImpl::add(&item);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::replaceAt(const TYPE& item, size_t index) {
+    return VectorImpl::replaceAt(&item, index);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::insertAt(size_t index, size_t numItems) {
+    return VectorImpl::insertAt(index, numItems);
+}
+
+template<class TYPE> inline
+void Vector<TYPE>::pop() {
+    VectorImpl::pop();
+}
+
+template<class TYPE> inline
+void Vector<TYPE>::push() {
+    VectorImpl::push();
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::add() {
+    return VectorImpl::add();
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::replaceAt(size_t index) {
+    return VectorImpl::replaceAt(index);
+}
+
+template<class TYPE> inline
+ssize_t Vector<TYPE>::removeItemsAt(size_t index, size_t count) {
+    return VectorImpl::removeItemsAt(index, count);
+}
+
+template<class TYPE> inline
+status_t Vector<TYPE>::sort(Vector<TYPE>::compar_t cmp) {
+    return VectorImpl::sort((VectorImpl::compar_t)cmp);
+}
+
+template<class TYPE> inline
+status_t Vector<TYPE>::sort(Vector<TYPE>::compar_r_t cmp, void* state) {
+    return VectorImpl::sort((VectorImpl::compar_r_t)cmp, state);
+}
+
+// ---------------------------------------------------------------------------
+
+template<class TYPE>
+void Vector<TYPE>::do_construct(void* storage, size_t num) const {
+    construct_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_destroy(void* storage, size_t num) const {
+    destroy_type( reinterpret_cast<TYPE*>(storage), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_copy(void* dest, const void* from, size_t num) const {
+    copy_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_splat(void* dest, const void* item, size_t num) const {
+    splat_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(item), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_move_forward(void* dest, const void* from, size_t num) const {
+    move_forward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+template<class TYPE>
+void Vector<TYPE>::do_move_backward(void* dest, const void* from, size_t num) const {
+    move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
+}
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_VECTOR_H
diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h
new file mode 100644
index 0000000..21ad71c
--- /dev/null
+++ b/include/utils/VectorImpl.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VECTOR_IMPL_H
+#define ANDROID_VECTOR_IMPL_H
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts in here...
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+/*!
+ * Implementation of the guts of the vector<> class
+ * this ensures backward binary compatibility and
+ * reduces code size.
+ * For performance reasons, we expose mStorage and mCount
+ * so these fields are set in stone.
+ *
+ */
+
+class VectorImpl
+{
+public:
+    enum { // flags passed to the ctor
+        HAS_TRIVIAL_CTOR    = 0x00000001,
+        HAS_TRIVIAL_DTOR    = 0x00000002,
+        HAS_TRIVIAL_COPY    = 0x00000004,
+    };
+
+                            VectorImpl(size_t itemSize, uint32_t flags);
+                            VectorImpl(const VectorImpl& rhs);
+    virtual                 ~VectorImpl();
+
+    /*! must be called from subclasses destructor */
+            void            finish_vector();
+
+            VectorImpl&     operator = (const VectorImpl& rhs);    
+            
+    /*! C-style array access */
+    inline  const void*     arrayImpl() const       { return mStorage; }
+            void*           editArrayImpl();
+            
+    /*! vector stats */
+    inline  size_t          size() const        { return mCount; }
+    inline  bool            isEmpty() const     { return mCount == 0; }
+            size_t          capacity() const;
+            ssize_t         setCapacity(size_t size);
+            ssize_t         resize(size_t size);
+
+            /*! append/insert another vector or array */
+            ssize_t         insertVectorAt(const VectorImpl& vector, size_t index);
+            ssize_t         appendVector(const VectorImpl& vector);
+            ssize_t         insertArrayAt(const void* array, size_t index, size_t length);
+            ssize_t         appendArray(const void* array, size_t length);
+            
+            /*! add/insert/replace items */
+            ssize_t         insertAt(size_t where, size_t numItems = 1);
+            ssize_t         insertAt(const void* item, size_t where, size_t numItems = 1);
+            void            pop();
+            void            push();
+            void            push(const void* item);
+            ssize_t         add();
+            ssize_t         add(const void* item);
+            ssize_t         replaceAt(size_t index);
+            ssize_t         replaceAt(const void* item, size_t index);
+
+            /*! remove items */
+            ssize_t         removeItemsAt(size_t index, size_t count = 1);
+            void            clear();
+
+            const void*     itemLocation(size_t index) const;
+            void*           editItemLocation(size_t index);
+
+            typedef int (*compar_t)(const void* lhs, const void* rhs);
+            typedef int (*compar_r_t)(const void* lhs, const void* rhs, void* state);
+            status_t        sort(compar_t cmp);
+            status_t        sort(compar_r_t cmp, void* state);
+
+protected:
+            size_t          itemSize() const;
+            void            release_storage();
+
+    virtual void            do_construct(void* storage, size_t num) const = 0;
+    virtual void            do_destroy(void* storage, size_t num) const = 0;
+    virtual void            do_copy(void* dest, const void* from, size_t num) const = 0;
+    virtual void            do_splat(void* dest, const void* item, size_t num) const = 0;
+    virtual void            do_move_forward(void* dest, const void* from, size_t num) const = 0;
+    virtual void            do_move_backward(void* dest, const void* from, size_t num) const = 0;
+    
+private:
+        void* _grow(size_t where, size_t amount);
+        void  _shrink(size_t where, size_t amount);
+
+        inline void _do_construct(void* storage, size_t num) const;
+        inline void _do_destroy(void* storage, size_t num) const;
+        inline void _do_copy(void* dest, const void* from, size_t num) const;
+        inline void _do_splat(void* dest, const void* item, size_t num) const;
+        inline void _do_move_forward(void* dest, const void* from, size_t num) const;
+        inline void _do_move_backward(void* dest, const void* from, size_t num) const;
+
+            // These 2 fields are exposed in the inlines below,
+            // so they're set in stone.
+            void *      mStorage;   // base address of the vector
+            size_t      mCount;     // number of items
+
+    const   uint32_t    mFlags;
+    const   size_t      mItemSize;
+};
+
+
+
+class SortedVectorImpl : public VectorImpl
+{
+public:
+                            SortedVectorImpl(size_t itemSize, uint32_t flags);
+                            SortedVectorImpl(const VectorImpl& rhs);
+    virtual                 ~SortedVectorImpl();
+    
+    SortedVectorImpl&     operator = (const SortedVectorImpl& rhs);    
+
+    //! finds the index of an item
+            ssize_t         indexOf(const void* item) const;
+
+    //! finds where this item should be inserted
+            size_t          orderOf(const void* item) const;
+
+    //! add an item in the right place (or replaces it if there is one)
+            ssize_t         add(const void* item);
+
+    //! merges a vector into this one
+            ssize_t         merge(const VectorImpl& vector);
+            ssize_t         merge(const SortedVectorImpl& vector);
+             
+    //! removes an item
+            ssize_t         remove(const void* item);
+        
+protected:
+    virtual int             do_compare(const void* lhs, const void* rhs) const = 0;
+
+private:
+            ssize_t         _indexOrderOf(const void* item, size_t* order = 0) const;
+
+            // these are made private, because they can't be used on a SortedVector
+            // (they don't have an implementation either)
+            ssize_t         add();
+            void            pop();
+            void            push();
+            void            push(const void* item);
+            ssize_t         insertVectorAt(const VectorImpl& vector, size_t index);
+            ssize_t         appendVector(const VectorImpl& vector);
+            ssize_t         insertArrayAt(const void* array, size_t index, size_t length);
+            ssize_t         appendArray(const void* array, size_t length);
+            ssize_t         insertAt(size_t where, size_t numItems = 1);
+            ssize_t         insertAt(const void* item, size_t where, size_t numItems = 1);
+            ssize_t         replaceAt(size_t index);
+            ssize_t         replaceAt(const void* item, size_t index);
+};
+
+}; // namespace android
+
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_VECTOR_IMPL_H
diff --git a/include/utils/ashmem.h b/include/utils/ashmem.h
new file mode 100644
index 0000000..0854775
--- /dev/null
+++ b/include/utils/ashmem.h
@@ -0,0 +1,41 @@
+/* utils/ashmem.h
+ **
+ ** Copyright 2008 The Android Open Source Project
+ **
+ ** This file is dual licensed.  It may be redistributed and/or modified
+ ** under the terms of the Apache 2.0 License OR version 2 of the GNU
+ ** General Public License.
+ */
+
+#ifndef _UTILS_ASHMEM_H
+#define _UTILS_ASHMEM_H
+
+#include <linux/limits.h>
+#include <linux/ioctl.h>
+
+#define ASHMEM_NAME_LEN		256
+
+#define ASHMEM_NAME_DEF		"dev/ashmem"
+
+/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
+#define ASHMEM_NOT_REAPED	0
+#define ASHMEM_WAS_REAPED	1
+
+/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
+#define ASHMEM_NOW_UNPINNED	0
+#define ASHMEM_NOW_PINNED	1
+
+#define __ASHMEMIOC		0x77
+
+#define ASHMEM_SET_NAME		_IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
+#define ASHMEM_GET_NAME		_IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
+#define ASHMEM_SET_SIZE		_IOW(__ASHMEMIOC, 3, size_t)
+#define ASHMEM_GET_SIZE		_IO(__ASHMEMIOC, 4)
+#define ASHMEM_SET_PROT_MASK	_IOW(__ASHMEMIOC, 5, unsigned long)
+#define ASHMEM_GET_PROT_MASK	_IO(__ASHMEMIOC, 6)
+#define ASHMEM_PIN		_IO(__ASHMEMIOC, 7)
+#define ASHMEM_UNPIN		_IO(__ASHMEMIOC, 8)
+#define ASHMEM_ISPINNED		_IO(__ASHMEMIOC, 9)
+#define ASHMEM_PURGE_ALL_CACHES	_IO(__ASHMEMIOC, 10)
+
+#endif	/* _UTILS_ASHMEM_H */
diff --git a/include/utils/misc.h b/include/utils/misc.h
new file mode 100644
index 0000000..6cccec3
--- /dev/null
+++ b/include/utils/misc.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Handy utility functions and portability code.
+//
+#ifndef _LIBS_UTILS_MISC_H
+#define _LIBS_UTILS_MISC_H
+
+#include <utils/Endian.h>
+
+/* get #of elements in a static array */
+#ifndef NELEM
+# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
+#endif
+
+namespace android {
+
+typedef void (*sysprop_change_callback)(void);
+void add_sysprop_change_callback(sysprop_change_callback cb, int priority);
+void report_sysprop_change();
+
+}; // namespace android
+
+#endif // _LIBS_UTILS_MISC_H
diff --git a/include/cutils/zygote.h b/include/utils/threads.h
similarity index 61%
copy from include/cutils/zygote.h
copy to include/utils/threads.h
index a7480d3..9de3382 100644
--- a/include/cutils/zygote.h
+++ b/include/utils/threads.h
@@ -14,18 +14,25 @@
  * limitations under the License.
  */
 
-#ifndef __CUTILS_ZYGOTE_H
-#define __CUTILS_ZYGOTE_H
+#ifndef _LIBS_UTILS_THREADS_H
+#define _LIBS_UTILS_THREADS_H
+
+/*
+ * Please, DO NOT USE!
+ *
+ * This file is here only for legacy reasons. Instead, include directly
+ * the headers you need below.
+ *
+ */
+
+#include <utils/AndroidThreads.h>
 
 #ifdef __cplusplus
-extern "C" {
+#include <utils/Condition.h>
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
+#include <utils/RWLock.h>
+#include <utils/Thread.h>
 #endif
 
-int zygote_run_oneshot(int sendStdio, int argc, const char **argv);
-int zygote_run(int argc, const char **argv);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __CUTILS_ZYGOTE_H */
+#endif // _LIBS_UTILS_THREADS_H
diff --git a/init/Android.mk b/init/Android.mk
index 8b436db..1f43ba6 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -38,7 +38,9 @@
 	libcutils \
 	liblog \
 	libc \
-	libselinux
+	libselinux \
+	libmincrypt \
+	libext4_utils_static
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/init/builtins.c b/init/builtins.c
index 33fc6c6..e2932d5 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -32,6 +32,7 @@
 #include <sys/wait.h>
 #include <linux/loop.h>
 #include <cutils/partition_utils.h>
+#include <cutils/android_reboot.h>
 #include <sys/system_properties.h>
 #include <fs_mgr.h>
 
@@ -56,7 +57,7 @@
 {
     int fd, ret, len;
 
-    fd = open(path, O_WRONLY|O_CREAT, 0622);
+    fd = open(path, O_WRONLY|O_CREAT|O_NOFOLLOW, 0600);
 
     if (fd < 0)
         return -errno;
@@ -515,6 +516,18 @@
     return ret;
 }
 
+int do_swapon_all(int nargs, char **args)
+{
+    struct fstab *fstab;
+    int ret;
+
+    fstab = fs_mgr_read_fstab(args[1]);
+    ret = fs_mgr_swapon_all(fstab);
+    fs_mgr_free_fstab(fstab);
+
+    return ret;
+}
+
 int do_setcon(int nargs, char **args) {
     if (is_selinux_enabled() <= 0)
         return 0;
@@ -598,6 +611,43 @@
     return 0;
 }
 
+int do_powerctl(int nargs, char **args)
+{
+    char command[PROP_VALUE_MAX];
+    int res;
+    int len = 0;
+    int cmd = 0;
+    char *reboot_target;
+
+    res = expand_props(command, args[1], sizeof(command));
+    if (res) {
+        ERROR("powerctl: cannot expand '%s'\n", args[1]);
+        return -EINVAL;
+    }
+
+    if (strncmp(command, "shutdown", 8) == 0) {
+        cmd = ANDROID_RB_POWEROFF;
+        len = 8;
+    } else if (strncmp(command, "reboot", 6) == 0) {
+        cmd = ANDROID_RB_RESTART2;
+        len = 6;
+    } else {
+        ERROR("powerctl: unrecognized command '%s'\n", command);
+        return -EINVAL;
+    }
+
+    if (command[len] == ',') {
+        reboot_target = &command[len + 1];
+    } else if (command[len] == '\0') {
+        reboot_target = "";
+    } else {
+        ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
+        return -EINVAL;
+    }
+
+    return android_reboot(cmd, 0, reboot_target);
+}
+
 int do_trigger(int nargs, char **args)
 {
     action_for_each_trigger(args[1], action_add_queue_tail);
diff --git a/init/init.c b/init/init.c
index 525b69f..864fc6c 100644
--- a/init/init.c
+++ b/init/init.c
@@ -42,6 +42,7 @@
 #include <cutils/android_reboot.h>
 #include <cutils/sockets.h>
 #include <cutils/iosched_policy.h>
+#include <cutils/fs.h>
 #include <private/android_filesystem_config.h>
 #include <termios.h>
 
@@ -556,6 +557,84 @@
     return ret;
 }
 
+/*
+ * Writes 512 bytes of output from Hardware RNG (/dev/hw_random, backed
+ * by Linux kernel's hw_random framework) into Linux RNG's via /dev/urandom.
+ * Does nothing if Hardware RNG is not present.
+ *
+ * Since we don't yet trust the quality of Hardware RNG, these bytes are not
+ * mixed into the primary pool of Linux RNG and the entropy estimate is left
+ * unmodified.
+ *
+ * If the HW RNG device /dev/hw_random is present, we require that at least
+ * 512 bytes read from it are written into Linux RNG. QA is expected to catch
+ * devices/configurations where these I/O operations are blocking for a long
+ * time. We do not reboot or halt on failures, as this is a best-effort
+ * attempt.
+ */
+static int mix_hwrng_into_linux_rng_action(int nargs, char **args)
+{
+    int result = -1;
+    int hwrandom_fd = -1;
+    int urandom_fd = -1;
+    char buf[512];
+    ssize_t chunk_size;
+    size_t total_bytes_written = 0;
+
+    hwrandom_fd = TEMP_FAILURE_RETRY(
+            open("/dev/hw_random", O_RDONLY | O_NOFOLLOW));
+    if (hwrandom_fd == -1) {
+        if (errno == ENOENT) {
+          ERROR("/dev/hw_random not found\n");
+          /* It's not an error to not have a Hardware RNG. */
+          result = 0;
+        } else {
+          ERROR("Failed to open /dev/hw_random: %s\n", strerror(errno));
+        }
+        goto ret;
+    }
+
+    urandom_fd = TEMP_FAILURE_RETRY(
+            open("/dev/urandom", O_WRONLY | O_NOFOLLOW));
+    if (urandom_fd == -1) {
+        ERROR("Failed to open /dev/urandom: %s\n", strerror(errno));
+        goto ret;
+    }
+
+    while (total_bytes_written < sizeof(buf)) {
+        chunk_size = TEMP_FAILURE_RETRY(
+                read(hwrandom_fd, buf, sizeof(buf) - total_bytes_written));
+        if (chunk_size == -1) {
+            ERROR("Failed to read from /dev/hw_random: %s\n", strerror(errno));
+            goto ret;
+        } else if (chunk_size == 0) {
+            ERROR("Failed to read from /dev/hw_random: EOF\n");
+            goto ret;
+        }
+
+        chunk_size = TEMP_FAILURE_RETRY(write(urandom_fd, buf, chunk_size));
+        if (chunk_size == -1) {
+            ERROR("Failed to write to /dev/urandom: %s\n", strerror(errno));
+            goto ret;
+        }
+        total_bytes_written += chunk_size;
+    }
+
+    INFO("Mixed %d bytes from /dev/hw_random into /dev/urandom",
+                total_bytes_written);
+    result = 0;
+
+ret:
+    if (hwrandom_fd != -1) {
+        close(hwrandom_fd);
+    }
+    if (urandom_fd != -1) {
+        close(urandom_fd);
+    }
+    memset(buf, 0, sizeof(buf));
+    return result;
+}
+
 static int keychord_init_action(int nargs, char **args)
 {
     keychord_init();
@@ -958,6 +1037,7 @@
     action_for_each_trigger("early-init", action_add_queue_tail);
 
     queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
+    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
     queue_builtin_action(keychord_init_action, "keychord_init");
     queue_builtin_action(console_init_action, "console_init");
 
@@ -972,6 +1052,11 @@
         action_for_each_trigger("post-fs-data", action_add_queue_tail);
     }
 
+    /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
+     * wasn't ready immediately after wait_for_coldboot_done
+     */
+    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
+
     queue_builtin_action(property_service_init_action, "property_service_init");
     queue_builtin_action(signal_init_action, "signal_init");
     queue_builtin_action(check_startup_action, "check_startup");
diff --git a/init/init_parser.c b/init/init_parser.c
index 38582f5..3f0838f 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -130,6 +130,8 @@
         if (!strcmp(s, "neshot")) return K_oneshot;
         if (!strcmp(s, "nrestart")) return K_onrestart;
         break;
+    case 'p':
+        if (!strcmp(s, "owerctl")) return K_powerctl;
     case 'r':
         if (!strcmp(s, "estart")) return K_restart;
         if (!strcmp(s, "estorecon")) return K_restorecon;
@@ -150,6 +152,7 @@
         if (!strcmp(s, "ocket")) return K_socket;
         if (!strcmp(s, "tart")) return K_start;
         if (!strcmp(s, "top")) return K_stop;
+        if (!strcmp(s, "wapon_all")) return K_swapon_all;
         if (!strcmp(s, "ymlink")) return K_symlink;
         if (!strcmp(s, "ysclktz")) return K_sysclktz;
         break;
diff --git a/init/keywords.h b/init/keywords.h
index 414db08..97fe50c 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -14,6 +14,7 @@
 int do_mkdir(int nargs, char **args);
 int do_mount_all(int nargs, char **args);
 int do_mount(int nargs, char **args);
+int do_powerctl(int nargs, char **args);
 int do_restart(int nargs, char **args);
 int do_restorecon(int nargs, char **args);
 int do_restorecon_recursive(int nargs, char **args);
@@ -27,6 +28,7 @@
 int do_setsebool(int nargs, char **args);
 int do_start(int nargs, char **args);
 int do_stop(int nargs, char **args);
+int do_swapon_all(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);
@@ -67,6 +69,7 @@
     KEYWORD(on,          SECTION, 0, 0)
     KEYWORD(oneshot,     OPTION,  0, 0)
     KEYWORD(onrestart,   OPTION,  0, 0)
+    KEYWORD(powerctl,    COMMAND, 1, do_powerctl)
     KEYWORD(restart,     COMMAND, 1, do_restart)
     KEYWORD(restorecon,  COMMAND, 1, do_restorecon)
     KEYWORD(restorecon_recursive,  COMMAND, 1, do_restorecon_recursive)
@@ -84,6 +87,7 @@
     KEYWORD(socket,      OPTION,  0, 0)
     KEYWORD(start,       COMMAND, 1, do_start)
     KEYWORD(stop,        COMMAND, 1, do_stop)
+    KEYWORD(swapon_all,  COMMAND, 1, do_swapon_all)
     KEYWORD(trigger,     COMMAND, 1, do_trigger)
     KEYWORD(symlink,     COMMAND, 1, do_symlink)
     KEYWORD(sysclktz,    COMMAND, 1, do_sysclktz)
diff --git a/init/property_service.c b/init/property_service.c
old mode 100755
new mode 100644
index f5f5457..c370769
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -78,6 +78,7 @@
     { "runtime.",         AID_SYSTEM,   0 },
     { "hw.",              AID_SYSTEM,   0 },
     { "sys.",             AID_SYSTEM,   0 },
+    { "sys.powerctl",     AID_SHELL,    0 },
     { "service.",         AID_SYSTEM,   0 },
     { "wlan.",            AID_SYSTEM,   0 },
     { "gps.",             AID_GPS,      0 },
@@ -277,6 +278,34 @@
     }
 }
 
+static bool is_legal_property_name(const char* name, size_t namelen)
+{
+    size_t i;
+    bool previous_was_dot = false;
+    if (namelen >= PROP_NAME_MAX) return false;
+    if (namelen < 1) return false;
+    if (name[0] == '.') return false;
+    if (name[namelen - 1] == '.') return false;
+
+    /* Only allow alphanumeric, plus '.', '-', or '_' */
+    /* Don't allow ".." to appear in a property name */
+    for (i = 0; i < namelen; i++) {
+        if (name[i] == '.') {
+            if (previous_was_dot == true) return false;
+            previous_was_dot = true;
+            continue;
+        }
+        previous_was_dot = false;
+        if (name[i] == '_' || name[i] == '-') continue;
+        if (name[i] >= 'a' && name[i] <= 'z') continue;
+        if (name[i] >= 'A' && name[i] <= 'Z') continue;
+        if (name[i] >= '0' && name[i] <= '9') continue;
+        return false;
+    }
+
+    return true;
+}
+
 int property_set(const char *name, const char *value)
 {
     prop_info *pi;
@@ -285,9 +314,8 @@
     size_t namelen = strlen(name);
     size_t valuelen = strlen(value);
 
-    if(namelen >= PROP_NAME_MAX) return -1;
-    if(valuelen >= PROP_VALUE_MAX) return -1;
-    if(namelen < 1) return -1;
+    if (!is_legal_property_name(name, namelen)) return -1;
+    if (valuelen >= PROP_VALUE_MAX) return -1;
 
     pi = (prop_info*) __system_property_find(name);
 
@@ -299,7 +327,7 @@
     } else {
         ret = __system_property_add(name, namelen, value, valuelen);
         if (ret < 0) {
-            ERROR("Failed to set '%s'='%s'", name, value);
+            ERROR("Failed to set '%s'='%s'\n", name, value);
             return ret;
         }
     }
@@ -365,6 +393,12 @@
         msg.name[PROP_NAME_MAX-1] = 0;
         msg.value[PROP_VALUE_MAX-1] = 0;
 
+        if (!is_legal_property_name(msg.name, strlen(msg.name))) {
+            ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);
+            close(s);
+            return;
+        }
+
         getpeercon(s, &source_ctx);
 
         if(memcmp(msg.name,"ctl.",4) == 0) {
diff --git a/libcorkscrew/backtrace.c b/libcorkscrew/backtrace.c
index b365e5b..f1dd61d 100644
--- a/libcorkscrew/backtrace.c
+++ b/libcorkscrew/backtrace.c
@@ -319,16 +319,17 @@
     if (symbolName) {
         uint32_t pc_offset = symbol->relative_pc - symbol->relative_symbol_addr;
         if (pc_offset) {
-            snprintf(buffer, bufferSize, "#%02u  pc %p  %.*s (%.*s+%u)",
-                    frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName,
-                    fieldWidth, symbolName, pc_offset);
+            snprintf(buffer, bufferSize, "#%02u  pc %08x  %.*s (%.*s+%u)",
+                    frameNumber, (unsigned int) symbol->relative_pc,
+                    fieldWidth, mapName, fieldWidth, symbolName, pc_offset);
         } else {
-            snprintf(buffer, bufferSize, "#%02u  pc %p  %.*s (%.*s)",
-                    frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName,
-                    fieldWidth, symbolName);
+            snprintf(buffer, bufferSize, "#%02u  pc %08x  %.*s (%.*s)",
+                    frameNumber, (unsigned int) symbol->relative_pc,
+                    fieldWidth, mapName, fieldWidth, symbolName);
         }
     } else {
-        snprintf(buffer, bufferSize, "#%02u  pc %p  %.*s",
-                frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName);
+        snprintf(buffer, bufferSize, "#%02u  pc %08x  %.*s",
+                frameNumber, (unsigned int) symbol->relative_pc,
+                fieldWidth, mapName);
     }
 }
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 6207f1f..f8dda36 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -24,11 +24,9 @@
 hostSmpFlag := -DANDROID_SMP=0
 
 commonSources := \
-	array.c \
 	hashmap.c \
 	atomic.c.arm \
 	native_handle.c \
-	buffer.c \
 	socket_inaddr_any_server.c \
 	socket_local_client.c \
 	socket_local_server.c \
@@ -45,8 +43,6 @@
 	strdup8to16.c \
 	record_stream.c \
 	process_name.c \
-	properties.c \
-	qsort_r_compat.c \
 	threads.c \
 	sched_policy.c \
 	iosched_policy.c \
@@ -69,16 +65,10 @@
     WINDOWS_HOST_ONLY := 1
 endif
 
-ifeq ($(WINDOWS_HOST_ONLY),1)
+ifneq ($(WINDOWS_HOST_ONLY),1)
     commonSources += \
-        uio.c
-else
-    commonSources += \
-        abort_socket.c \
         fs.c \
-        selector.c \
-        multiuser.c \
-        zygote.c
+        multiuser.c
 endif
 
 
@@ -113,8 +103,8 @@
         ashmem-dev.c \
         debugger.c \
         klog.c \
-        mq.c \
         partition_utils.c \
+        properties.c \
         qtaguid.c \
         trace.c \
         uevent.c
diff --git a/libcutils/abort_socket.c b/libcutils/abort_socket.c
deleted file mode 100644
index 6a5e5e4..0000000
--- a/libcutils/abort_socket.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright 2009, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-
-#include "cutils/abort_socket.h"
-
-struct asocket *asocket_init(int fd) {
-    int abort_fd[2];
-    int flags;
-    struct asocket *s;
-
-    /* set primary socket to non-blocking */
-    flags = fcntl(fd, F_GETFL);
-    if (flags == -1)
-        return NULL;
-    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
-        return NULL;
-
-    /* create pipe with non-blocking write, so that asocket_close() cannot
-       block */
-    if (pipe(abort_fd))
-        return NULL;
-    flags = fcntl(abort_fd[1], F_GETFL);
-    if (flags == -1)
-        return NULL;
-    if (fcntl(abort_fd[1], F_SETFL, flags | O_NONBLOCK))
-        return NULL;
-
-    s = malloc(sizeof(struct asocket));
-    if (!s)
-        return NULL;
-
-    s->fd = fd;
-    s->abort_fd[0] = abort_fd[0];
-    s->abort_fd[1] = abort_fd[1];
-
-    return s;
-}
-
-int asocket_connect(struct asocket *s, const struct sockaddr *addr,
-        socklen_t addrlen, int timeout) {
-
-    int ret;
-
-    do {
-        ret = connect(s->fd, addr, addrlen);
-    } while (ret && errno == EINTR);
-
-    if (ret && errno == EINPROGRESS) {
-        /* ready to poll() */
-        socklen_t retlen;
-        struct pollfd pfd[2];
-
-        pfd[0].fd = s->fd;
-        pfd[0].events = POLLOUT;
-        pfd[0].revents = 0;
-        pfd[1].fd = s->abort_fd[0];
-        pfd[1].events = POLLIN;
-        pfd[1].revents = 0;
-
-        do {
-            ret = poll(pfd, 2, timeout);
-        } while (ret < 0 && errno == EINTR);
-
-        if (ret < 0)
-            return -1;
-        else if (ret == 0) {
-            /* timeout */
-            errno = ETIMEDOUT;
-            return -1;
-        }
-
-        if (pfd[1].revents) {
-            /* abort due to asocket_abort() */
-            errno = ECANCELED;
-            return -1;
-        }
-
-        if (pfd[0].revents) {
-            if (pfd[0].revents & POLLOUT) {
-                /* connect call complete, read return code */
-                retlen = sizeof(ret);
-                if (getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &ret, &retlen))
-                    return -1;
-                /* got connect() return code */
-                if (ret) {
-                    errno = ret;
-                }
-            } else {
-                /* some error event on this fd */
-                errno = ECONNABORTED;
-                return -1;
-            }
-        }
-    }
-
-    return ret;
-}
-
-int asocket_accept(struct asocket *s, struct sockaddr *addr,
-        socklen_t *addrlen, int timeout) {
-
-    int ret;
-    struct pollfd pfd[2];
-
-    pfd[0].fd = s->fd;
-    pfd[0].events = POLLIN;
-    pfd[0].revents = 0;
-    pfd[1].fd = s->abort_fd[0];
-    pfd[1].events = POLLIN;
-    pfd[1].revents = 0;
-
-    do {
-        ret = poll(pfd, 2, timeout);
-    } while (ret < 0 && errno == EINTR);
-
-    if (ret < 0)
-        return -1;
-    else if (ret == 0) {
-        /* timeout */
-        errno = ETIMEDOUT;
-        return -1;
-    }
-
-    if (pfd[1].revents) {
-        /* abort due to asocket_abort() */
-        errno = ECANCELED;
-        return -1;
-    }
-
-    if (pfd[0].revents) {
-        if (pfd[0].revents & POLLIN) {
-            /* ready to accept() without blocking */
-            do {
-                ret = accept(s->fd, addr, addrlen);
-            } while (ret < 0 && errno == EINTR);
-        } else {
-            /* some error event on this fd */
-            errno = ECONNABORTED;
-            return -1;
-        }
-    }
-
-    return ret;
-}
-
-int asocket_read(struct asocket *s, void *buf, size_t count, int timeout) {
-    int ret;
-    struct pollfd pfd[2];
-
-    pfd[0].fd = s->fd;
-    pfd[0].events = POLLIN;
-    pfd[0].revents = 0;
-    pfd[1].fd = s->abort_fd[0];
-    pfd[1].events = POLLIN;
-    pfd[1].revents = 0;
-
-    do {
-        ret = poll(pfd, 2, timeout);
-    } while (ret < 0 && errno == EINTR);
-
-    if (ret < 0)
-        return -1;
-    else if (ret == 0) {
-        /* timeout */
-        errno = ETIMEDOUT;
-        return -1;
-    }
-
-    if (pfd[1].revents) {
-        /* abort due to asocket_abort() */
-        errno = ECANCELED;
-        return -1;
-    }
-
-    if (pfd[0].revents) {
-        if (pfd[0].revents & POLLIN) {
-            /* ready to read() without blocking */
-            do {
-                ret = read(s->fd, buf, count);
-            } while (ret < 0 && errno == EINTR);
-        } else {
-            /* some error event on this fd */
-            errno = ECONNABORTED;
-            return -1;
-        }
-    }
-
-    return ret;
-}
-
-int asocket_write(struct asocket *s, const void *buf, size_t count,
-        int timeout) {
-    int ret;
-    struct pollfd pfd[2];
-
-    pfd[0].fd = s->fd;
-    pfd[0].events = POLLOUT;
-    pfd[0].revents = 0;
-    pfd[1].fd = s->abort_fd[0];
-    pfd[1].events = POLLIN;
-    pfd[1].revents = 0;
-
-    do {
-        ret = poll(pfd, 2, timeout);
-    } while (ret < 0 && errno == EINTR);
-
-    if (ret < 0)
-        return -1;
-    else if (ret == 0) {
-        /* timeout */
-        errno = ETIMEDOUT;
-        return -1;
-    }
-
-    if (pfd[1].revents) {
-        /* abort due to asocket_abort() */
-        errno = ECANCELED;
-        return -1;
-    }
-
-    if (pfd[0].revents) {
-        if (pfd[0].revents & POLLOUT) {
-            /* ready to write() without blocking */
-            do {
-                ret = write(s->fd, buf, count);
-            } while (ret < 0 && errno == EINTR);
-        } else {
-            /* some error event on this fd */
-            errno = ECONNABORTED;
-            return -1;
-        }
-    }
-
-    return ret;
-}
-
-void asocket_abort(struct asocket *s) {
-    int ret;
-    char buf = 0;
-
-    /* Prevent further use of fd, without yet releasing the fd */
-    shutdown(s->fd, SHUT_RDWR);
-
-    /* wake up calls blocked at poll() */
-    do {
-        ret = write(s->abort_fd[1], &buf, 1);
-    } while (ret < 0 && errno == EINTR);
-}
-
-void asocket_destroy(struct asocket *s) {
-    struct asocket s_copy = *s;
-
-    /* Clients should *not* be using these fd's after calling
-       asocket_destroy(), but in case they do, set to -1 so they cannot use a
-       stale fd */
-    s->fd = -1;
-    s->abort_fd[0] = -1;
-    s->abort_fd[1] = -1;
-
-    /* Call asocket_abort() in case there are still threads blocked on this
-       socket. Clients should not rely on this behavior - it is racy because we
-       are about to close() these sockets - clients should instead make sure
-       all threads are done with the socket before calling asocket_destory().
-     */
-    asocket_abort(&s_copy);
-
-    /* enough safety checks, close and release memory */
-    close(s_copy.abort_fd[1]);
-    close(s_copy.abort_fd[0]);
-    close(s_copy.fd);
-
-    free(s);
-}
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index 33a7358..16f82bb 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -105,11 +105,8 @@
 {
     int ret;
 
-    if (!(flags & ANDROID_RB_FLAG_NO_SYNC))
-        sync();
-
-    if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO))
-        remount_ro();
+    sync();
+    remount_ro();
 
     switch (cmd) {
         case ANDROID_RB_RESTART:
diff --git a/libcutils/array.c b/libcutils/array.c
deleted file mode 100644
index 55ec055..0000000
--- a/libcutils/array.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2007 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 <cutils/array.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-
-#define INITIAL_CAPACITY (4)
-#define MAX_CAPACITY     ((int)(UINT_MAX/sizeof(void*)))
-
-struct Array {
-    void** contents;
-    int size;
-    int capacity;
-};
-
-Array* arrayCreate() {
-    return calloc(1, sizeof(struct Array));
-}
-
-void arrayFree(Array* array) {
-    assert(array != NULL);
-
-    // Free internal array.
-    free(array->contents);
-
-    // Free the Array itself.
-    free(array);
-}
-
-/** Returns 0 if successful, < 0 otherwise.. */
-static int ensureCapacity(Array* array, int capacity) {
-    int oldCapacity = array->capacity;
-    if (capacity > oldCapacity) {
-        int newCapacity = (oldCapacity == 0) ? INITIAL_CAPACITY : oldCapacity;
-
-        // Ensure we're not doing something nasty
-        if (capacity > MAX_CAPACITY)
-            return -1;
-
-        // Keep doubling capacity until we surpass necessary capacity.
-        while (newCapacity < capacity) {
-            int  newCap = newCapacity*2;
-            // Handle integer overflows
-            if (newCap < newCapacity || newCap > MAX_CAPACITY) {
-                newCap = MAX_CAPACITY;
-            }
-            newCapacity = newCap;
-        }
-
-        // Should not happen, but better be safe than sorry
-        if (newCapacity < 0 || newCapacity > MAX_CAPACITY)
-            return -1;
-
-        void** newContents;
-        if (array->contents == NULL) {
-            // Allocate new array.
-            newContents = malloc(newCapacity * sizeof(void*));
-            if (newContents == NULL) {
-                return -1;
-            }
-        } else {
-            // Expand existing array.
-            newContents = realloc(array->contents, sizeof(void*) * newCapacity);
-            if (newContents == NULL) {
-                return -1;
-            }
-        }
-
-        array->capacity = newCapacity;
-        array->contents = newContents;
-    }
-
-    return 0;
-}
-
-int arrayAdd(Array* array, void* pointer) {
-    assert(array != NULL);
-    int size = array->size;
-    int result = ensureCapacity(array, size + 1);
-    if (result < 0) {
-        return result;
-    }
-    array->contents[size] = pointer;
-    array->size++;
-    return 0;
-}
-
-static inline void checkBounds(Array* array, int index) {
-    assert(array != NULL);
-    assert(index < array->size);
-    assert(index >= 0);
-}
-
-void* arrayGet(Array* array, int index) {
-    checkBounds(array, index);
-    return array->contents[index];
-}
-
-void* arrayRemove(Array* array, int index) {
-    checkBounds(array, index);
-
-    void* pointer = array->contents[index];
-    
-    int newSize = array->size - 1;
-    
-    // Shift entries left.
-    if (index != newSize) {
-        memmove(array->contents + index, array->contents + index + 1, 
-                (sizeof(void*)) * (newSize - index));
-    }
-
-    array->size = newSize;
-
-    return pointer;
-}
-
-void* arraySet(Array* array, int index, void* pointer) {
-    checkBounds(array, index);
-    void* old = array->contents[index];
-    array->contents[index] = pointer;
-    return old;
-}
-
-int arraySetSize(Array* array, int newSize) {
-    assert(array != NULL);
-    assert(newSize >= 0);
-   
-    int oldSize = array->size;
-    
-    if (newSize > oldSize) {
-        // Expand.
-        int result = ensureCapacity(array, newSize);
-        if (result < 0) {
-            return result;
-        }
-
-        // Zero out new entries.
-        memset(array->contents + sizeof(void*) * oldSize, 0,
-                sizeof(void*) * (newSize - oldSize));
-    }
-
-    array->size = newSize;
-
-    return 0;
-}
-
-int arraySize(Array* array) {
-    assert(array != NULL);
-    return array->size;
-}
-
-const void** arrayUnwrap(Array* array) {
-    return (const void**)array->contents;
-}
diff --git a/libcutils/buffer.c b/libcutils/buffer.c
deleted file mode 100644
index af99bd7..0000000
--- a/libcutils/buffer.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#define LOG_TAG "buffer"
-
-#include <assert.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "buffer.h"
-#include "loghack.h"
-
-Buffer* bufferCreate(size_t capacity) {
-    Buffer* buffer = malloc(sizeof(Buffer));
-    if (buffer == NULL) {
-        return NULL;
-    }
-    buffer->capacity = capacity;
-    buffer->expected = 0;
-    buffer->data = malloc(capacity);
-    if (buffer->data == NULL) {
-        free(buffer);
-        return NULL;
-    }
-    return buffer;
-}
-
-void bufferFree(Buffer* buffer) {
-    free(buffer->data);
-    free(buffer);
-}
-
-Buffer* bufferWrap(char* data, size_t capacity, size_t size) {
-    Buffer* buffer = malloc(sizeof(Buffer));
-    if (buffer == NULL) {
-        return NULL;
-    }
-
-    buffer->data = data;
-    buffer->capacity = capacity;
-    buffer->size = size;
-    buffer->expected = 0;
-    return buffer;
-}
-
-int bufferPrepareForRead(Buffer* buffer, size_t expected) {
-    if (expected > buffer->capacity) {
-        // Expand buffer.
-        char* expanded = realloc(buffer->data, expected);
-        if (expanded == NULL) {
-            errno = ENOMEM;
-            return -1;
-        }
-        buffer->capacity = expected;
-        buffer->data = expanded;
-    }
-
-    buffer->size = 0;
-    buffer->expected = expected;
-    return 0;
-}
-
-ssize_t bufferRead(Buffer* buffer, int fd) {
-    assert(buffer->size < buffer->expected);
-    
-    ssize_t bytesRead = read(fd, 
-            buffer->data + buffer->size, 
-            buffer->expected - buffer->size);
-
-    if (bytesRead > 0) {
-        buffer->size += bytesRead;
-        return buffer->size;        
-    }
-
-    return bytesRead;
-}
-
-void bufferPrepareForWrite(Buffer* buffer) {
-    buffer->remaining = buffer->size;
-}
-
-ssize_t bufferWrite(Buffer* buffer, int fd) {
-    assert(buffer->remaining > 0);
-    assert(buffer->remaining <= buffer->size);
-
-    ssize_t bytesWritten = write(fd, 
-            buffer->data + buffer->size - buffer->remaining,
-            buffer->remaining);
-
-    if (bytesWritten >= 0) {
-        buffer->remaining -= bytesWritten;
-
-        ALOGD("Buffer bytes written: %d", (int) bytesWritten);
-        ALOGD("Buffer size: %d", (int) buffer->size);
-        ALOGD("Buffer remaining: %d", (int) buffer->remaining);
-
-        return buffer->remaining;
-    }
-
-    return bytesWritten;
-}
-
diff --git a/libcutils/buffer.h b/libcutils/buffer.h
deleted file mode 100644
index d8bc108..0000000
--- a/libcutils/buffer.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-/**
- * Byte buffer utilities.
- */
-
-#ifndef __BUFFER_H
-#define __BUFFER_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdlib.h>
-
-/** 
- * Byte buffer of known size. Keeps track of how much data has been read
- * into or written out of the buffer.
- */
-typedef struct {
-    /** Buffered data. */
-    char* data;
-
-    union {
-        /** For reading. # of bytes we expect. */
-        size_t expected;
-
-        /** For writing. # of bytes to write. */
-        size_t remaining;
-    };
-
-    /** Actual # of bytes in the buffer. */
-    size_t size;
-
-    /** Amount of memory allocated for this buffer. */
-    size_t capacity;
-} Buffer;
-
-/**
- * Returns true if all data has been read into the buffer.
- */
-#define bufferReadComplete(buffer) (buffer->expected == buffer->size)
-
-/**
- * Returns true if the buffer has been completely written.
- */
-#define bufferWriteComplete(buffer) (buffer->remaining == 0)
-
-/**
- * Creates a new buffer with the given initial capacity.
- */
-Buffer* bufferCreate(size_t initialCapacity);
-
-/**
- * Wraps an existing byte array.
- */
-Buffer* bufferWrap(char* data, size_t capacity, size_t size);
-
-/**
- * Frees and its data.
- */
-void bufferFree(Buffer* buffer);
-
-/**
- * Prepares buffer to read 'expected' number of bytes. Expands capacity if
- * necessary. Returns 0 if successful or -1 if an error occurs allocating
- * memory.
- */
-int bufferPrepareForRead(Buffer* buffer, size_t expected);
-
-/**
- * Reads some data into a buffer. Returns -1 in case of an error and sets 
- * errno (see read()). Returns 0 for EOF. Updates buffer->size and returns
- * the new size after a succesful read. 
- *
- * Precondition: buffer->size < buffer->expected
- */
-ssize_t bufferRead(Buffer* buffer, int fd);
-
-/**
- * Prepares a buffer to be written out.
- */
-void bufferPrepareForWrite(Buffer* buffer);
-
-/**
- * Writes data from buffer to the given fd. Returns -1 and sets errno in case
- * of an error. Updates buffer->remaining and returns the number of remaining
- * bytes to be written after a successful write. 
- *
- * Precondition: buffer->remaining > 0
- */
-ssize_t bufferWrite(Buffer* buffer, int fd);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __BUFFER_H */ 
diff --git a/libcutils/fs.c b/libcutils/fs.c
index 116526d..286a8eb 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.c
@@ -16,6 +16,11 @@
 
 #define LOG_TAG "cutils"
 
+/* These defines are only needed because prebuilt headers are out of date */
+#define __USE_XOPEN2K8 1
+#define _ATFILE_SOURCE 1
+#define _GNU_SOURCE 1
+
 #include <cutils/fs.h>
 #include <cutils/log.h>
 
@@ -27,6 +32,7 @@
 #include <string.h>
 #include <limits.h>
 #include <stdlib.h>
+#include <dirent.h>
 
 #define ALL_PERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
 #define BUF_SIZE 64
@@ -141,3 +147,91 @@
     unlink(temp);
     return -1;
 }
+
+#ifndef __APPLE__
+
+int fs_mkdirs(const char* path, mode_t mode) {
+    int res = 0;
+    int fd = 0;
+    struct stat sb;
+    char* buf = strdup(path);
+
+    if (*buf != '/') {
+        ALOGE("Relative paths are not allowed: %s", buf);
+        res = -EINVAL;
+        goto done;
+    }
+
+    if ((fd = open("/", 0)) == -1) {
+        ALOGE("Failed to open(/): %s", strerror(errno));
+        res = -errno;
+        goto done;
+    }
+
+    char* segment = buf + 1;
+    char* p = segment;
+    while (*p != '\0') {
+        if (*p == '/') {
+            *p = '\0';
+
+            if (!strcmp(segment, "..") || !strcmp(segment, ".") || !strcmp(segment, "")) {
+                ALOGE("Invalid path: %s", buf);
+                res = -EINVAL;
+                goto done_close;
+            }
+
+            if (fstatat(fd, segment, &sb, AT_SYMLINK_NOFOLLOW) != 0) {
+                if (errno == ENOENT) {
+                    /* Nothing there yet; let's create it! */
+                    if (mkdirat(fd, segment, mode) != 0) {
+                        if (errno == EEXIST) {
+                            /* We raced with someone; ignore */
+                        } else {
+                            ALOGE("Failed to mkdirat(%s): %s", buf, strerror(errno));
+                            res = -errno;
+                            goto done_close;
+                        }
+                    }
+                } else {
+                    ALOGE("Failed to fstatat(%s): %s", buf, strerror(errno));
+                    res = -errno;
+                    goto done_close;
+                }
+            } else {
+                if (S_ISLNK(sb.st_mode)) {
+                    ALOGE("Symbolic links are not allowed: %s", buf);
+                    res = -ELOOP;
+                    goto done_close;
+                }
+                if (!S_ISDIR(sb.st_mode)) {
+                    ALOGE("Existing segment not a directory: %s", buf);
+                    res = -ENOTDIR;
+                    goto done_close;
+                }
+            }
+
+            /* Yay, segment is ready for us to step into */
+            int next_fd;
+            if ((next_fd = openat(fd, segment, 0)) == -1) {
+                ALOGE("Failed to openat(%s): %s", buf, strerror(errno));
+                res = -errno;
+                goto done_close;
+            }
+
+            close(fd);
+            fd = next_fd;
+
+            *p = '/';
+            segment = p + 1;
+        }
+        p++;
+    }
+
+done_close:
+    close(fd);
+done:
+    free(buf);
+    return res;
+}
+
+#endif
diff --git a/libcutils/klog.c b/libcutils/klog.c
index 812af3b..d69fb10 100644
--- a/libcutils/klog.c
+++ b/libcutils/klog.c
@@ -40,6 +40,8 @@
 
     if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {
         klog_fd = open(name, O_WRONLY);
+        if (klog_fd < 0)
+                return;
         fcntl(klog_fd, F_SETFD, FD_CLOEXEC);
         unlink(name);
     }
@@ -54,6 +56,7 @@
 
     if (level > klog_level) return;
     if (klog_fd < 0) klog_init();
+    if (klog_fd < 0) return;
 
     va_start(ap, fmt);
     vsnprintf(buf, LOG_BUF_MAX, fmt, ap);
diff --git a/libcutils/mq.c b/libcutils/mq.c
deleted file mode 100644
index 899b1bc..0000000
--- a/libcutils/mq.c
+++ /dev/null
@@ -1,1357 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#define LOG_TAG "mq"
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <sys/uio.h>
-
-#include <cutils/array.h>
-#include <cutils/hashmap.h>
-#include <cutils/selector.h>
-
-#include "loghack.h"
-#include "buffer.h"
-
-/** Number of dead peers to remember. */
-#define PEER_HISTORY (16)
-
-typedef struct sockaddr SocketAddress;
-typedef struct sockaddr_un UnixAddress;
-
-/** 
- * Process/user/group ID. We don't use ucred directly because it's only 
- * available on Linux.
- */
-typedef struct {
-    pid_t pid;
-    uid_t uid;
-    gid_t gid;
-} Credentials;
-
-/** Listens for bytes coming from remote peers. */
-typedef void BytesListener(Credentials credentials, char* bytes, size_t size);
-
-/** Listens for the deaths of remote peers. */
-typedef void DeathListener(pid_t pid);
-
-/** Types of packets. */
-typedef enum {
-    /** Request for a connection to another peer. */
-    CONNECTION_REQUEST, 
-
-    /** A connection to another peer. */
-    CONNECTION, 
-
-    /** Reports a failed connection attempt. */
-    CONNECTION_ERROR, 
-
-    /** A generic packet of bytes. */
-    BYTES,
-} PacketType;
-
-typedef enum {
-    /** Reading a packet header. */
-    READING_HEADER,
-
-    /** Waiting for a connection from the master. */
-    ACCEPTING_CONNECTION,
-
-    /** Reading bytes. */
-    READING_BYTES,
-} InputState;
-
-/** A packet header. */
-// TODO: Use custom headers for master->peer, peer->master, peer->peer.
-typedef struct {
-    PacketType type;
-    union {
-        /** Packet size. Used for BYTES. */
-        size_t size;
-
-        /** Credentials. Used for CONNECTION and CONNECTION_REQUEST. */
-        Credentials credentials; 
-    };
-} Header;
-
-/** A packet which will be sent to a peer. */
-typedef struct OutgoingPacket OutgoingPacket;
-struct OutgoingPacket {
-    /** Packet header. */
-    Header header; 
-    
-    union {
-        /** Connection to peer. Used with CONNECTION. */
-        int socket;
-        
-        /** Buffer of bytes. Used with BYTES. */
-        Buffer* bytes;
-    };
-
-    /** Frees all resources associated with this packet. */
-    void (*free)(OutgoingPacket* packet);
-   
-    /** Optional context. */
-    void* context;
-    
-    /** Next packet in the queue. */
-    OutgoingPacket* nextPacket;
-};
-
-/** Represents a remote peer. */
-typedef struct PeerProxy PeerProxy;
-
-/** Local peer state. You typically have one peer per process. */
-typedef struct {
-    /** This peer's PID. */
-    pid_t pid;
-    
-    /** 
-     * Map from pid to peer proxy. The peer has a peer proxy for each remote
-     * peer it's connected to. 
-     *
-     * Acquire mutex before use.
-     */
-    Hashmap* peerProxies;
-
-    /** Manages I/O. */
-    Selector* selector;
-   
-    /** Used to synchronize operations with the selector thread. */
-    pthread_mutex_t mutex; 
-
-    /** Is this peer the master? */
-    bool master;
-
-    /** Peer proxy for the master. */
-    PeerProxy* masterProxy;
-    
-    /** Listens for packets from remote peers. */
-    BytesListener* onBytes;
-    
-    /** Listens for deaths of remote peers. */
-    DeathListener* onDeath;
-    
-    /** Keeps track of recently dead peers. Requires mutex. */
-    pid_t deadPeers[PEER_HISTORY];
-    size_t deadPeerCursor;
-} Peer;
-
-struct PeerProxy {
-    /** Credentials of the remote process. */
-    Credentials credentials;
-
-    /** Keeps track of data coming in from the remote peer. */
-    InputState inputState;
-    Buffer* inputBuffer;
-    PeerProxy* connecting;
-
-    /** File descriptor for this peer. */
-    SelectableFd* fd;
-
-    /** 
-     * Queue of packets to be written out to the remote peer.
-     *
-     * Requires mutex.
-     */
-    // TODO: Limit queue length.
-    OutgoingPacket* currentPacket;
-    OutgoingPacket* lastPacket;
-    
-    /** Used to write outgoing header. */
-    Buffer outgoingHeader;
-    
-    /** True if this is the master's proxy. */
-    bool master;
-
-    /** Reference back to the local peer. */
-    Peer* peer;
-
-    /**
-     * Used in master only. Maps this peer proxy to other peer proxies to
-     * which the peer has been connected to. Maps pid to PeerProxy. Helps
-     * keep track of which connections we've sent to whom.
-     */
-    Hashmap* connections;
-};
-
-/** Server socket path. */
-static const char* MASTER_PATH = "/master.peer";
-
-/** Credentials of the master peer. */
-static const Credentials MASTER_CREDENTIALS = {0, 0, 0};
-
-/** Creates a peer proxy and adds it to the peer proxy map. */
-static PeerProxy* peerProxyCreate(Peer* peer, Credentials credentials);
-
-/** Sets the non-blocking flag on a descriptor. */
-static void setNonBlocking(int fd) {
-    int flags;
-    if ((flags = fcntl(fd, F_GETFL, 0)) < 0) { 
-        LOG_ALWAYS_FATAL("fcntl() error: %s", strerror(errno));
-    } 
-    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { 
-        LOG_ALWAYS_FATAL("fcntl() error: %s", strerror(errno));
-    } 
-}
-
-/** Closes a fd and logs a warning if the close fails. */
-static void closeWithWarning(int fd) {
-    int result = close(fd);
-    if (result == -1) {
-        ALOGW("close() error: %s", strerror(errno));
-    }
-}
-
-/** Hashes pid_t keys. */
-static int pidHash(void* key) {
-    pid_t* pid = (pid_t*) key;
-    return (int) (*pid);
-}
-
-/** Compares pid_t keys. */
-static bool pidEquals(void* keyA, void* keyB) {
-    pid_t* a = (pid_t*) keyA;
-    pid_t* b = (pid_t*) keyB;
-    return *a == *b;
-}
-
-/** Gets the master address. Not thread safe. */
-static UnixAddress* getMasterAddress() {
-    static UnixAddress masterAddress;
-    static bool initialized = false;
-    if (initialized == false) {
-        masterAddress.sun_family = AF_LOCAL;
-        strcpy(masterAddress.sun_path, MASTER_PATH); 
-        initialized = true;
-    }
-    return &masterAddress;
-}
-
-/** Gets exclusive access to the peer for this thread. */
-static void peerLock(Peer* peer) {
-    pthread_mutex_lock(&peer->mutex);
-}
-
-/** Releases exclusive access to the peer. */
-static void peerUnlock(Peer* peer) {
-    pthread_mutex_unlock(&peer->mutex);
-}
-
-/** Frees a simple, i.e. header-only, outgoing packet. */
-static void outgoingPacketFree(OutgoingPacket* packet) {
-    ALOGD("Freeing outgoing packet.");
-	free(packet);
-}
-
-/**
- * Prepare to read a new packet from the peer.
- */
-static void peerProxyExpectHeader(PeerProxy* peerProxy) {
-    peerProxy->inputState = READING_HEADER;
-    bufferPrepareForRead(peerProxy->inputBuffer, sizeof(Header));
-}
-
-/** Sets up the buffer for the outgoing header. */
-static void peerProxyPrepareOutgoingHeader(PeerProxy* peerProxy) {
-    peerProxy->outgoingHeader.data 
-        = (char*) &(peerProxy->currentPacket->header);
-    peerProxy->outgoingHeader.size = sizeof(Header);
-    bufferPrepareForWrite(&peerProxy->outgoingHeader);
-}
-
-/** Adds a packet to the end of the queue. Callers must have the mutex. */
-static void peerProxyEnqueueOutgoingPacket(PeerProxy* peerProxy,
-        OutgoingPacket* newPacket) {
-    newPacket->nextPacket = NULL; // Just in case.
-    if (peerProxy->currentPacket == NULL) {
-        // The queue is empty.
-        peerProxy->currentPacket = newPacket;
-        peerProxy->lastPacket = newPacket;
-        
-        peerProxyPrepareOutgoingHeader(peerProxy); 
-    } else {
-        peerProxy->lastPacket->nextPacket = newPacket;
-    }
-}
-
-/** Takes the peer lock and enqueues the given packet. */
-static void peerProxyLockAndEnqueueOutgoingPacket(PeerProxy* peerProxy,
-        OutgoingPacket* newPacket) {
-    Peer* peer = peerProxy->peer;
-    peerLock(peer);
-    peerProxyEnqueueOutgoingPacket(peerProxy, newPacket);
-    peerUnlock(peer);
-}
-
-/** 
- * Frees current packet and moves to the next one. Returns true if there is
- * a next packet or false if the queue is empty.
- */
-static bool peerProxyNextPacket(PeerProxy* peerProxy) {
-    Peer* peer = peerProxy->peer;
-    peerLock(peer);
-    
-    OutgoingPacket* current = peerProxy->currentPacket;
-    
-    if (current == NULL) {
-    	// The queue is already empty.
-        peerUnlock(peer);
-        return false;
-    }
-    
-    OutgoingPacket* next = current->nextPacket;
-    peerProxy->currentPacket = next;
-    current->nextPacket = NULL;
-    current->free(current);
-    if (next == NULL) {
-        // The queue is empty.
-        peerProxy->lastPacket = NULL;
-        peerUnlock(peer);
-        return false;
-    } else {
-        peerUnlock(peer);
-        peerProxyPrepareOutgoingHeader(peerProxy); 
-
-        // TODO: Start writing next packet? It would reduce the number of
-        // system calls, but we could also starve other peers.
-        return true;
-    }
-}
-
-/**
- * Checks whether a peer died recently.
- */
-static bool peerIsDead(Peer* peer, pid_t pid) {
-    size_t i;
-    for (i = 0; i < PEER_HISTORY; i++) {
-        pid_t deadPeer = peer->deadPeers[i];
-        if (deadPeer == 0) {
-            return false;
-        }
-        if (deadPeer == pid) {
-            return true;
-        }
-    }
-    return false;
-}
-
-/**
- * Cleans up connection information.
- */
-static bool peerProxyRemoveConnection(void* key, void* value, void* context) {
-    PeerProxy* deadPeer = (PeerProxy*) context;
-    PeerProxy* otherPeer = (PeerProxy*) value;
-    hashmapRemove(otherPeer->connections, &(deadPeer->credentials.pid));
-    return true;
-}
-
-/**
- * Called when the peer dies.
- */
-static void peerProxyKill(PeerProxy* peerProxy, bool errnoIsSet) {
-    if (errnoIsSet) {
-        ALOGI("Peer %d died. errno: %s", peerProxy->credentials.pid, 
-                strerror(errno));
-    } else {
-        ALOGI("Peer %d died.", peerProxy->credentials.pid);
-    }
-    
-    // If we lost the master, we're up a creek. We can't let this happen.
-    if (peerProxy->master) {    
-        LOG_ALWAYS_FATAL("Lost connection to master.");
-    }
-
-    Peer* localPeer = peerProxy->peer;
-    pid_t pid = peerProxy->credentials.pid;
-    
-    peerLock(localPeer);
-    
-    // Remember for awhile that the peer died.
-    localPeer->deadPeers[localPeer->deadPeerCursor] 
-        = peerProxy->credentials.pid;
-    localPeer->deadPeerCursor++;
-    if (localPeer->deadPeerCursor == PEER_HISTORY) {
-        localPeer->deadPeerCursor = 0;
-    }
-  
-    // Remove from peer map.
-    hashmapRemove(localPeer->peerProxies, &pid);
-    
-    // External threads can no longer get to this peer proxy, so we don't 
-    // need the lock anymore.
-    peerUnlock(localPeer);
-    
-    // Remove the fd from the selector.
-    if (peerProxy->fd != NULL) {
-        peerProxy->fd->remove = true;
-    }
-
-    // Clear outgoing packet queue.
-    while (peerProxyNextPacket(peerProxy)) {}
-
-    bufferFree(peerProxy->inputBuffer);
-
-    // This only applies to the master.
-    if (peerProxy->connections != NULL) {
-        // We can't leave these other maps pointing to freed memory.
-        hashmapForEach(peerProxy->connections, &peerProxyRemoveConnection, 
-                peerProxy);
-        hashmapFree(peerProxy->connections);
-    }
-
-    // Invoke death listener.
-    localPeer->onDeath(pid);
-
-    // Free the peer proxy itself.
-    free(peerProxy);
-}
-
-static void peerProxyHandleError(PeerProxy* peerProxy, char* functionName) {
-    if (errno == EINTR) {
-        // Log interruptions but otherwise ignore them.
-        ALOGW("%s() interrupted.", functionName);
-    } else if (errno == EAGAIN) {
-        ALOGD("EWOULDBLOCK");
-        // Ignore.
-    } else {
-        ALOGW("Error returned by %s().", functionName);
-        peerProxyKill(peerProxy, true);
-    }
-}
-
-/**
- * Buffers output sent to a peer. May be called multiple times until the entire
- * buffer is filled. Returns true when the buffer is empty.
- */
-static bool peerProxyWriteFromBuffer(PeerProxy* peerProxy, Buffer* outgoing) {
-    ssize_t size = bufferWrite(outgoing, peerProxy->fd->fd);
-    if (size < 0) {
-        peerProxyHandleError(peerProxy, "write");
-        return false;
-    } else {
-        return bufferWriteComplete(outgoing);
-    }
-}
-
-/** Writes packet bytes to peer. */
-static void peerProxyWriteBytes(PeerProxy* peerProxy) {	
-	Buffer* buffer = peerProxy->currentPacket->bytes;
-	if (peerProxyWriteFromBuffer(peerProxy, buffer)) {
-        ALOGD("Bytes written.");
-        peerProxyNextPacket(peerProxy);
-    }    
-}
-
-/** Sends a socket to the peer. */
-static void peerProxyWriteConnection(PeerProxy* peerProxy) {
-    int socket = peerProxy->currentPacket->socket;
-
-    // Why does sending and receiving fds have to be such a PITA?
-    struct msghdr msg;
-    struct iovec iov[1];
-    
-    union {
-        struct cmsghdr cm;
-        char control[CMSG_SPACE(sizeof(int))];
-    } control_un;
-   
-    struct cmsghdr *cmptr;
-    
-    msg.msg_control = control_un.control;
-    msg.msg_controllen = sizeof(control_un.control);
-    cmptr = CMSG_FIRSTHDR(&msg);
-    cmptr->cmsg_len = CMSG_LEN(sizeof(int));
-    cmptr->cmsg_level = SOL_SOCKET;
-    cmptr->cmsg_type = SCM_RIGHTS;
-   
-    // Store the socket in the message.
-    *((int *) CMSG_DATA(cmptr)) = peerProxy->currentPacket->socket;
-
-    msg.msg_name = NULL;
-    msg.msg_namelen = 0;
-    iov[0].iov_base = "";
-    iov[0].iov_len = 1;
-    msg.msg_iov = iov;
-    msg.msg_iovlen = 1;
-
-    ssize_t result = sendmsg(peerProxy->fd->fd, &msg, 0);
-    
-    if (result < 0) {
-        peerProxyHandleError(peerProxy, "sendmsg");
-    } else {
-        // Success. Queue up the next packet.
-        peerProxyNextPacket(peerProxy);
-        
-    }
-}
-
-/**
- * Writes some outgoing data.
- */
-static void peerProxyWrite(SelectableFd* fd) {
-    // TODO: Try to write header and body with one system call.
-
-    PeerProxy* peerProxy = (PeerProxy*) fd->data;
-    OutgoingPacket* current = peerProxy->currentPacket;
-    
-    if (current == NULL) {
-        // We have nothing left to write.
-        return;
-    }
-
-    // Write the header.
-    Buffer* outgoingHeader = &peerProxy->outgoingHeader;
-    bool headerWritten = bufferWriteComplete(outgoingHeader);
-    if (!headerWritten) {
-        ALOGD("Writing header...");
-        headerWritten = peerProxyWriteFromBuffer(peerProxy, outgoingHeader);
-        if (headerWritten) {
-            ALOGD("Header written.");
-        }
-    }    
-
-    // Write body.
-    if (headerWritten) {
-        PacketType type = current->header.type;
-        switch (type) {
-            case CONNECTION:
-                peerProxyWriteConnection(peerProxy);
-                break;
-            case BYTES:
-                peerProxyWriteBytes(peerProxy);
-                break;
-            case CONNECTION_REQUEST:
-            case CONNECTION_ERROR:
-                // These packets consist solely of a header.
-                peerProxyNextPacket(peerProxy);
-                break;
-            default:
-                LOG_ALWAYS_FATAL("Unknown packet type: %d", type); 
-        }
-    }
-}
-
-/**
- * Sets up a peer proxy's fd before we try to select() it.
- */
-static void peerProxyBeforeSelect(SelectableFd* fd) {
-    ALOGD("Before select...");
-
-    PeerProxy* peerProxy = (PeerProxy*) fd->data;
-  
-    peerLock(peerProxy->peer);
-    bool hasPackets = peerProxy->currentPacket != NULL;
-    peerUnlock(peerProxy->peer);
-    
-    if (hasPackets) {
-        ALOGD("Packets found. Setting onWritable().");
-            
-        fd->onWritable = &peerProxyWrite;
-    } else {
-        // We have nothing to write.
-        fd->onWritable = NULL;
-    }
-}
-
-/** Prepare to read bytes from the peer. */
-static void peerProxyExpectBytes(PeerProxy* peerProxy, Header* header) {
-    ALOGD("Expecting %zd bytes.", header->size);
-
-    peerProxy->inputState = READING_BYTES;
-    if (bufferPrepareForRead(peerProxy->inputBuffer, header->size) == -1) {
-        ALOGW("Couldn't allocate memory for incoming data. Size: %u",
-                (unsigned int) header->size);    
-        
-        // TODO: Ignore the packet and log a warning?
-        peerProxyKill(peerProxy, false);
-    }
-}
-
-/**
- * Gets a peer proxy for the given ID. Creates a peer proxy if necessary.
- * Sends a connection request to the master if desired.
- *
- * Returns NULL if an error occurs. Sets errno to EHOSTDOWN if the peer died
- * or ENOMEM if memory couldn't be allocated.
- */
-static PeerProxy* peerProxyGetOrCreate(Peer* peer, pid_t pid, 
-        bool requestConnection) {
-    if (pid == peer->pid) {
-        errno = EINVAL;
-        return NULL;
-    }
-    
-    if (peerIsDead(peer, pid)) {
-        errno = EHOSTDOWN;
-        return NULL;
-    }
-    
-    PeerProxy* peerProxy = hashmapGet(peer->peerProxies, &pid);
-    if (peerProxy != NULL) {
-        return peerProxy;
-    }
-
-    // If this is the master peer, we already know about all peers.
-    if (peer->master) {
-        errno = EHOSTDOWN;
-        return NULL;
-    }
-
-    // Try to create a peer proxy.
-    Credentials credentials;
-    credentials.pid = pid;
-
-    // Fake gid and uid until we have the real thing. The real creds are
-    // filled in by masterProxyExpectConnection(). These fake creds will
-    // never be exposed to the user.
-    credentials.uid = 0;
-    credentials.gid = 0;
-
-    // Make sure we can allocate the connection request packet.
-    OutgoingPacket* packet = NULL;
-    if (requestConnection) {
-        packet = calloc(1, sizeof(OutgoingPacket));
-        if (packet == NULL) {
-            errno = ENOMEM;
-            return NULL;
-        }
-
-        packet->header.type = CONNECTION_REQUEST;
-        packet->header.credentials = credentials;
-        packet->free = &outgoingPacketFree;
-    }
-    
-    peerProxy = peerProxyCreate(peer, credentials);
-    if (peerProxy == NULL) {
-        free(packet);
-        errno = ENOMEM;
-        return NULL;
-    } else {
-        // Send a connection request to the master.
-        if (requestConnection) {
-            PeerProxy* masterProxy = peer->masterProxy;
-            peerProxyEnqueueOutgoingPacket(masterProxy, packet);
-        }
-        
-        return peerProxy;
-    }
-}
-
-/**
- * Switches the master peer proxy into a state where it's waiting for a
- * connection from the master.
- */
-static void masterProxyExpectConnection(PeerProxy* masterProxy,
-        Header* header) {
-    // TODO: Restructure things so we don't need this check.
-    // Verify that this really is the master.
-    if (!masterProxy->master) {
-        ALOGW("Non-master process %d tried to send us a connection.", 
-            masterProxy->credentials.pid);
-        // Kill off the evil peer.
-        peerProxyKill(masterProxy, false);
-        return;
-    }
-    
-    masterProxy->inputState = ACCEPTING_CONNECTION;
-    Peer* localPeer = masterProxy->peer;
-   
-    // Create a peer proxy so we have somewhere to stash the creds.
-    // See if we already have a proxy set up.
-    pid_t pid = header->credentials.pid;
-    peerLock(localPeer);
-    PeerProxy* peerProxy = peerProxyGetOrCreate(localPeer, pid, false);
-    if (peerProxy == NULL) {
-        ALOGW("Peer proxy creation failed: %s", strerror(errno));
-    } else {
-        // Fill in full credentials.
-        peerProxy->credentials = header->credentials;
-    }
-    peerUnlock(localPeer);
-    
-    // Keep track of which peer proxy we're accepting a connection for.
-    masterProxy->connecting = peerProxy;
-}
-
-/**
- * Reads input from a peer process.
- */
-static void peerProxyRead(SelectableFd* fd);
-
-/** Sets up fd callbacks. */
-static void peerProxySetFd(PeerProxy* peerProxy, SelectableFd* fd) {
-    peerProxy->fd = fd;
-    fd->data = peerProxy;
-    fd->onReadable = &peerProxyRead;
-    fd->beforeSelect = &peerProxyBeforeSelect;
-    
-    // Make the socket non-blocking.
-    setNonBlocking(fd->fd);
-}
-
-/**
- * Accepts a connection sent by the master proxy.
- */
-static void masterProxyAcceptConnection(PeerProxy* masterProxy) {
-    struct msghdr msg;
-    struct iovec iov[1];
-    ssize_t size;
-    char ignored;
-    int incomingFd;
-    
-    // TODO: Reuse code which writes the connection. Who the heck designed
-    // this API anyway?
-    union {
-        struct cmsghdr cm;
-        char control[CMSG_SPACE(sizeof(int))];
-    } control_un;
-    struct cmsghdr *cmptr;
-    msg.msg_control = control_un.control;
-    msg.msg_controllen = sizeof(control_un.control);
-
-    msg.msg_name = NULL;
-    msg.msg_namelen = 0;
-
-    // We sent 1 byte of data so we can detect EOF.
-    iov[0].iov_base = &ignored;
-    iov[0].iov_len = 1;
-    msg.msg_iov = iov;
-    msg.msg_iovlen = 1;
-
-    size = recvmsg(masterProxy->fd->fd, &msg, 0);
-    if (size < 0) {
-        if (errno == EINTR) {
-            // Log interruptions but otherwise ignore them.
-            ALOGW("recvmsg() interrupted.");
-            return;
-        } else if (errno == EAGAIN) {
-            // Keep waiting for the connection.
-            return;
-        } else {
-            LOG_ALWAYS_FATAL("Error reading connection from master: %s",
-                    strerror(errno));
-        }
-    } else if (size == 0) {
-        // EOF.
-        LOG_ALWAYS_FATAL("Received EOF from master.");
-    }
-
-    // Extract fd from message.
-    if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL 
-            && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
-        if (cmptr->cmsg_level != SOL_SOCKET) {
-            LOG_ALWAYS_FATAL("Expected SOL_SOCKET.");
-        }
-        if (cmptr->cmsg_type != SCM_RIGHTS) {
-            LOG_ALWAYS_FATAL("Expected SCM_RIGHTS.");
-        }
-        incomingFd = *((int*) CMSG_DATA(cmptr));
-    } else {
-        LOG_ALWAYS_FATAL("Expected fd.");
-    }
-    
-    // The peer proxy this connection is for.
-    PeerProxy* peerProxy = masterProxy->connecting;
-    if (peerProxy == NULL) {
-        ALOGW("Received connection for unknown peer.");
-        closeWithWarning(incomingFd);
-    } else {
-        Peer* peer = masterProxy->peer;
-        
-        SelectableFd* selectableFd = selectorAdd(peer->selector, incomingFd);
-        if (selectableFd == NULL) {
-            ALOGW("Error adding fd to selector for %d.",
-                    peerProxy->credentials.pid);
-            closeWithWarning(incomingFd);
-            peerProxyKill(peerProxy, false);
-        }
-
-        peerProxySetFd(peerProxy, selectableFd);
-    }
-    
-    peerProxyExpectHeader(masterProxy);
-}
-
-/**
- * Frees an outgoing packet containing a connection.
- */
-static void outgoingPacketFreeSocket(OutgoingPacket* packet) {
-    closeWithWarning(packet->socket);
-    outgoingPacketFree(packet);
-}
-
-/**
- * Connects two known peers.
- */
-static void masterConnectPeers(PeerProxy* peerA, PeerProxy* peerB) {
-    int sockets[2];
-    int result = socketpair(AF_LOCAL, SOCK_STREAM, 0, sockets);
-    if (result == -1) {
-        ALOGW("socketpair() error: %s", strerror(errno));
-        // TODO: Send CONNECTION_FAILED packets to peers.
-        return;
-    }
-
-    OutgoingPacket* packetA = calloc(1, sizeof(OutgoingPacket));
-    OutgoingPacket* packetB = calloc(1, sizeof(OutgoingPacket));
-    if (packetA == NULL || packetB == NULL) {
-        free(packetA);
-        free(packetB);
-        ALOGW("malloc() error. Failed to tell process %d that process %d is"
-                " dead.", peerA->credentials.pid, peerB->credentials.pid);
-        return;
-    }
-   
-    packetA->header.type = CONNECTION;
-    packetB->header.type = CONNECTION;
-    
-    packetA->header.credentials = peerB->credentials;
-    packetB->header.credentials = peerA->credentials;
-
-    packetA->socket = sockets[0];
-    packetB->socket = sockets[1];
-
-    packetA->free = &outgoingPacketFreeSocket;
-    packetB->free = &outgoingPacketFreeSocket;
-   
-    peerLock(peerA->peer);
-    peerProxyEnqueueOutgoingPacket(peerA, packetA);   
-    peerProxyEnqueueOutgoingPacket(peerB, packetB);   
-    peerUnlock(peerA->peer);
-}
-
-/**
- * Informs a peer that the peer they're trying to connect to couldn't be
- * found.
- */
-static void masterReportConnectionError(PeerProxy* peerProxy,
-        Credentials credentials) {
-    OutgoingPacket* packet = calloc(1, sizeof(OutgoingPacket));
-    if (packet == NULL) {
-        ALOGW("malloc() error. Failed to tell process %d that process %d is"
-                " dead.", peerProxy->credentials.pid, credentials.pid);
-        return;
-    }
-   
-    packet->header.type = CONNECTION_ERROR;
-    packet->header.credentials = credentials;
-    packet->free = &outgoingPacketFree;
-    
-    peerProxyLockAndEnqueueOutgoingPacket(peerProxy, packet);   
-}
-
-/**
- * Handles a request to be connected to another peer.
- */
-static void masterHandleConnectionRequest(PeerProxy* peerProxy, 
-        Header* header) {
-    Peer* master = peerProxy->peer;
-    pid_t targetPid = header->credentials.pid;
-    if (!hashmapContainsKey(peerProxy->connections, &targetPid)) {
-        // We haven't connected these peers yet.
-        PeerProxy* targetPeer 
-            = (PeerProxy*) hashmapGet(master->peerProxies, &targetPid);
-        if (targetPeer == NULL) {
-            // Unknown process.
-            masterReportConnectionError(peerProxy, header->credentials);
-        } else {
-            masterConnectPeers(peerProxy, targetPeer);
-        }
-    }
-    
-    // This packet is complete. Get ready for the next one.
-    peerProxyExpectHeader(peerProxy);
-}
-
-/**
- * The master told us this peer is dead.
- */
-static void masterProxyHandleConnectionError(PeerProxy* masterProxy,
-        Header* header) {
-    Peer* peer = masterProxy->peer;
-    
-    // Look up the peer proxy.
-    pid_t pid = header->credentials.pid;
-    PeerProxy* peerProxy = NULL;
-    peerLock(peer);
-    peerProxy = hashmapGet(peer->peerProxies, &pid);
-    peerUnlock(peer);
-
-    if (peerProxy != NULL) {
-        ALOGI("Couldn't connect to %d.", pid);
-        peerProxyKill(peerProxy, false);
-    } else {
-        ALOGW("Peer proxy for %d not found. This shouldn't happen.", pid);
-    }
-    
-    peerProxyExpectHeader(masterProxy);
-}
-
-/**
- * Handles a packet header.
- */
-static void peerProxyHandleHeader(PeerProxy* peerProxy, Header* header) {
-    switch (header->type) {
-        case CONNECTION_REQUEST:
-            masterHandleConnectionRequest(peerProxy, header);
-            break;
-        case CONNECTION:
-            masterProxyExpectConnection(peerProxy, header);
-            break;
-        case CONNECTION_ERROR:
-            masterProxyHandleConnectionError(peerProxy, header);
-            break;
-        case BYTES:    
-            peerProxyExpectBytes(peerProxy, header);
-            break;
-        default:
-            ALOGW("Invalid packet type from %d: %d", peerProxy->credentials.pid, 
-                    header->type);
-            peerProxyKill(peerProxy, false);
-    }
-}
-
-/**
- * Buffers input sent by peer. May be called multiple times until the entire
- * buffer is filled. Returns true when the buffer is full.
- */
-static bool peerProxyBufferInput(PeerProxy* peerProxy) {
-    Buffer* in = peerProxy->inputBuffer;
-    ssize_t size = bufferRead(in, peerProxy->fd->fd);
-    if (size < 0) {
-        peerProxyHandleError(peerProxy, "read");
-        return false;
-    } else if (size == 0) {
-        // EOF.
-    	ALOGI("EOF");
-        peerProxyKill(peerProxy, false);
-        return false;
-    } else if (bufferReadComplete(in)) {
-        // We're done!
-        return true;
-    } else {
-        // Continue reading.
-        return false;
-    }
-}
-
-/**
- * Reads input from a peer process.
- */
-static void peerProxyRead(SelectableFd* fd) {
-    ALOGD("Reading...");
-    PeerProxy* peerProxy = (PeerProxy*) fd->data;
-    int state = peerProxy->inputState;
-    Buffer* in = peerProxy->inputBuffer;
-    switch (state) {
-        case READING_HEADER:
-            if (peerProxyBufferInput(peerProxy)) {
-                ALOGD("Header read.");
-                // We've read the complete header.
-                Header* header = (Header*) in->data;
-                peerProxyHandleHeader(peerProxy, header);
-            }
-            break;
-        case READING_BYTES:
-            ALOGD("Reading bytes...");
-            if (peerProxyBufferInput(peerProxy)) {
-                ALOGD("Bytes read.");
-                // We have the complete packet. Notify bytes listener.
-                peerProxy->peer->onBytes(peerProxy->credentials,
-                    in->data, in->size);
-                        
-                // Get ready for the next packet.
-                peerProxyExpectHeader(peerProxy);
-            }
-            break;
-        case ACCEPTING_CONNECTION:
-            masterProxyAcceptConnection(peerProxy);
-            break;
-        default:
-            LOG_ALWAYS_FATAL("Unknown state: %d", state);
-    }
-}
-
-static PeerProxy* peerProxyCreate(Peer* peer, Credentials credentials) {
-    PeerProxy* peerProxy = calloc(1, sizeof(PeerProxy));
-    if (peerProxy == NULL) {
-        return NULL;
-    }
-   
-    peerProxy->inputBuffer = bufferCreate(sizeof(Header));
-    if (peerProxy->inputBuffer == NULL) {
-        free(peerProxy);
-        return NULL;
-    }
-
-    peerProxy->peer = peer;
-    peerProxy->credentials = credentials;
-
-    // Initial state == expecting a header.
-    peerProxyExpectHeader(peerProxy); 
-  
-    // Add this proxy to the map. Make sure the key points to the stable memory
-    // inside of the peer proxy itself.
-    pid_t* pid = &(peerProxy->credentials.pid);
-    hashmapPut(peer->peerProxies, pid, peerProxy);
-    return peerProxy;
-}
-
-/** Accepts a connection to the master peer. */
-static void masterAcceptConnection(SelectableFd* listenerFd) {
-    // Accept connection.
-    int socket = accept(listenerFd->fd, NULL, NULL);
-    if (socket == -1) {
-        ALOGW("accept() error: %s", strerror(errno));
-        return;
-    }
-    
-    ALOGD("Accepted connection as fd %d.", socket);
-    
-    // Get credentials.
-    Credentials credentials;
-    struct ucred ucredentials;
-    socklen_t credentialsSize = sizeof(struct ucred);
-    int result = getsockopt(socket, SOL_SOCKET, SO_PEERCRED, 
-                &ucredentials, &credentialsSize);
-    // We might want to verify credentialsSize.
-    if (result == -1) {
-        ALOGW("getsockopt() error: %s", strerror(errno));
-        closeWithWarning(socket);
-        return;
-    }
-
-    // Copy values into our own structure so we know we have the types right.
-    credentials.pid = ucredentials.pid;
-    credentials.uid = ucredentials.uid;
-    credentials.gid = ucredentials.gid;
-    
-    ALOGI("Accepted connection from process %d.", credentials.pid);
-   
-    Peer* masterPeer = (Peer*) listenerFd->data;
-    
-    peerLock(masterPeer);
-    
-    // Make sure we don't already have a connection from that process.
-    PeerProxy* peerProxy 
-        = hashmapGet(masterPeer->peerProxies, &credentials.pid);
-    if (peerProxy != NULL) {
-        peerUnlock(masterPeer);
-        ALOGW("Alread connected to process %d.", credentials.pid);
-        closeWithWarning(socket);
-        return;
-    }
-   
-    // Add connection to the selector.
-    SelectableFd* socketFd = selectorAdd(masterPeer->selector, socket);
-    if (socketFd == NULL) {
-        peerUnlock(masterPeer);
-        ALOGW("malloc() failed.");
-        closeWithWarning(socket);
-        return;
-    }
-
-    // Create a peer proxy.
-    peerProxy = peerProxyCreate(masterPeer, credentials);
-    peerUnlock(masterPeer);
-    if (peerProxy == NULL) {
-        ALOGW("malloc() failed.");
-        socketFd->remove = true;
-        closeWithWarning(socket);
-    }
-    peerProxy->connections = hashmapCreate(10, &pidHash, &pidEquals);
-    peerProxySetFd(peerProxy, socketFd);
-}
-
-/**
- * Creates the local peer.
- */
-static Peer* peerCreate() {
-    Peer* peer = calloc(1, sizeof(Peer));
-    if (peer == NULL) {
-        LOG_ALWAYS_FATAL("malloc() error.");
-    }
-    peer->peerProxies = hashmapCreate(10, &pidHash, &pidEquals);
-    peer->selector = selectorCreate();
-    
-    pthread_mutexattr_t attributes;
-    if (pthread_mutexattr_init(&attributes) != 0) {
-        LOG_ALWAYS_FATAL("pthread_mutexattr_init() error.");
-    }
-    if (pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE) != 0) {
-        LOG_ALWAYS_FATAL("pthread_mutexattr_settype() error.");
-    }
-    if (pthread_mutex_init(&peer->mutex, &attributes) != 0) {
-        LOG_ALWAYS_FATAL("pthread_mutex_init() error.");
-    }
-    
-    peer->pid = getpid();
-    return peer;
-}
-
-/** The local peer. */
-static Peer* localPeer;
-
-/** Frees a packet of bytes. */
-static void outgoingPacketFreeBytes(OutgoingPacket* packet) {
-    ALOGD("Freeing outgoing packet.");
-    bufferFree(packet->bytes);
-    free(packet);
-}
-
-/**
- * Sends a packet of bytes to a remote peer. Returns 0 on success.
- *
- * Returns -1 if an error occurs. Sets errno to ENOMEM if memory couldn't be
- * allocated. Sets errno to EHOSTDOWN if the peer died recently. Sets errno
- * to EINVAL if pid is the same as the local pid.
- */
-int peerSendBytes(pid_t pid, const char* bytes, size_t size) {
-	Peer* peer = localPeer;
-    assert(peer != NULL);
-
-    OutgoingPacket* packet = calloc(1, sizeof(OutgoingPacket));
-    if (packet == NULL) {
-        errno = ENOMEM;
-        return -1;
-    }
-
-    Buffer* copy = bufferCreate(size); 
-    if (copy == NULL) {
-        free(packet);
-        errno = ENOMEM;
-        return -1;
-    }
-
-    // Copy data.
-    memcpy(copy->data, bytes, size);
-    copy->size = size;
-    
-    packet->bytes = copy;
-    packet->header.type = BYTES;
-    packet->header.size = size;
-    packet->free = outgoingPacketFreeBytes;
-    bufferPrepareForWrite(packet->bytes);
-    
-    peerLock(peer);
-    
-    PeerProxy* peerProxy = peerProxyGetOrCreate(peer, pid, true);
-    if (peerProxy == NULL) {
-        // The peer is already dead or we couldn't alloc memory. Either way,
-        // errno is set.
-        peerUnlock(peer);
-        packet->free(packet); 
-        return -1;
-    } else {
-        peerProxyEnqueueOutgoingPacket(peerProxy, packet);
-        peerUnlock(peer);
-        selectorWakeUp(peer->selector);
-        return 0; 
-    }
-}
-
-/** Keeps track of how to free shared bytes. */
-typedef struct {
-    void (*free)(void* context);
-    void* context;
-} SharedBytesFreer;
-
-/** Frees shared bytes. */
-static void outgoingPacketFreeSharedBytes(OutgoingPacket* packet) {
-    SharedBytesFreer* sharedBytesFreer 
-        = (SharedBytesFreer*) packet->context;
-    sharedBytesFreer->free(sharedBytesFreer->context);
-    free(sharedBytesFreer);
-    free(packet);
-}
-
-/**
- * Sends a packet of bytes to a remote peer without copying the bytes. Calls
- * free() with context after the bytes have been sent.
- *
- * Returns -1 if an error occurs. Sets errno to ENOMEM if memory couldn't be
- * allocated. Sets errno to EHOSTDOWN if the peer died recently. Sets errno
- * to EINVAL if pid is the same as the local pid.
- */
-int peerSendSharedBytes(pid_t pid, char* bytes, size_t size,
-        void (*free)(void* context), void* context) {
-    Peer* peer = localPeer;
-    assert(peer != NULL);
-
-    OutgoingPacket* packet = calloc(1, sizeof(OutgoingPacket));
-    if (packet == NULL) {
-        errno = ENOMEM;
-        return -1;
-    }
-
-    Buffer* wrapper = bufferWrap(bytes, size, size);
-    if (wrapper == NULL) {
-        free(packet);
-        errno = ENOMEM;
-        return -1;
-    }
-
-    SharedBytesFreer* sharedBytesFreer = malloc(sizeof(SharedBytesFreer));
-    if (sharedBytesFreer == NULL) {
-        free(packet);
-        free(wrapper);
-        errno = ENOMEM;
-        return -1;
-    }
-    sharedBytesFreer->free = free;
-    sharedBytesFreer->context = context;
-    
-    packet->bytes = wrapper;
-    packet->context = sharedBytesFreer;
-    packet->header.type = BYTES;
-    packet->header.size = size;
-    packet->free = &outgoingPacketFreeSharedBytes;
-    bufferPrepareForWrite(packet->bytes);
-    
-    peerLock(peer);
-    
-    PeerProxy* peerProxy = peerProxyGetOrCreate(peer, pid, true);
-    if (peerProxy == NULL) {
-        // The peer is already dead or we couldn't alloc memory. Either way,
-        // errno is set.
-        peerUnlock(peer);
-        packet->free(packet); 
-        return -1;
-    } else {
-        peerProxyEnqueueOutgoingPacket(peerProxy, packet);
-        peerUnlock(peer);
-        selectorWakeUp(peer->selector);
-        return 0; 
-    }
-}
-
-/**
- * Starts the master peer. The master peer differs from other peers in that
- * it is responsible for connecting the other peers. You can only have one
- * master peer.
- *
- * Goes into an I/O loop and does not return.
- */
-void masterPeerInitialize(BytesListener* bytesListener, 
-        DeathListener* deathListener) {
-    // Create and bind socket.
-    int listenerSocket = socket(AF_LOCAL, SOCK_STREAM, 0);
-    if (listenerSocket == -1) {
-        LOG_ALWAYS_FATAL("socket() error: %s", strerror(errno));
-    }
-    unlink(MASTER_PATH);
-    int result = bind(listenerSocket, (SocketAddress*) getMasterAddress(), 
-            sizeof(UnixAddress));
-    if (result == -1) {
-        LOG_ALWAYS_FATAL("bind() error: %s", strerror(errno));
-    }
-
-    ALOGD("Listener socket: %d",  listenerSocket);
-    
-    // Queue up to 16 connections.
-    result = listen(listenerSocket, 16);
-    if (result != 0) {
-        LOG_ALWAYS_FATAL("listen() error: %s", strerror(errno));
-    }
-
-    // Make socket non-blocking.
-    setNonBlocking(listenerSocket);
-
-    // Create the peer for this process. Fail if we already have one.
-    if (localPeer != NULL) {
-        LOG_ALWAYS_FATAL("Peer is already initialized.");
-    }
-    localPeer = peerCreate();
-    if (localPeer == NULL) {
-        LOG_ALWAYS_FATAL("malloc() failed.");
-    }
-    localPeer->master = true;
-    localPeer->onBytes = bytesListener;
-    localPeer->onDeath = deathListener;
-    
-    // Make listener socket selectable.
-    SelectableFd* listenerFd = selectorAdd(localPeer->selector, listenerSocket);
-    if (listenerFd == NULL) {
-        LOG_ALWAYS_FATAL("malloc() error.");
-    }
-    listenerFd->data = localPeer;
-    listenerFd->onReadable = &masterAcceptConnection;
-}
-
-/**
- * Starts a local peer.
- *
- * Goes into an I/O loop and does not return.
- */
-void peerInitialize(BytesListener* bytesListener, 
-        DeathListener* deathListener) {
-    // Connect to master peer.
-    int masterSocket = socket(AF_LOCAL, SOCK_STREAM, 0);
-    if (masterSocket == -1) {
-        LOG_ALWAYS_FATAL("socket() error: %s", strerror(errno));
-    }
-    int result = connect(masterSocket, (SocketAddress*) getMasterAddress(),
-            sizeof(UnixAddress));
-    if (result != 0) {
-        LOG_ALWAYS_FATAL("connect() error: %s", strerror(errno));
-    }
-
-    // Create the peer for this process. Fail if we already have one.
-    if (localPeer != NULL) {
-        LOG_ALWAYS_FATAL("Peer is already initialized.");
-    }
-    localPeer = peerCreate();
-    if (localPeer == NULL) {
-        LOG_ALWAYS_FATAL("malloc() failed.");
-    }
-    localPeer->onBytes = bytesListener;
-    localPeer->onDeath = deathListener;
-    
-    // Make connection selectable.
-    SelectableFd* masterFd = selectorAdd(localPeer->selector, masterSocket);
-    if (masterFd == NULL) {
-        LOG_ALWAYS_FATAL("malloc() error.");
-    }
-
-    // Create a peer proxy for the master peer.
-    PeerProxy* masterProxy = peerProxyCreate(localPeer, MASTER_CREDENTIALS);
-    if (masterProxy == NULL) {
-        LOG_ALWAYS_FATAL("malloc() error.");
-    }
-    peerProxySetFd(masterProxy, masterFd);
-    masterProxy->master = true;
-    localPeer->masterProxy = masterProxy;
-}
-
-/** Starts the master peer I/O loop. Doesn't return. */
-void peerLoop() {
-    assert(localPeer != NULL);
-    
-    // Start selector.
-    selectorLoop(localPeer->selector);
-}
-
diff --git a/libcutils/process_name.c b/libcutils/process_name.c
index bda9d08..a6ab951 100644
--- a/libcutils/process_name.c
+++ b/libcutils/process_name.c
@@ -17,7 +17,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <cutils/process_name.h>
+#ifdef HAVE_ANDROID_OS
 #include <cutils/properties.h>
+#endif
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -33,7 +35,9 @@
 static int running_in_emulator = -1;
 
 void set_process_name(const char* new_name) {
+#ifdef HAVE_ANDROID_OS
     char  propBuf[PROPERTY_VALUE_MAX];
+#endif
 
     if (new_name == NULL) {
         return;
@@ -53,6 +57,7 @@
     }
 #endif
 
+#ifdef HAVE_ANDROID_OS
     // If we know we are not running in the emulator, then return.
     if (running_in_emulator == 0) {
         return;
@@ -82,6 +87,7 @@
         return;
     write(fd, process_name, strlen(process_name) + 1);
     close(fd);
+#endif
 }
 
 const char* get_process_name(void) {
diff --git a/libcutils/qsort_r_compat.c b/libcutils/qsort_r_compat.c
deleted file mode 100644
index 8971cb5..0000000
--- a/libcutils/qsort_r_compat.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdlib.h>
-#include <cutils/qsort_r_compat.h>
-
-#if HAVE_BSD_QSORT_R
-
-/*
- * BSD qsort_r parameter order is as we have defined here.
- */
-
-void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
-        int (*compar)(void*, const void* , const void*)) {
-    qsort_r(base, nel, width, thunk, compar);
-}
-
-#elif HAVE_GNU_QSORT_R
-
-/*
- * GNU qsort_r parameter order places the thunk parameter last.
- */
-
-struct compar_data {
-    void* thunk;
-    int (*compar)(void*, const void* , const void*);
-};
-
-static int compar_wrapper(const void* a, const void* b, void* data) {
-    struct compar_data* compar_data = (struct compar_data*)data;
-    return compar_data->compar(compar_data->thunk, a, b);
-}
-
-void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
-        int (*compar)(void*, const void* , const void*)) {
-    struct compar_data compar_data;
-    compar_data.thunk = thunk;
-    compar_data.compar = compar;
-    qsort_r(base, nel, width, compar_wrapper, &compar_data);
-}
-
-#else
-
-/*
- * Emulate qsort_r using thread local storage to access the thunk data.
- */
-
-#include <cutils/threads.h>
-
-static thread_store_t compar_data_key = THREAD_STORE_INITIALIZER;
-
-struct compar_data {
-    void* thunk;
-    int (*compar)(void*, const void* , const void*);
-};
-
-static int compar_wrapper(const void* a, const void* b) {
-    struct compar_data* compar_data = (struct compar_data*)thread_store_get(&compar_data_key);
-    return compar_data->compar(compar_data->thunk, a, b);
-}
-
-void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
-        int (*compar)(void*, const void* , const void*)) {
-    struct compar_data compar_data;
-    compar_data.thunk = thunk;
-    compar_data.compar = compar;
-    thread_store_set(&compar_data_key, &compar_data, NULL);
-    qsort(base, nel, width, compar_wrapper);
-}
-
-#endif
diff --git a/libcutils/selector.c b/libcutils/selector.c
deleted file mode 100644
index 3776bbb..0000000
--- a/libcutils/selector.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#define LOG_TAG "selector"
-
-#include <assert.h>
-#include <errno.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <cutils/array.h>
-#include <cutils/selector.h>
-
-#include "loghack.h"
-
-struct Selector {
-    Array* selectableFds;
-    bool looping;
-    fd_set readFds;
-    fd_set writeFds;
-    fd_set exceptFds;
-    int maxFd;
-    int wakeupPipe[2];
-    SelectableFd* wakeupFd;
-
-    bool inSelect;
-    pthread_mutex_t inSelectLock; 
-};
-
-/** Reads and ignores wake up data. */ 
-static void eatWakeupData(SelectableFd* wakeupFd) {
-    static char garbage[64];
-    if (read(wakeupFd->fd, garbage, sizeof(garbage)) < 0) {
-        if (errno == EINTR) {
-            ALOGI("read() interrupted.");    
-        } else {
-            LOG_ALWAYS_FATAL("This should never happen: %s", strerror(errno));
-        }
-    }
-}
-
-static void setInSelect(Selector* selector, bool inSelect) {
-    pthread_mutex_lock(&selector->inSelectLock);
-    selector->inSelect = inSelect;
-    pthread_mutex_unlock(&selector->inSelectLock);
-}
-
-static bool isInSelect(Selector* selector) {
-    pthread_mutex_lock(&selector->inSelectLock);
-    bool inSelect = selector->inSelect;
-    pthread_mutex_unlock(&selector->inSelectLock);
-    return inSelect;
-}
-
-void selectorWakeUp(Selector* selector) {
-    if (!isInSelect(selector)) {
-        // We only need to write wake-up data if we're blocked in select().
-        return;
-    }
-    
-    static char garbage[1];
-    if (write(selector->wakeupPipe[1], garbage, sizeof(garbage)) < 0) {
-        if (errno == EINTR) {
-            ALOGI("read() interrupted.");    
-        } else {
-            LOG_ALWAYS_FATAL("This should never happen: %s", strerror(errno));
-        }
-    }
-}
-
-Selector* selectorCreate(void) {
-    Selector* selector = calloc(1, sizeof(Selector));
-    if (selector == NULL) {
-        LOG_ALWAYS_FATAL("malloc() error.");
-    }
-    selector->selectableFds = arrayCreate();
-    
-    // Set up wake-up pipe.
-    if (pipe(selector->wakeupPipe) < 0) {
-        LOG_ALWAYS_FATAL("pipe() error: %s", strerror(errno));
-    }
-    
-    ALOGD("Wakeup fd: %d", selector->wakeupPipe[0]);
-    
-    SelectableFd* wakeupFd = selectorAdd(selector, selector->wakeupPipe[0]);
-    if (wakeupFd == NULL) {
-        LOG_ALWAYS_FATAL("malloc() error.");
-    }
-    wakeupFd->onReadable = &eatWakeupData; 
-    
-    pthread_mutex_init(&selector->inSelectLock, NULL);
-
-    return selector;
-}
-
-SelectableFd* selectorAdd(Selector* selector, int fd) {
-    assert(selector != NULL);
-
-    SelectableFd* selectableFd = calloc(1, sizeof(SelectableFd));
-    if (selectableFd != NULL) {
-        selectableFd->selector = selector;
-        selectableFd->fd = fd;
-    
-        arrayAdd(selector->selectableFds, selectableFd);
-    }
-
-    return selectableFd;
-}
-
-/**
- * Adds an fd to the given set if the callback is non-null. Returns true
- * if the fd was added.
- */
-static inline bool maybeAdd(SelectableFd* selectableFd,
-        void (*callback)(SelectableFd*), fd_set* fdSet) {
-    if (callback != NULL) {
-        FD_SET(selectableFd->fd, fdSet);
-        return true;
-    }
-    return false;
-}
-
-/**
- * Removes stale file descriptors and initializes file descriptor sets.
- */
-static void prepareForSelect(Selector* selector) {
-    fd_set* exceptFds = &selector->exceptFds;
-    fd_set* readFds = &selector->readFds;
-    fd_set* writeFds = &selector->writeFds;
-    
-    FD_ZERO(exceptFds);
-    FD_ZERO(readFds);
-    FD_ZERO(writeFds);
-
-    Array* selectableFds = selector->selectableFds;
-    int i = 0;
-    selector->maxFd = 0;
-    int size = arraySize(selectableFds);
-    while (i < size) {
-        SelectableFd* selectableFd = arrayGet(selectableFds, i);
-        if (selectableFd->remove) {
-            // This descriptor should be removed.
-            arrayRemove(selectableFds, i);
-            size--;
-            if (selectableFd->onRemove != NULL) {
-                selectableFd->onRemove(selectableFd);
-            }
-            free(selectableFd);
-        } else {
-            if (selectableFd->beforeSelect != NULL) {
-                selectableFd->beforeSelect(selectableFd);
-            }
-            
-            bool inSet = false;
-            if (maybeAdd(selectableFd, selectableFd->onExcept, exceptFds)) {
-                ALOGD("Selecting fd %d for writing...", selectableFd->fd);
-                inSet = true;
-            }
-            if (maybeAdd(selectableFd, selectableFd->onReadable, readFds)) {
-                ALOGD("Selecting fd %d for reading...", selectableFd->fd);
-                inSet = true;
-            }
-            if (maybeAdd(selectableFd, selectableFd->onWritable, writeFds)) {
-                inSet = true;
-            }
-
-            if (inSet) {
-                // If the fd is in a set, check it against max.
-                int fd = selectableFd->fd;
-                if (fd > selector->maxFd) {
-                    selector->maxFd = fd;
-                }
-            }
-            
-            // Move to next descriptor.
-            i++;
-        }
-    }
-}
-
-/**
- * Invokes a callback if the callback is non-null and the fd is in the given
- * set.
- */
-static inline void maybeInvoke(SelectableFd* selectableFd,
-        void (*callback)(SelectableFd*), fd_set* fdSet) {
-    if (callback != NULL && !selectableFd->remove && 
-            FD_ISSET(selectableFd->fd, fdSet)) {
-        ALOGD("Selected fd %d.", selectableFd->fd);
-        callback(selectableFd);
-    }
-}
-
-/**
- * Notifies user if file descriptors are readable or writable, or if
- * out-of-band data is present.
- */
-static void fireEvents(Selector* selector) {
-    Array* selectableFds = selector->selectableFds;
-    int size = arraySize(selectableFds);
-    int i;
-    for (i = 0; i < size; i++) {
-        SelectableFd* selectableFd = arrayGet(selectableFds, i);
-        maybeInvoke(selectableFd, selectableFd->onExcept,
-                &selector->exceptFds);
-        maybeInvoke(selectableFd, selectableFd->onReadable,
-                &selector->readFds);
-        maybeInvoke(selectableFd, selectableFd->onWritable,
-                &selector->writeFds);
-    }
-}
-
-void selectorLoop(Selector* selector) {
-    // Make sure we're not already looping.
-    if (selector->looping) {
-        LOG_ALWAYS_FATAL("Already looping.");
-    }
-    selector->looping = true;
-    
-    while (true) {
-        setInSelect(selector, true);
-        
-        prepareForSelect(selector);
-
-        ALOGD("Entering select().");
-        
-        // Select file descriptors.
-        int result = select(selector->maxFd + 1, &selector->readFds, 
-                &selector->writeFds, &selector->exceptFds, NULL);
-        
-        ALOGD("Exiting select().");
-        
-        setInSelect(selector, false);
-        
-        if (result == -1) {
-            // Abort on everything except EINTR.
-            if (errno == EINTR) {
-                ALOGI("select() interrupted.");    
-            } else {
-                LOG_ALWAYS_FATAL("select() error: %s", 
-                        strerror(errno));
-            }
-        } else if (result > 0) {
-            fireEvents(selector);
-        }
-    }
-}
diff --git a/libcutils/zygote.c b/libcutils/zygote.c
deleted file mode 100644
index 37236e8..0000000
--- a/libcutils/zygote.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#define LOG_TAG "Zygote"
-
-#include <cutils/sockets.h>
-#include <cutils/zygote.h>
-#include <cutils/log.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#define ZYGOTE_SOCKET "zygote"
-
-#define ZYGOTE_RETRY_COUNT 1000
-#define ZYGOTE_RETRY_MILLIS 500
-
-static void replace_nl(char *str);
-
-/*
- * If sendStdio is non-zero, the current process's stdio file descriptors
- * will be sent and inherited by the spawned process.
- */
-static int send_request(int fd, int sendStdio, int argc, const char **argv)
-{
-#ifndef HAVE_ANDROID_OS
-    // not supported on simulator targets
-    //ALOGE("zygote_* not supported on simulator targets");
-    return -1;
-#else /* HAVE_ANDROID_OS */
-    uint32_t pid;
-    int i;
-    struct iovec ivs[2];
-    struct msghdr msg;
-    char argc_buffer[12];
-    const char *newline_string = "\n";
-    struct cmsghdr *cmsg;
-    char msgbuf[CMSG_SPACE(sizeof(int) * 3)];
-    int *cmsg_payload;
-    ssize_t ret;
-
-    memset(&msg, 0, sizeof(msg));
-    memset(&ivs, 0, sizeof(ivs));
-
-    // First line is arg count 
-    snprintf(argc_buffer, sizeof(argc_buffer), "%d\n", argc);
-
-    ivs[0].iov_base = argc_buffer;
-    ivs[0].iov_len = strlen(argc_buffer);
-
-    msg.msg_iov = ivs;
-    msg.msg_iovlen = 1;
-
-    if (sendStdio != 0) {
-        // Pass the file descriptors with the first write
-        msg.msg_control = msgbuf;
-        msg.msg_controllen = sizeof msgbuf;
-
-        cmsg = CMSG_FIRSTHDR(&msg);
-
-        cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int));
-        cmsg->cmsg_level = SOL_SOCKET;
-        cmsg->cmsg_type = SCM_RIGHTS;
-
-        cmsg_payload = (int *)CMSG_DATA(cmsg);
-        cmsg_payload[0] = STDIN_FILENO;
-        cmsg_payload[1] = STDOUT_FILENO;
-        cmsg_payload[2] = STDERR_FILENO;
-    }
-
-    do {
-        ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
-    } while (ret < 0 && errno == EINTR);
-
-    if (ret < 0) {
-        return -1;
-    }
-
-    // Only send the fd's once
-    msg.msg_control = NULL;
-    msg.msg_controllen = 0;
-
-    // replace any newlines with spaces and send the args
-    for (i = 0; i < argc; i++) {
-        char *tofree = NULL;
-        const char *toprint;
-
-        toprint = argv[i];
-
-        if (strchr(toprint, '\n') != NULL) {
-            tofree = strdup(toprint);
-            toprint = tofree;
-            replace_nl(tofree);
-        }
-
-        ivs[0].iov_base = (char *)toprint;
-        ivs[0].iov_len = strlen(toprint);
-        ivs[1].iov_base = (char *)newline_string;
-        ivs[1].iov_len = 1;
-
-        msg.msg_iovlen = 2;
-
-        do {
-            ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
-        } while (ret < 0 && errno == EINTR);
-
-        if (tofree != NULL) {
-            free(tofree);
-        }
-
-        if (ret < 0) {
-            return -1;
-        }
-    }
-
-    // Read the pid, as a 4-byte network-order integer
-
-    ivs[0].iov_base = &pid;
-    ivs[0].iov_len = sizeof(pid);
-    msg.msg_iovlen = 1;
-
-    do {
-        do {
-            ret = recvmsg(fd, &msg, MSG_NOSIGNAL | MSG_WAITALL);
-        } while (ret < 0 && errno == EINTR);
-
-        if (ret < 0) {
-            return -1;
-        }
-
-        ivs[0].iov_len -= ret;
-        ivs[0].iov_base += ret;
-    } while (ivs[0].iov_len > 0);
-
-    pid = ntohl(pid);
-
-    return pid;
-#endif /* HAVE_ANDROID_OS */
-}
-
-/**
- * Spawns a new dalvik instance via the Zygote process. The non-zygote
- * arguments are passed to com.android.internal.os.RuntimeInit(). The
- * first non-option argument should be a class name in the system class path.
- *
- * The arg list  may start with zygote params such as --set-uid.
- *
- * If sendStdio is non-zero, the current process's stdio file descriptors
- * will be sent and inherited by the spawned process.
- *
- * The pid of the child process is returned, or -1 if an error was 
- * encountered.
- *
- * zygote_run_oneshot waits up to ZYGOTE_RETRY_COUNT * 
- * ZYGOTE_RETRY_MILLIS for the zygote socket to be available.
- */
-int zygote_run_oneshot(int sendStdio, int argc, const char **argv) 
-{
-    int fd = -1;
-    int err;
-    int i;
-    int retries;
-    int pid;
-    const char **newargv = argv;
-    const int newargc = argc;
-
-    for (retries = 0; (fd < 0) && (retries < ZYGOTE_RETRY_COUNT); retries++) {
-        if (retries > 0) { 
-            struct timespec ts;
-
-            memset(&ts, 0, sizeof(ts));
-            ts.tv_nsec = ZYGOTE_RETRY_MILLIS * 1000 * 1000;
-
-            do {
-                err = nanosleep (&ts, &ts);
-            } while (err < 0 && errno == EINTR);
-        }
-        fd = socket_local_client(ZYGOTE_SOCKET, AF_LOCAL, 
-                ANDROID_SOCKET_NAMESPACE_RESERVED);
-    }
-
-    if (fd < 0) {
-        return -1;
-    }
-
-    pid = send_request(fd, 0, newargc, newargv);
-
-    do {
-        err = close(fd);
-    } while (err < 0 && errno == EINTR);
-
-    return pid;
-}
-
-/**
- * Replaces all occurrances of newline with space.
- */
-static void replace_nl(char *str)
-{
-    for(; *str; str++) {
-        if (*str == '\n') {
-            *str = ' ';
-        }
-    }
-}
-
-
-
diff --git a/liblog/Android.mk b/liblog/Android.mk
index be5cec2..6bfb119 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -36,6 +36,9 @@
     liblog_sources += \
         logprint.c \
         event_tag_map.c
+else
+    liblog_sources += \
+        uio.c
 endif
 
 liblog_host_sources := $(liblog_sources) fake_log_device.c
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index e70754e..f3d1e2f 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -13,8 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include "cutils/event_tag_map.h"
-#include "cutils/log.h"
+#include <log/event_tag_map.h>
+#include <log/log.h>
 
 #include <stdlib.h>
 #include <string.h>
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index df43299..5283619 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -19,7 +19,7 @@
  * passed on to the underlying (fake) log device.  When not in the
  * simulator, messages are printed to stderr.
  */
-#include "cutils/logd.h"
+#include <log/logd.h>
 
 #include <stdlib.h>
 #include <string.h>
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 3613d25..fff7cc4 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -27,9 +27,9 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#include <cutils/logger.h>
-#include <cutils/logd.h>
-#include <cutils/log.h>
+#include <log/logger.h>
+#include <log/logd.h>
+#include <log/log.h>
 
 #define LOG_BUF_SIZE	1024
 
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 6fac84b..508c825 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -26,8 +26,8 @@
 #include <assert.h>
 #include <arpa/inet.h>
 
-#include <cutils/logd.h>
-#include <cutils/logprint.h>
+#include <log/logd.h>
+#include <log/logprint.h>
 
 typedef struct FilterInfo_t {
     char *mTag;
diff --git a/libcutils/uio.c b/liblog/uio.c
similarity index 98%
rename from libcutils/uio.c
rename to liblog/uio.c
index baa8051..cfa4cb1 100644
--- a/libcutils/uio.c
+++ b/liblog/uio.c
@@ -16,7 +16,7 @@
 
 #ifndef HAVE_SYS_UIO_H
 
-#include <cutils/uio.h>
+#include <log/uio.h>
 #include <unistd.h>
 
 int  readv( int  fd, struct iovec*  vecs, int  count )
diff --git a/libmemtrack/Android.mk b/libmemtrack/Android.mk
new file mode 100644
index 0000000..a8fb3eb
--- /dev/null
+++ b/libmemtrack/Android.mk
@@ -0,0 +1,19 @@
+# Copyright 2013 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := memtrack.c
+LOCAL_MODULE := libmemtrack
+LOCAL_C_INCLUDES += hardware/libhardware/include
+LOCAL_SHARED_LIBRARIES := libhardware liblog
+LOCAL_CFLAGS := -Wall -Werror
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := memtrack_test.c
+LOCAL_MODULE := memtrack_test
+LOCAL_C_INCLUDES := $(call include-path-for, libpagemap)
+LOCAL_SHARED_LIBRARIES := libmemtrack libpagemap
+LOCAL_CFLAGS := -Wall -Werror
+include $(BUILD_EXECUTABLE)
diff --git a/libmemtrack/memtrack.c b/libmemtrack/memtrack.c
new file mode 100644
index 0000000..9a656df
--- /dev/null
+++ b/libmemtrack/memtrack.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2013 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 <memtrack/memtrack.h>
+
+#define LOG_TAG "memtrack"
+
+#include <log/log.h>
+
+#include <hardware/memtrack.h>
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+static const memtrack_module_t *module;
+
+struct memtrack_proc {
+    pid_t pid;
+    struct memtrack_proc_type {
+        enum memtrack_type type;
+        size_t num_records;
+        size_t allocated_records;
+        struct memtrack_record *records;
+    } types[MEMTRACK_NUM_TYPES];
+};
+
+int memtrack_init(void)
+{
+    int err;
+
+    if (module) {
+        return 0;
+    }
+
+    err = hw_get_module(MEMTRACK_HARDWARE_MODULE_ID,
+            (hw_module_t const**)&module);
+    if (err) {
+        ALOGE("Couldn't load %s module (%s)", MEMTRACK_HARDWARE_MODULE_ID,
+                strerror(-err));
+        return err;
+    }
+
+    return module->init(module);
+}
+
+struct memtrack_proc *memtrack_proc_new(void)
+{
+    if (!module) {
+        return NULL;
+    }
+
+    return calloc(sizeof(struct memtrack_proc), 1);
+}
+
+void memtrack_proc_destroy(struct memtrack_proc *p)
+{
+    enum memtrack_type i;
+
+    if (p) {
+        for (i = 0; i < MEMTRACK_NUM_TYPES; i++) {
+            free(p->types[i].records);
+        }
+    }
+    free(p);
+}
+
+static int memtrack_proc_get_type(struct memtrack_proc_type *t,
+            pid_t pid, enum memtrack_type type)
+{
+    size_t num_records = t->num_records;
+    int ret;
+
+retry:
+    ret = module->getMemory(module, pid, type, t->records, &num_records);
+    if (ret) {
+        t->num_records = 0;
+        return ret;
+    }
+    if (num_records > t->allocated_records) {
+        /* Need more records than allocated */
+        free(t->records);
+        t->records = calloc(sizeof(*t->records), num_records);
+        if (!t->records) {
+            return -ENOMEM;
+        }
+        t->allocated_records = num_records;
+        goto retry;
+    }
+    t->num_records = num_records;
+
+    return 0;
+}
+
+/* TODO: sanity checks on return values from HALs:
+ *   make sure no records have invalid flags set
+ *    - unknown flags
+ *    - too many flags of a single category
+ *    - missing ACCOUNTED/UNACCOUNTED
+ *   make sure there are not overlapping SHARED and SHARED_PSS records
+ */
+static int memtrack_proc_sanity_check(struct memtrack_proc *p)
+{
+    (void)p;
+    return 0;
+}
+
+int memtrack_proc_get(struct memtrack_proc *p, pid_t pid)
+{
+    enum memtrack_type i;
+
+    if (!module) {
+        return -EINVAL;
+    }
+
+    if (!p) {
+        return -EINVAL;
+    }
+
+    p->pid = pid;
+    for (i = 0; i < MEMTRACK_NUM_TYPES; i++) {
+        memtrack_proc_get_type(&p->types[i], pid, i);
+    }
+
+    return memtrack_proc_sanity_check(p);
+}
+
+static ssize_t memtrack_proc_sum(struct memtrack_proc *p,
+            enum memtrack_type types[], size_t num_types,
+            unsigned int flags)
+{
+    ssize_t sum = 0;
+    size_t i;
+    size_t j;
+
+    for (i = 0; i < num_types; i++) {
+        enum memtrack_type type = types[i];
+        for (j = 0; j < p->types[type].num_records; j++) {
+            if ((p->types[type].records[j].flags & flags) == flags) {
+                sum += p->types[type].records[j].size_in_bytes;
+            }
+        }
+    }
+
+    return sum;
+}
+
+ssize_t memtrack_proc_graphics_total(struct memtrack_proc *p)
+{
+    enum memtrack_type types[] = { MEMTRACK_TYPE_GRAPHICS };
+    return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
+}
+
+ssize_t memtrack_proc_graphics_pss(struct memtrack_proc *p)
+{
+    enum memtrack_type types[] = { MEMTRACK_TYPE_GRAPHICS };
+    return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
+                MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
+}
+
+ssize_t memtrack_proc_gl_total(struct memtrack_proc *p)
+{
+    enum memtrack_type types[] = { MEMTRACK_TYPE_GL };
+    return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
+}
+
+ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p)
+{
+    enum memtrack_type types[] = { MEMTRACK_TYPE_GL };
+    return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
+                MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
+}
+
+ssize_t memtrack_proc_other_total(struct memtrack_proc *p)
+{
+    enum memtrack_type types[] = { MEMTRACK_TYPE_MULTIMEDIA,
+                                        MEMTRACK_TYPE_CAMERA,
+                                        MEMTRACK_TYPE_OTHER };
+    return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
+}
+
+ssize_t memtrack_proc_other_pss(struct memtrack_proc *p)
+{
+    enum memtrack_type types[] = { MEMTRACK_TYPE_MULTIMEDIA,
+                                        MEMTRACK_TYPE_CAMERA,
+                                        MEMTRACK_TYPE_OTHER };
+    return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
+                MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
+}
diff --git a/libmemtrack/memtrack_test.c b/libmemtrack/memtrack_test.c
new file mode 100644
index 0000000..cd94bc5
--- /dev/null
+++ b/libmemtrack/memtrack_test.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <memtrack/memtrack.h>
+
+#include <pagemap/pagemap.h>
+
+#define DIV_ROUND_UP(x,y) (((x) + (y) - 1) / (y))
+
+static int getprocname(pid_t pid, char *buf, int len) {
+    char *filename;
+    FILE *f;
+    int rc = 0;
+    static const char* unknown_cmdline = "<unknown>";
+
+    if (len <= 0) {
+        return -1;
+    }
+
+    if (asprintf(&filename, "/proc/%zd/cmdline", pid) < 0) {
+        rc = 1;
+        goto exit;
+    }
+
+    f = fopen(filename, "r");
+    if (f == NULL) {
+        rc = 2;
+        goto releasefilename;
+    }
+
+    if (fgets(buf, len, f) == NULL) {
+        rc = 3;
+        goto closefile;
+    }
+
+closefile:
+    (void) fclose(f);
+releasefilename:
+    free(filename);
+exit:
+    if (rc != 0) {
+        /*
+         * The process went away before we could read its process name. Try
+         * to give the user "<unknown>" here, but otherwise they get to look
+         * at a blank.
+         */
+        if (strlcpy(buf, unknown_cmdline, (size_t)len) >= (size_t)len) {
+            rc = 4;
+        }
+    }
+
+    return rc;
+}
+
+int main(int argc, char *argv[])
+{
+    int ret;
+    pm_kernel_t *ker;
+    size_t num_procs;
+    pid_t *pids;
+    struct memtrack_proc *p;
+    size_t i;
+
+    (void)argc;
+    (void)argv;
+
+    ret = memtrack_init();
+    if (ret < 0) {
+        fprintf(stderr, "failed to initialize HAL: %s (%d)\n", strerror(-ret), ret);
+        exit(EXIT_FAILURE);
+    }
+
+    ret = pm_kernel_create(&ker);
+    if (ret) {
+        fprintf(stderr, "Error creating kernel interface -- "
+                        "does this kernel have pagemap?\n");
+        exit(EXIT_FAILURE);
+    }
+
+    ret = pm_kernel_pids(ker, &pids, &num_procs);
+    if (ret) {
+        fprintf(stderr, "Error listing processes.\n");
+        exit(EXIT_FAILURE);
+    }
+
+    p = memtrack_proc_new();
+    if (ret) {
+        fprintf(stderr, "failed to create memtrack process handle\n");
+        exit(EXIT_FAILURE);
+    }
+
+    for (i = 0; i < num_procs; i++) {
+        pid_t pid = pids[i];
+        char cmdline[256];
+        size_t v1;
+        size_t v2;
+        size_t v3;
+        size_t v4;
+        size_t v5;
+        size_t v6;
+
+        getprocname(pid, cmdline, (int)sizeof(cmdline));
+
+        ret = memtrack_proc_get(p, pid);
+        if (ret) {
+            fprintf(stderr, "failed to get memory info for pid %d: %s (%d)\n",
+                    pid, strerror(-ret), ret);
+            continue;
+        }
+
+        v1 = DIV_ROUND_UP(memtrack_proc_graphics_total(p), 1024);
+        v2 = DIV_ROUND_UP(memtrack_proc_graphics_pss(p), 1024);
+        v3 = DIV_ROUND_UP(memtrack_proc_gl_total(p), 1024);
+        v4 = DIV_ROUND_UP(memtrack_proc_gl_pss(p), 1024);
+        v5 = DIV_ROUND_UP(memtrack_proc_other_total(p), 1024);
+        v6 = DIV_ROUND_UP(memtrack_proc_other_pss(p), 1024);
+
+        if (v1 | v2 | v3 | v4 | v5 | v6) {
+            printf("%5d %6zu %6zu %6zu %6zu %6zu %6zu %s\n", pid,
+                   v1, v2, v3, v4, v5, v6, cmdline);
+        }
+    }
+
+    memtrack_proc_destroy(p);
+
+    return 0;
+}
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index da00f74..e1df874 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -92,7 +92,8 @@
                      char *server,
                      uint32_t *lease,
                      char *vendorInfo,
-                     char *domain)
+                     char *domain,
+                     char *mtu)
 {
     char prop_name[PROPERTY_KEY_MAX];
     char prop_value[PROPERTY_VALUE_MAX];
@@ -158,6 +159,10 @@
             p2p_interface);
     property_get(prop_name, domain, NULL);
 
+    snprintf(prop_name, sizeof(prop_name), "%s.%s.mtu", DHCP_PROP_NAME_PREFIX,
+            p2p_interface);
+    property_get(prop_name, mtu, NULL);
+
     return 0;
 }
 
@@ -186,7 +191,8 @@
                     char *server,
                     uint32_t *lease,
                     char *vendorInfo,
-                    char *domain)
+                    char *domain,
+                    char *mtu)
 {
     char result_prop_name[PROPERTY_KEY_MAX];
     char daemon_prop_name[PROPERTY_KEY_MAX];
@@ -238,7 +244,7 @@
     if (strcmp(prop_value, "ok") == 0) {
         char dns_prop_name[PROPERTY_KEY_MAX];
         if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
-                server, lease, vendorInfo, domain) == -1) {
+                server, lease, vendorInfo, domain, mtu) == -1) {
             return -1;
         }
         return 0;
@@ -329,7 +335,8 @@
                     char *server,
                     uint32_t *lease,
                     char *vendorInfo,
-                    char *domain)
+                    char *domain,
+                    char *mtu)
 {
     char result_prop_name[PROPERTY_KEY_MAX];
     char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
@@ -366,7 +373,7 @@
     }
     if (strcmp(prop_value, "ok") == 0) {
         return fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
-                server, lease, vendorInfo, domain);
+                server, lease, vendorInfo, domain, mtu);
     } else {
         snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value);
         return -1;
diff --git a/libutils/Android.mk b/libutils/Android.mk
new file mode 100644
index 0000000..720443e
--- /dev/null
+++ b/libutils/Android.mk
@@ -0,0 +1,146 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+# libutils is a little unique: It's built twice, once for the host
+# and once for the device.
+
+commonSources:= \
+	BasicHashtable.cpp \
+	BlobCache.cpp \
+	CallStack.cpp \
+	FileMap.cpp \
+	JenkinsHash.cpp \
+	LinearAllocator.cpp \
+	LinearTransform.cpp \
+	Log.cpp \
+	Printer.cpp \
+	ProcessCallStack.cpp \
+	PropertyMap.cpp \
+	RefBase.cpp \
+	SharedBuffer.cpp \
+	Static.cpp \
+	StopWatch.cpp \
+	String8.cpp \
+	String16.cpp \
+	SystemClock.cpp \
+	Threads.cpp \
+	Timers.cpp \
+	Tokenizer.cpp \
+	Unicode.cpp \
+	VectorImpl.cpp \
+	misc.cpp
+
+host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS)
+
+ifeq ($(HOST_OS),windows)
+ifeq ($(strip $(USE_CYGWIN),),)
+# Under MinGW, ctype.h doesn't need multi-byte support
+host_commonCflags += -DMB_CUR_MAX=1
+endif
+endif
+
+host_commonLdlibs :=
+
+ifeq ($(TARGET_OS),linux)
+host_commonLdlibs += -lrt -ldl
+endif
+
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= $(commonSources)
+ifeq ($(HOST_OS), linux)
+LOCAL_SRC_FILES += Looper.cpp
+endif
+LOCAL_MODULE:= libutils
+LOCAL_STATIC_LIBRARIES := liblog
+LOCAL_CFLAGS += $(host_commonCflags)
+LOCAL_LDLIBS += $(host_commonLdlibs)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# For the host, 64-bit
+# =====================================================
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= $(commonSources)
+ifeq ($(HOST_OS), linux)
+LOCAL_SRC_FILES += Looper.cpp
+endif
+LOCAL_MODULE:= lib64utils
+LOCAL_STATIC_LIBRARIES := liblog
+LOCAL_CFLAGS += $(host_commonCflags) -m64
+LOCAL_LDLIBS += $(host_commonLdlibs)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# For the device, static
+# =====================================================
+include $(CLEAR_VARS)
+
+
+# we have the common sources, plus some device-specific stuff
+LOCAL_SRC_FILES:= \
+	$(commonSources) \
+	Looper.cpp \
+	Trace.cpp
+
+ifeq ($(TARGET_OS),linux)
+LOCAL_LDLIBS += -lrt -ldl
+endif
+
+ifeq ($(TARGET_ARCH),mips)
+LOCAL_CFLAGS += -DALIGN_DOUBLE
+endif
+
+LOCAL_C_INCLUDES += \
+		bionic/libc/private \
+		external/zlib
+
+LOCAL_LDLIBS += -lpthread
+
+LOCAL_STATIC_LIBRARIES := \
+	libcutils
+
+LOCAL_SHARED_LIBRARIES := \
+        libcorkscrew \
+        liblog \
+        libdl
+
+LOCAL_MODULE:= libutils
+include $(BUILD_STATIC_LIBRARY)
+
+# For the device, shared
+# =====================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE:= libutils
+LOCAL_WHOLE_STATIC_LIBRARIES := libutils
+LOCAL_SHARED_LIBRARIES := \
+        liblog \
+        libcutils \
+        libdl \
+        libcorkscrew
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/libutils/BasicHashtable.cpp b/libutils/BasicHashtable.cpp
new file mode 100644
index 0000000..491d9e9
--- /dev/null
+++ b/libutils/BasicHashtable.cpp
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#define LOG_TAG "BasicHashtable"
+
+#include <math.h>
+
+#include <utils/Log.h>
+#include <utils/BasicHashtable.h>
+#include <utils/misc.h>
+
+namespace android {
+
+BasicHashtableImpl::BasicHashtableImpl(size_t entrySize, bool hasTrivialDestructor,
+        size_t minimumInitialCapacity, float loadFactor) :
+        mBucketSize(entrySize + sizeof(Bucket)), mHasTrivialDestructor(hasTrivialDestructor),
+        mLoadFactor(loadFactor), mSize(0),
+        mFilledBuckets(0), mBuckets(NULL) {
+    determineCapacity(minimumInitialCapacity, mLoadFactor, &mBucketCount, &mCapacity);
+}
+
+BasicHashtableImpl::BasicHashtableImpl(const BasicHashtableImpl& other) :
+        mBucketSize(other.mBucketSize), mHasTrivialDestructor(other.mHasTrivialDestructor),
+        mCapacity(other.mCapacity), mLoadFactor(other.mLoadFactor),
+        mSize(other.mSize), mFilledBuckets(other.mFilledBuckets),
+        mBucketCount(other.mBucketCount), mBuckets(other.mBuckets) {
+    if (mBuckets) {
+        SharedBuffer::bufferFromData(mBuckets)->acquire();
+    }
+}
+
+BasicHashtableImpl::~BasicHashtableImpl()
+{
+}
+
+void BasicHashtableImpl::dispose() {
+    if (mBuckets) {
+        releaseBuckets(mBuckets, mBucketCount);
+    }
+}
+
+void BasicHashtableImpl::clone() {
+    if (mBuckets) {
+        void* newBuckets = allocateBuckets(mBucketCount);
+        copyBuckets(mBuckets, newBuckets, mBucketCount);
+        releaseBuckets(mBuckets, mBucketCount);
+        mBuckets = newBuckets;
+    }
+}
+
+void BasicHashtableImpl::setTo(const BasicHashtableImpl& other) {
+    if (mBuckets) {
+        releaseBuckets(mBuckets, mBucketCount);
+    }
+
+    mCapacity = other.mCapacity;
+    mLoadFactor = other.mLoadFactor;
+    mSize = other.mSize;
+    mFilledBuckets = other.mFilledBuckets;
+    mBucketCount = other.mBucketCount;
+    mBuckets = other.mBuckets;
+
+    if (mBuckets) {
+        SharedBuffer::bufferFromData(mBuckets)->acquire();
+    }
+}
+
+void BasicHashtableImpl::clear() {
+    if (mBuckets) {
+        if (mFilledBuckets) {
+            SharedBuffer* sb = SharedBuffer::bufferFromData(mBuckets);
+            if (sb->onlyOwner()) {
+                destroyBuckets(mBuckets, mBucketCount);
+                for (size_t i = 0; i < mBucketCount; i++) {
+                    Bucket& bucket = bucketAt(mBuckets, i);
+                    bucket.cookie = 0;
+                }
+            } else {
+                releaseBuckets(mBuckets, mBucketCount);
+                mBuckets = NULL;
+            }
+            mFilledBuckets = 0;
+        }
+        mSize = 0;
+    }
+}
+
+ssize_t BasicHashtableImpl::next(ssize_t index) const {
+    if (mSize) {
+        while (size_t(++index) < mBucketCount) {
+            const Bucket& bucket = bucketAt(mBuckets, index);
+            if (bucket.cookie & Bucket::PRESENT) {
+                return index;
+            }
+        }
+    }
+    return -1;
+}
+
+ssize_t BasicHashtableImpl::find(ssize_t index, hash_t hash,
+        const void* __restrict__ key) const {
+    if (!mSize) {
+        return -1;
+    }
+
+    hash = trimHash(hash);
+    if (index < 0) {
+        index = chainStart(hash, mBucketCount);
+
+        const Bucket& bucket = bucketAt(mBuckets, size_t(index));
+        if (bucket.cookie & Bucket::PRESENT) {
+            if (compareBucketKey(bucket, key)) {
+                return index;
+            }
+        } else {
+            if (!(bucket.cookie & Bucket::COLLISION)) {
+                return -1;
+            }
+        }
+    }
+
+    size_t inc = chainIncrement(hash, mBucketCount);
+    for (;;) {
+        index = chainSeek(index, inc, mBucketCount);
+
+        const Bucket& bucket = bucketAt(mBuckets, size_t(index));
+        if (bucket.cookie & Bucket::PRESENT) {
+            if ((bucket.cookie & Bucket::HASH_MASK) == hash
+                    && compareBucketKey(bucket, key)) {
+                return index;
+            }
+        }
+        if (!(bucket.cookie & Bucket::COLLISION)) {
+            return -1;
+        }
+    }
+}
+
+size_t BasicHashtableImpl::add(hash_t hash, const void* entry) {
+    if (!mBuckets) {
+        mBuckets = allocateBuckets(mBucketCount);
+    } else {
+        edit();
+    }
+
+    hash = trimHash(hash);
+    for (;;) {
+        size_t index = chainStart(hash, mBucketCount);
+        Bucket* bucket = &bucketAt(mBuckets, size_t(index));
+        if (bucket->cookie & Bucket::PRESENT) {
+            size_t inc = chainIncrement(hash, mBucketCount);
+            do {
+                bucket->cookie |= Bucket::COLLISION;
+                index = chainSeek(index, inc, mBucketCount);
+                bucket = &bucketAt(mBuckets, size_t(index));
+            } while (bucket->cookie & Bucket::PRESENT);
+        }
+
+        uint32_t collision = bucket->cookie & Bucket::COLLISION;
+        if (!collision) {
+            if (mFilledBuckets >= mCapacity) {
+                rehash(mCapacity * 2, mLoadFactor);
+                continue;
+            }
+            mFilledBuckets += 1;
+        }
+
+        bucket->cookie = collision | Bucket::PRESENT | hash;
+        mSize += 1;
+        initializeBucketEntry(*bucket, entry);
+        return index;
+    }
+}
+
+void BasicHashtableImpl::removeAt(size_t index) {
+    edit();
+
+    Bucket& bucket = bucketAt(mBuckets, index);
+    bucket.cookie &= ~Bucket::PRESENT;
+    if (!(bucket.cookie & Bucket::COLLISION)) {
+        mFilledBuckets -= 1;
+    }
+    mSize -= 1;
+    if (!mHasTrivialDestructor) {
+        destroyBucketEntry(bucket);
+    }
+}
+
+void BasicHashtableImpl::rehash(size_t minimumCapacity, float loadFactor) {
+    if (minimumCapacity < mSize) {
+        minimumCapacity = mSize;
+    }
+    size_t newBucketCount, newCapacity;
+    determineCapacity(minimumCapacity, loadFactor, &newBucketCount, &newCapacity);
+
+    if (newBucketCount != mBucketCount || newCapacity != mCapacity) {
+        if (mBuckets) {
+            void* newBuckets;
+            if (mSize) {
+                newBuckets = allocateBuckets(newBucketCount);
+                for (size_t i = 0; i < mBucketCount; i++) {
+                    const Bucket& fromBucket = bucketAt(mBuckets, i);
+                    if (fromBucket.cookie & Bucket::PRESENT) {
+                        hash_t hash = fromBucket.cookie & Bucket::HASH_MASK;
+                        size_t index = chainStart(hash, newBucketCount);
+                        Bucket* toBucket = &bucketAt(newBuckets, size_t(index));
+                        if (toBucket->cookie & Bucket::PRESENT) {
+                            size_t inc = chainIncrement(hash, newBucketCount);
+                            do {
+                                toBucket->cookie |= Bucket::COLLISION;
+                                index = chainSeek(index, inc, newBucketCount);
+                                toBucket = &bucketAt(newBuckets, size_t(index));
+                            } while (toBucket->cookie & Bucket::PRESENT);
+                        }
+                        toBucket->cookie = Bucket::PRESENT | hash;
+                        initializeBucketEntry(*toBucket, fromBucket.entry);
+                    }
+                }
+            } else {
+                newBuckets = NULL;
+            }
+            releaseBuckets(mBuckets, mBucketCount);
+            mBuckets = newBuckets;
+            mFilledBuckets = mSize;
+        }
+        mBucketCount = newBucketCount;
+        mCapacity = newCapacity;
+    }
+    mLoadFactor = loadFactor;
+}
+
+void* BasicHashtableImpl::allocateBuckets(size_t count) const {
+    size_t bytes = count * mBucketSize;
+    SharedBuffer* sb = SharedBuffer::alloc(bytes);
+    LOG_ALWAYS_FATAL_IF(!sb, "Could not allocate %u bytes for hashtable with %u buckets.",
+            uint32_t(bytes), uint32_t(count));
+    void* buckets = sb->data();
+    for (size_t i = 0; i < count; i++) {
+        Bucket& bucket = bucketAt(buckets, i);
+        bucket.cookie = 0;
+    }
+    return buckets;
+}
+
+void BasicHashtableImpl::releaseBuckets(void* __restrict__ buckets, size_t count) const {
+    SharedBuffer* sb = SharedBuffer::bufferFromData(buckets);
+    if (sb->release(SharedBuffer::eKeepStorage) == 1) {
+        destroyBuckets(buckets, count);
+        SharedBuffer::dealloc(sb);
+    }
+}
+
+void BasicHashtableImpl::destroyBuckets(void* __restrict__ buckets, size_t count) const {
+    if (!mHasTrivialDestructor) {
+        for (size_t i = 0; i < count; i++) {
+            Bucket& bucket = bucketAt(buckets, i);
+            if (bucket.cookie & Bucket::PRESENT) {
+                destroyBucketEntry(bucket);
+            }
+        }
+    }
+}
+
+void BasicHashtableImpl::copyBuckets(const void* __restrict__ fromBuckets,
+        void* __restrict__ toBuckets, size_t count) const {
+    for (size_t i = 0; i < count; i++) {
+        const Bucket& fromBucket = bucketAt(fromBuckets, i);
+        Bucket& toBucket = bucketAt(toBuckets, i);
+        toBucket.cookie = fromBucket.cookie;
+        if (fromBucket.cookie & Bucket::PRESENT) {
+            initializeBucketEntry(toBucket, fromBucket.entry);
+        }
+    }
+}
+
+// Table of 31-bit primes where each prime is no less than twice as large
+// as the previous one.  Generated by "primes.py".
+static size_t PRIMES[] = {
+    5,
+    11,
+    23,
+    47,
+    97,
+    197,
+    397,
+    797,
+    1597,
+    3203,
+    6421,
+    12853,
+    25717,
+    51437,
+    102877,
+    205759,
+    411527,
+    823117,
+    1646237,
+    3292489,
+    6584983,
+    13169977,
+    26339969,
+    52679969,
+    105359939,
+    210719881,
+    421439783,
+    842879579,
+    1685759167,
+    0,
+};
+
+void BasicHashtableImpl::determineCapacity(size_t minimumCapacity, float loadFactor,
+        size_t* __restrict__ outBucketCount, size_t* __restrict__ outCapacity) {
+    LOG_ALWAYS_FATAL_IF(loadFactor <= 0.0f || loadFactor > 1.0f,
+            "Invalid load factor %0.3f.  Must be in the range (0, 1].", loadFactor);
+
+    size_t count = ceilf(minimumCapacity / loadFactor) + 1;
+    size_t i = 0;
+    while (count > PRIMES[i] && i < NELEM(PRIMES)) {
+        i++;
+    }
+    count = PRIMES[i];
+    LOG_ALWAYS_FATAL_IF(!count, "Could not determine required number of buckets for "
+            "hashtable with minimum capacity %u and load factor %0.3f.",
+            uint32_t(minimumCapacity), loadFactor);
+    *outBucketCount = count;
+    *outCapacity = ceilf((count - 1) * loadFactor);
+}
+
+}; // namespace android
diff --git a/libutils/BlobCache.cpp b/libutils/BlobCache.cpp
new file mode 100644
index 0000000..0fb1d8e
--- /dev/null
+++ b/libutils/BlobCache.cpp
@@ -0,0 +1,362 @@
+/*
+ ** Copyright 2011, 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.
+ */
+
+#define LOG_TAG "BlobCache"
+//#define LOG_NDEBUG 0
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <utils/BlobCache.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+namespace android {
+
+// BlobCache::Header::mMagicNumber value
+static const uint32_t blobCacheMagic = '_Bb$';
+
+// BlobCache::Header::mBlobCacheVersion value
+static const uint32_t blobCacheVersion = 1;
+
+// BlobCache::Header::mDeviceVersion value
+static const uint32_t blobCacheDeviceVersion = 1;
+
+BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize):
+        mMaxKeySize(maxKeySize),
+        mMaxValueSize(maxValueSize),
+        mMaxTotalSize(maxTotalSize),
+        mTotalSize(0) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+#ifdef _WIN32
+    srand(now);
+#else
+    mRandState[0] = (now >> 0) & 0xFFFF;
+    mRandState[1] = (now >> 16) & 0xFFFF;
+    mRandState[2] = (now >> 32) & 0xFFFF;
+#endif
+    ALOGV("initializing random seed using %lld", now);
+}
+
+void BlobCache::set(const void* key, size_t keySize, const void* value,
+        size_t valueSize) {
+    if (mMaxKeySize < keySize) {
+        ALOGV("set: not caching because the key is too large: %d (limit: %d)",
+                keySize, mMaxKeySize);
+        return;
+    }
+    if (mMaxValueSize < valueSize) {
+        ALOGV("set: not caching because the value is too large: %d (limit: %d)",
+                valueSize, mMaxValueSize);
+        return;
+    }
+    if (mMaxTotalSize < keySize + valueSize) {
+        ALOGV("set: not caching because the combined key/value size is too "
+                "large: %d (limit: %d)", keySize + valueSize, mMaxTotalSize);
+        return;
+    }
+    if (keySize == 0) {
+        ALOGW("set: not caching because keySize is 0");
+        return;
+    }
+    if (valueSize <= 0) {
+        ALOGW("set: not caching because valueSize is 0");
+        return;
+    }
+
+    sp<Blob> dummyKey(new Blob(key, keySize, false));
+    CacheEntry dummyEntry(dummyKey, NULL);
+
+    while (true) {
+        ssize_t index = mCacheEntries.indexOf(dummyEntry);
+        if (index < 0) {
+            // Create a new cache entry.
+            sp<Blob> keyBlob(new Blob(key, keySize, true));
+            sp<Blob> valueBlob(new Blob(value, valueSize, true));
+            size_t newTotalSize = mTotalSize + keySize + valueSize;
+            if (mMaxTotalSize < newTotalSize) {
+                if (isCleanable()) {
+                    // Clean the cache and try again.
+                    clean();
+                    continue;
+                } else {
+                    ALOGV("set: not caching new key/value pair because the "
+                            "total cache size limit would be exceeded: %d "
+                            "(limit: %d)",
+                            keySize + valueSize, mMaxTotalSize);
+                    break;
+                }
+            }
+            mCacheEntries.add(CacheEntry(keyBlob, valueBlob));
+            mTotalSize = newTotalSize;
+            ALOGV("set: created new cache entry with %d byte key and %d byte value",
+                    keySize, valueSize);
+        } else {
+            // Update the existing cache entry.
+            sp<Blob> valueBlob(new Blob(value, valueSize, true));
+            sp<Blob> oldValueBlob(mCacheEntries[index].getValue());
+            size_t newTotalSize = mTotalSize + valueSize - oldValueBlob->getSize();
+            if (mMaxTotalSize < newTotalSize) {
+                if (isCleanable()) {
+                    // Clean the cache and try again.
+                    clean();
+                    continue;
+                } else {
+                    ALOGV("set: not caching new value because the total cache "
+                            "size limit would be exceeded: %d (limit: %d)",
+                            keySize + valueSize, mMaxTotalSize);
+                    break;
+                }
+            }
+            mCacheEntries.editItemAt(index).setValue(valueBlob);
+            mTotalSize = newTotalSize;
+            ALOGV("set: updated existing cache entry with %d byte key and %d byte "
+                    "value", keySize, valueSize);
+        }
+        break;
+    }
+}
+
+size_t BlobCache::get(const void* key, size_t keySize, void* value,
+        size_t valueSize) {
+    if (mMaxKeySize < keySize) {
+        ALOGV("get: not searching because the key is too large: %d (limit %d)",
+                keySize, mMaxKeySize);
+        return 0;
+    }
+    sp<Blob> dummyKey(new Blob(key, keySize, false));
+    CacheEntry dummyEntry(dummyKey, NULL);
+    ssize_t index = mCacheEntries.indexOf(dummyEntry);
+    if (index < 0) {
+        ALOGV("get: no cache entry found for key of size %d", keySize);
+        return 0;
+    }
+
+    // The key was found. Return the value if the caller's buffer is large
+    // enough.
+    sp<Blob> valueBlob(mCacheEntries[index].getValue());
+    size_t valueBlobSize = valueBlob->getSize();
+    if (valueBlobSize <= valueSize) {
+        ALOGV("get: copying %d bytes to caller's buffer", valueBlobSize);
+        memcpy(value, valueBlob->getData(), valueBlobSize);
+    } else {
+        ALOGV("get: caller's buffer is too small for value: %d (needs %d)",
+                valueSize, valueBlobSize);
+    }
+    return valueBlobSize;
+}
+
+static inline size_t align4(size_t size) {
+    return (size + 3) & ~3;
+}
+
+size_t BlobCache::getFlattenedSize() const {
+    size_t size = sizeof(Header);
+    for (size_t i = 0; i < mCacheEntries.size(); i++) {
+        const CacheEntry& e(mCacheEntries[i]);
+        sp<Blob> keyBlob = e.getKey();
+        sp<Blob> valueBlob = e.getValue();
+        size = align4(size);
+        size += sizeof(EntryHeader) + keyBlob->getSize() +
+                valueBlob->getSize();
+    }
+    return size;
+}
+
+status_t BlobCache::flatten(void* buffer, size_t size) const {
+    // Write the cache header
+    if (size < sizeof(Header)) {
+        ALOGE("flatten: not enough room for cache header");
+        return BAD_VALUE;
+    }
+    Header* header = reinterpret_cast<Header*>(buffer);
+    header->mMagicNumber = blobCacheMagic;
+    header->mBlobCacheVersion = blobCacheVersion;
+    header->mDeviceVersion = blobCacheDeviceVersion;
+    header->mNumEntries = mCacheEntries.size();
+
+    // Write cache entries
+    uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer);
+    off_t byteOffset = align4(sizeof(Header));
+    for (size_t i = 0; i < mCacheEntries.size(); i++) {
+        const CacheEntry& e(mCacheEntries[i]);
+        sp<Blob> keyBlob = e.getKey();
+        sp<Blob> valueBlob = e.getValue();
+        size_t keySize = keyBlob->getSize();
+        size_t valueSize = valueBlob->getSize();
+
+        size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
+        if (byteOffset + entrySize > size) {
+            ALOGE("flatten: not enough room for cache entries");
+            return BAD_VALUE;
+        }
+
+        EntryHeader* eheader = reinterpret_cast<EntryHeader*>(
+            &byteBuffer[byteOffset]);
+        eheader->mKeySize = keySize;
+        eheader->mValueSize = valueSize;
+
+        memcpy(eheader->mData, keyBlob->getData(), keySize);
+        memcpy(eheader->mData + keySize, valueBlob->getData(), valueSize);
+
+        byteOffset += align4(entrySize);
+    }
+
+    return OK;
+}
+
+status_t BlobCache::unflatten(void const* buffer, size_t size) {
+    // All errors should result in the BlobCache being in an empty state.
+    mCacheEntries.clear();
+
+    // Read the cache header
+    if (size < sizeof(Header)) {
+        ALOGE("unflatten: not enough room for cache header");
+        return BAD_VALUE;
+    }
+    const Header* header = reinterpret_cast<const Header*>(buffer);
+    if (header->mMagicNumber != blobCacheMagic) {
+        ALOGE("unflatten: bad magic number: %d", header->mMagicNumber);
+        return BAD_VALUE;
+    }
+    if (header->mBlobCacheVersion != blobCacheVersion ||
+            header->mDeviceVersion != blobCacheDeviceVersion) {
+        // We treat version mismatches as an empty cache.
+        return OK;
+    }
+
+    // Read cache entries
+    const uint8_t* byteBuffer = reinterpret_cast<const uint8_t*>(buffer);
+    off_t byteOffset = align4(sizeof(Header));
+    size_t numEntries = header->mNumEntries;
+    for (size_t i = 0; i < numEntries; i++) {
+        if (byteOffset + sizeof(EntryHeader) > size) {
+            mCacheEntries.clear();
+            ALOGE("unflatten: not enough room for cache entry headers");
+            return BAD_VALUE;
+        }
+
+        const EntryHeader* eheader = reinterpret_cast<const EntryHeader*>(
+                &byteBuffer[byteOffset]);
+        size_t keySize = eheader->mKeySize;
+        size_t valueSize = eheader->mValueSize;
+        size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
+
+        if (byteOffset + entrySize > size) {
+            mCacheEntries.clear();
+            ALOGE("unflatten: not enough room for cache entry headers");
+            return BAD_VALUE;
+        }
+
+        const uint8_t* data = eheader->mData;
+        set(data, keySize, data + keySize, valueSize);
+
+        byteOffset += align4(entrySize);
+    }
+
+    return OK;
+}
+
+long int BlobCache::blob_random() {
+#ifdef _WIN32
+    return rand();
+#else
+    return nrand48(mRandState);
+#endif
+}
+
+void BlobCache::clean() {
+    // Remove a random cache entry until the total cache size gets below half
+    // the maximum total cache size.
+    while (mTotalSize > mMaxTotalSize / 2) {
+        size_t i = size_t(blob_random() % (mCacheEntries.size()));
+        const CacheEntry& entry(mCacheEntries[i]);
+        mTotalSize -= entry.getKey()->getSize() + entry.getValue()->getSize();
+        mCacheEntries.removeAt(i);
+    }
+}
+
+bool BlobCache::isCleanable() const {
+    return mTotalSize > mMaxTotalSize / 2;
+}
+
+BlobCache::Blob::Blob(const void* data, size_t size, bool copyData):
+        mData(copyData ? malloc(size) : data),
+        mSize(size),
+        mOwnsData(copyData) {
+    if (data != NULL && copyData) {
+        memcpy(const_cast<void*>(mData), data, size);
+    }
+}
+
+BlobCache::Blob::~Blob() {
+    if (mOwnsData) {
+        free(const_cast<void*>(mData));
+    }
+}
+
+bool BlobCache::Blob::operator<(const Blob& rhs) const {
+    if (mSize == rhs.mSize) {
+        return memcmp(mData, rhs.mData, mSize) < 0;
+    } else {
+        return mSize < rhs.mSize;
+    }
+}
+
+const void* BlobCache::Blob::getData() const {
+    return mData;
+}
+
+size_t BlobCache::Blob::getSize() const {
+    return mSize;
+}
+
+BlobCache::CacheEntry::CacheEntry() {
+}
+
+BlobCache::CacheEntry::CacheEntry(const sp<Blob>& key, const sp<Blob>& value):
+        mKey(key),
+        mValue(value) {
+}
+
+BlobCache::CacheEntry::CacheEntry(const CacheEntry& ce):
+        mKey(ce.mKey),
+        mValue(ce.mValue) {
+}
+
+bool BlobCache::CacheEntry::operator<(const CacheEntry& rhs) const {
+    return *mKey < *rhs.mKey;
+}
+
+const BlobCache::CacheEntry& BlobCache::CacheEntry::operator=(const CacheEntry& rhs) {
+    mKey = rhs.mKey;
+    mValue = rhs.mValue;
+    return *this;
+}
+
+sp<BlobCache::Blob> BlobCache::CacheEntry::getKey() const {
+    return mKey;
+}
+
+sp<BlobCache::Blob> BlobCache::CacheEntry::getValue() const {
+    return mValue;
+}
+
+void BlobCache::CacheEntry::setValue(const sp<Blob>& value) {
+    mValue = value;
+}
+
+} // namespace android
diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp
new file mode 100644
index 0000000..4ceaa7c
--- /dev/null
+++ b/libutils/CallStack.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "CallStack"
+
+#include <utils/CallStack.h>
+#include <utils/Printer.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <corkscrew/backtrace.h>
+
+namespace android {
+
+CallStack::CallStack() :
+        mCount(0) {
+}
+
+CallStack::CallStack(const char* logtag, int32_t ignoreDepth, int32_t maxDepth) {
+    this->update(ignoreDepth+1, maxDepth, CURRENT_THREAD);
+    this->log(logtag);
+}
+
+CallStack::CallStack(const CallStack& rhs) :
+        mCount(rhs.mCount) {
+    if (mCount) {
+        memcpy(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t));
+    }
+}
+
+CallStack::~CallStack() {
+}
+
+CallStack& CallStack::operator = (const CallStack& rhs) {
+    mCount = rhs.mCount;
+    if (mCount) {
+        memcpy(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t));
+    }
+    return *this;
+}
+
+bool CallStack::operator == (const CallStack& rhs) const {
+    if (mCount != rhs.mCount)
+        return false;
+    return !mCount || memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) == 0;
+}
+
+bool CallStack::operator != (const CallStack& rhs) const {
+    return !operator == (rhs);
+}
+
+bool CallStack::operator < (const CallStack& rhs) const {
+    if (mCount != rhs.mCount)
+        return mCount < rhs.mCount;
+    return memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) < 0;
+}
+
+bool CallStack::operator >= (const CallStack& rhs) const {
+    return !operator < (rhs);
+}
+
+bool CallStack::operator > (const CallStack& rhs) const {
+    if (mCount != rhs.mCount)
+        return mCount > rhs.mCount;
+    return memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) > 0;
+}
+
+bool CallStack::operator <= (const CallStack& rhs) const {
+    return !operator > (rhs);
+}
+
+const void* CallStack::operator [] (int index) const {
+    if (index >= int(mCount))
+        return 0;
+    return reinterpret_cast<const void*>(mStack[index].absolute_pc);
+}
+
+void CallStack::clear() {
+    mCount = 0;
+}
+
+void CallStack::update(int32_t ignoreDepth, int32_t maxDepth, pid_t tid) {
+    if (maxDepth > MAX_DEPTH) {
+        maxDepth = MAX_DEPTH;
+    }
+    ssize_t count;
+
+    if (tid >= 0) {
+        count = unwind_backtrace_thread(tid, mStack, ignoreDepth + 1, maxDepth);
+    } else if (tid == CURRENT_THREAD) {
+        count = unwind_backtrace(mStack, ignoreDepth + 1, maxDepth);
+    } else {
+        ALOGE("%s: Invalid tid specified (%d)", __FUNCTION__, tid);
+        count = 0;
+    }
+
+    mCount = count > 0 ? count : 0;
+}
+
+void CallStack::log(const char* logtag, android_LogPriority priority, const char* prefix) const {
+    LogPrinter printer(logtag, priority, prefix, /*ignoreBlankLines*/false);
+    print(printer);
+}
+
+void CallStack::dump(int fd, int indent, const char* prefix) const {
+    FdPrinter printer(fd, indent, prefix);
+    print(printer);
+}
+
+String8 CallStack::toString(const char* prefix) const {
+    String8 str;
+
+    String8Printer printer(&str, prefix);
+    print(printer);
+
+    return str;
+}
+
+void CallStack::print(Printer& printer) const {
+    backtrace_symbol_t symbols[mCount];
+
+    get_backtrace_symbols(mStack, mCount, symbols);
+    for (size_t i = 0; i < mCount; i++) {
+        char line[MAX_BACKTRACE_LINE_LENGTH];
+        format_backtrace_line(i, &mStack[i], &symbols[i],
+                line, MAX_BACKTRACE_LINE_LENGTH);
+        printer.printLine(line);
+    }
+    free_backtrace_symbols(symbols, mCount);
+}
+
+}; // namespace android
diff --git a/libutils/CleanSpec.mk b/libutils/CleanSpec.mk
new file mode 100644
index 0000000..c3c5651
--- /dev/null
+++ b/libutils/CleanSpec.mk
@@ -0,0 +1,51 @@
+# Copyright (C) 2012 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(HOST_OUT)/obj/STATIC_LIBRARIES/libutils_intermediates/import_includes)
+$(call add-clean-step, rm -rf $(HOST_OUT)/obj/STATIC_LIBRARIES/lib64utils_intermediates/import_includes)
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
new file mode 100644
index 0000000..9ce370e
--- /dev/null
+++ b/libutils/FileMap.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+//
+// Shared file mapping class.
+//
+
+#define LOG_TAG "filemap"
+
+#include <utils/FileMap.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_POSIX_FILEMAP
+#include <sys/mman.h>
+#endif
+
+#include <string.h>
+#include <memory.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+/*static*/ long FileMap::mPageSize = -1;
+
+
+/*
+ * Constructor.  Create an empty object.
+ */
+FileMap::FileMap(void)
+    : mRefCount(1), mFileName(NULL), mBasePtr(NULL), mBaseLength(0),
+      mDataPtr(NULL), mDataLength(0)
+{
+}
+
+/*
+ * Destructor.
+ */
+FileMap::~FileMap(void)
+{
+    assert(mRefCount == 0);
+
+    //printf("+++ removing FileMap %p %u\n", mDataPtr, mDataLength);
+
+    mRefCount = -100;       // help catch double-free
+    if (mFileName != NULL) {
+        free(mFileName);
+    }
+#ifdef HAVE_POSIX_FILEMAP    
+    if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) {
+        ALOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength);
+    }
+#endif
+#ifdef HAVE_WIN32_FILEMAP
+    if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) {
+        ALOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr,
+              GetLastError() );
+    }
+    if (mFileMapping != INVALID_HANDLE_VALUE) {
+        CloseHandle(mFileMapping);
+    }
+    CloseHandle(mFileHandle);
+#endif
+}
+
+
+/*
+ * Create a new mapping on an open file.
+ *
+ * Closing the file descriptor does not unmap the pages, so we don't
+ * claim ownership of the fd.
+ *
+ * Returns "false" on failure.
+ */
+bool FileMap::create(const char* origFileName, int fd, off64_t offset, size_t length,
+        bool readOnly)
+{
+#ifdef HAVE_WIN32_FILEMAP
+    int     adjust;
+    off64_t adjOffset;
+    size_t  adjLength;
+
+    if (mPageSize == -1) {
+        SYSTEM_INFO  si;
+        
+        GetSystemInfo( &si );
+        mPageSize = si.dwAllocationGranularity;
+    }
+
+    DWORD  protect = readOnly ? PAGE_READONLY : PAGE_READWRITE;
+    
+    mFileHandle  = (HANDLE) _get_osfhandle(fd);
+    mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL);
+    if (mFileMapping == NULL) {
+        ALOGE("CreateFileMapping(%p, %lx) failed with error %ld\n",
+              mFileHandle, protect, GetLastError() );
+        return false;
+    }
+    
+    adjust    = offset % mPageSize;
+    adjOffset = offset - adjust;
+    adjLength = length + adjust;
+    
+    mBasePtr = MapViewOfFile( mFileMapping, 
+                              readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
+                              0,
+                              (DWORD)(adjOffset),
+                              adjLength );
+    if (mBasePtr == NULL) {
+        ALOGE("MapViewOfFile(%ld, %ld) failed with error %ld\n",
+              adjOffset, adjLength, GetLastError() );
+        CloseHandle(mFileMapping);
+        mFileMapping = INVALID_HANDLE_VALUE;
+        return false;
+    }
+#endif
+#ifdef HAVE_POSIX_FILEMAP
+    int     prot, flags, adjust;
+    off64_t adjOffset;
+    size_t  adjLength;
+
+    void* ptr;
+
+    assert(mRefCount == 1);
+    assert(fd >= 0);
+    assert(offset >= 0);
+    assert(length > 0);
+
+    /* init on first use */
+    if (mPageSize == -1) {
+#if NOT_USING_KLIBC
+        mPageSize = sysconf(_SC_PAGESIZE);
+        if (mPageSize == -1) {
+            ALOGE("could not get _SC_PAGESIZE\n");
+            return false;
+        }
+#else
+        /* this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM */
+        mPageSize = 4096;
+#endif
+    }
+
+    adjust   = offset % mPageSize;
+try_again:
+    adjOffset = offset - adjust;
+    adjLength = length + adjust;
+
+    flags = MAP_SHARED;
+    prot = PROT_READ;
+    if (!readOnly)
+        prot |= PROT_WRITE;
+
+    ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset);
+    if (ptr == MAP_FAILED) {
+    	// Cygwin does not seem to like file mapping files from an offset.
+    	// So if we fail, try again with offset zero
+    	if (adjOffset > 0) {
+    		adjust = offset;
+    		goto try_again;
+    	}
+    
+        ALOGE("mmap(%ld,%ld) failed: %s\n",
+            (long) adjOffset, (long) adjLength, strerror(errno));
+        return false;
+    }
+    mBasePtr = ptr;
+#endif /* HAVE_POSIX_FILEMAP */
+
+    mFileName = origFileName != NULL ? strdup(origFileName) : NULL;
+    mBaseLength = adjLength;
+    mDataOffset = offset;
+    mDataPtr = (char*) mBasePtr + adjust;
+    mDataLength = length;
+
+    assert(mBasePtr != NULL);
+
+    ALOGV("MAP: base %p/%d data %p/%d\n",
+        mBasePtr, (int) mBaseLength, mDataPtr, (int) mDataLength);
+
+    return true;
+}
+
+/*
+ * Provide guidance to the system.
+ */
+int FileMap::advise(MapAdvice advice)
+{
+#if HAVE_MADVISE
+    int cc, sysAdvice;
+
+    switch (advice) {
+        case NORMAL:        sysAdvice = MADV_NORMAL;        break;
+        case RANDOM:        sysAdvice = MADV_RANDOM;        break;
+        case SEQUENTIAL:    sysAdvice = MADV_SEQUENTIAL;    break;
+        case WILLNEED:      sysAdvice = MADV_WILLNEED;      break;
+        case DONTNEED:      sysAdvice = MADV_DONTNEED;      break;
+        default:
+                            assert(false);
+                            return -1;
+    }
+
+    cc = madvise(mBasePtr, mBaseLength, sysAdvice);
+    if (cc != 0)
+        ALOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno));
+    return cc;
+#else
+	return -1;
+#endif // HAVE_MADVISE
+}
diff --git a/libutils/JenkinsHash.cpp b/libutils/JenkinsHash.cpp
new file mode 100644
index 0000000..52c9bb7
--- /dev/null
+++ b/libutils/JenkinsHash.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/* Implementation of Jenkins one-at-a-time hash function. These choices are
+ * optimized for code size and portability, rather than raw speed. But speed
+ * should still be quite good.
+ **/
+
+#include <utils/JenkinsHash.h>
+
+namespace android {
+
+hash_t JenkinsHashWhiten(uint32_t hash) {
+    hash += (hash << 3);
+    hash ^= (hash >> 11);
+    hash += (hash << 15);
+    return hash;
+}
+
+uint32_t JenkinsHashMixBytes(uint32_t hash, const uint8_t* bytes, size_t size) {
+    hash = JenkinsHashMix(hash, (uint32_t)size);
+    size_t i;
+    for (i = 0; i < (size & -4); i += 4) {
+        uint32_t data = bytes[i] | (bytes[i+1] << 8) | (bytes[i+2] << 16) | (bytes[i+3] << 24);
+        hash = JenkinsHashMix(hash, data);
+    }
+    if (size & 3) {
+        uint32_t data = bytes[i];
+        data |= ((size & 3) > 1) ? (bytes[i+1] << 8) : 0;
+        data |= ((size & 3) > 2) ? (bytes[i+2] << 16) : 0;
+        hash = JenkinsHashMix(hash, data);
+    }
+    return hash;
+}
+
+uint32_t JenkinsHashMixShorts(uint32_t hash, const uint16_t* shorts, size_t size) {
+    hash = JenkinsHashMix(hash, (uint32_t)size);
+    size_t i;
+    for (i = 0; i < (size & -2); i += 2) {
+        uint32_t data = shorts[i] | (shorts[i+1] << 16);
+        hash = JenkinsHashMix(hash, data);
+    }
+    if (size & 1) {
+        uint32_t data = shorts[i];
+        hash = JenkinsHashMix(hash, data);
+    }
+    return hash;
+}
+
+}
+
diff --git a/libutils/LinearAllocator.cpp b/libutils/LinearAllocator.cpp
new file mode 100644
index 0000000..a07a291
--- /dev/null
+++ b/libutils/LinearAllocator.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "LinearAllocator"
+#define LOG_NDEBUG 1
+
+#include <stdlib.h>
+#include <utils/LinearAllocator.h>
+#include <utils/Log.h>
+
+
+// The ideal size of a page allocation (these need to be multiples of 8)
+#define INITIAL_PAGE_SIZE ((size_t)4096) // 4kb
+#define MAX_PAGE_SIZE ((size_t)131072) // 128kb
+
+// The maximum amount of wasted space we can have per page
+// Allocations exceeding this will have their own dedicated page
+// If this is too low, we will malloc too much
+// Too high, and we may waste too much space
+// Must be smaller than INITIAL_PAGE_SIZE
+#define MAX_WASTE_SIZE ((size_t)1024)
+
+#if ALIGN_DOUBLE
+#define ALIGN_SZ (sizeof(double))
+#else
+#define ALIGN_SZ (sizeof(int))
+#endif
+
+#define ALIGN(x) ((x + ALIGN_SZ - 1 ) & ~(ALIGN_SZ - 1))
+#define ALIGN_PTR(p) ((void*)(ALIGN((size_t)p)))
+
+#if LOG_NDEBUG
+#define ADD_ALLOCATION(size)
+#define RM_ALLOCATION(size)
+#else
+#include <utils/Thread.h>
+#include <utils/Timers.h>
+static size_t s_totalAllocations = 0;
+static nsecs_t s_nextLog = 0;
+static android::Mutex s_mutex;
+
+static void _logUsageLocked() {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    if (now > s_nextLog) {
+        s_nextLog = now + milliseconds_to_nanoseconds(10);
+        ALOGV("Total memory usage: %zu kb", s_totalAllocations / 1024);
+    }
+}
+
+static void _addAllocation(size_t size) {
+    android::AutoMutex lock(s_mutex);
+    s_totalAllocations += size;
+    _logUsageLocked();
+}
+
+#define ADD_ALLOCATION(size) _addAllocation(size);
+#define RM_ALLOCATION(size) _addAllocation(-size);
+#endif
+
+#define min(x,y) (((x) < (y)) ? (x) : (y))
+
+namespace android {
+
+class LinearAllocator::Page {
+public:
+    Page* next() { return mNextPage; }
+    void setNext(Page* next) { mNextPage = next; }
+
+    Page()
+        : mNextPage(0)
+    {}
+
+    void* operator new(size_t size, void* buf) { return buf; }
+
+    void* start() {
+        return (void*) (((size_t)this) + sizeof(Page));
+    }
+
+    void* end(int pageSize) {
+        return (void*) (((size_t)start()) + pageSize);
+    }
+
+private:
+    Page(const Page& other) {}
+    Page* mNextPage;
+};
+
+LinearAllocator::LinearAllocator()
+    : mPageSize(INITIAL_PAGE_SIZE)
+    , mMaxAllocSize(MAX_WASTE_SIZE)
+    , mNext(0)
+    , mCurrentPage(0)
+    , mPages(0)
+    , mTotalAllocated(0)
+    , mWastedSpace(0)
+    , mPageCount(0)
+    , mDedicatedPageCount(0) {}
+
+LinearAllocator::~LinearAllocator(void) {
+    Page* p = mPages;
+    while (p) {
+        Page* next = p->next();
+        p->~Page();
+        free(p);
+        RM_ALLOCATION(mPageSize);
+        p = next;
+    }
+}
+
+void* LinearAllocator::start(Page* p) {
+    return ALIGN_PTR(((size_t*)p) + sizeof(Page));
+}
+
+void* LinearAllocator::end(Page* p) {
+    return ((char*)p) + mPageSize;
+}
+
+bool LinearAllocator::fitsInCurrentPage(size_t size) {
+    return mNext && ((char*)mNext + size) <= end(mCurrentPage);
+}
+
+void LinearAllocator::ensureNext(size_t size) {
+    if (fitsInCurrentPage(size)) return;
+
+    if (mCurrentPage && mPageSize < MAX_PAGE_SIZE) {
+        mPageSize = min(MAX_PAGE_SIZE, mPageSize * 2);
+        mPageSize = ALIGN(mPageSize);
+    }
+    mWastedSpace += mPageSize;
+    Page* p = newPage(mPageSize);
+    if (mCurrentPage) {
+        mCurrentPage->setNext(p);
+    }
+    mCurrentPage = p;
+    if (!mPages) {
+        mPages = mCurrentPage;
+    }
+    mNext = start(mCurrentPage);
+}
+
+void* LinearAllocator::alloc(size_t size) {
+    size = ALIGN(size);
+    if (size > mMaxAllocSize && !fitsInCurrentPage(size)) {
+        ALOGV("Exceeded max size %zu > %zu", size, mMaxAllocSize);
+        // Allocation is too large, create a dedicated page for the allocation
+        Page* page = newPage(size);
+        mDedicatedPageCount++;
+        page->setNext(mPages);
+        mPages = page;
+        if (!mCurrentPage)
+            mCurrentPage = mPages;
+        return start(page);
+    }
+    ensureNext(size);
+    void* ptr = mNext;
+    mNext = ((char*)mNext) + size;
+    mWastedSpace -= size;
+    return ptr;
+}
+
+void LinearAllocator::rewindIfLastAlloc(void* ptr, size_t allocSize) {
+    // Don't bother rewinding across pages
+    allocSize = ALIGN(allocSize);
+    if (ptr >= start(mCurrentPage) && ptr < end(mCurrentPage)
+            && ptr == ((char*)mNext - allocSize)) {
+        mTotalAllocated -= allocSize;
+        mWastedSpace += allocSize;
+        mNext = ptr;
+    }
+}
+
+LinearAllocator::Page* LinearAllocator::newPage(size_t pageSize) {
+    pageSize = ALIGN(pageSize + sizeof(LinearAllocator::Page));
+    ADD_ALLOCATION(pageSize);
+    mTotalAllocated += pageSize;
+    mPageCount++;
+    void* buf = malloc(pageSize);
+    return new (buf) Page();
+}
+
+static const char* toSize(size_t value, float& result) {
+    if (value < 2000) {
+        result = value;
+        return "B";
+    }
+    if (value < 2000000) {
+        result = value / 1024.0f;
+        return "KB";
+    }
+    result = value / 1048576.0f;
+    return "MB";
+}
+
+void LinearAllocator::dumpMemoryStats(const char* prefix) {
+    float prettySize;
+    const char* prettySuffix;
+    prettySuffix = toSize(mTotalAllocated, prettySize);
+    ALOGD("%sTotal allocated: %.2f%s", prefix, prettySize, prettySuffix);
+    prettySuffix = toSize(mWastedSpace, prettySize);
+    ALOGD("%sWasted space: %.2f%s (%.1f%%)", prefix, prettySize, prettySuffix,
+          (float) mWastedSpace / (float) mTotalAllocated * 100.0f);
+    ALOGD("%sPages %zu (dedicated %zu)", prefix, mPageCount, mDedicatedPageCount);
+}
+
+}; // namespace android
diff --git a/libutils/LinearTransform.cpp b/libutils/LinearTransform.cpp
new file mode 100644
index 0000000..b7d28d4
--- /dev/null
+++ b/libutils/LinearTransform.cpp
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#define __STDC_LIMIT_MACROS
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <utils/LinearTransform.h>
+
+namespace android {
+
+template<class T> static inline T ABS(T x) { return (x < 0) ? -x : x; }
+
+// Static math methods involving linear transformations
+static bool scale_u64_to_u64(
+        uint64_t val,
+        uint32_t N,
+        uint32_t D,
+        uint64_t* res,
+        bool round_up_not_down) {
+    uint64_t tmp1, tmp2;
+    uint32_t r;
+
+    assert(res);
+    assert(D);
+
+    // Let U32(X) denote a uint32_t containing the upper 32 bits of a 64 bit
+    // integer X.
+    // Let L32(X) denote a uint32_t containing the lower 32 bits of a 64 bit
+    // integer X.
+    // Let X[A, B] with A <= B denote bits A through B of the integer X.
+    // Let (A | B) denote the concatination of two 32 bit ints, A and B.
+    // IOW X = (A | B) => U32(X) == A && L32(X) == B
+    //
+    // compute M = val * N (a 96 bit int)
+    // ---------------------------------
+    // tmp2 = U32(val) * N (a 64 bit int)
+    // tmp1 = L32(val) * N (a 64 bit int)
+    // which means
+    // M = val * N = (tmp2 << 32) + tmp1
+    tmp2 = (val >> 32) * N;
+    tmp1 = (val & UINT32_MAX) * N;
+
+    // compute M[32, 95]
+    // tmp2 = tmp2 + U32(tmp1)
+    //      = (U32(val) * N) + U32(L32(val) * N)
+    //      = M[32, 95]
+    tmp2 += tmp1 >> 32;
+
+    // if M[64, 95] >= D, then M/D has bits > 63 set and we have
+    // an overflow.
+    if ((tmp2 >> 32) >= D) {
+        *res = UINT64_MAX;
+        return false;
+    }
+
+    // Divide.  Going in we know
+    // tmp2 = M[32, 95]
+    // U32(tmp2) < D
+    r = tmp2 % D;
+    tmp2 /= D;
+
+    // At this point
+    // tmp1      = L32(val) * N
+    // tmp2      = M[32, 95] / D
+    //           = (M / D)[32, 95]
+    // r         = M[32, 95] % D
+    // U32(tmp2) = 0
+    //
+    // compute tmp1 = (r | M[0, 31])
+    tmp1 = (tmp1 & UINT32_MAX) | ((uint64_t)r << 32);
+
+    // Divide again.  Keep the remainder around in order to round properly.
+    r = tmp1 % D;
+    tmp1 /= D;
+
+    // At this point
+    // tmp2      = (M / D)[32, 95]
+    // tmp1      = (M / D)[ 0, 31]
+    // r         =  M % D
+    // U32(tmp1) = 0
+    // U32(tmp2) = 0
+
+    // Pack the result and deal with the round-up case (As well as the
+    // remote possiblility over overflow in such a case).
+    *res = (tmp2 << 32) | tmp1;
+    if (r && round_up_not_down) {
+        ++(*res);
+        if (!(*res)) {
+            *res = UINT64_MAX;
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static bool linear_transform_s64_to_s64(
+        int64_t  val,
+        int64_t  basis1,
+        int32_t  N,
+        uint32_t D,
+        bool     invert_frac,
+        int64_t  basis2,
+        int64_t* out) {
+    uint64_t scaled, res;
+    uint64_t abs_val;
+    bool is_neg;
+
+    if (!out)
+        return false;
+
+    // Compute abs(val - basis_64). Keep track of whether or not this delta
+    // will be negative after the scale opertaion.
+    if (val < basis1) {
+        is_neg = true;
+        abs_val = basis1 - val;
+    } else {
+        is_neg = false;
+        abs_val = val - basis1;
+    }
+
+    if (N < 0)
+        is_neg = !is_neg;
+
+    if (!scale_u64_to_u64(abs_val,
+                          invert_frac ? D : ABS(N),
+                          invert_frac ? ABS(N) : D,
+                          &scaled,
+                          is_neg))
+        return false; // overflow/undeflow
+
+    // if scaled is >= 0x8000<etc>, then we are going to overflow or
+    // underflow unless ABS(basis2) is large enough to pull us back into the
+    // non-overflow/underflow region.
+    if (scaled & INT64_MIN) {
+        if (is_neg && (basis2 < 0))
+            return false; // certain underflow
+
+        if (!is_neg && (basis2 >= 0))
+            return false; // certain overflow
+
+        if (ABS(basis2) <= static_cast<int64_t>(scaled & INT64_MAX))
+            return false; // not enough
+
+        // Looks like we are OK
+        *out = (is_neg ? (-scaled) : scaled) + basis2;
+    } else {
+        // Scaled fits within signed bounds, so we just need to check for
+        // over/underflow for two signed integers.  Basically, if both scaled
+        // and basis2 have the same sign bit, and the result has a different
+        // sign bit, then we have under/overflow.  An easy way to compute this
+        // is
+        // (scaled_signbit XNOR basis_signbit) &&
+        // (scaled_signbit XOR res_signbit)
+        // ==
+        // (scaled_signbit XOR basis_signbit XOR 1) &&
+        // (scaled_signbit XOR res_signbit)
+
+        if (is_neg)
+            scaled = -scaled;
+        res = scaled + basis2;
+
+        if ((scaled ^ basis2 ^ INT64_MIN) & (scaled ^ res) & INT64_MIN)
+            return false;
+
+        *out = res;
+    }
+
+    return true;
+}
+
+bool LinearTransform::doForwardTransform(int64_t a_in, int64_t* b_out) const {
+    if (0 == a_to_b_denom)
+        return false;
+
+    return linear_transform_s64_to_s64(a_in,
+                                       a_zero,
+                                       a_to_b_numer,
+                                       a_to_b_denom,
+                                       false,
+                                       b_zero,
+                                       b_out);
+}
+
+bool LinearTransform::doReverseTransform(int64_t b_in, int64_t* a_out) const {
+    if (0 == a_to_b_numer)
+        return false;
+
+    return linear_transform_s64_to_s64(b_in,
+                                       b_zero,
+                                       a_to_b_numer,
+                                       a_to_b_denom,
+                                       true,
+                                       a_zero,
+                                       a_out);
+}
+
+template <class T> void LinearTransform::reduce(T* N, T* D) {
+    T a, b;
+    if (!N || !D || !(*D)) {
+        assert(false);
+        return;
+    }
+
+    a = *N;
+    b = *D;
+
+    if (a == 0) {
+        *D = 1;
+        return;
+    }
+
+    // This implements Euclid's method to find GCD.
+    if (a < b) {
+        T tmp = a;
+        a = b;
+        b = tmp;
+    }
+
+    while (1) {
+        // a is now the greater of the two.
+        const T remainder = a % b;
+        if (remainder == 0) {
+            *N /= b;
+            *D /= b;
+            return;
+        }
+        // by swapping remainder and b, we are guaranteeing that a is
+        // still the greater of the two upon entrance to the loop.
+        a = b;
+        b = remainder;
+    }
+};
+
+template void LinearTransform::reduce<uint64_t>(uint64_t* N, uint64_t* D);
+template void LinearTransform::reduce<uint32_t>(uint32_t* N, uint32_t* D);
+
+void LinearTransform::reduce(int32_t* N, uint32_t* D) {
+    if (N && D && *D) {
+        if (*N < 0) {
+            *N = -(*N);
+            reduce(reinterpret_cast<uint32_t*>(N), D);
+            *N = -(*N);
+        } else {
+            reduce(reinterpret_cast<uint32_t*>(N), D);
+        }
+    }
+}
+
+}  // namespace android
diff --git a/libutils/Log.cpp b/libutils/Log.cpp
new file mode 100644
index 0000000..bffb56e
--- /dev/null
+++ b/libutils/Log.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#define LOG_TAG "Log"
+
+#include <utils/Log.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+LogIfSlow::LogIfSlow(const char* tag, android_LogPriority priority,
+        int timeoutMillis, const char* message) :
+        mTag(tag), mPriority(priority), mTimeoutMillis(timeoutMillis), mMessage(message),
+        mStart(systemTime(SYSTEM_TIME_BOOTTIME)) {
+}
+
+LogIfSlow::~LogIfSlow() {
+    int durationMillis = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_BOOTTIME) - mStart);
+    if (durationMillis > mTimeoutMillis) {
+        LOG_PRI(mPriority, mTag, "%s: %dms", mMessage, durationMillis);
+    }
+}
+
+} // namespace android
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
new file mode 100644
index 0000000..c51df2d
--- /dev/null
+++ b/libutils/Looper.cpp
@@ -0,0 +1,573 @@
+//
+// Copyright 2010 The Android Open Source Project
+//
+// A looper implementation based on epoll().
+//
+#define LOG_TAG "Looper"
+
+//#define LOG_NDEBUG 0
+
+// Debugs poll and wake interactions.
+#define DEBUG_POLL_AND_WAKE 0
+
+// Debugs callback registration and invocation.
+#define DEBUG_CALLBACKS 0
+
+#include <cutils/log.h>
+#include <utils/Looper.h>
+#include <utils/Timers.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+
+
+namespace android {
+
+// --- WeakMessageHandler ---
+
+WeakMessageHandler::WeakMessageHandler(const wp<MessageHandler>& handler) :
+        mHandler(handler) {
+}
+
+WeakMessageHandler::~WeakMessageHandler() {
+}
+
+void WeakMessageHandler::handleMessage(const Message& message) {
+    sp<MessageHandler> handler = mHandler.promote();
+    if (handler != NULL) {
+        handler->handleMessage(message);
+    }
+}
+
+
+// --- SimpleLooperCallback ---
+
+SimpleLooperCallback::SimpleLooperCallback(ALooper_callbackFunc callback) :
+        mCallback(callback) {
+}
+
+SimpleLooperCallback::~SimpleLooperCallback() {
+}
+
+int SimpleLooperCallback::handleEvent(int fd, int events, void* data) {
+    return mCallback(fd, events, data);
+}
+
+
+// --- Looper ---
+
+// Hint for number of file descriptors to be associated with the epoll instance.
+static const int EPOLL_SIZE_HINT = 8;
+
+// Maximum number of file descriptors for which to retrieve poll events each iteration.
+static const int EPOLL_MAX_EVENTS = 16;
+
+static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT;
+static pthread_key_t gTLSKey = 0;
+
+Looper::Looper(bool allowNonCallbacks) :
+        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
+        mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
+    int wakeFds[2];
+    int result = pipe(wakeFds);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);
+
+    mWakeReadPipeFd = wakeFds[0];
+    mWakeWritePipeFd = wakeFds[1];
+
+    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
+            errno);
+
+    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
+            errno);
+
+    mIdling = false;
+
+    // Allocate the epoll instance and register the wake pipe.
+    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
+    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);
+
+    struct epoll_event eventItem;
+    memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
+    eventItem.events = EPOLLIN;
+    eventItem.data.fd = mWakeReadPipeFd;
+    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",
+            errno);
+}
+
+Looper::~Looper() {
+    close(mWakeReadPipeFd);
+    close(mWakeWritePipeFd);
+    close(mEpollFd);
+}
+
+void Looper::initTLSKey() {
+    int result = pthread_key_create(& gTLSKey, threadDestructor);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not allocate TLS key.");
+}
+
+void Looper::threadDestructor(void *st) {
+    Looper* const self = static_cast<Looper*>(st);
+    if (self != NULL) {
+        self->decStrong((void*)threadDestructor);
+    }
+}
+
+void Looper::setForThread(const sp<Looper>& looper) {
+    sp<Looper> old = getForThread(); // also has side-effect of initializing TLS
+
+    if (looper != NULL) {
+        looper->incStrong((void*)threadDestructor);
+    }
+
+    pthread_setspecific(gTLSKey, looper.get());
+
+    if (old != NULL) {
+        old->decStrong((void*)threadDestructor);
+    }
+}
+
+sp<Looper> Looper::getForThread() {
+    int result = pthread_once(& gTLSOnce, initTLSKey);
+    LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed");
+
+    return (Looper*)pthread_getspecific(gTLSKey);
+}
+
+sp<Looper> Looper::prepare(int opts) {
+    bool allowNonCallbacks = opts & ALOOPER_PREPARE_ALLOW_NON_CALLBACKS;
+    sp<Looper> looper = Looper::getForThread();
+    if (looper == NULL) {
+        looper = new Looper(allowNonCallbacks);
+        Looper::setForThread(looper);
+    }
+    if (looper->getAllowNonCallbacks() != allowNonCallbacks) {
+        ALOGW("Looper already prepared for this thread with a different value for the "
+                "ALOOPER_PREPARE_ALLOW_NON_CALLBACKS option.");
+    }
+    return looper;
+}
+
+bool Looper::getAllowNonCallbacks() const {
+    return mAllowNonCallbacks;
+}
+
+int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
+    int result = 0;
+    for (;;) {
+        while (mResponseIndex < mResponses.size()) {
+            const Response& response = mResponses.itemAt(mResponseIndex++);
+            int ident = response.request.ident;
+            if (ident >= 0) {
+                int fd = response.request.fd;
+                int events = response.events;
+                void* data = response.request.data;
+#if DEBUG_POLL_AND_WAKE
+                ALOGD("%p ~ pollOnce - returning signalled identifier %d: "
+                        "fd=%d, events=0x%x, data=%p",
+                        this, ident, fd, events, data);
+#endif
+                if (outFd != NULL) *outFd = fd;
+                if (outEvents != NULL) *outEvents = events;
+                if (outData != NULL) *outData = data;
+                return ident;
+            }
+        }
+
+        if (result != 0) {
+#if DEBUG_POLL_AND_WAKE
+            ALOGD("%p ~ pollOnce - returning result %d", this, result);
+#endif
+            if (outFd != NULL) *outFd = 0;
+            if (outEvents != NULL) *outEvents = 0;
+            if (outData != NULL) *outData = NULL;
+            return result;
+        }
+
+        result = pollInner(timeoutMillis);
+    }
+}
+
+int Looper::pollInner(int timeoutMillis) {
+#if DEBUG_POLL_AND_WAKE
+    ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
+#endif
+
+    // Adjust the timeout based on when the next message is due.
+    if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
+        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+        int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
+        if (messageTimeoutMillis >= 0
+                && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
+            timeoutMillis = messageTimeoutMillis;
+        }
+#if DEBUG_POLL_AND_WAKE
+        ALOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d",
+                this, mNextMessageUptime - now, timeoutMillis);
+#endif
+    }
+
+    // Poll.
+    int result = ALOOPER_POLL_WAKE;
+    mResponses.clear();
+    mResponseIndex = 0;
+
+    // We are about to idle.
+    mIdling = true;
+
+    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
+    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
+
+    // No longer idling.
+    mIdling = false;
+
+    // Acquire lock.
+    mLock.lock();
+
+    // Check for poll error.
+    if (eventCount < 0) {
+        if (errno == EINTR) {
+            goto Done;
+        }
+        ALOGW("Poll failed with an unexpected error, errno=%d", errno);
+        result = ALOOPER_POLL_ERROR;
+        goto Done;
+    }
+
+    // Check for poll timeout.
+    if (eventCount == 0) {
+#if DEBUG_POLL_AND_WAKE
+        ALOGD("%p ~ pollOnce - timeout", this);
+#endif
+        result = ALOOPER_POLL_TIMEOUT;
+        goto Done;
+    }
+
+    // Handle all events.
+#if DEBUG_POLL_AND_WAKE
+    ALOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
+#endif
+
+    for (int i = 0; i < eventCount; i++) {
+        int fd = eventItems[i].data.fd;
+        uint32_t epollEvents = eventItems[i].events;
+        if (fd == mWakeReadPipeFd) {
+            if (epollEvents & EPOLLIN) {
+                awoken();
+            } else {
+                ALOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
+            }
+        } else {
+            ssize_t requestIndex = mRequests.indexOfKey(fd);
+            if (requestIndex >= 0) {
+                int events = 0;
+                if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
+                if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
+                if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
+                if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
+                pushResponse(events, mRequests.valueAt(requestIndex));
+            } else {
+                ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
+                        "no longer registered.", epollEvents, fd);
+            }
+        }
+    }
+Done: ;
+
+    // Invoke pending message callbacks.
+    mNextMessageUptime = LLONG_MAX;
+    while (mMessageEnvelopes.size() != 0) {
+        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
+        if (messageEnvelope.uptime <= now) {
+            // Remove the envelope from the list.
+            // We keep a strong reference to the handler until the call to handleMessage
+            // finishes.  Then we drop it so that the handler can be deleted *before*
+            // we reacquire our lock.
+            { // obtain handler
+                sp<MessageHandler> handler = messageEnvelope.handler;
+                Message message = messageEnvelope.message;
+                mMessageEnvelopes.removeAt(0);
+                mSendingMessage = true;
+                mLock.unlock();
+
+#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
+                ALOGD("%p ~ pollOnce - sending message: handler=%p, what=%d",
+                        this, handler.get(), message.what);
+#endif
+                handler->handleMessage(message);
+            } // release handler
+
+            mLock.lock();
+            mSendingMessage = false;
+            result = ALOOPER_POLL_CALLBACK;
+        } else {
+            // The last message left at the head of the queue determines the next wakeup time.
+            mNextMessageUptime = messageEnvelope.uptime;
+            break;
+        }
+    }
+
+    // Release lock.
+    mLock.unlock();
+
+    // Invoke all response callbacks.
+    for (size_t i = 0; i < mResponses.size(); i++) {
+        Response& response = mResponses.editItemAt(i);
+        if (response.request.ident == ALOOPER_POLL_CALLBACK) {
+            int fd = response.request.fd;
+            int events = response.events;
+            void* data = response.request.data;
+#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
+            ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
+                    this, response.request.callback.get(), fd, events, data);
+#endif
+            int callbackResult = response.request.callback->handleEvent(fd, events, data);
+            if (callbackResult == 0) {
+                removeFd(fd);
+            }
+            // Clear the callback reference in the response structure promptly because we
+            // will not clear the response vector itself until the next poll.
+            response.request.callback.clear();
+            result = ALOOPER_POLL_CALLBACK;
+        }
+    }
+    return result;
+}
+
+int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
+    if (timeoutMillis <= 0) {
+        int result;
+        do {
+            result = pollOnce(timeoutMillis, outFd, outEvents, outData);
+        } while (result == ALOOPER_POLL_CALLBACK);
+        return result;
+    } else {
+        nsecs_t endTime = systemTime(SYSTEM_TIME_MONOTONIC)
+                + milliseconds_to_nanoseconds(timeoutMillis);
+
+        for (;;) {
+            int result = pollOnce(timeoutMillis, outFd, outEvents, outData);
+            if (result != ALOOPER_POLL_CALLBACK) {
+                return result;
+            }
+
+            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+            timeoutMillis = toMillisecondTimeoutDelay(now, endTime);
+            if (timeoutMillis == 0) {
+                return ALOOPER_POLL_TIMEOUT;
+            }
+        }
+    }
+}
+
+void Looper::wake() {
+#if DEBUG_POLL_AND_WAKE
+    ALOGD("%p ~ wake", this);
+#endif
+
+    ssize_t nWrite;
+    do {
+        nWrite = write(mWakeWritePipeFd, "W", 1);
+    } while (nWrite == -1 && errno == EINTR);
+
+    if (nWrite != 1) {
+        if (errno != EAGAIN) {
+            ALOGW("Could not write wake signal, errno=%d", errno);
+        }
+    }
+}
+
+void Looper::awoken() {
+#if DEBUG_POLL_AND_WAKE
+    ALOGD("%p ~ awoken", this);
+#endif
+
+    char buffer[16];
+    ssize_t nRead;
+    do {
+        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
+    } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
+}
+
+void Looper::pushResponse(int events, const Request& request) {
+    Response response;
+    response.events = events;
+    response.request = request;
+    mResponses.push(response);
+}
+
+int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {
+    return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data);
+}
+
+int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
+#if DEBUG_CALLBACKS
+    ALOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident,
+            events, callback.get(), data);
+#endif
+
+    if (!callback.get()) {
+        if (! mAllowNonCallbacks) {
+            ALOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
+            return -1;
+        }
+
+        if (ident < 0) {
+            ALOGE("Invalid attempt to set NULL callback with ident < 0.");
+            return -1;
+        }
+    } else {
+        ident = ALOOPER_POLL_CALLBACK;
+    }
+
+    int epollEvents = 0;
+    if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN;
+    if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT;
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        Request request;
+        request.fd = fd;
+        request.ident = ident;
+        request.callback = callback;
+        request.data = data;
+
+        struct epoll_event eventItem;
+        memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
+        eventItem.events = epollEvents;
+        eventItem.data.fd = fd;
+
+        ssize_t requestIndex = mRequests.indexOfKey(fd);
+        if (requestIndex < 0) {
+            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
+            if (epollResult < 0) {
+                ALOGE("Error adding epoll events for fd %d, errno=%d", fd, errno);
+                return -1;
+            }
+            mRequests.add(fd, request);
+        } else {
+            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
+            if (epollResult < 0) {
+                ALOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno);
+                return -1;
+            }
+            mRequests.replaceValueAt(requestIndex, request);
+        }
+    } // release lock
+    return 1;
+}
+
+int Looper::removeFd(int fd) {
+#if DEBUG_CALLBACKS
+    ALOGD("%p ~ removeFd - fd=%d", this, fd);
+#endif
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+        ssize_t requestIndex = mRequests.indexOfKey(fd);
+        if (requestIndex < 0) {
+            return 0;
+        }
+
+        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
+        if (epollResult < 0) {
+            ALOGE("Error removing epoll events for fd %d, errno=%d", fd, errno);
+            return -1;
+        }
+
+        mRequests.removeItemsAt(requestIndex);
+    } // release lock
+    return 1;
+}
+
+void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    sendMessageAtTime(now, handler, message);
+}
+
+void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
+        const Message& message) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    sendMessageAtTime(now + uptimeDelay, handler, message);
+}
+
+void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
+        const Message& message) {
+#if DEBUG_CALLBACKS
+    ALOGD("%p ~ sendMessageAtTime - uptime=%lld, handler=%p, what=%d",
+            this, uptime, handler.get(), message.what);
+#endif
+
+    size_t i = 0;
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        size_t messageCount = mMessageEnvelopes.size();
+        while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
+            i += 1;
+        }
+
+        MessageEnvelope messageEnvelope(uptime, handler, message);
+        mMessageEnvelopes.insertAt(messageEnvelope, i, 1);
+
+        // Optimization: If the Looper is currently sending a message, then we can skip
+        // the call to wake() because the next thing the Looper will do after processing
+        // messages is to decide when the next wakeup time should be.  In fact, it does
+        // not even matter whether this code is running on the Looper thread.
+        if (mSendingMessage) {
+            return;
+        }
+    } // release lock
+
+    // Wake the poll loop only when we enqueue a new message at the head.
+    if (i == 0) {
+        wake();
+    }
+}
+
+void Looper::removeMessages(const sp<MessageHandler>& handler) {
+#if DEBUG_CALLBACKS
+    ALOGD("%p ~ removeMessages - handler=%p", this, handler.get());
+#endif
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        for (size_t i = mMessageEnvelopes.size(); i != 0; ) {
+            const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i);
+            if (messageEnvelope.handler == handler) {
+                mMessageEnvelopes.removeAt(i);
+            }
+        }
+    } // release lock
+}
+
+void Looper::removeMessages(const sp<MessageHandler>& handler, int what) {
+#if DEBUG_CALLBACKS
+    ALOGD("%p ~ removeMessages - handler=%p, what=%d", this, handler.get(), what);
+#endif
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        for (size_t i = mMessageEnvelopes.size(); i != 0; ) {
+            const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i);
+            if (messageEnvelope.handler == handler
+                    && messageEnvelope.message.what == what) {
+                mMessageEnvelopes.removeAt(i);
+            }
+        }
+    } // release lock
+}
+
+bool Looper::isIdling() const {
+    return mIdling;
+}
+
+} // namespace android
diff --git a/libutils/MODULE_LICENSE_APACHE2 b/libutils/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libutils/MODULE_LICENSE_APACHE2
diff --git a/libutils/NOTICE b/libutils/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libutils/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp
new file mode 100644
index 0000000..ac729e0
--- /dev/null
+++ b/libutils/Printer.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#define LOG_TAG "Printer"
+// #define LOG_NDEBUG 0
+
+#include <utils/Printer.h>
+#include <utils/String8.h>
+#include <utils/Log.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef __BIONIC__
+#define fdprintf dprintf
+#endif
+
+namespace android {
+
+/*
+ * Implementation of Printer
+ */
+Printer::Printer() {
+    // Intentionally left empty
+}
+
+Printer::~Printer() {
+    // Intentionally left empty
+}
+
+void Printer::printFormatLine(const char* format, ...) {
+    va_list arglist;
+    va_start(arglist, format);
+
+    char* formattedString;
+
+#ifndef USE_MINGW
+    if (vasprintf(&formattedString, format, arglist) < 0) { // returns -1 on error
+        ALOGE("%s: Failed to format string", __FUNCTION__);
+        return;
+    }
+#else
+    return;
+#endif
+
+    va_end(arglist);
+
+    printLine(formattedString);
+    free(formattedString);
+}
+
+/*
+ * Implementation of LogPrinter
+ */
+LogPrinter::LogPrinter(const char* logtag,
+                       android_LogPriority priority,
+                       const char* prefix,
+                       bool ignoreBlankLines) :
+        mLogTag(logtag),
+        mPriority(priority),
+        mPrefix(prefix ?: ""),
+        mIgnoreBlankLines(ignoreBlankLines) {
+}
+
+void LogPrinter::printLine(const char* string) {
+    if (string == NULL) {
+        ALOGW("%s: NULL string passed in", __FUNCTION__);
+        return;
+    }
+
+    if (mIgnoreBlankLines || (*string)) {
+        // Simple case: Line is not blank, or we don't care about printing blank lines
+        printRaw(string);
+    } else {
+        // Force logcat to print empty lines by adding prefixing with a space
+        printRaw(" ");
+    }
+}
+
+void LogPrinter::printRaw(const char* string) {
+    __android_log_print(mPriority, mLogTag, "%s%s", mPrefix, string);
+}
+
+
+/*
+ * Implementation of FdPrinter
+ */
+FdPrinter::FdPrinter(int fd, unsigned int indent, const char* prefix) :
+        mFd(fd), mIndent(indent), mPrefix(prefix ?: "") {
+
+    if (fd < 0) {
+        ALOGW("%s: File descriptor out of range (%d)", __FUNCTION__, fd);
+    }
+
+    // <indent><prefix><line> -- e.g. '%-4s%s\n' for indent=4
+    snprintf(mFormatString, sizeof(mFormatString), "%%-%us%%s\n", mIndent);
+}
+
+void FdPrinter::printLine(const char* string) {
+    if (string == NULL) {
+        ALOGW("%s: NULL string passed in", __FUNCTION__);
+        return;
+    } else if (mFd < 0) {
+        ALOGW("%s: File descriptor out of range (%d)", __FUNCTION__, mFd);
+        return;
+    }
+
+#ifndef USE_MINGW
+    fdprintf(mFd, mFormatString, mPrefix, string);
+#endif
+}
+
+/*
+ * Implementation of String8Printer
+ */
+String8Printer::String8Printer(String8* target, const char* prefix) :
+        mTarget(target),
+        mPrefix(prefix ?: "") {
+
+    if (target == NULL) {
+        ALOGW("%s: Target string was NULL", __FUNCTION__);
+    }
+}
+
+void String8Printer::printLine(const char* string) {
+    if (string == NULL) {
+        ALOGW("%s: NULL string passed in", __FUNCTION__);
+        return;
+    } else if (mTarget == NULL) {
+        ALOGW("%s: Target string was NULL", __FUNCTION__);
+        return;
+    }
+
+    mTarget->append(string);
+    mTarget->append("\n");
+}
+
+/*
+ * Implementation of PrefixPrinter
+ */
+PrefixPrinter::PrefixPrinter(Printer& printer, const char* prefix) :
+        mPrinter(printer), mPrefix(prefix ?: "") {
+}
+
+void PrefixPrinter::printLine(const char* string) {
+    mPrinter.printFormatLine("%s%s", mPrefix, string);
+}
+
+}; //namespace android
diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp
new file mode 100644
index 0000000..f9340c5
--- /dev/null
+++ b/libutils/ProcessCallStack.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#define LOG_TAG "ProcessCallStack"
+// #define LOG_NDEBUG 0
+
+#include <string.h>
+#include <stdio.h>
+#include <dirent.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/ProcessCallStack.h>
+#include <utils/Printer.h>
+
+#include <limits.h>
+
+namespace android {
+
+enum {
+    // Max sizes for various dynamically generated strings
+    MAX_TIME_STRING = 64,
+    MAX_PROC_PATH = 1024,
+
+    // Dump related prettiness constants
+    IGNORE_DEPTH_CURRENT_THREAD = 2,
+};
+
+static const char* CALL_STACK_PREFIX = "  ";
+static const char* PATH_THREAD_NAME = "/proc/self/task/%d/comm";
+static const char* PATH_SELF_TASK = "/proc/self/task";
+
+static void dumpProcessHeader(Printer& printer, pid_t pid, const char* timeStr) {
+    if (timeStr == NULL) {
+        ALOGW("%s: timeStr was NULL", __FUNCTION__);
+        return;
+    }
+
+    char path[PATH_MAX];
+    char procNameBuf[MAX_PROC_PATH];
+    char* procName = NULL;
+    FILE* fp;
+
+    snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
+    if ((fp = fopen(path, "r"))) {
+        procName = fgets(procNameBuf, sizeof(procNameBuf), fp);
+        fclose(fp);
+    }
+
+    if (!procName) {
+        procName = const_cast<char*>("<unknown>");
+    }
+
+    printer.printLine();
+    printer.printLine();
+    printer.printFormatLine("----- pid %d at %s -----", pid, timeStr);
+    printer.printFormatLine("Cmd line: %s", procName);
+}
+
+static void dumpProcessFooter(Printer& printer, pid_t pid) {
+    printer.printLine();
+    printer.printFormatLine("----- end %d -----", pid);
+    printer.printLine();
+}
+
+static String8 getThreadName(pid_t tid) {
+    char path[PATH_MAX];
+    char* procName = NULL;
+    char procNameBuf[MAX_PROC_PATH];
+    FILE* fp;
+
+    snprintf(path, sizeof(path), PATH_THREAD_NAME, tid);
+    if ((fp = fopen(path, "r"))) {
+        procName = fgets(procNameBuf, sizeof(procNameBuf), fp);
+        fclose(fp);
+    } else {
+        ALOGE("%s: Failed to open %s", __FUNCTION__, path);
+    }
+
+    // Strip ending newline
+    strtok(procName, "\n");
+
+    return String8(procName);
+}
+
+static String8 getTimeString(struct tm tm) {
+    char timestr[MAX_TIME_STRING];
+    // i.e. '2013-10-22 14:42:05'
+    strftime(timestr, sizeof(timestr), "%F %T", &tm);
+
+    return String8(timestr);
+}
+
+/*
+ * Implementation of ProcessCallStack
+ */
+ProcessCallStack::ProcessCallStack() {
+}
+
+ProcessCallStack::ProcessCallStack(const ProcessCallStack& rhs) :
+        mThreadMap(rhs.mThreadMap),
+        mTimeUpdated(rhs.mTimeUpdated) {
+}
+
+ProcessCallStack::~ProcessCallStack() {
+}
+
+void ProcessCallStack::clear() {
+    mThreadMap.clear();
+    mTimeUpdated = tm();
+}
+
+void ProcessCallStack::update(int32_t maxDepth) {
+    DIR *dp;
+    struct dirent *ep;
+    struct dirent entry;
+
+    dp = opendir(PATH_SELF_TASK);
+    if (dp == NULL) {
+        ALOGE("%s: Failed to update the process's call stacks (errno = %d, '%s')",
+              __FUNCTION__, errno, strerror(errno));
+        return;
+    }
+
+    pid_t selfPid = getpid();
+
+    clear();
+
+    // Get current time.
+#ifndef USE_MINGW
+    {
+        time_t t = time(NULL);
+        struct tm tm;
+        localtime_r(&t, &tm);
+
+        mTimeUpdated = tm;
+    }
+
+    /*
+     * Each tid is a directory inside of /proc/self/task
+     * - Read every file in directory => get every tid
+     */
+    int code;
+    while ((code = readdir_r(dp, &entry, &ep)) == 0 && ep != NULL) {
+        pid_t tid = -1;
+        sscanf(ep->d_name, "%d", &tid);
+
+        if (tid < 0) {
+            // Ignore '.' and '..'
+            ALOGV("%s: Failed to read tid from %s/%s",
+                  __FUNCTION__, PATH_SELF_TASK, ep->d_name);
+            continue;
+        }
+
+        ssize_t idx = mThreadMap.add(tid, ThreadInfo());
+        if (idx < 0) { // returns negative error value on error
+            ALOGE("%s: Failed to add new ThreadInfo (errno = %zd, '%s')",
+                  __FUNCTION__, idx, strerror(-idx));
+            continue;
+        }
+
+        ThreadInfo& threadInfo = mThreadMap.editValueAt(static_cast<size_t>(idx));
+
+        /*
+         * Ignore CallStack::update and ProcessCallStack::update for current thread
+         * - Every other thread doesn't need this since we call update off-thread
+         */
+        int ignoreDepth = (selfPid == tid) ? IGNORE_DEPTH_CURRENT_THREAD : 0;
+
+        // Update thread's call stacks
+        CallStack& cs = threadInfo.callStack;
+        cs.update(ignoreDepth, maxDepth, tid);
+
+        // Read/save thread name
+        threadInfo.threadName = getThreadName(tid);
+
+        ALOGV("%s: Got call stack for tid %d (size %zu)",
+              __FUNCTION__, tid, cs.size());
+    }
+    if (code != 0) { // returns positive error value on error
+        ALOGE("%s: Failed to readdir from %s (errno = %d, '%s')",
+              __FUNCTION__, PATH_SELF_TASK, -code, strerror(code));
+    }
+#endif
+
+    closedir(dp);
+}
+
+void ProcessCallStack::log(const char* logtag, android_LogPriority priority,
+                           const char* prefix) const {
+    LogPrinter printer(logtag, priority, prefix, /*ignoreBlankLines*/false);
+    print(printer);
+}
+
+void ProcessCallStack::print(Printer& printer) const {
+    /*
+     * Print the header/footer with the regular printer.
+     * Print the callstack with an additional two spaces as the prefix for legibility.
+     */
+    PrefixPrinter csPrinter(printer, CALL_STACK_PREFIX);
+    printInternal(printer, csPrinter);
+}
+
+void ProcessCallStack::printInternal(Printer& printer, Printer& csPrinter) const {
+    dumpProcessHeader(printer, getpid(),
+                      getTimeString(mTimeUpdated).string());
+
+    for (size_t i = 0; i < mThreadMap.size(); ++i) {
+        pid_t tid = mThreadMap.keyAt(i);
+        const ThreadInfo& threadInfo = mThreadMap.valueAt(i);
+        const CallStack& cs = threadInfo.callStack;
+        const String8& threadName = threadInfo.threadName;
+
+        printer.printLine("");
+        printer.printFormatLine("\"%s\" sysTid=%d", threadName.string(), tid);
+
+        cs.print(csPrinter);
+    }
+
+    dumpProcessFooter(printer, getpid());
+}
+
+void ProcessCallStack::dump(int fd, int indent, const char* prefix) const {
+
+    if (indent < 0) {
+        ALOGW("%s: Bad indent (%d)", __FUNCTION__, indent);
+        return;
+    }
+
+    FdPrinter printer(fd, static_cast<unsigned int>(indent), prefix);
+    print(printer);
+}
+
+String8 ProcessCallStack::toString(const char* prefix) const {
+
+    String8 dest;
+    String8Printer printer(&dest, prefix);
+    print(printer);
+
+    return dest;
+}
+
+size_t ProcessCallStack::size() const {
+    return mThreadMap.size();
+}
+
+}; //namespace android
diff --git a/libutils/PropertyMap.cpp b/libutils/PropertyMap.cpp
new file mode 100644
index 0000000..5520702
--- /dev/null
+++ b/libutils/PropertyMap.cpp
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "PropertyMap"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <utils/PropertyMap.h>
+#include <utils/Log.h>
+
+// Enables debug output for the parser.
+#define DEBUG_PARSER 0
+
+// Enables debug output for parser performance.
+#define DEBUG_PARSER_PERFORMANCE 0
+
+
+namespace android {
+
+static const char* WHITESPACE = " \t\r";
+static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r=";
+
+
+// --- PropertyMap ---
+
+PropertyMap::PropertyMap() {
+}
+
+PropertyMap::~PropertyMap() {
+}
+
+void PropertyMap::clear() {
+    mProperties.clear();
+}
+
+void PropertyMap::addProperty(const String8& key, const String8& value) {
+    mProperties.add(key, value);
+}
+
+bool PropertyMap::hasProperty(const String8& key) const {
+    return mProperties.indexOfKey(key) >= 0;
+}
+
+bool PropertyMap::tryGetProperty(const String8& key, String8& outValue) const {
+    ssize_t index = mProperties.indexOfKey(key);
+    if (index < 0) {
+        return false;
+    }
+
+    outValue = mProperties.valueAt(index);
+    return true;
+}
+
+bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const {
+    int32_t intValue;
+    if (!tryGetProperty(key, intValue)) {
+        return false;
+    }
+
+    outValue = intValue;
+    return true;
+}
+
+bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const {
+    String8 stringValue;
+    if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) {
+        return false;
+    }
+
+    char* end;
+    int value = strtol(stringValue.string(), & end, 10);
+    if (*end != '\0') {
+        ALOGW("Property key '%s' has invalid value '%s'.  Expected an integer.",
+                key.string(), stringValue.string());
+        return false;
+    }
+    outValue = value;
+    return true;
+}
+
+bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const {
+    String8 stringValue;
+    if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) {
+        return false;
+    }
+
+    char* end;
+    float value = strtof(stringValue.string(), & end);
+    if (*end != '\0') {
+        ALOGW("Property key '%s' has invalid value '%s'.  Expected a float.",
+                key.string(), stringValue.string());
+        return false;
+    }
+    outValue = value;
+    return true;
+}
+
+void PropertyMap::addAll(const PropertyMap* map) {
+    for (size_t i = 0; i < map->mProperties.size(); i++) {
+        mProperties.add(map->mProperties.keyAt(i), map->mProperties.valueAt(i));
+    }
+}
+
+status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) {
+    *outMap = NULL;
+
+    Tokenizer* tokenizer;
+    status_t status = Tokenizer::open(filename, &tokenizer);
+    if (status) {
+        ALOGE("Error %d opening property file %s.", status, filename.string());
+    } else {
+        PropertyMap* map = new PropertyMap();
+        if (!map) {
+            ALOGE("Error allocating property map.");
+            status = NO_MEMORY;
+        } else {
+#if DEBUG_PARSER_PERFORMANCE
+            nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
+#endif
+            Parser parser(map, tokenizer);
+            status = parser.parse();
+#if DEBUG_PARSER_PERFORMANCE
+            nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
+            ALOGD("Parsed property file '%s' %d lines in %0.3fms.",
+                    tokenizer->getFilename().string(), tokenizer->getLineNumber(),
+                    elapsedTime / 1000000.0);
+#endif
+            if (status) {
+                delete map;
+            } else {
+                *outMap = map;
+            }
+        }
+        delete tokenizer;
+    }
+    return status;
+}
+
+
+// --- PropertyMap::Parser ---
+
+PropertyMap::Parser::Parser(PropertyMap* map, Tokenizer* tokenizer) :
+        mMap(map), mTokenizer(tokenizer) {
+}
+
+PropertyMap::Parser::~Parser() {
+}
+
+status_t PropertyMap::Parser::parse() {
+    while (!mTokenizer->isEof()) {
+#if DEBUG_PARSER
+        ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
+                mTokenizer->peekRemainderOfLine().string());
+#endif
+
+        mTokenizer->skipDelimiters(WHITESPACE);
+
+        if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
+            String8 keyToken = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
+            if (keyToken.isEmpty()) {
+                ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string());
+                return BAD_VALUE;
+            }
+
+            mTokenizer->skipDelimiters(WHITESPACE);
+
+            if (mTokenizer->nextChar() != '=') {
+                ALOGE("%s: Expected '=' between property key and value.",
+                        mTokenizer->getLocation().string());
+                return BAD_VALUE;
+            }
+
+            mTokenizer->skipDelimiters(WHITESPACE);
+
+            String8 valueToken = mTokenizer->nextToken(WHITESPACE);
+            if (valueToken.find("\\", 0) >= 0 || valueToken.find("\"", 0) >= 0) {
+                ALOGE("%s: Found reserved character '\\' or '\"' in property value.",
+                        mTokenizer->getLocation().string());
+                return BAD_VALUE;
+            }
+
+            mTokenizer->skipDelimiters(WHITESPACE);
+            if (!mTokenizer->isEol()) {
+                ALOGE("%s: Expected end of line, got '%s'.",
+                        mTokenizer->getLocation().string(),
+                        mTokenizer->peekRemainderOfLine().string());
+                return BAD_VALUE;
+            }
+
+            if (mMap->hasProperty(keyToken)) {
+                ALOGE("%s: Duplicate property value for key '%s'.",
+                        mTokenizer->getLocation().string(), keyToken.string());
+                return BAD_VALUE;
+            }
+
+            mMap->addProperty(keyToken, valueToken);
+        }
+
+        mTokenizer->nextLine();
+    }
+    return NO_ERROR;
+}
+
+} // namespace android
diff --git a/libutils/README b/libutils/README
new file mode 100644
index 0000000..01741e0
--- /dev/null
+++ b/libutils/README
@@ -0,0 +1,289 @@
+Android Utility Function Library
+================================
+
+
+If you need a feature that is native to Linux but not present on other
+platforms, construct a platform-dependent implementation that shares
+the Linux interface.  That way the actual device runs as "light" as
+possible.
+
+If that isn't feasible, create a system-independent interface and hide
+the details.
+
+The ultimate goal is *not* to create a super-duper platform abstraction
+layer.  The goal is to provide an optimized solution for Linux with
+reasonable implementations for other platforms.
+
+
+
+Resource overlay
+================
+
+
+Introduction
+------------
+
+Overlay packages are special .apk files which provide no code but
+additional resource values (and possibly new configurations) for
+resources in other packages. When an application requests resources,
+the system will return values from either the application's original
+package or any associated overlay package. Any redirection is completely
+transparent to the calling application.
+
+Resource values have the following precedence table, listed in
+descending precedence.
+
+ * overlay package, matching config (eg res/values-en-land)
+
+ * original package, matching config
+
+ * overlay package, no config (eg res/values)
+
+ * original package, no config
+
+During compilation, overlay packages are differentiated from regular
+packages by passing the -o flag to aapt.
+
+
+Background
+----------
+
+This section provides generic background material on resources in
+Android.
+
+
+How resources are bundled in .apk files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Android .apk files are .zip files, usually housing .dex code,
+certificates and resources, though packages containing resources but
+no code are possible. Resources can be divided into the following
+categories; a `configuration' indicates a set of phone language, display
+density, network operator, etc.
+
+ * assets: uncompressed, raw files packaged as part of an .apk and
+           explicitly referenced by filename. These files are
+           independent of configuration.
+
+ * res/drawable: bitmap or xml graphics. Each file may have different
+                 values depending on configuration.
+
+ * res/values: integers, strings, etc. Each resource may have different
+               values depending on configuration.
+
+Resource meta information and information proper is stored in a binary
+format in a named file resources.arsc, bundled as part of the .apk.
+
+Resource IDs and lookup
+~~~~~~~~~~~~~~~~~~~~~~~
+During compilation, the aapt tool gathers application resources and
+generates a resources.arsc file. Each resource name is assigned an
+integer ID 0xppttiii (translated to a symbolic name via R.java), where
+
+ * pp: corresponds to the package namespace (details below).
+
+ * tt: corresponds to the resource type (string, int, etc). Every
+       resource of the same type within the same package has the same
+       tt value, but depending on available types, the actual numerical
+       value may be different between packages.
+
+ * iiii: sequential number, assigned in the order resources are found.
+
+Resource values are specified paired with a set of configuration
+constraints (the default being the empty set), eg res/values-sv-port
+which imposes restrictions on language (Swedish) and display orientation
+(portrait). During lookup, every constraint set is matched against the
+current configuration, and the value corresponding to the best matching
+constraint set is returned (ResourceTypes.{h,cpp}).
+
+Parsing of resources.arsc is handled by ResourceTypes.cpp; this utility
+is governed by AssetManager.cpp, which tracks loaded resources per
+process.
+
+Assets are looked up by path and filename in AssetManager.cpp. The path
+to resources in res/drawable are located by ResourceTypes.cpp and then
+handled like assets by AssetManager.cpp. Other resources are handled
+solely by ResourceTypes.cpp.
+
+Package ID as namespace
+~~~~~~~~~~~~~~~~~~~~~~~
+The pp part of a resource ID defines a namespace. Android currently
+defines two namespaces:
+
+ * 0x01: system resources (pre-installed in framework-res.apk)
+
+ * 0x7f: application resources (bundled in the application .apk)
+
+ResourceTypes.cpp supports package IDs between 0x01 and 0x7f
+(inclusive); values outside this range are invalid.
+
+Each running (Dalvik) process is assigned a unique instance of
+AssetManager, which in turn keeps a forest structure of loaded
+resource.arsc files. Normally, this forest is structured as follows,
+where mPackageMap is the internal vector employed in ResourceTypes.cpp.
+
+mPackageMap[0x00] -> system package
+mPackageMap[0x01] -> NULL
+mPackageMap[0x02] -> NULL
+...
+mPackageMap[0x7f - 2] -> NULL
+mPackageMap[0x7f - 1] -> application package
+
+
+
+The resource overlay extension
+------------------------------
+
+The resource overlay mechanism aims to (partly) shadow and extend
+existing resources with new values for defined and new configurations.
+Technically, this is achieved by adding resource-only packages (called
+overlay packages) to existing resource namespaces, like so:
+
+mPackageMap[0x00] -> system package -> system overlay package
+mPackageMap[0x01] -> NULL
+mPackageMap[0x02] -> NULL
+...
+mPackageMap[0x7f - 2] -> NULL
+mPackageMap[0x7f - 1] -> application package -> overlay 1 -> overlay 2
+
+The use of overlay resources is completely transparent to
+applications; no additional resource identifiers are introduced, only
+configuration/value pairs. Any number of overlay packages may be loaded
+at a time; overlay packages are agnostic to what they target -- both
+system and application resources are fair game.
+
+The package targeted by an overlay package is called the target or
+original package.
+
+Resource overlay operates on symbolic resources names. Hence, to
+override the string/str1 resources in a package, the overlay package
+would include a resource also named string/str1. The end user does not
+have to worry about the numeric resources IDs assigned by aapt, as this
+is resolved automatically by the system.
+
+As of this writing, the use of resource overlay has not been fully
+explored. Until it has, only OEMs are trusted to use resource overlay.
+For this reason, overlay packages must reside in /system/overlay.
+
+
+Resource ID mapping
+~~~~~~~~~~~~~~~~~~~
+Resource identifiers must be coherent within the same namespace (ie
+PackageGroup in ResourceTypes.cpp). Calling applications will refer to
+resources using the IDs defined in the original package, but there is no
+guarantee aapt has assigned the same ID to the corresponding resource in
+an overlay package. To translate between the two, a resource ID mapping
+{original ID -> overlay ID} is created during package installation
+(PackageManagerService.java) and used during resource lookup. The
+mapping is stored in /data/resource-cache, with a @idmap file name
+suffix.
+
+The idmap file format is documented in a separate section, below.
+
+
+Package management
+~~~~~~~~~~~~~~~~~~
+Packages are managed by the PackageManagerService. Addition and removal
+of packages are monitored via the inotify framework, exposed via
+android.os.FileObserver.
+
+During initialization of a Dalvik process, ActivityThread.java requests
+the process' AssetManager (by proxy, via AssetManager.java and JNI)
+to load a list of packages. This list includes overlay packages, if
+present.
+
+When a target package or a corresponding overlay package is installed,
+the target package's process is stopped and a new idmap is generated.
+This is similar to how applications are stopped when their packages are
+upgraded.
+
+
+Creating overlay packages
+-------------------------
+
+Overlay packages should contain no code, define (some) resources with
+the same type and name as in the original package, and be compiled with
+the -o flag passed to aapt.
+
+The aapt -o flag instructs aapt to create an overlay package.
+Technically, this means the package will be assigned package id 0x00.
+
+There are no restrictions on overlay packages names, though the naming
+convention <original.package.name>.overlay.<name> is recommended.
+
+
+Example overlay package
+~~~~~~~~~~~~~~~~~~~~~~~
+
+To overlay the resource bool/b in package com.foo.bar, to be applied
+when the display is in landscape mode, create a new package with
+no source code and a single .xml file under res/values-land, with
+an entry for bool/b. Compile with aapt -o and place the results in
+/system/overlay by adding the following to Android.mk:
+
+LOCAL_AAPT_FLAGS := -o com.foo.bar
+LOCAL_MODULE_PATH := $(TARGET_OUT)/overlay
+
+
+The ID map (idmap) file format
+------------------------------
+
+The idmap format is designed for lookup performance. However, leading
+and trailing undefined overlay values are discarded to reduce the memory
+footprint.
+
+
+idmap grammar
+~~~~~~~~~~~~~
+All atoms (names in square brackets) are uint32_t integers. The
+idmap-magic constant spells "idmp" in ASCII. Offsets are given relative
+to the data_header, not to the beginning of the file.
+
+map          := header data
+header       := idmap-magic <crc32-original-pkg> <crc32-overlay-pkg>
+idmap-magic  := <0x706d6469>
+data         := data_header type_block+
+data_header  := <m> header_block{m}
+header_block := <0> | <type_block_offset>
+type_block   := <n> <id_offset> entry{n}
+entry        := <resource_id_in_target_package>
+
+
+idmap example
+~~~~~~~~~~~~~
+Given a pair of target and overlay packages with CRC sums 0x216a8fe2
+and 0x6b9beaec, each defining the following resources
+
+Name          Target package  Overlay package
+string/str0   0x7f010000      -
+string/str1   0x7f010001      0x7f010000
+string/str2   0x7f010002      -
+string/str3   0x7f010003      0x7f010001
+string/str4   0x7f010004      -
+bool/bool0    0x7f020000      -
+integer/int0  0x7f030000      0x7f020000
+integer/int1  0x7f030001      -
+
+the corresponding resource map is
+
+0x706d6469 0x216a8fe2 0x6b9beaec 0x00000003 \
+0x00000004 0x00000000 0x00000009 0x00000003 \
+0x00000001 0x7f010000 0x00000000 0x7f010001 \
+0x00000001 0x00000000 0x7f020000
+
+or, formatted differently
+
+0x706d6469  # magic: all idmap files begin with this constant
+0x216a8fe2  # CRC32 of the resources.arsc file in the original package
+0x6b9beaec  # CRC32 of the resources.arsc file in the overlay package
+0x00000003  # header; three types (string, bool, integer) in the target package
+0x00000004  #   header_block for type 0 (string) is located at offset 4
+0x00000000  #   no bool type exists in overlay package -> no header_block
+0x00000009  #   header_block for type 2 (integer) is located at offset 9
+0x00000003  # header_block for string; overlay IDs span 3 elements
+0x00000001  #   the first string in target package is entry 1 == offset
+0x7f010000  #   target 0x7f01001 -> overlay 0x7f010000
+0x00000000  #   str2 not defined in overlay package
+0x7f010001  #   target 0x7f010003 -> overlay 0x7f010001
+0x00000001  # header_block for integer; overlay IDs span 1 element
+0x00000000  #   offset == 0
+0x7f020000  #   target 0x7f030000 -> overlay 0x7f020000
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
new file mode 100644
index 0000000..f398a82
--- /dev/null
+++ b/libutils/RefBase.cpp
@@ -0,0 +1,650 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "RefBase"
+// #define LOG_NDEBUG 0
+
+#include <utils/RefBase.h>
+
+#include <utils/Atomic.h>
+#include <utils/CallStack.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <typeinfo>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+// compile with refcounting debugging enabled
+#define DEBUG_REFS                      0
+
+// whether ref-tracking is enabled by default, if not, trackMe(true, false)
+// needs to be called explicitly
+#define DEBUG_REFS_ENABLED_BY_DEFAULT   0
+
+// whether callstack are collected (significantly slows things down)
+#define DEBUG_REFS_CALLSTACK_ENABLED    1
+
+// folder where stack traces are saved when DEBUG_REFS is enabled
+// this folder needs to exist and be writable
+#define DEBUG_REFS_CALLSTACK_PATH       "/data/debug"
+
+// log all reference counting operations
+#define PRINT_REFS                      0
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+#define INITIAL_STRONG_VALUE (1<<28)
+
+// ---------------------------------------------------------------------------
+
+class RefBase::weakref_impl : public RefBase::weakref_type
+{
+public:
+    volatile int32_t    mStrong;
+    volatile int32_t    mWeak;
+    RefBase* const      mBase;
+    volatile int32_t    mFlags;
+
+#if !DEBUG_REFS
+
+    weakref_impl(RefBase* base)
+        : mStrong(INITIAL_STRONG_VALUE)
+        , mWeak(0)
+        , mBase(base)
+        , mFlags(0)
+    {
+    }
+
+    void addStrongRef(const void* /*id*/) { }
+    void removeStrongRef(const void* /*id*/) { }
+    void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
+    void addWeakRef(const void* /*id*/) { }
+    void removeWeakRef(const void* /*id*/) { }
+    void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
+    void printRefs() const { }
+    void trackMe(bool, bool) { }
+
+#else
+
+    weakref_impl(RefBase* base)
+        : mStrong(INITIAL_STRONG_VALUE)
+        , mWeak(0)
+        , mBase(base)
+        , mFlags(0)
+        , mStrongRefs(NULL)
+        , mWeakRefs(NULL)
+        , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
+        , mRetain(false)
+    {
+    }
+    
+    ~weakref_impl()
+    {
+        bool dumpStack = false;
+        if (!mRetain && mStrongRefs != NULL) {
+            dumpStack = true;
+            ALOGE("Strong references remain:");
+            ref_entry* refs = mStrongRefs;
+            while (refs) {
+                char inc = refs->ref >= 0 ? '+' : '-';
+                ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
+#if DEBUG_REFS_CALLSTACK_ENABLED
+                refs->stack.dump(LOG_TAG);
+#endif
+                refs = refs->next;
+            }
+        }
+
+        if (!mRetain && mWeakRefs != NULL) {
+            dumpStack = true;
+            ALOGE("Weak references remain!");
+            ref_entry* refs = mWeakRefs;
+            while (refs) {
+                char inc = refs->ref >= 0 ? '+' : '-';
+                ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
+#if DEBUG_REFS_CALLSTACK_ENABLED
+                refs->stack.dump(LOG_TAG);
+#endif
+                refs = refs->next;
+            }
+        }
+        if (dumpStack) {
+            ALOGE("above errors at:");
+            CallStack stack(LOG_TAG);
+        }
+    }
+
+    void addStrongRef(const void* id) {
+        //ALOGD_IF(mTrackEnabled,
+        //        "addStrongRef: RefBase=%p, id=%p", mBase, id);
+        addRef(&mStrongRefs, id, mStrong);
+    }
+
+    void removeStrongRef(const void* id) {
+        //ALOGD_IF(mTrackEnabled,
+        //        "removeStrongRef: RefBase=%p, id=%p", mBase, id);
+        if (!mRetain) {
+            removeRef(&mStrongRefs, id);
+        } else {
+            addRef(&mStrongRefs, id, -mStrong);
+        }
+    }
+
+    void renameStrongRefId(const void* old_id, const void* new_id) {
+        //ALOGD_IF(mTrackEnabled,
+        //        "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
+        //        mBase, old_id, new_id);
+        renameRefsId(mStrongRefs, old_id, new_id);
+    }
+
+    void addWeakRef(const void* id) {
+        addRef(&mWeakRefs, id, mWeak);
+    }
+
+    void removeWeakRef(const void* id) {
+        if (!mRetain) {
+            removeRef(&mWeakRefs, id);
+        } else {
+            addRef(&mWeakRefs, id, -mWeak);
+        }
+    }
+
+    void renameWeakRefId(const void* old_id, const void* new_id) {
+        renameRefsId(mWeakRefs, old_id, new_id);
+    }
+
+    void trackMe(bool track, bool retain)
+    { 
+        mTrackEnabled = track;
+        mRetain = retain;
+    }
+
+    void printRefs() const
+    {
+        String8 text;
+
+        {
+            Mutex::Autolock _l(mMutex);
+            char buf[128];
+            sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
+            text.append(buf);
+            printRefsLocked(&text, mStrongRefs);
+            sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
+            text.append(buf);
+            printRefsLocked(&text, mWeakRefs);
+        }
+
+        {
+            char name[100];
+            snprintf(name, 100, DEBUG_REFS_CALLSTACK_PATH "/%p.stack", this);
+            int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
+            if (rc >= 0) {
+                write(rc, text.string(), text.length());
+                close(rc);
+                ALOGD("STACK TRACE for %p saved in %s", this, name);
+            }
+            else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
+                      name, strerror(errno));
+        }
+    }
+
+private:
+    struct ref_entry
+    {
+        ref_entry* next;
+        const void* id;
+#if DEBUG_REFS_CALLSTACK_ENABLED
+        CallStack stack;
+#endif
+        int32_t ref;
+    };
+
+    void addRef(ref_entry** refs, const void* id, int32_t mRef)
+    {
+        if (mTrackEnabled) {
+            AutoMutex _l(mMutex);
+
+            ref_entry* ref = new ref_entry;
+            // Reference count at the time of the snapshot, but before the
+            // update.  Positive value means we increment, negative--we
+            // decrement the reference count.
+            ref->ref = mRef;
+            ref->id = id;
+#if DEBUG_REFS_CALLSTACK_ENABLED
+            ref->stack.update(2);
+#endif
+            ref->next = *refs;
+            *refs = ref;
+        }
+    }
+
+    void removeRef(ref_entry** refs, const void* id)
+    {
+        if (mTrackEnabled) {
+            AutoMutex _l(mMutex);
+            
+            ref_entry* const head = *refs;
+            ref_entry* ref = head;
+            while (ref != NULL) {
+                if (ref->id == id) {
+                    *refs = ref->next;
+                    delete ref;
+                    return;
+                }
+                refs = &ref->next;
+                ref = *refs;
+            }
+
+            ALOGE("RefBase: removing id %p on RefBase %p"
+                    "(weakref_type %p) that doesn't exist!",
+                    id, mBase, this);
+
+            ref = head;
+            while (ref) {
+                char inc = ref->ref >= 0 ? '+' : '-';
+                ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
+                ref = ref->next;
+            }
+
+            CallStack stack(LOG_TAG);
+        }
+    }
+
+    void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
+    {
+        if (mTrackEnabled) {
+            AutoMutex _l(mMutex);
+            ref_entry* ref = r;
+            while (ref != NULL) {
+                if (ref->id == old_id) {
+                    ref->id = new_id;
+                }
+                ref = ref->next;
+            }
+        }
+    }
+
+    void printRefsLocked(String8* out, const ref_entry* refs) const
+    {
+        char buf[128];
+        while (refs) {
+            char inc = refs->ref >= 0 ? '+' : '-';
+            sprintf(buf, "\t%c ID %p (ref %d):\n", 
+                    inc, refs->id, refs->ref);
+            out->append(buf);
+#if DEBUG_REFS_CALLSTACK_ENABLED
+            out->append(refs->stack.toString("\t\t"));
+#else
+            out->append("\t\t(call stacks disabled)");
+#endif
+            refs = refs->next;
+        }
+    }
+
+    mutable Mutex mMutex;
+    ref_entry* mStrongRefs;
+    ref_entry* mWeakRefs;
+
+    bool mTrackEnabled;
+    // Collect stack traces on addref and removeref, instead of deleting the stack references
+    // on removeref that match the address ones.
+    bool mRetain;
+
+#endif
+};
+
+// ---------------------------------------------------------------------------
+
+void RefBase::incStrong(const void* id) const
+{
+    weakref_impl* const refs = mRefs;
+    refs->incWeak(id);
+    
+    refs->addStrongRef(id);
+    const int32_t c = android_atomic_inc(&refs->mStrong);
+    ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
+#if PRINT_REFS
+    ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
+#endif
+    if (c != INITIAL_STRONG_VALUE)  {
+        return;
+    }
+
+    android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
+    refs->mBase->onFirstRef();
+}
+
+void RefBase::decStrong(const void* id) const
+{
+    weakref_impl* const refs = mRefs;
+    refs->removeStrongRef(id);
+    const int32_t c = android_atomic_dec(&refs->mStrong);
+#if PRINT_REFS
+    ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
+#endif
+    ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
+    if (c == 1) {
+        refs->mBase->onLastStrongRef(id);
+        if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
+            delete this;
+        }
+    }
+    refs->decWeak(id);
+}
+
+void RefBase::forceIncStrong(const void* id) const
+{
+    weakref_impl* const refs = mRefs;
+    refs->incWeak(id);
+    
+    refs->addStrongRef(id);
+    const int32_t c = android_atomic_inc(&refs->mStrong);
+    ALOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
+               refs);
+#if PRINT_REFS
+    ALOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
+#endif
+
+    switch (c) {
+    case INITIAL_STRONG_VALUE:
+        android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
+        // fall through...
+    case 0:
+        refs->mBase->onFirstRef();
+    }
+}
+
+int32_t RefBase::getStrongCount() const
+{
+    return mRefs->mStrong;
+}
+
+RefBase* RefBase::weakref_type::refBase() const
+{
+    return static_cast<const weakref_impl*>(this)->mBase;
+}
+
+void RefBase::weakref_type::incWeak(const void* id)
+{
+    weakref_impl* const impl = static_cast<weakref_impl*>(this);
+    impl->addWeakRef(id);
+    const int32_t c = android_atomic_inc(&impl->mWeak);
+    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
+}
+
+
+void RefBase::weakref_type::decWeak(const void* id)
+{
+    weakref_impl* const impl = static_cast<weakref_impl*>(this);
+    impl->removeWeakRef(id);
+    const int32_t c = android_atomic_dec(&impl->mWeak);
+    ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
+    if (c != 1) return;
+
+    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
+        // This is the regular lifetime case. The object is destroyed
+        // when the last strong reference goes away. Since weakref_impl
+        // outlive the object, it is not destroyed in the dtor, and
+        // we'll have to do it here.
+        if (impl->mStrong == INITIAL_STRONG_VALUE) {
+            // Special case: we never had a strong reference, so we need to
+            // destroy the object now.
+            delete impl->mBase;
+        } else {
+            // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
+            delete impl;
+        }
+    } else {
+        // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
+        impl->mBase->onLastWeakRef(id);
+        if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
+            // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
+            // is gone, we can destroy the object.
+            delete impl->mBase;
+        }
+    }
+}
+
+bool RefBase::weakref_type::attemptIncStrong(const void* id)
+{
+    incWeak(id);
+    
+    weakref_impl* const impl = static_cast<weakref_impl*>(this);
+    int32_t curCount = impl->mStrong;
+
+    ALOG_ASSERT(curCount >= 0,
+            "attemptIncStrong called on %p after underflow", this);
+
+    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
+        // we're in the easy/common case of promoting a weak-reference
+        // from an existing strong reference.
+        if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
+            break;
+        }
+        // the strong count has changed on us, we need to re-assert our
+        // situation.
+        curCount = impl->mStrong;
+    }
+    
+    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
+        // we're now in the harder case of either:
+        // - there never was a strong reference on us
+        // - or, all strong references have been released
+        if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
+            // this object has a "normal" life-time, i.e.: it gets destroyed
+            // when the last strong reference goes away
+            if (curCount <= 0) {
+                // the last strong-reference got released, the object cannot
+                // be revived.
+                decWeak(id);
+                return false;
+            }
+
+            // here, curCount == INITIAL_STRONG_VALUE, which means
+            // there never was a strong-reference, so we can try to
+            // promote this object; we need to do that atomically.
+            while (curCount > 0) {
+                if (android_atomic_cmpxchg(curCount, curCount + 1,
+                        &impl->mStrong) == 0) {
+                    break;
+                }
+                // the strong count has changed on us, we need to re-assert our
+                // situation (e.g.: another thread has inc/decStrong'ed us)
+                curCount = impl->mStrong;
+            }
+
+            if (curCount <= 0) {
+                // promote() failed, some other thread destroyed us in the
+                // meantime (i.e.: strong count reached zero).
+                decWeak(id);
+                return false;
+            }
+        } else {
+            // this object has an "extended" life-time, i.e.: it can be
+            // revived from a weak-reference only.
+            // Ask the object's implementation if it agrees to be revived
+            if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
+                // it didn't so give-up.
+                decWeak(id);
+                return false;
+            }
+            // grab a strong-reference, which is always safe due to the
+            // extended life-time.
+            curCount = android_atomic_inc(&impl->mStrong);
+        }
+
+        // If the strong reference count has already been incremented by
+        // someone else, the implementor of onIncStrongAttempted() is holding
+        // an unneeded reference.  So call onLastStrongRef() here to remove it.
+        // (No, this is not pretty.)  Note that we MUST NOT do this if we
+        // are in fact acquiring the first reference.
+        if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
+            impl->mBase->onLastStrongRef(id);
+        }
+    }
+    
+    impl->addStrongRef(id);
+
+#if PRINT_REFS
+    ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
+#endif
+
+    // now we need to fix-up the count if it was INITIAL_STRONG_VALUE
+    // this must be done safely, i.e.: handle the case where several threads
+    // were here in attemptIncStrong().
+    curCount = impl->mStrong;
+    while (curCount >= INITIAL_STRONG_VALUE) {
+        ALOG_ASSERT(curCount > INITIAL_STRONG_VALUE,
+                "attemptIncStrong in %p underflowed to INITIAL_STRONG_VALUE",
+                this);
+        if (android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE,
+                &impl->mStrong) == 0) {
+            break;
+        }
+        // the strong-count changed on us, we need to re-assert the situation,
+        // for e.g.: it's possible the fix-up happened in another thread.
+        curCount = impl->mStrong;
+    }
+
+    return true;
+}
+
+bool RefBase::weakref_type::attemptIncWeak(const void* id)
+{
+    weakref_impl* const impl = static_cast<weakref_impl*>(this);
+
+    int32_t curCount = impl->mWeak;
+    ALOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
+               this);
+    while (curCount > 0) {
+        if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
+            break;
+        }
+        curCount = impl->mWeak;
+    }
+
+    if (curCount > 0) {
+        impl->addWeakRef(id);
+    }
+
+    return curCount > 0;
+}
+
+int32_t RefBase::weakref_type::getWeakCount() const
+{
+    return static_cast<const weakref_impl*>(this)->mWeak;
+}
+
+void RefBase::weakref_type::printRefs() const
+{
+    static_cast<const weakref_impl*>(this)->printRefs();
+}
+
+void RefBase::weakref_type::trackMe(bool enable, bool retain)
+{
+    static_cast<weakref_impl*>(this)->trackMe(enable, retain);
+}
+
+RefBase::weakref_type* RefBase::createWeak(const void* id) const
+{
+    mRefs->incWeak(id);
+    return mRefs;
+}
+
+RefBase::weakref_type* RefBase::getWeakRefs() const
+{
+    return mRefs;
+}
+
+RefBase::RefBase()
+    : mRefs(new weakref_impl(this))
+{
+}
+
+RefBase::~RefBase()
+{
+    if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
+        // we never acquired a strong (and/or weak) reference on this object.
+        delete mRefs;
+    } else {
+        // life-time of this object is extended to WEAK or FOREVER, in
+        // which case weakref_impl doesn't out-live the object and we
+        // can free it now.
+        if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
+            // It's possible that the weak count is not 0 if the object
+            // re-acquired a weak reference in its destructor
+            if (mRefs->mWeak == 0) {
+                delete mRefs;
+            }
+        }
+    }
+    // for debugging purposes, clear this.
+    const_cast<weakref_impl*&>(mRefs) = NULL;
+}
+
+void RefBase::extendObjectLifetime(int32_t mode)
+{
+    android_atomic_or(mode, &mRefs->mFlags);
+}
+
+void RefBase::onFirstRef()
+{
+}
+
+void RefBase::onLastStrongRef(const void* /*id*/)
+{
+}
+
+bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
+{
+    return (flags&FIRST_INC_STRONG) ? true : false;
+}
+
+void RefBase::onLastWeakRef(const void* /*id*/)
+{
+}
+
+// ---------------------------------------------------------------------------
+
+void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
+#if DEBUG_REFS
+    for (size_t i=0 ; i<n ; i++) {
+        renamer(i);
+    }
+#endif
+}
+
+void RefBase::renameRefId(weakref_type* ref,
+        const void* old_id, const void* new_id) {
+    weakref_impl* const impl = static_cast<weakref_impl*>(ref);
+    impl->renameStrongRefId(old_id, new_id);
+    impl->renameWeakRefId(old_id, new_id);
+}
+
+void RefBase::renameRefId(RefBase* ref,
+        const void* old_id, const void* new_id) {
+    ref->mRefs->renameStrongRefId(old_id, new_id);
+    ref->mRefs->renameWeakRefId(old_id, new_id);
+}
+
+}; // namespace android
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
new file mode 100644
index 0000000..3555fb7
--- /dev/null
+++ b/libutils/SharedBuffer.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <utils/SharedBuffer.h>
+#include <utils/Atomic.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+SharedBuffer* SharedBuffer::alloc(size_t size)
+{
+    SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size));
+    if (sb) {
+        sb->mRefs = 1;
+        sb->mSize = size;
+    }
+    return sb;
+}
+
+
+ssize_t SharedBuffer::dealloc(const SharedBuffer* released)
+{
+    if (released->mRefs != 0) return -1; // XXX: invalid operation
+    free(const_cast<SharedBuffer*>(released));
+    return 0;
+}
+
+SharedBuffer* SharedBuffer::edit() const
+{
+    if (onlyOwner()) {
+        return const_cast<SharedBuffer*>(this);
+    }
+    SharedBuffer* sb = alloc(mSize);
+    if (sb) {
+        memcpy(sb->data(), data(), size());
+        release();
+    }
+    return sb;    
+}
+
+SharedBuffer* SharedBuffer::editResize(size_t newSize) const
+{
+    if (onlyOwner()) {
+        SharedBuffer* buf = const_cast<SharedBuffer*>(this);
+        if (buf->mSize == newSize) return buf;
+        buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize);
+        if (buf != NULL) {
+            buf->mSize = newSize;
+            return buf;
+        }
+    }
+    SharedBuffer* sb = alloc(newSize);
+    if (sb) {
+        const size_t mySize = mSize;
+        memcpy(sb->data(), data(), newSize < mySize ? newSize : mySize);
+        release();
+    }
+    return sb;    
+}
+
+SharedBuffer* SharedBuffer::attemptEdit() const
+{
+    if (onlyOwner()) {
+        return const_cast<SharedBuffer*>(this);
+    }
+    return 0;
+}
+
+SharedBuffer* SharedBuffer::reset(size_t new_size) const
+{
+    // cheap-o-reset.
+    SharedBuffer* sb = alloc(new_size);
+    if (sb) {
+        release();
+    }
+    return sb;
+}
+
+void SharedBuffer::acquire() const {
+    android_atomic_inc(&mRefs);
+}
+
+int32_t SharedBuffer::release(uint32_t flags) const
+{
+    int32_t prev = 1;
+    if (onlyOwner() || ((prev = android_atomic_dec(&mRefs)) == 1)) {
+        mRefs = 0;
+        if ((flags & eKeepStorage) == 0) {
+            free(const_cast<SharedBuffer*>(this));
+        }
+    }
+    return prev;
+}
+
+
+}; // namespace android
diff --git a/libutils/Static.cpp b/libutils/Static.cpp
new file mode 100644
index 0000000..3ed07a1
--- /dev/null
+++ b/libutils/Static.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+// All static variables go here, to control initialization and
+// destruction order in the library.
+
+namespace android {
+
+// For String8.cpp
+extern void initialize_string8();
+extern void terminate_string8();
+
+// For String16.cpp
+extern void initialize_string16();
+extern void terminate_string16();
+
+class LibUtilsFirstStatics
+{
+public:
+    LibUtilsFirstStatics()
+    {
+        initialize_string8();
+        initialize_string16();
+    }
+    
+    ~LibUtilsFirstStatics()
+    {
+        terminate_string16();
+        terminate_string8();
+    }
+};
+
+static LibUtilsFirstStatics gFirstStatics;
+int gDarwinCantLoadAllObjects = 1;
+
+}   // namespace android
diff --git a/libutils/StopWatch.cpp b/libutils/StopWatch.cpp
new file mode 100644
index 0000000..b1708d6
--- /dev/null
+++ b/libutils/StopWatch.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "StopWatch"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* for PRId64 */
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/StopWatch.h>
+
+/*****************************************************************************/
+
+namespace android {
+
+
+StopWatch::StopWatch(const char *name, int clock, uint32_t flags)
+    :   mName(name), mClock(clock), mFlags(flags)
+{
+    reset();
+}
+
+StopWatch::~StopWatch()
+{
+    nsecs_t elapsed = elapsedTime();
+    const int n = mNumLaps;
+    ALOGD("StopWatch %s (us): %" PRId64 " ", mName, ns2us(elapsed));
+    for (int i=0 ; i<n ; i++) {
+        const nsecs_t soFar = mLaps[i].soFar;
+        const nsecs_t thisLap = mLaps[i].thisLap;
+        ALOGD(" [%d: %" PRId64 ", %" PRId64, i, ns2us(soFar), ns2us(thisLap));
+    }
+}
+
+const char* StopWatch::name() const
+{
+    return mName;
+}
+
+nsecs_t StopWatch::lap()
+{
+    nsecs_t elapsed = elapsedTime();
+    if (mNumLaps >= 8) {
+        elapsed = 0;
+    } else {
+        const int n = mNumLaps;
+        mLaps[n].soFar   = elapsed;
+        mLaps[n].thisLap = n ? (elapsed - mLaps[n-1].soFar) : elapsed;
+        mNumLaps = n+1;
+    }
+    return elapsed;
+}
+
+nsecs_t StopWatch::elapsedTime() const
+{
+    return systemTime(mClock) - mStartTime;
+}
+
+void StopWatch::reset()
+{
+    mNumLaps = 0;
+    mStartTime = systemTime(mClock);
+}
+
+
+/*****************************************************************************/
+
+}; // namespace android
+
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
new file mode 100644
index 0000000..b09b728
--- /dev/null
+++ b/libutils/String16.cpp
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/String16.h>
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/Unicode.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
+
+#include <memory.h>
+#include <stdio.h>
+#include <ctype.h>
+
+
+namespace android {
+
+static SharedBuffer* gEmptyStringBuf = NULL;
+static char16_t* gEmptyString = NULL;
+
+static inline char16_t* getEmptyString()
+{
+    gEmptyStringBuf->acquire();
+   return gEmptyString;
+}
+
+void initialize_string16()
+{
+    SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t));
+    char16_t* str = (char16_t*)buf->data();
+    *str = 0;
+    gEmptyStringBuf = buf;
+    gEmptyString = str;
+}
+
+void terminate_string16()
+{
+    SharedBuffer::bufferFromData(gEmptyString)->release();
+    gEmptyStringBuf = NULL;
+    gEmptyString = NULL;
+}
+
+// ---------------------------------------------------------------------------
+
+static char16_t* allocFromUTF8(const char* u8str, size_t u8len)
+{
+    if (u8len == 0) return getEmptyString();
+
+    const uint8_t* u8cur = (const uint8_t*) u8str;
+
+    const ssize_t u16len = utf8_to_utf16_length(u8cur, u8len);
+    if (u16len < 0) {
+        return getEmptyString();
+    }
+
+    const uint8_t* const u8end = u8cur + u8len;
+
+    SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)*(u16len+1));
+    if (buf) {
+        u8cur = (const uint8_t*) u8str;
+        char16_t* u16str = (char16_t*)buf->data();
+
+        utf8_to_utf16(u8cur, u8len, u16str);
+
+        //printf("Created UTF-16 string from UTF-8 \"%s\":", in);
+        //printHexData(1, str, buf->size(), 16, 1);
+        //printf("\n");
+        
+        return u16str;
+    }
+
+    return getEmptyString();
+}
+
+// ---------------------------------------------------------------------------
+
+String16::String16()
+    : mString(getEmptyString())
+{
+}
+
+String16::String16(StaticLinkage)
+    : mString(0)
+{
+    // this constructor is used when we can't rely on the static-initializers
+    // having run. In this case we always allocate an empty string. It's less
+    // efficient than using getEmptyString(), but we assume it's uncommon.
+
+    char16_t* data = static_cast<char16_t*>(
+            SharedBuffer::alloc(sizeof(char16_t))->data());
+    data[0] = 0;
+    mString = data;
+}
+
+String16::String16(const String16& o)
+    : mString(o.mString)
+{
+    SharedBuffer::bufferFromData(mString)->acquire();
+}
+
+String16::String16(const String16& o, size_t len, size_t begin)
+    : mString(getEmptyString())
+{
+    setTo(o, len, begin);
+}
+
+String16::String16(const char16_t* o)
+{
+    size_t len = strlen16(o);
+    SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
+    ALOG_ASSERT(buf, "Unable to allocate shared buffer");
+    if (buf) {
+        char16_t* str = (char16_t*)buf->data();
+        strcpy16(str, o);
+        mString = str;
+        return;
+    }
+    
+    mString = getEmptyString();
+}
+
+String16::String16(const char16_t* o, size_t len)
+{
+    SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
+    ALOG_ASSERT(buf, "Unable to allocate shared buffer");
+    if (buf) {
+        char16_t* str = (char16_t*)buf->data();
+        memcpy(str, o, len*sizeof(char16_t));
+        str[len] = 0;
+        mString = str;
+        return;
+    }
+    
+    mString = getEmptyString();
+}
+
+String16::String16(const String8& o)
+    : mString(allocFromUTF8(o.string(), o.size()))
+{
+}
+
+String16::String16(const char* o)
+    : mString(allocFromUTF8(o, strlen(o)))
+{
+}
+
+String16::String16(const char* o, size_t len)
+    : mString(allocFromUTF8(o, len))
+{
+}
+
+String16::~String16()
+{
+    SharedBuffer::bufferFromData(mString)->release();
+}
+
+void String16::setTo(const String16& other)
+{
+    SharedBuffer::bufferFromData(other.mString)->acquire();
+    SharedBuffer::bufferFromData(mString)->release();
+    mString = other.mString;
+}
+
+status_t String16::setTo(const String16& other, size_t len, size_t begin)
+{
+    const size_t N = other.size();
+    if (begin >= N) {
+        SharedBuffer::bufferFromData(mString)->release();
+        mString = getEmptyString();
+        return NO_ERROR;
+    }
+    if ((begin+len) > N) len = N-begin;
+    if (begin == 0 && len == N) {
+        setTo(other);
+        return NO_ERROR;
+    }
+
+    if (&other == this) {
+        LOG_ALWAYS_FATAL("Not implemented");
+    }
+
+    return setTo(other.string()+begin, len);
+}
+
+status_t String16::setTo(const char16_t* other)
+{
+    return setTo(other, strlen16(other));
+}
+
+status_t String16::setTo(const char16_t* other, size_t len)
+{
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((len+1)*sizeof(char16_t));
+    if (buf) {
+        char16_t* str = (char16_t*)buf->data();
+        memmove(str, other, len*sizeof(char16_t));
+        str[len] = 0;
+        mString = str;
+        return NO_ERROR;
+    }
+    return NO_MEMORY;
+}
+
+status_t String16::append(const String16& other)
+{
+    const size_t myLen = size();
+    const size_t otherLen = other.size();
+    if (myLen == 0) {
+        setTo(other);
+        return NO_ERROR;
+    } else if (otherLen == 0) {
+        return NO_ERROR;
+    }
+    
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((myLen+otherLen+1)*sizeof(char16_t));
+    if (buf) {
+        char16_t* str = (char16_t*)buf->data();
+        memcpy(str+myLen, other, (otherLen+1)*sizeof(char16_t));
+        mString = str;
+        return NO_ERROR;
+    }
+    return NO_MEMORY;
+}
+
+status_t String16::append(const char16_t* chrs, size_t otherLen)
+{
+    const size_t myLen = size();
+    if (myLen == 0) {
+        setTo(chrs, otherLen);
+        return NO_ERROR;
+    } else if (otherLen == 0) {
+        return NO_ERROR;
+    }
+    
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((myLen+otherLen+1)*sizeof(char16_t));
+    if (buf) {
+        char16_t* str = (char16_t*)buf->data();
+        memcpy(str+myLen, chrs, otherLen*sizeof(char16_t));
+        str[myLen+otherLen] = 0;
+        mString = str;
+        return NO_ERROR;
+    }
+    return NO_MEMORY;
+}
+
+status_t String16::insert(size_t pos, const char16_t* chrs)
+{
+    return insert(pos, chrs, strlen16(chrs));
+}
+
+status_t String16::insert(size_t pos, const char16_t* chrs, size_t len)
+{
+    const size_t myLen = size();
+    if (myLen == 0) {
+        return setTo(chrs, len);
+        return NO_ERROR;
+    } else if (len == 0) {
+        return NO_ERROR;
+    }
+
+    if (pos > myLen) pos = myLen;
+
+    #if 0
+    printf("Insert in to %s: pos=%d, len=%d, myLen=%d, chrs=%s\n",
+           String8(*this).string(), pos,
+           len, myLen, String8(chrs, len).string());
+    #endif
+
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((myLen+len+1)*sizeof(char16_t));
+    if (buf) {
+        char16_t* str = (char16_t*)buf->data();
+        if (pos < myLen) {
+            memmove(str+pos+len, str+pos, (myLen-pos)*sizeof(char16_t));
+        }
+        memcpy(str+pos, chrs, len*sizeof(char16_t));
+        str[myLen+len] = 0;
+        mString = str;
+        #if 0
+        printf("Result (%d chrs): %s\n", size(), String8(*this).string());
+        #endif
+        return NO_ERROR;
+    }
+    return NO_MEMORY;
+}
+
+ssize_t String16::findFirst(char16_t c) const
+{
+    const char16_t* str = string();
+    const char16_t* p = str;
+    const char16_t* e = p + size();
+    while (p < e) {
+        if (*p == c) {
+            return p-str;
+        }
+        p++;
+    }
+    return -1;
+}
+
+ssize_t String16::findLast(char16_t c) const
+{
+    const char16_t* str = string();
+    const char16_t* p = str;
+    const char16_t* e = p + size();
+    while (p < e) {
+        e--;
+        if (*e == c) {
+            return e-str;
+        }
+    }
+    return -1;
+}
+
+bool String16::startsWith(const String16& prefix) const
+{
+    const size_t ps = prefix.size();
+    if (ps > size()) return false;
+    return strzcmp16(mString, ps, prefix.string(), ps) == 0;
+}
+
+bool String16::startsWith(const char16_t* prefix) const
+{
+    const size_t ps = strlen16(prefix);
+    if (ps > size()) return false;
+    return strncmp16(mString, prefix, ps) == 0;
+}
+
+status_t String16::makeLower()
+{
+    const size_t N = size();
+    const char16_t* str = string();
+    char16_t* edit = NULL;
+    for (size_t i=0; i<N; i++) {
+        const char16_t v = str[i];
+        if (v >= 'A' && v <= 'Z') {
+            if (!edit) {
+                SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
+                if (!buf) {
+                    return NO_MEMORY;
+                }
+                edit = (char16_t*)buf->data();
+                mString = str = edit;
+            }
+            edit[i] = tolower((char)v);
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t String16::replaceAll(char16_t replaceThis, char16_t withThis)
+{
+    const size_t N = size();
+    const char16_t* str = string();
+    char16_t* edit = NULL;
+    for (size_t i=0; i<N; i++) {
+        if (str[i] == replaceThis) {
+            if (!edit) {
+                SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit();
+                if (!buf) {
+                    return NO_MEMORY;
+                }
+                edit = (char16_t*)buf->data();
+                mString = str = edit;
+            }
+            edit[i] = withThis;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t String16::remove(size_t len, size_t begin)
+{
+    const size_t N = size();
+    if (begin >= N) {
+        SharedBuffer::bufferFromData(mString)->release();
+        mString = getEmptyString();
+        return NO_ERROR;
+    }
+    if ((begin+len) > N) len = N-begin;
+    if (begin == 0 && len == N) {
+        return NO_ERROR;
+    }
+
+    if (begin > 0) {
+        SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+            ->editResize((N+1)*sizeof(char16_t));
+        if (!buf) {
+            return NO_MEMORY;
+        }
+        char16_t* str = (char16_t*)buf->data();
+        memmove(str, str+begin, (N-begin+1)*sizeof(char16_t));
+        mString = str;
+    }
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize((len+1)*sizeof(char16_t));
+    if (buf) {
+        char16_t* str = (char16_t*)buf->data();
+        str[len] = 0;
+        mString = str;
+        return NO_ERROR;
+    }
+    return NO_MEMORY;
+}
+
+}; // namespace android
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
new file mode 100644
index 0000000..e852d77
--- /dev/null
+++ b/libutils/String8.cpp
@@ -0,0 +1,640 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/String8.h>
+
+#include <utils/Log.h>
+#include <utils/Unicode.h>
+#include <utils/SharedBuffer.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+
+#include <ctype.h>
+
+/*
+ * Functions outside android is below the namespace android, since they use
+ * functions and constants in android namespace.
+ */
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+// Separator used by resource paths. This is not platform dependent contrary
+// to OS_PATH_SEPARATOR.
+#define RES_PATH_SEPARATOR '/'
+
+static SharedBuffer* gEmptyStringBuf = NULL;
+static char* gEmptyString = NULL;
+
+extern int gDarwinCantLoadAllObjects;
+int gDarwinIsReallyAnnoying;
+
+void initialize_string8();
+
+static inline char* getEmptyString()
+{
+    gEmptyStringBuf->acquire();
+    return gEmptyString;
+}
+
+void initialize_string8()
+{
+    // HACK: This dummy dependency forces linking libutils Static.cpp,
+    // which is needed to initialize String8/String16 classes.
+    // These variables are named for Darwin, but are needed elsewhere too,
+    // including static linking on any platform.
+    gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
+
+    SharedBuffer* buf = SharedBuffer::alloc(1);
+    char* str = (char*)buf->data();
+    *str = 0;
+    gEmptyStringBuf = buf;
+    gEmptyString = str;
+}
+
+void terminate_string8()
+{
+    SharedBuffer::bufferFromData(gEmptyString)->release();
+    gEmptyStringBuf = NULL;
+    gEmptyString = NULL;
+}
+
+// ---------------------------------------------------------------------------
+
+static char* allocFromUTF8(const char* in, size_t len)
+{
+    if (len > 0) {
+        SharedBuffer* buf = SharedBuffer::alloc(len+1);
+        ALOG_ASSERT(buf, "Unable to allocate shared buffer");
+        if (buf) {
+            char* str = (char*)buf->data();
+            memcpy(str, in, len);
+            str[len] = 0;
+            return str;
+        }
+        return NULL;
+    }
+
+    return getEmptyString();
+}
+
+static char* allocFromUTF16(const char16_t* in, size_t len)
+{
+    if (len == 0) return getEmptyString();
+
+    const ssize_t bytes = utf16_to_utf8_length(in, len);
+    if (bytes < 0) {
+        return getEmptyString();
+    }
+
+    SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
+    ALOG_ASSERT(buf, "Unable to allocate shared buffer");
+    if (!buf) {
+        return getEmptyString();
+    }
+
+    char* str = (char*)buf->data();
+    utf16_to_utf8(in, len, str);
+    return str;
+}
+
+static char* allocFromUTF32(const char32_t* in, size_t len)
+{
+    if (len == 0) {
+        return getEmptyString();
+    }
+
+    const ssize_t bytes = utf32_to_utf8_length(in, len);
+    if (bytes < 0) {
+        return getEmptyString();
+    }
+
+    SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
+    ALOG_ASSERT(buf, "Unable to allocate shared buffer");
+    if (!buf) {
+        return getEmptyString();
+    }
+
+    char* str = (char*) buf->data();
+    utf32_to_utf8(in, len, str);
+
+    return str;
+}
+
+// ---------------------------------------------------------------------------
+
+String8::String8()
+    : mString(getEmptyString())
+{
+}
+
+String8::String8(StaticLinkage)
+    : mString(0)
+{
+    // this constructor is used when we can't rely on the static-initializers
+    // having run. In this case we always allocate an empty string. It's less
+    // efficient than using getEmptyString(), but we assume it's uncommon.
+
+    char* data = static_cast<char*>(
+            SharedBuffer::alloc(sizeof(char))->data());
+    data[0] = 0;
+    mString = data;
+}
+
+String8::String8(const String8& o)
+    : mString(o.mString)
+{
+    SharedBuffer::bufferFromData(mString)->acquire();
+}
+
+String8::String8(const char* o)
+    : mString(allocFromUTF8(o, strlen(o)))
+{
+    if (mString == NULL) {
+        mString = getEmptyString();
+    }
+}
+
+String8::String8(const char* o, size_t len)
+    : mString(allocFromUTF8(o, len))
+{
+    if (mString == NULL) {
+        mString = getEmptyString();
+    }
+}
+
+String8::String8(const String16& o)
+    : mString(allocFromUTF16(o.string(), o.size()))
+{
+}
+
+String8::String8(const char16_t* o)
+    : mString(allocFromUTF16(o, strlen16(o)))
+{
+}
+
+String8::String8(const char16_t* o, size_t len)
+    : mString(allocFromUTF16(o, len))
+{
+}
+
+String8::String8(const char32_t* o)
+    : mString(allocFromUTF32(o, strlen32(o)))
+{
+}
+
+String8::String8(const char32_t* o, size_t len)
+    : mString(allocFromUTF32(o, len))
+{
+}
+
+String8::~String8()
+{
+    SharedBuffer::bufferFromData(mString)->release();
+}
+
+String8 String8::format(const char* fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+
+    String8 result(formatV(fmt, args));
+
+    va_end(args);
+    return result;
+}
+
+String8 String8::formatV(const char* fmt, va_list args)
+{
+    String8 result;
+    result.appendFormatV(fmt, args);
+    return result;
+}
+
+void String8::clear() {
+    SharedBuffer::bufferFromData(mString)->release();
+    mString = getEmptyString();
+}
+
+void String8::setTo(const String8& other)
+{
+    SharedBuffer::bufferFromData(other.mString)->acquire();
+    SharedBuffer::bufferFromData(mString)->release();
+    mString = other.mString;
+}
+
+status_t String8::setTo(const char* other)
+{
+    const char *newString = allocFromUTF8(other, strlen(other));
+    SharedBuffer::bufferFromData(mString)->release();
+    mString = newString;
+    if (mString) return NO_ERROR;
+
+    mString = getEmptyString();
+    return NO_MEMORY;
+}
+
+status_t String8::setTo(const char* other, size_t len)
+{
+    const char *newString = allocFromUTF8(other, len);
+    SharedBuffer::bufferFromData(mString)->release();
+    mString = newString;
+    if (mString) return NO_ERROR;
+
+    mString = getEmptyString();
+    return NO_MEMORY;
+}
+
+status_t String8::setTo(const char16_t* other, size_t len)
+{
+    const char *newString = allocFromUTF16(other, len);
+    SharedBuffer::bufferFromData(mString)->release();
+    mString = newString;
+    if (mString) return NO_ERROR;
+
+    mString = getEmptyString();
+    return NO_MEMORY;
+}
+
+status_t String8::setTo(const char32_t* other, size_t len)
+{
+    const char *newString = allocFromUTF32(other, len);
+    SharedBuffer::bufferFromData(mString)->release();
+    mString = newString;
+    if (mString) return NO_ERROR;
+
+    mString = getEmptyString();
+    return NO_MEMORY;
+}
+
+status_t String8::append(const String8& other)
+{
+    const size_t otherLen = other.bytes();
+    if (bytes() == 0) {
+        setTo(other);
+        return NO_ERROR;
+    } else if (otherLen == 0) {
+        return NO_ERROR;
+    }
+
+    return real_append(other.string(), otherLen);
+}
+
+status_t String8::append(const char* other)
+{
+    return append(other, strlen(other));
+}
+
+status_t String8::append(const char* other, size_t otherLen)
+{
+    if (bytes() == 0) {
+        return setTo(other, otherLen);
+    } else if (otherLen == 0) {
+        return NO_ERROR;
+    }
+
+    return real_append(other, otherLen);
+}
+
+status_t String8::appendFormat(const char* fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+
+    status_t result = appendFormatV(fmt, args);
+
+    va_end(args);
+    return result;
+}
+
+status_t String8::appendFormatV(const char* fmt, va_list args)
+{
+    int result = NO_ERROR;
+    int n = vsnprintf(NULL, 0, fmt, args);
+    if (n != 0) {
+        size_t oldLength = length();
+        char* buf = lockBuffer(oldLength + n);
+        if (buf) {
+            vsnprintf(buf + oldLength, n + 1, fmt, args);
+        } else {
+            result = NO_MEMORY;
+        }
+    }
+    return result;
+}
+
+status_t String8::real_append(const char* other, size_t otherLen)
+{
+    const size_t myLen = bytes();
+    
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize(myLen+otherLen+1);
+    if (buf) {
+        char* str = (char*)buf->data();
+        mString = str;
+        str += myLen;
+        memcpy(str, other, otherLen);
+        str[otherLen] = '\0';
+        return NO_ERROR;
+    }
+    return NO_MEMORY;
+}
+
+char* String8::lockBuffer(size_t size)
+{
+    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+        ->editResize(size+1);
+    if (buf) {
+        char* str = (char*)buf->data();
+        mString = str;
+        return str;
+    }
+    return NULL;
+}
+
+void String8::unlockBuffer()
+{
+    unlockBuffer(strlen(mString));
+}
+
+status_t String8::unlockBuffer(size_t size)
+{
+    if (size != this->size()) {
+        SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+            ->editResize(size+1);
+        if (! buf) {
+            return NO_MEMORY;
+        }
+
+        char* str = (char*)buf->data();
+        str[size] = 0;
+        mString = str;
+    }
+
+    return NO_ERROR;
+}
+
+ssize_t String8::find(const char* other, size_t start) const
+{
+    size_t len = size();
+    if (start >= len) {
+        return -1;
+    }
+    const char* s = mString+start;
+    const char* p = strstr(s, other);
+    return p ? p-mString : -1;
+}
+
+void String8::toLower()
+{
+    toLower(0, size());
+}
+
+void String8::toLower(size_t start, size_t length)
+{
+    const size_t len = size();
+    if (start >= len) {
+        return;
+    }
+    if (start+length > len) {
+        length = len-start;
+    }
+    char* buf = lockBuffer(len);
+    buf += start;
+    while (length > 0) {
+        *buf = tolower(*buf);
+        buf++;
+        length--;
+    }
+    unlockBuffer(len);
+}
+
+void String8::toUpper()
+{
+    toUpper(0, size());
+}
+
+void String8::toUpper(size_t start, size_t length)
+{
+    const size_t len = size();
+    if (start >= len) {
+        return;
+    }
+    if (start+length > len) {
+        length = len-start;
+    }
+    char* buf = lockBuffer(len);
+    buf += start;
+    while (length > 0) {
+        *buf = toupper(*buf);
+        buf++;
+        length--;
+    }
+    unlockBuffer(len);
+}
+
+size_t String8::getUtf32Length() const
+{
+    return utf8_to_utf32_length(mString, length());
+}
+
+int32_t String8::getUtf32At(size_t index, size_t *next_index) const
+{
+    return utf32_from_utf8_at(mString, length(), index, next_index);
+}
+
+void String8::getUtf32(char32_t* dst) const
+{
+    utf8_to_utf32(mString, length(), dst);
+}
+
+// ---------------------------------------------------------------------------
+// Path functions
+
+void String8::setPathName(const char* name)
+{
+    setPathName(name, strlen(name));
+}
+
+void String8::setPathName(const char* name, size_t len)
+{
+    char* buf = lockBuffer(len);
+
+    memcpy(buf, name, len);
+
+    // remove trailing path separator, if present
+    if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
+        len--;
+
+    buf[len] = '\0';
+
+    unlockBuffer(len);
+}
+
+String8 String8::getPathLeaf(void) const
+{
+    const char* cp;
+    const char*const buf = mString;
+
+    cp = strrchr(buf, OS_PATH_SEPARATOR);
+    if (cp == NULL)
+        return String8(*this);
+    else
+        return String8(cp+1);
+}
+
+String8 String8::getPathDir(void) const
+{
+    const char* cp;
+    const char*const str = mString;
+
+    cp = strrchr(str, OS_PATH_SEPARATOR);
+    if (cp == NULL)
+        return String8("");
+    else
+        return String8(str, cp - str);
+}
+
+String8 String8::walkPath(String8* outRemains) const
+{
+    const char* cp;
+    const char*const str = mString;
+    const char* buf = str;
+
+    cp = strchr(buf, OS_PATH_SEPARATOR);
+    if (cp == buf) {
+        // don't include a leading '/'.
+        buf = buf+1;
+        cp = strchr(buf, OS_PATH_SEPARATOR);
+    }
+
+    if (cp == NULL) {
+        String8 res = buf != str ? String8(buf) : *this;
+        if (outRemains) *outRemains = String8("");
+        return res;
+    }
+
+    String8 res(buf, cp-buf);
+    if (outRemains) *outRemains = String8(cp+1);
+    return res;
+}
+
+/*
+ * Helper function for finding the start of an extension in a pathname.
+ *
+ * Returns a pointer inside mString, or NULL if no extension was found.
+ */
+char* String8::find_extension(void) const
+{
+    const char* lastSlash;
+    const char* lastDot;
+    int extLen;
+    const char* const str = mString;
+
+    // only look at the filename
+    lastSlash = strrchr(str, OS_PATH_SEPARATOR);
+    if (lastSlash == NULL)
+        lastSlash = str;
+    else
+        lastSlash++;
+
+    // find the last dot
+    lastDot = strrchr(lastSlash, '.');
+    if (lastDot == NULL)
+        return NULL;
+
+    // looks good, ship it
+    return const_cast<char*>(lastDot);
+}
+
+String8 String8::getPathExtension(void) const
+{
+    char* ext;
+
+    ext = find_extension();
+    if (ext != NULL)
+        return String8(ext);
+    else
+        return String8("");
+}
+
+String8 String8::getBasePath(void) const
+{
+    char* ext;
+    const char* const str = mString;
+
+    ext = find_extension();
+    if (ext == NULL)
+        return String8(*this);
+    else
+        return String8(str, ext - str);
+}
+
+String8& String8::appendPath(const char* name)
+{
+    // TODO: The test below will fail for Win32 paths. Fix later or ignore.
+    if (name[0] != OS_PATH_SEPARATOR) {
+        if (*name == '\0') {
+            // nothing to do
+            return *this;
+        }
+
+        size_t len = length();
+        if (len == 0) {
+            // no existing filename, just use the new one
+            setPathName(name);
+            return *this;
+        }
+
+        // make room for oldPath + '/' + newPath
+        int newlen = strlen(name);
+
+        char* buf = lockBuffer(len+1+newlen);
+
+        // insert a '/' if needed
+        if (buf[len-1] != OS_PATH_SEPARATOR)
+            buf[len++] = OS_PATH_SEPARATOR;
+
+        memcpy(buf+len, name, newlen+1);
+        len += newlen;
+
+        unlockBuffer(len);
+
+        return *this;
+    } else {
+        setPathName(name);
+        return *this;
+    }
+}
+
+String8& String8::convertToResPath()
+{
+#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
+    size_t len = length();
+    if (len > 0) {
+        char * buf = lockBuffer(len);
+        for (char * end = buf + len; buf < end; ++buf) {
+            if (*buf == OS_PATH_SEPARATOR)
+                *buf = RES_PATH_SEPARATOR;
+        }
+        unlockBuffer(len);
+    }
+#endif
+    return *this;
+}
+
+}; // namespace android
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
new file mode 100644
index 0000000..ac8da88
--- /dev/null
+++ b/libutils/SystemClock.cpp
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+
+/*
+ * System clock functions.
+ */
+
+#ifdef HAVE_ANDROID_OS
+#include <linux/ioctl.h>
+#include <linux/rtc.h>
+#include <utils/Atomic.h>
+#include <linux/android_alarm.h>
+#endif
+
+#include <sys/time.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include <utils/SystemClock.h>
+#include <utils/Timers.h>
+
+#define LOG_TAG "SystemClock"
+#include <utils/Log.h>
+
+namespace android {
+
+/*
+ * native public static long uptimeMillis();
+ */
+int64_t uptimeMillis()
+{
+    int64_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+    return (int64_t) nanoseconds_to_milliseconds(when);
+}
+
+/*
+ * native public static long elapsedRealtime();
+ */
+int64_t elapsedRealtime()
+{
+	return nanoseconds_to_milliseconds(elapsedRealtimeNano());
+}
+
+#define METHOD_CLOCK_GETTIME    0
+#define METHOD_IOCTL            1
+#define METHOD_SYSTEMTIME       2
+
+/*
+ * To debug/verify the timestamps returned by the kernel, change
+ * DEBUG_TIMESTAMP to 1 and call the timestamp routine from a single thread
+ * in the test program. b/10899829
+ */
+#define DEBUG_TIMESTAMP         0
+
+static const char *gettime_method_names[] = {
+    "clock_gettime",
+    "ioctl",
+    "systemTime",
+};
+
+#if DEBUG_TIMESTAMP
+static inline void checkTimeStamps(int64_t timestamp,
+                                   int64_t volatile *prevTimestampPtr,
+                                   int volatile *prevMethodPtr,
+                                   int curMethod)
+{
+    /*
+     * Disable the check for SDK since the prebuilt toolchain doesn't contain
+     * gettid, and int64_t is different on the ARM platform
+     * (ie long vs long long).
+     */
+#ifdef ARCH_ARM
+    int64_t prevTimestamp = *prevTimestampPtr;
+    int prevMethod = *prevMethodPtr;
+
+    if (timestamp < prevTimestamp) {
+        ALOGW("time going backwards: prev %lld(%s) vs now %lld(%s), tid=%d",
+              prevTimestamp, gettime_method_names[prevMethod],
+              timestamp, gettime_method_names[curMethod],
+              gettid());
+    }
+    // NOTE - not atomic and may generate spurious warnings if the 64-bit
+    // write is interrupted or not observed as a whole.
+    *prevTimestampPtr = timestamp;
+    *prevMethodPtr = curMethod;
+#endif
+}
+#else
+#define checkTimeStamps(timestamp, prevTimestampPtr, prevMethodPtr, curMethod)
+#endif
+
+/*
+ * native public static long elapsedRealtimeNano();
+ */
+int64_t elapsedRealtimeNano()
+{
+#ifdef HAVE_ANDROID_OS
+    struct timespec ts;
+    int result;
+    int64_t timestamp;
+#if DEBUG_TIMESTAMP
+    static volatile int64_t prevTimestamp;
+    static volatile int prevMethod;
+#endif
+
+#if 0
+    /*
+     * b/7100774
+     * clock_gettime appears to have clock skews and can sometimes return
+     * backwards values. Disable its use until we find out what's wrong.
+     */
+    result = clock_gettime(CLOCK_BOOTTIME, &ts);
+    if (result == 0) {
+        timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
+        checkTimeStamps(timestamp, &prevTimestamp, &prevMethod,
+                        METHOD_CLOCK_GETTIME);
+        return timestamp;
+    }
+#endif
+
+    // CLOCK_BOOTTIME doesn't exist, fallback to /dev/alarm
+    static int s_fd = -1;
+
+    if (s_fd == -1) {
+        int fd = open("/dev/alarm", O_RDONLY);
+        if (android_atomic_cmpxchg(-1, fd, &s_fd)) {
+            close(fd);
+        }
+    }
+
+    result = ioctl(s_fd,
+            ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts);
+
+    if (result == 0) {
+        timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
+        checkTimeStamps(timestamp, &prevTimestamp, &prevMethod, METHOD_IOCTL);
+        return timestamp;
+    }
+
+    // XXX: there was an error, probably because the driver didn't
+    // exist ... this should return
+    // a real error, like an exception!
+    timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+    checkTimeStamps(timestamp, &prevTimestamp, &prevMethod,
+                    METHOD_SYSTEMTIME);
+    return timestamp;
+#else
+    return systemTime(SYSTEM_TIME_MONOTONIC);
+#endif
+}
+
+}; // namespace android
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
new file mode 100644
index 0000000..ff74914
--- /dev/null
+++ b/libutils/Threads.cpp
@@ -0,0 +1,878 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "libutils.threads"
+
+#include <utils/threads.h>
+#include <utils/Log.h>
+
+#include <cutils/sched_policy.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+
+#if defined(HAVE_PTHREADS)
+# include <pthread.h>
+# include <sched.h>
+# include <sys/resource.h>
+#ifdef HAVE_ANDROID_OS
+# include <bionic_pthread.h>
+#endif
+#elif defined(HAVE_WIN32_THREADS)
+# include <windows.h>
+# include <stdint.h>
+# include <process.h>
+# define HAVE_CREATETHREAD  // Cygwin, vs. HAVE__BEGINTHREADEX for MinGW
+#endif
+
+#if defined(HAVE_PRCTL)
+#include <sys/prctl.h>
+#endif
+
+/*
+ * ===========================================================================
+ *      Thread wrappers
+ * ===========================================================================
+ */
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+#if defined(HAVE_PTHREADS)
+// ----------------------------------------------------------------------------
+
+/*
+ * Create and run a new thread.
+ *
+ * We create it "detached", so it cleans up after itself.
+ */
+
+typedef void* (*android_pthread_entry)(void*);
+
+struct thread_data_t {
+    thread_func_t   entryFunction;
+    void*           userData;
+    int             priority;
+    char *          threadName;
+
+    // we use this trampoline when we need to set the priority with
+    // nice/setpriority, and name with prctl.
+    static int trampoline(const thread_data_t* t) {
+        thread_func_t f = t->entryFunction;
+        void* u = t->userData;
+        int prio = t->priority;
+        char * name = t->threadName;
+        delete t;
+        setpriority(PRIO_PROCESS, 0, prio);
+        if (prio >= ANDROID_PRIORITY_BACKGROUND) {
+            set_sched_policy(0, SP_BACKGROUND);
+        } else {
+            set_sched_policy(0, SP_FOREGROUND);
+        }
+        
+        if (name) {
+            androidSetThreadName(name);
+            free(name);
+        }
+        return f(u);
+    }
+};
+
+void androidSetThreadName(const char* name) {
+#if defined(HAVE_PRCTL)
+    // Mac OS doesn't have this, and we build libutil for the host too
+    int hasAt = 0;
+    int hasDot = 0;
+    const char *s = name;
+    while (*s) {
+        if (*s == '.') hasDot = 1;
+        else if (*s == '@') hasAt = 1;
+        s++;
+    }
+    int len = s - name;
+    if (len < 15 || hasAt || !hasDot) {
+        s = name;
+    } else {
+        s = name + len - 15;
+    }
+    prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0);
+#endif
+}
+
+int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
+                               void *userData,
+                               const char* threadName,
+                               int32_t threadPriority,
+                               size_t threadStackSize,
+                               android_thread_id_t *threadId)
+{
+    pthread_attr_t attr; 
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+#ifdef HAVE_ANDROID_OS  /* valgrind is rejecting RT-priority create reqs */
+    if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {
+        // Now that the pthread_t has a method to find the associated
+        // android_thread_id_t (pid) from pthread_t, it would be possible to avoid
+        // this trampoline in some cases as the parent could set the properties
+        // for the child.  However, there would be a race condition because the
+        // child becomes ready immediately, and it doesn't work for the name.
+        // prctl(PR_SET_NAME) only works for self; prctl(PR_SET_THREAD_NAME) was
+        // proposed but not yet accepted.
+        thread_data_t* t = new thread_data_t;
+        t->priority = threadPriority;
+        t->threadName = threadName ? strdup(threadName) : NULL;
+        t->entryFunction = entryFunction;
+        t->userData = userData;
+        entryFunction = (android_thread_func_t)&thread_data_t::trampoline;
+        userData = t;            
+    }
+#endif
+
+    if (threadStackSize) {
+        pthread_attr_setstacksize(&attr, threadStackSize);
+    }
+    
+    errno = 0;
+    pthread_t thread;
+    int result = pthread_create(&thread, &attr,
+                    (android_pthread_entry)entryFunction, userData);
+    pthread_attr_destroy(&attr);
+    if (result != 0) {
+        ALOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n"
+             "(android threadPriority=%d)",
+            entryFunction, result, errno, threadPriority);
+        return 0;
+    }
+
+    // Note that *threadID is directly available to the parent only, as it is
+    // assigned after the child starts.  Use memory barrier / lock if the child
+    // or other threads also need access.
+    if (threadId != NULL) {
+        *threadId = (android_thread_id_t)thread; // XXX: this is not portable
+    }
+    return 1;
+}
+
+#ifdef HAVE_ANDROID_OS
+static pthread_t android_thread_id_t_to_pthread(android_thread_id_t thread)
+{
+    return (pthread_t) thread;
+}
+#endif
+
+android_thread_id_t androidGetThreadId()
+{
+    return (android_thread_id_t)pthread_self();
+}
+
+// ----------------------------------------------------------------------------
+#elif defined(HAVE_WIN32_THREADS)
+// ----------------------------------------------------------------------------
+
+/*
+ * Trampoline to make us __stdcall-compliant.
+ *
+ * We're expected to delete "vDetails" when we're done.
+ */
+struct threadDetails {
+    int (*func)(void*);
+    void* arg;
+};
+static __stdcall unsigned int threadIntermediary(void* vDetails)
+{
+    struct threadDetails* pDetails = (struct threadDetails*) vDetails;
+    int result;
+
+    result = (*(pDetails->func))(pDetails->arg);
+
+    delete pDetails;
+
+    ALOG(LOG_VERBOSE, "thread", "thread exiting\n");
+    return (unsigned int) result;
+}
+
+/*
+ * Create and run a new thread.
+ */
+static bool doCreateThread(android_thread_func_t fn, void* arg, android_thread_id_t *id)
+{
+    HANDLE hThread;
+    struct threadDetails* pDetails = new threadDetails; // must be on heap
+    unsigned int thrdaddr;
+
+    pDetails->func = fn;
+    pDetails->arg = arg;
+
+#if defined(HAVE__BEGINTHREADEX)
+    hThread = (HANDLE) _beginthreadex(NULL, 0, threadIntermediary, pDetails, 0,
+                    &thrdaddr);
+    if (hThread == 0)
+#elif defined(HAVE_CREATETHREAD)
+    hThread = CreateThread(NULL, 0,
+                    (LPTHREAD_START_ROUTINE) threadIntermediary,
+                    (void*) pDetails, 0, (DWORD*) &thrdaddr);
+    if (hThread == NULL)
+#endif
+    {
+        ALOG(LOG_WARN, "thread", "WARNING: thread create failed\n");
+        return false;
+    }
+
+#if defined(HAVE_CREATETHREAD)
+    /* close the management handle */
+    CloseHandle(hThread);
+#endif
+
+    if (id != NULL) {
+      	*id = (android_thread_id_t)thrdaddr;
+    }
+
+    return true;
+}
+
+int androidCreateRawThreadEtc(android_thread_func_t fn,
+                               void *userData,
+                               const char* threadName,
+                               int32_t threadPriority,
+                               size_t threadStackSize,
+                               android_thread_id_t *threadId)
+{
+    return doCreateThread(  fn, userData, threadId);
+}
+
+android_thread_id_t androidGetThreadId()
+{
+    return (android_thread_id_t)GetCurrentThreadId();
+}
+
+// ----------------------------------------------------------------------------
+#else
+#error "Threads not supported"
+#endif
+
+// ----------------------------------------------------------------------------
+
+int androidCreateThread(android_thread_func_t fn, void* arg)
+{
+    return createThreadEtc(fn, arg);
+}
+
+int androidCreateThreadGetID(android_thread_func_t fn, void *arg, android_thread_id_t *id)
+{
+    return createThreadEtc(fn, arg, "android:unnamed_thread",
+                           PRIORITY_DEFAULT, 0, id);
+}
+
+static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc;
+
+int androidCreateThreadEtc(android_thread_func_t entryFunction,
+                            void *userData,
+                            const char* threadName,
+                            int32_t threadPriority,
+                            size_t threadStackSize,
+                            android_thread_id_t *threadId)
+{
+    return gCreateThreadFn(entryFunction, userData, threadName,
+        threadPriority, threadStackSize, threadId);
+}
+
+void androidSetCreateThreadFunc(android_create_thread_fn func)
+{
+    gCreateThreadFn = func;
+}
+
+pid_t androidGetTid()
+{
+#ifdef HAVE_GETTID
+    return gettid();
+#else
+    return getpid();
+#endif
+}
+
+#ifdef HAVE_ANDROID_OS
+int androidSetThreadPriority(pid_t tid, int pri)
+{
+    int rc = 0;
+    
+#if defined(HAVE_PTHREADS)
+    int lasterr = 0;
+
+    if (pri >= ANDROID_PRIORITY_BACKGROUND) {
+        rc = set_sched_policy(tid, SP_BACKGROUND);
+    } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
+        rc = set_sched_policy(tid, SP_FOREGROUND);
+    }
+
+    if (rc) {
+        lasterr = errno;
+    }
+
+    if (setpriority(PRIO_PROCESS, tid, pri) < 0) {
+        rc = INVALID_OPERATION;
+    } else {
+        errno = lasterr;
+    }
+#endif
+    
+    return rc;
+}
+
+int androidGetThreadPriority(pid_t tid) {
+#if defined(HAVE_PTHREADS)
+    return getpriority(PRIO_PROCESS, tid);
+#else
+    return ANDROID_PRIORITY_NORMAL;
+#endif
+}
+
+#endif
+
+namespace android {
+
+/*
+ * ===========================================================================
+ *      Mutex class
+ * ===========================================================================
+ */
+
+#if defined(HAVE_PTHREADS)
+// implemented as inlines in threads.h
+#elif defined(HAVE_WIN32_THREADS)
+
+Mutex::Mutex()
+{
+    HANDLE hMutex;
+
+    assert(sizeof(hMutex) == sizeof(mState));
+
+    hMutex = CreateMutex(NULL, FALSE, NULL);
+    mState = (void*) hMutex;
+}
+
+Mutex::Mutex(const char* name)
+{
+    // XXX: name not used for now
+    HANDLE hMutex;
+
+    assert(sizeof(hMutex) == sizeof(mState));
+
+    hMutex = CreateMutex(NULL, FALSE, NULL);
+    mState = (void*) hMutex;
+}
+
+Mutex::Mutex(int type, const char* name)
+{
+    // XXX: type and name not used for now
+    HANDLE hMutex;
+
+    assert(sizeof(hMutex) == sizeof(mState));
+
+    hMutex = CreateMutex(NULL, FALSE, NULL);
+    mState = (void*) hMutex;
+}
+
+Mutex::~Mutex()
+{
+    CloseHandle((HANDLE) mState);
+}
+
+status_t Mutex::lock()
+{
+    DWORD dwWaitResult;
+    dwWaitResult = WaitForSingleObject((HANDLE) mState, INFINITE);
+    return dwWaitResult != WAIT_OBJECT_0 ? -1 : NO_ERROR;
+}
+
+void Mutex::unlock()
+{
+    if (!ReleaseMutex((HANDLE) mState))
+        ALOG(LOG_WARN, "thread", "WARNING: bad result from unlocking mutex\n");
+}
+
+status_t Mutex::tryLock()
+{
+    DWORD dwWaitResult;
+
+    dwWaitResult = WaitForSingleObject((HANDLE) mState, 0);
+    if (dwWaitResult != WAIT_OBJECT_0 && dwWaitResult != WAIT_TIMEOUT)
+        ALOG(LOG_WARN, "thread", "WARNING: bad result from try-locking mutex\n");
+    return (dwWaitResult == WAIT_OBJECT_0) ? 0 : -1;
+}
+
+#else
+#error "Somebody forgot to implement threads for this platform."
+#endif
+
+
+/*
+ * ===========================================================================
+ *      Condition class
+ * ===========================================================================
+ */
+
+#if defined(HAVE_PTHREADS)
+// implemented as inlines in threads.h
+#elif defined(HAVE_WIN32_THREADS)
+
+/*
+ * Windows doesn't have a condition variable solution.  It's possible
+ * to create one, but it's easy to get it wrong.  For a discussion, and
+ * the origin of this implementation, see:
+ *
+ *  http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+ *
+ * The implementation shown on the page does NOT follow POSIX semantics.
+ * As an optimization they require acquiring the external mutex before
+ * calling signal() and broadcast(), whereas POSIX only requires grabbing
+ * it before calling wait().  The implementation here has been un-optimized
+ * to have the correct behavior.
+ */
+typedef struct WinCondition {
+    // Number of waiting threads.
+    int                 waitersCount;
+
+    // Serialize access to waitersCount.
+    CRITICAL_SECTION    waitersCountLock;
+
+    // Semaphore used to queue up threads waiting for the condition to
+    // become signaled.
+    HANDLE              sema;
+
+    // An auto-reset event used by the broadcast/signal thread to wait
+    // for all the waiting thread(s) to wake up and be released from
+    // the semaphore.
+    HANDLE              waitersDone;
+
+    // This mutex wouldn't be necessary if we required that the caller
+    // lock the external mutex before calling signal() and broadcast().
+    // I'm trying to mimic pthread semantics though.
+    HANDLE              internalMutex;
+
+    // Keeps track of whether we were broadcasting or signaling.  This
+    // allows us to optimize the code if we're just signaling.
+    bool                wasBroadcast;
+
+    status_t wait(WinCondition* condState, HANDLE hMutex, nsecs_t* abstime)
+    {
+        // Increment the wait count, avoiding race conditions.
+        EnterCriticalSection(&condState->waitersCountLock);
+        condState->waitersCount++;
+        //printf("+++ wait: incr waitersCount to %d (tid=%ld)\n",
+        //    condState->waitersCount, getThreadId());
+        LeaveCriticalSection(&condState->waitersCountLock);
+    
+        DWORD timeout = INFINITE;
+        if (abstime) {
+            nsecs_t reltime = *abstime - systemTime();
+            if (reltime < 0)
+                reltime = 0;
+            timeout = reltime/1000000;
+        }
+        
+        // Atomically release the external mutex and wait on the semaphore.
+        DWORD res =
+            SignalObjectAndWait(hMutex, condState->sema, timeout, FALSE);
+    
+        //printf("+++ wait: awake (tid=%ld)\n", getThreadId());
+    
+        // Reacquire lock to avoid race conditions.
+        EnterCriticalSection(&condState->waitersCountLock);
+    
+        // No longer waiting.
+        condState->waitersCount--;
+    
+        // Check to see if we're the last waiter after a broadcast.
+        bool lastWaiter = (condState->wasBroadcast && condState->waitersCount == 0);
+    
+        //printf("+++ wait: lastWaiter=%d (wasBc=%d wc=%d)\n",
+        //    lastWaiter, condState->wasBroadcast, condState->waitersCount);
+    
+        LeaveCriticalSection(&condState->waitersCountLock);
+    
+        // If we're the last waiter thread during this particular broadcast
+        // then signal broadcast() that we're all awake.  It'll drop the
+        // internal mutex.
+        if (lastWaiter) {
+            // Atomically signal the "waitersDone" event and wait until we
+            // can acquire the internal mutex.  We want to do this in one step
+            // because it ensures that everybody is in the mutex FIFO before
+            // any thread has a chance to run.  Without it, another thread
+            // could wake up, do work, and hop back in ahead of us.
+            SignalObjectAndWait(condState->waitersDone, condState->internalMutex,
+                INFINITE, FALSE);
+        } else {
+            // Grab the internal mutex.
+            WaitForSingleObject(condState->internalMutex, INFINITE);
+        }
+    
+        // Release the internal and grab the external.
+        ReleaseMutex(condState->internalMutex);
+        WaitForSingleObject(hMutex, INFINITE);
+    
+        return res == WAIT_OBJECT_0 ? NO_ERROR : -1;
+    }
+} WinCondition;
+
+/*
+ * Constructor.  Set up the WinCondition stuff.
+ */
+Condition::Condition()
+{
+    WinCondition* condState = new WinCondition;
+
+    condState->waitersCount = 0;
+    condState->wasBroadcast = false;
+    // semaphore: no security, initial value of 0
+    condState->sema = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
+    InitializeCriticalSection(&condState->waitersCountLock);
+    // auto-reset event, not signaled initially
+    condState->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
+    // used so we don't have to lock external mutex on signal/broadcast
+    condState->internalMutex = CreateMutex(NULL, FALSE, NULL);
+
+    mState = condState;
+}
+
+/*
+ * Destructor.  Free Windows resources as well as our allocated storage.
+ */
+Condition::~Condition()
+{
+    WinCondition* condState = (WinCondition*) mState;
+    if (condState != NULL) {
+        CloseHandle(condState->sema);
+        CloseHandle(condState->waitersDone);
+        delete condState;
+    }
+}
+
+
+status_t Condition::wait(Mutex& mutex)
+{
+    WinCondition* condState = (WinCondition*) mState;
+    HANDLE hMutex = (HANDLE) mutex.mState;
+    
+    return ((WinCondition*)mState)->wait(condState, hMutex, NULL);
+}
+
+status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
+{
+    WinCondition* condState = (WinCondition*) mState;
+    HANDLE hMutex = (HANDLE) mutex.mState;
+    nsecs_t absTime = systemTime()+reltime;
+
+    return ((WinCondition*)mState)->wait(condState, hMutex, &absTime);
+}
+
+/*
+ * Signal the condition variable, allowing one thread to continue.
+ */
+void Condition::signal()
+{
+    WinCondition* condState = (WinCondition*) mState;
+
+    // Lock the internal mutex.  This ensures that we don't clash with
+    // broadcast().
+    WaitForSingleObject(condState->internalMutex, INFINITE);
+
+    EnterCriticalSection(&condState->waitersCountLock);
+    bool haveWaiters = (condState->waitersCount > 0);
+    LeaveCriticalSection(&condState->waitersCountLock);
+
+    // If no waiters, then this is a no-op.  Otherwise, knock the semaphore
+    // down a notch.
+    if (haveWaiters)
+        ReleaseSemaphore(condState->sema, 1, 0);
+
+    // Release internal mutex.
+    ReleaseMutex(condState->internalMutex);
+}
+
+/*
+ * Signal the condition variable, allowing all threads to continue.
+ *
+ * First we have to wake up all threads waiting on the semaphore, then
+ * we wait until all of the threads have actually been woken before
+ * releasing the internal mutex.  This ensures that all threads are woken.
+ */
+void Condition::broadcast()
+{
+    WinCondition* condState = (WinCondition*) mState;
+
+    // Lock the internal mutex.  This keeps the guys we're waking up
+    // from getting too far.
+    WaitForSingleObject(condState->internalMutex, INFINITE);
+
+    EnterCriticalSection(&condState->waitersCountLock);
+    bool haveWaiters = false;
+
+    if (condState->waitersCount > 0) {
+        haveWaiters = true;
+        condState->wasBroadcast = true;
+    }
+
+    if (haveWaiters) {
+        // Wake up all the waiters.
+        ReleaseSemaphore(condState->sema, condState->waitersCount, 0);
+
+        LeaveCriticalSection(&condState->waitersCountLock);
+
+        // Wait for all awakened threads to acquire the counting semaphore.
+        // The last guy who was waiting sets this.
+        WaitForSingleObject(condState->waitersDone, INFINITE);
+
+        // Reset wasBroadcast.  (No crit section needed because nobody
+        // else can wake up to poke at it.)
+        condState->wasBroadcast = 0;
+    } else {
+        // nothing to do
+        LeaveCriticalSection(&condState->waitersCountLock);
+    }
+
+    // Release internal mutex.
+    ReleaseMutex(condState->internalMutex);
+}
+
+#else
+#error "condition variables not supported on this platform"
+#endif
+
+// ----------------------------------------------------------------------------
+
+/*
+ * This is our thread object!
+ */
+
+Thread::Thread(bool canCallJava)
+    :   mCanCallJava(canCallJava),
+        mThread(thread_id_t(-1)),
+        mLock("Thread::mLock"),
+        mStatus(NO_ERROR),
+        mExitPending(false), mRunning(false)
+#ifdef HAVE_ANDROID_OS
+        , mTid(-1)
+#endif
+{
+}
+
+Thread::~Thread()
+{
+}
+
+status_t Thread::readyToRun()
+{
+    return NO_ERROR;
+}
+
+status_t Thread::run(const char* name, int32_t priority, size_t stack)
+{
+    Mutex::Autolock _l(mLock);
+
+    if (mRunning) {
+        // thread already started
+        return INVALID_OPERATION;
+    }
+
+    // reset status and exitPending to their default value, so we can
+    // try again after an error happened (either below, or in readyToRun())
+    mStatus = NO_ERROR;
+    mExitPending = false;
+    mThread = thread_id_t(-1);
+    
+    // hold a strong reference on ourself
+    mHoldSelf = this;
+
+    mRunning = true;
+
+    bool res;
+    if (mCanCallJava) {
+        res = createThreadEtc(_threadLoop,
+                this, name, priority, stack, &mThread);
+    } else {
+        res = androidCreateRawThreadEtc(_threadLoop,
+                this, name, priority, stack, &mThread);
+    }
+    
+    if (res == false) {
+        mStatus = UNKNOWN_ERROR;   // something happened!
+        mRunning = false;
+        mThread = thread_id_t(-1);
+        mHoldSelf.clear();  // "this" may have gone away after this.
+
+        return UNKNOWN_ERROR;
+    }
+    
+    // Do not refer to mStatus here: The thread is already running (may, in fact
+    // already have exited with a valid mStatus result). The NO_ERROR indication
+    // here merely indicates successfully starting the thread and does not
+    // imply successful termination/execution.
+    return NO_ERROR;
+
+    // Exiting scope of mLock is a memory barrier and allows new thread to run
+}
+
+int Thread::_threadLoop(void* user)
+{
+    Thread* const self = static_cast<Thread*>(user);
+
+    sp<Thread> strong(self->mHoldSelf);
+    wp<Thread> weak(strong);
+    self->mHoldSelf.clear();
+
+#ifdef HAVE_ANDROID_OS
+    // this is very useful for debugging with gdb
+    self->mTid = gettid();
+#endif
+
+    bool first = true;
+
+    do {
+        bool result;
+        if (first) {
+            first = false;
+            self->mStatus = self->readyToRun();
+            result = (self->mStatus == NO_ERROR);
+
+            if (result && !self->exitPending()) {
+                // Binder threads (and maybe others) rely on threadLoop
+                // running at least once after a successful ::readyToRun()
+                // (unless, of course, the thread has already been asked to exit
+                // at that point).
+                // This is because threads are essentially used like this:
+                //   (new ThreadSubclass())->run();
+                // The caller therefore does not retain a strong reference to
+                // the thread and the thread would simply disappear after the
+                // successful ::readyToRun() call instead of entering the
+                // threadLoop at least once.
+                result = self->threadLoop();
+            }
+        } else {
+            result = self->threadLoop();
+        }
+
+        // establish a scope for mLock
+        {
+        Mutex::Autolock _l(self->mLock);
+        if (result == false || self->mExitPending) {
+            self->mExitPending = true;
+            self->mRunning = false;
+            // clear thread ID so that requestExitAndWait() does not exit if
+            // called by a new thread using the same thread ID as this one.
+            self->mThread = thread_id_t(-1);
+            // note that interested observers blocked in requestExitAndWait are
+            // awoken by broadcast, but blocked on mLock until break exits scope
+            self->mThreadExitedCondition.broadcast();
+            break;
+        }
+        }
+        
+        // Release our strong reference, to let a chance to the thread
+        // to die a peaceful death.
+        strong.clear();
+        // And immediately, re-acquire a strong reference for the next loop
+        strong = weak.promote();
+    } while(strong != 0);
+    
+    return 0;
+}
+
+void Thread::requestExit()
+{
+    Mutex::Autolock _l(mLock);
+    mExitPending = true;
+}
+
+status_t Thread::requestExitAndWait()
+{
+    Mutex::Autolock _l(mLock);
+    if (mThread == getThreadId()) {
+        ALOGW(
+        "Thread (this=%p): don't call waitForExit() from this "
+        "Thread object's thread. It's a guaranteed deadlock!",
+        this);
+
+        return WOULD_BLOCK;
+    }
+    
+    mExitPending = true;
+
+    while (mRunning == true) {
+        mThreadExitedCondition.wait(mLock);
+    }
+    // This next line is probably not needed any more, but is being left for
+    // historical reference. Note that each interested party will clear flag.
+    mExitPending = false;
+
+    return mStatus;
+}
+
+status_t Thread::join()
+{
+    Mutex::Autolock _l(mLock);
+    if (mThread == getThreadId()) {
+        ALOGW(
+        "Thread (this=%p): don't call join() from this "
+        "Thread object's thread. It's a guaranteed deadlock!",
+        this);
+
+        return WOULD_BLOCK;
+    }
+
+    while (mRunning == true) {
+        mThreadExitedCondition.wait(mLock);
+    }
+
+    return mStatus;
+}
+
+bool Thread::isRunning() const {
+    Mutex::Autolock _l(mLock);
+    return mRunning;
+}
+
+#ifdef HAVE_ANDROID_OS
+pid_t Thread::getTid() const
+{
+    // mTid is not defined until the child initializes it, and the caller may need it earlier
+    Mutex::Autolock _l(mLock);
+    pid_t tid;
+    if (mRunning) {
+        pthread_t pthread = android_thread_id_t_to_pthread(mThread);
+        tid = __pthread_gettid(pthread);
+    } else {
+        ALOGW("Thread (this=%p): getTid() is undefined before run()", this);
+        tid = -1;
+    }
+    return tid;
+}
+#endif
+
+bool Thread::exitPending() const
+{
+    Mutex::Autolock _l(mLock);
+    return mExitPending;
+}
+
+
+
+};  // namespace android
diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp
new file mode 100644
index 0000000..5293cd2
--- /dev/null
+++ b/libutils/Timers.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Timer functions.
+//
+#include <utils/Timers.h>
+#include <utils/Log.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+#include <limits.h>
+
+#ifdef HAVE_WIN32_THREADS
+#include <windows.h>
+#endif
+
+nsecs_t systemTime(int clock)
+{
+#if defined(HAVE_POSIX_CLOCKS)
+    static const clockid_t clocks[] = {
+            CLOCK_REALTIME,
+            CLOCK_MONOTONIC,
+            CLOCK_PROCESS_CPUTIME_ID,
+            CLOCK_THREAD_CPUTIME_ID,
+            CLOCK_BOOTTIME
+    };
+    struct timespec t;
+    t.tv_sec = t.tv_nsec = 0;
+    clock_gettime(clocks[clock], &t);
+    return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+#else
+    // we don't support the clocks here.
+    struct timeval t;
+    t.tv_sec = t.tv_usec = 0;
+    gettimeofday(&t, NULL);
+    return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL;
+#endif
+}
+
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime)
+{
+    int timeoutDelayMillis;
+    if (timeoutTime > referenceTime) {
+        uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime);
+        if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) {
+            timeoutDelayMillis = -1;
+        } else {
+            timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL;
+        }
+    } else {
+        timeoutDelayMillis = 0;
+    }
+    return timeoutDelayMillis;
+}
diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp
new file mode 100644
index 0000000..7067533
--- /dev/null
+++ b/libutils/Tokenizer.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#define LOG_TAG "Tokenizer"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <utils/Log.h>
+#include <utils/Tokenizer.h>
+
+// Enables debug output for the tokenizer.
+#define DEBUG_TOKENIZER 0
+
+
+namespace android {
+
+static inline bool isDelimiter(char ch, const char* delimiters) {
+    return strchr(delimiters, ch) != NULL;
+}
+
+Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer,
+        bool ownBuffer, size_t length) :
+        mFilename(filename), mFileMap(fileMap),
+        mBuffer(buffer), mOwnBuffer(ownBuffer), mLength(length),
+        mCurrent(buffer), mLineNumber(1) {
+}
+
+Tokenizer::~Tokenizer() {
+    if (mFileMap) {
+        mFileMap->release();
+    }
+    if (mOwnBuffer) {
+        delete[] mBuffer;
+    }
+}
+
+status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) {
+    *outTokenizer = NULL;
+
+    int result = NO_ERROR;
+    int fd = ::open(filename.string(), O_RDONLY);
+    if (fd < 0) {
+        result = -errno;
+        ALOGE("Error opening file '%s', %s.", filename.string(), strerror(errno));
+    } else {
+        struct stat stat;
+        if (fstat(fd, &stat)) {
+            result = -errno;
+            ALOGE("Error getting size of file '%s', %s.", filename.string(), strerror(errno));
+        } else {
+            size_t length = size_t(stat.st_size);
+
+            FileMap* fileMap = new FileMap();
+            bool ownBuffer = false;
+            char* buffer;
+            if (fileMap->create(NULL, fd, 0, length, true)) {
+                fileMap->advise(FileMap::SEQUENTIAL);
+                buffer = static_cast<char*>(fileMap->getDataPtr());
+            } else {
+                fileMap->release();
+                fileMap = NULL;
+
+                // Fall back to reading into a buffer since we can't mmap files in sysfs.
+                // The length we obtained from stat is wrong too (it will always be 4096)
+                // so we must trust that read will read the entire file.
+                buffer = new char[length];
+                ownBuffer = true;
+                ssize_t nrd = read(fd, buffer, length);
+                if (nrd < 0) {
+                    result = -errno;
+                    ALOGE("Error reading file '%s', %s.", filename.string(), strerror(errno));
+                    delete[] buffer;
+                    buffer = NULL;
+                } else {
+                    length = size_t(nrd);
+                }
+            }
+
+            if (!result) {
+                *outTokenizer = new Tokenizer(filename, fileMap, buffer, ownBuffer, length);
+            }
+        }
+        close(fd);
+    }
+    return result;
+}
+
+status_t Tokenizer::fromContents(const String8& filename,
+        const char* contents, Tokenizer** outTokenizer) {
+    *outTokenizer = new Tokenizer(filename, NULL,
+            const_cast<char*>(contents), false, strlen(contents));
+    return OK;
+}
+
+String8 Tokenizer::getLocation() const {
+    String8 result;
+    result.appendFormat("%s:%d", mFilename.string(), mLineNumber);
+    return result;
+}
+
+String8 Tokenizer::peekRemainderOfLine() const {
+    const char* end = getEnd();
+    const char* eol = mCurrent;
+    while (eol != end) {
+        char ch = *eol;
+        if (ch == '\n') {
+            break;
+        }
+        eol += 1;
+    }
+    return String8(mCurrent, eol - mCurrent);
+}
+
+String8 Tokenizer::nextToken(const char* delimiters) {
+#if DEBUG_TOKENIZER
+    ALOGD("nextToken");
+#endif
+    const char* end = getEnd();
+    const char* tokenStart = mCurrent;
+    while (mCurrent != end) {
+        char ch = *mCurrent;
+        if (ch == '\n' || isDelimiter(ch, delimiters)) {
+            break;
+        }
+        mCurrent += 1;
+    }
+    return String8(tokenStart, mCurrent - tokenStart);
+}
+
+void Tokenizer::nextLine() {
+#if DEBUG_TOKENIZER
+    ALOGD("nextLine");
+#endif
+    const char* end = getEnd();
+    while (mCurrent != end) {
+        char ch = *(mCurrent++);
+        if (ch == '\n') {
+            mLineNumber += 1;
+            break;
+        }
+    }
+}
+
+void Tokenizer::skipDelimiters(const char* delimiters) {
+#if DEBUG_TOKENIZER
+    ALOGD("skipDelimiters");
+#endif
+    const char* end = getEnd();
+    while (mCurrent != end) {
+        char ch = *mCurrent;
+        if (ch == '\n' || !isDelimiter(ch, delimiters)) {
+            break;
+        }
+        mCurrent += 1;
+    }
+}
+
+} // namespace android
diff --git a/include/cutils/zygote.h b/libutils/Trace.cpp
similarity index 63%
copy from include/cutils/zygote.h
copy to libutils/Trace.cpp
index a7480d3..36fd802 100644
--- a/include/cutils/zygote.h
+++ b/libutils/Trace.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -14,18 +14,12 @@
  * limitations under the License.
  */
 
-#ifndef __CUTILS_ZYGOTE_H
-#define __CUTILS_ZYGOTE_H
+#include <utils/misc.h>
+#include <utils/Trace.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+static void traceInit() __attribute__((constructor));
 
-int zygote_run_oneshot(int sendStdio, int argc, const char **argv);
-int zygote_run(int argc, const char **argv);
-
-#ifdef __cplusplus
+static void traceInit()
+{
+    ::android::add_sysprop_change_callback(atrace_update_tags, 0);
 }
-#endif
-
-#endif /* __CUTILS_ZYGOTE_H */
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
new file mode 100644
index 0000000..a66e3bb
--- /dev/null
+++ b/libutils/Unicode.cpp
@@ -0,0 +1,606 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/Unicode.h>
+
+#include <stddef.h>
+
+#ifdef HAVE_WINSOCK
+# undef  nhtol
+# undef  htonl
+# undef  nhtos
+# undef  htons
+
+# ifdef HAVE_LITTLE_ENDIAN
+#  define ntohl(x)    ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
+#  define htonl(x)    ntohl(x)
+#  define ntohs(x)    ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
+#  define htons(x)    ntohs(x)
+# else
+#  define ntohl(x)    (x)
+#  define htonl(x)    (x)
+#  define ntohs(x)    (x)
+#  define htons(x)    (x)
+# endif
+#else
+# include <netinet/in.h>
+#endif
+
+extern "C" {
+
+static const char32_t kByteMask = 0x000000BF;
+static const char32_t kByteMark = 0x00000080;
+
+// Surrogates aren't valid for UTF-32 characters, so define some
+// constants that will let us screen them out.
+static const char32_t kUnicodeSurrogateHighStart  = 0x0000D800;
+static const char32_t kUnicodeSurrogateHighEnd    = 0x0000DBFF;
+static const char32_t kUnicodeSurrogateLowStart   = 0x0000DC00;
+static const char32_t kUnicodeSurrogateLowEnd     = 0x0000DFFF;
+static const char32_t kUnicodeSurrogateStart      = kUnicodeSurrogateHighStart;
+static const char32_t kUnicodeSurrogateEnd        = kUnicodeSurrogateLowEnd;
+static const char32_t kUnicodeMaxCodepoint        = 0x0010FFFF;
+
+// Mask used to set appropriate bits in first byte of UTF-8 sequence,
+// indexed by number of bytes in the sequence.
+// 0xxxxxxx
+// -> (00-7f) 7bit. Bit mask for the first byte is 0x00000000
+// 110yyyyx 10xxxxxx
+// -> (c0-df)(80-bf) 11bit. Bit mask is 0x000000C0
+// 1110yyyy 10yxxxxx 10xxxxxx
+// -> (e0-ef)(80-bf)(80-bf) 16bit. Bit mask is 0x000000E0
+// 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx
+// -> (f0-f7)(80-bf)(80-bf)(80-bf) 21bit. Bit mask is 0x000000F0
+static const char32_t kFirstByteMark[] = {
+    0x00000000, 0x00000000, 0x000000C0, 0x000000E0, 0x000000F0
+};
+
+// --------------------------------------------------------------------------
+// UTF-32
+// --------------------------------------------------------------------------
+
+/**
+ * Return number of UTF-8 bytes required for the character. If the character
+ * is invalid, return size of 0.
+ */
+static inline size_t utf32_codepoint_utf8_length(char32_t srcChar)
+{
+    // Figure out how many bytes the result will require.
+    if (srcChar < 0x00000080) {
+        return 1;
+    } else if (srcChar < 0x00000800) {
+        return 2;
+    } else if (srcChar < 0x00010000) {
+        if ((srcChar < kUnicodeSurrogateStart) || (srcChar > kUnicodeSurrogateEnd)) {
+            return 3;
+        } else {
+            // Surrogates are invalid UTF-32 characters.
+            return 0;
+        }
+    }
+    // Max code point for Unicode is 0x0010FFFF.
+    else if (srcChar <= kUnicodeMaxCodepoint) {
+        return 4;
+    } else {
+        // Invalid UTF-32 character.
+        return 0;
+    }
+}
+
+// Write out the source character to <dstP>.
+
+static inline void utf32_codepoint_to_utf8(uint8_t* dstP, char32_t srcChar, size_t bytes)
+{
+    dstP += bytes;
+    switch (bytes)
+    {   /* note: everything falls through. */
+        case 4: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+        case 3: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+        case 2: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6;
+        case 1: *--dstP = (uint8_t)(srcChar | kFirstByteMark[bytes]);
+    }
+}
+
+size_t strlen32(const char32_t *s)
+{
+  const char32_t *ss = s;
+  while ( *ss )
+    ss++;
+  return ss-s;
+}
+
+size_t strnlen32(const char32_t *s, size_t maxlen)
+{
+  const char32_t *ss = s;
+  while ((maxlen > 0) && *ss) {
+    ss++;
+    maxlen--;
+  }
+  return ss-s;
+}
+
+static inline int32_t utf32_at_internal(const char* cur, size_t *num_read)
+{
+    const char first_char = *cur;
+    if ((first_char & 0x80) == 0) { // ASCII
+        *num_read = 1;
+        return *cur;
+    }
+    cur++;
+    char32_t mask, to_ignore_mask;
+    size_t num_to_read = 0;
+    char32_t utf32 = first_char;
+    for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0xFFFFFF80;
+         (first_char & mask);
+         num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
+        // 0x3F == 00111111
+        utf32 = (utf32 << 6) + (*cur++ & 0x3F);
+    }
+    to_ignore_mask |= mask;
+    utf32 &= ~(to_ignore_mask << (6 * (num_to_read - 1)));
+
+    *num_read = num_to_read;
+    return static_cast<int32_t>(utf32);
+}
+
+int32_t utf32_from_utf8_at(const char *src, size_t src_len, size_t index, size_t *next_index)
+{
+    if (index >= src_len) {
+        return -1;
+    }
+    size_t dummy_index;
+    if (next_index == NULL) {
+        next_index = &dummy_index;
+    }
+    size_t num_read;
+    int32_t ret = utf32_at_internal(src + index, &num_read);
+    if (ret >= 0) {
+        *next_index = index + num_read;
+    }
+
+    return ret;
+}
+
+ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len)
+{
+    if (src == NULL || src_len == 0) {
+        return -1;
+    }
+
+    size_t ret = 0;
+    const char32_t *end = src + src_len;
+    while (src < end) {
+        ret += utf32_codepoint_utf8_length(*src++);
+    }
+    return ret;
+}
+
+void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst)
+{
+    if (src == NULL || src_len == 0 || dst == NULL) {
+        return;
+    }
+
+    const char32_t *cur_utf32 = src;
+    const char32_t *end_utf32 = src + src_len;
+    char *cur = dst;
+    while (cur_utf32 < end_utf32) {
+        size_t len = utf32_codepoint_utf8_length(*cur_utf32);
+        utf32_codepoint_to_utf8((uint8_t *)cur, *cur_utf32++, len);
+        cur += len;
+    }
+    *cur = '\0';
+}
+
+// --------------------------------------------------------------------------
+// UTF-16
+// --------------------------------------------------------------------------
+
+int strcmp16(const char16_t *s1, const char16_t *s2)
+{
+  char16_t ch;
+  int d = 0;
+
+  while ( 1 ) {
+    d = (int)(ch = *s1++) - (int)*s2++;
+    if ( d || !ch )
+      break;
+  }
+
+  return d;
+}
+
+int strncmp16(const char16_t *s1, const char16_t *s2, size_t n)
+{
+  char16_t ch;
+  int d = 0;
+
+  while ( n-- ) {
+    d = (int)(ch = *s1++) - (int)*s2++;
+    if ( d || !ch )
+      break;
+  }
+
+  return d;
+}
+
+char16_t *strcpy16(char16_t *dst, const char16_t *src)
+{
+  char16_t *q = dst;
+  const char16_t *p = src;
+  char16_t ch;
+
+  do {
+    *q++ = ch = *p++;
+  } while ( ch );
+
+  return dst;
+}
+
+size_t strlen16(const char16_t *s)
+{
+  const char16_t *ss = s;
+  while ( *ss )
+    ss++;
+  return ss-s;
+}
+
+
+char16_t *strncpy16(char16_t *dst, const char16_t *src, size_t n)
+{
+  char16_t *q = dst;
+  const char16_t *p = src;
+  char ch;
+
+  while (n) {
+    n--;
+    *q++ = ch = *p++;
+    if ( !ch )
+      break;
+  }
+
+  *q = 0;
+
+  return dst;
+}
+
+size_t strnlen16(const char16_t *s, size_t maxlen)
+{
+  const char16_t *ss = s;
+
+  /* Important: the maxlen test must precede the reference through ss;
+     since the byte beyond the maximum may segfault */
+  while ((maxlen > 0) && *ss) {
+    ss++;
+    maxlen--;
+  }
+  return ss-s;
+}
+
+int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2)
+{
+    const char16_t* e1 = s1+n1;
+    const char16_t* e2 = s2+n2;
+
+    while (s1 < e1 && s2 < e2) {
+        const int d = (int)*s1++ - (int)*s2++;
+        if (d) {
+            return d;
+        }
+    }
+
+    return n1 < n2
+        ? (0 - (int)*s2)
+        : (n1 > n2
+           ? ((int)*s1 - 0)
+           : 0);
+}
+
+int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2)
+{
+    const char16_t* e1 = s1H+n1;
+    const char16_t* e2 = s2N+n2;
+
+    while (s1H < e1 && s2N < e2) {
+        const char16_t c2 = ntohs(*s2N);
+        const int d = (int)*s1H++ - (int)c2;
+        s2N++;
+        if (d) {
+            return d;
+        }
+    }
+
+    return n1 < n2
+        ? (0 - (int)ntohs(*s2N))
+        : (n1 > n2
+           ? ((int)*s1H - 0)
+           : 0);
+}
+
+void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst)
+{
+    if (src == NULL || src_len == 0 || dst == NULL) {
+        return;
+    }
+
+    const char16_t* cur_utf16 = src;
+    const char16_t* const end_utf16 = src + src_len;
+    char *cur = dst;
+    while (cur_utf16 < end_utf16) {
+        char32_t utf32;
+        // surrogate pairs
+        if ((*cur_utf16 & 0xFC00) == 0xD800) {
+            utf32 = (*cur_utf16++ - 0xD800) << 10;
+            utf32 |= *cur_utf16++ - 0xDC00;
+            utf32 += 0x10000;
+        } else {
+            utf32 = (char32_t) *cur_utf16++;
+        }
+        const size_t len = utf32_codepoint_utf8_length(utf32);
+        utf32_codepoint_to_utf8((uint8_t*)cur, utf32, len);
+        cur += len;
+    }
+    *cur = '\0';
+}
+
+// --------------------------------------------------------------------------
+// UTF-8
+// --------------------------------------------------------------------------
+
+ssize_t utf8_length(const char *src)
+{
+    const char *cur = src;
+    size_t ret = 0;
+    while (*cur != '\0') {
+        const char first_char = *cur++;
+        if ((first_char & 0x80) == 0) { // ASCII
+            ret += 1;
+            continue;
+        }
+        // (UTF-8's character must not be like 10xxxxxx,
+        //  but 110xxxxx, 1110xxxx, ... or 1111110x)
+        if ((first_char & 0x40) == 0) {
+            return -1;
+        }
+
+        int32_t mask, to_ignore_mask;
+        size_t num_to_read = 0;
+        char32_t utf32 = 0;
+        for (num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80;
+             num_to_read < 5 && (first_char & mask);
+             num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
+            if ((*cur & 0xC0) != 0x80) { // must be 10xxxxxx
+                return -1;
+            }
+            // 0x3F == 00111111
+            utf32 = (utf32 << 6) + (*cur++ & 0x3F);
+        }
+        // "first_char" must be (110xxxxx - 11110xxx)
+        if (num_to_read == 5) {
+            return -1;
+        }
+        to_ignore_mask |= mask;
+        utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1));
+        if (utf32 > kUnicodeMaxCodepoint) {
+            return -1;
+        }
+
+        ret += num_to_read;
+    }
+    return ret;
+}
+
+ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len)
+{
+    if (src == NULL || src_len == 0) {
+        return -1;
+    }
+
+    size_t ret = 0;
+    const char16_t* const end = src + src_len;
+    while (src < end) {
+        if ((*src & 0xFC00) == 0xD800 && (src + 1) < end
+                && (*++src & 0xFC00) == 0xDC00) {
+            // surrogate pairs are always 4 bytes.
+            ret += 4;
+            src++;
+        } else {
+            ret += utf32_codepoint_utf8_length((char32_t) *src++);
+        }
+    }
+    return ret;
+}
+
+/**
+ * Returns 1-4 based on the number of leading bits.
+ *
+ * 1111 -> 4
+ * 1110 -> 3
+ * 110x -> 2
+ * 10xx -> 1
+ * 0xxx -> 1
+ */
+static inline size_t utf8_codepoint_len(uint8_t ch)
+{
+    return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1;
+}
+
+static inline void utf8_shift_and_mask(uint32_t* codePoint, const uint8_t byte)
+{
+    *codePoint <<= 6;
+    *codePoint |= 0x3F & byte;
+}
+
+size_t utf8_to_utf32_length(const char *src, size_t src_len)
+{
+    if (src == NULL || src_len == 0) {
+        return 0;
+    }
+    size_t ret = 0;
+    const char* cur;
+    const char* end;
+    size_t num_to_skip;
+    for (cur = src, end = src + src_len, num_to_skip = 1;
+         cur < end;
+         cur += num_to_skip, ret++) {
+        const char first_char = *cur;
+        num_to_skip = 1;
+        if ((first_char & 0x80) == 0) {  // ASCII
+            continue;
+        }
+        int32_t mask;
+
+        for (mask = 0x40; (first_char & mask); num_to_skip++, mask >>= 1) {
+        }
+    }
+    return ret;
+}
+
+void utf8_to_utf32(const char* src, size_t src_len, char32_t* dst)
+{
+    if (src == NULL || src_len == 0 || dst == NULL) {
+        return;
+    }
+
+    const char* cur = src;
+    const char* const end = src + src_len;
+    char32_t* cur_utf32 = dst;
+    while (cur < end) {
+        size_t num_read;
+        *cur_utf32++ = static_cast<char32_t>(utf32_at_internal(cur, &num_read));
+        cur += num_read;
+    }
+    *cur_utf32 = 0;
+}
+
+static inline uint32_t utf8_to_utf32_codepoint(const uint8_t *src, size_t length)
+{
+    uint32_t unicode;
+
+    switch (length)
+    {
+        case 1:
+            return src[0];
+        case 2:
+            unicode = src[0] & 0x1f;
+            utf8_shift_and_mask(&unicode, src[1]);
+            return unicode;
+        case 3:
+            unicode = src[0] & 0x0f;
+            utf8_shift_and_mask(&unicode, src[1]);
+            utf8_shift_and_mask(&unicode, src[2]);
+            return unicode;
+        case 4:
+            unicode = src[0] & 0x07;
+            utf8_shift_and_mask(&unicode, src[1]);
+            utf8_shift_and_mask(&unicode, src[2]);
+            utf8_shift_and_mask(&unicode, src[3]);
+            return unicode;
+        default:
+            return 0xffff;
+    }
+
+    //printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result);
+}
+
+ssize_t utf8_to_utf16_length(const uint8_t* u8str, size_t u8len)
+{
+    const uint8_t* const u8end = u8str + u8len;
+    const uint8_t* u8cur = u8str;
+
+    /* Validate that the UTF-8 is the correct len */
+    size_t u16measuredLen = 0;
+    while (u8cur < u8end) {
+        u16measuredLen++;
+        int u8charLen = utf8_codepoint_len(*u8cur);
+        uint32_t codepoint = utf8_to_utf32_codepoint(u8cur, u8charLen);
+        if (codepoint > 0xFFFF) u16measuredLen++; // this will be a surrogate pair in utf16
+        u8cur += u8charLen;
+    }
+
+    /**
+     * Make sure that we ended where we thought we would and the output UTF-16
+     * will be exactly how long we were told it would be.
+     */
+    if (u8cur != u8end) {
+        return -1;
+    }
+
+    return u16measuredLen;
+}
+
+char16_t* utf8_to_utf16_no_null_terminator(const uint8_t* u8str, size_t u8len, char16_t* u16str)
+{
+    const uint8_t* const u8end = u8str + u8len;
+    const uint8_t* u8cur = u8str;
+    char16_t* u16cur = u16str;
+
+    while (u8cur < u8end) {
+        size_t u8len = utf8_codepoint_len(*u8cur);
+        uint32_t codepoint = utf8_to_utf32_codepoint(u8cur, u8len);
+
+        // Convert the UTF32 codepoint to one or more UTF16 codepoints
+        if (codepoint <= 0xFFFF) {
+            // Single UTF16 character
+            *u16cur++ = (char16_t) codepoint;
+        } else {
+            // Multiple UTF16 characters with surrogates
+            codepoint = codepoint - 0x10000;
+            *u16cur++ = (char16_t) ((codepoint >> 10) + 0xD800);
+            *u16cur++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00);
+        }
+
+        u8cur += u8len;
+    }
+    return u16cur;
+}
+
+void utf8_to_utf16(const uint8_t* u8str, size_t u8len, char16_t* u16str) {
+    char16_t* end = utf8_to_utf16_no_null_terminator(u8str, u8len, u16str);
+    *end = 0;
+}
+
+char16_t* utf8_to_utf16_n(const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen) {
+    const uint8_t* const u8end = src + srcLen;
+    const uint8_t* u8cur = src;
+    const uint16_t* const u16end = dst + dstLen;
+    char16_t* u16cur = dst;
+
+    while (u8cur < u8end && u16cur < u16end) {
+        size_t u8len = utf8_codepoint_len(*u8cur);
+        uint32_t codepoint = utf8_to_utf32_codepoint(u8cur, u8len);
+
+        // Convert the UTF32 codepoint to one or more UTF16 codepoints
+        if (codepoint <= 0xFFFF) {
+            // Single UTF16 character
+            *u16cur++ = (char16_t) codepoint;
+        } else {
+            // Multiple UTF16 characters with surrogates
+            codepoint = codepoint - 0x10000;
+            *u16cur++ = (char16_t) ((codepoint >> 10) + 0xD800);
+            if (u16cur >= u16end) {
+                // Ooops...  not enough room for this surrogate pair.
+                return u16cur-1;
+            }
+            *u16cur++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00);
+        }
+
+        u8cur += u8len;
+    }
+    return u16cur;
+}
+
+}
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
new file mode 100644
index 0000000..30ca663
--- /dev/null
+++ b/libutils/VectorImpl.cpp
@@ -0,0 +1,637 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Vector"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <cutils/log.h>
+
+#include <utils/Errors.h>
+#include <utils/SharedBuffer.h>
+#include <utils/VectorImpl.h>
+
+/*****************************************************************************/
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+const size_t kMinVectorCapacity = 4;
+
+static inline size_t max(size_t a, size_t b) {
+    return a>b ? a : b;
+}
+
+// ----------------------------------------------------------------------------
+
+VectorImpl::VectorImpl(size_t itemSize, uint32_t flags)
+    : mStorage(0), mCount(0), mFlags(flags), mItemSize(itemSize)
+{
+}
+
+VectorImpl::VectorImpl(const VectorImpl& rhs)
+    :   mStorage(rhs.mStorage), mCount(rhs.mCount),
+        mFlags(rhs.mFlags), mItemSize(rhs.mItemSize)
+{
+    if (mStorage) {
+        SharedBuffer::bufferFromData(mStorage)->acquire();
+    }
+}
+
+VectorImpl::~VectorImpl()
+{
+    ALOGW_IF(mCount,
+        "[%p] subclasses of VectorImpl must call finish_vector()"
+        " in their destructor. Leaking %d bytes.",
+        this, (int)(mCount*mItemSize));
+    // We can't call _do_destroy() here because the vtable is already gone. 
+}
+
+VectorImpl& VectorImpl::operator = (const VectorImpl& rhs)
+{
+    LOG_ALWAYS_FATAL_IF(mItemSize != rhs.mItemSize,
+        "Vector<> have different types (this=%p, rhs=%p)", this, &rhs);
+    if (this != &rhs) {
+        release_storage();
+        if (rhs.mCount) {
+            mStorage = rhs.mStorage;
+            mCount = rhs.mCount;
+            SharedBuffer::bufferFromData(mStorage)->acquire();
+        } else {
+            mStorage = 0;
+            mCount = 0;
+        }
+    }
+    return *this;
+}
+
+void* VectorImpl::editArrayImpl()
+{
+    if (mStorage) {
+        SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage)->attemptEdit();
+        if (sb == 0) {
+            sb = SharedBuffer::alloc(capacity() * mItemSize);
+            if (sb) {
+                _do_copy(sb->data(), mStorage, mCount);
+                release_storage();
+                mStorage = sb->data();
+            }
+        }
+    }
+    return mStorage;
+}
+
+size_t VectorImpl::capacity() const
+{
+    if (mStorage) {
+        return SharedBuffer::bufferFromData(mStorage)->size() / mItemSize;
+    }
+    return 0;
+}
+
+ssize_t VectorImpl::insertVectorAt(const VectorImpl& vector, size_t index)
+{
+    return insertArrayAt(vector.arrayImpl(), index, vector.size());
+}
+
+ssize_t VectorImpl::appendVector(const VectorImpl& vector)
+{
+    return insertVectorAt(vector, size());
+}
+
+ssize_t VectorImpl::insertArrayAt(const void* array, size_t index, size_t length)
+{
+    if (index > size())
+        return BAD_INDEX;
+    void* where = _grow(index, length);
+    if (where) {
+        _do_copy(where, array, length);
+    }
+    return where ? index : (ssize_t)NO_MEMORY;
+}
+
+ssize_t VectorImpl::appendArray(const void* array, size_t length)
+{
+    return insertArrayAt(array, size(), length);
+}
+
+ssize_t VectorImpl::insertAt(size_t index, size_t numItems)
+{
+    return insertAt(0, index, numItems);
+}
+
+ssize_t VectorImpl::insertAt(const void* item, size_t index, size_t numItems)
+{
+    if (index > size())
+        return BAD_INDEX;
+    void* where = _grow(index, numItems);
+    if (where) {
+        if (item) {
+            _do_splat(where, item, numItems);
+        } else {
+            _do_construct(where, numItems);
+        }
+    }
+    return where ? index : (ssize_t)NO_MEMORY;
+}
+
+static int sortProxy(const void* lhs, const void* rhs, void* func)
+{
+    return (*(VectorImpl::compar_t)func)(lhs, rhs);
+}
+
+status_t VectorImpl::sort(VectorImpl::compar_t cmp)
+{
+    return sort(sortProxy, (void*)cmp);
+}
+
+status_t VectorImpl::sort(VectorImpl::compar_r_t cmp, void* state)
+{
+    // the sort must be stable. we're using insertion sort which
+    // is well suited for small and already sorted arrays
+    // for big arrays, it could be better to use mergesort
+    const ssize_t count = size();
+    if (count > 1) {
+        void* array = const_cast<void*>(arrayImpl());
+        void* temp = 0;
+        ssize_t i = 1;
+        while (i < count) {
+            void* item = reinterpret_cast<char*>(array) + mItemSize*(i);
+            void* curr = reinterpret_cast<char*>(array) + mItemSize*(i-1);
+            if (cmp(curr, item, state) > 0) {
+
+                if (!temp) {
+                    // we're going to have to modify the array...
+                    array = editArrayImpl();
+                    if (!array) return NO_MEMORY;
+                    temp = malloc(mItemSize);
+                    if (!temp) return NO_MEMORY;
+                    item = reinterpret_cast<char*>(array) + mItemSize*(i);
+                    curr = reinterpret_cast<char*>(array) + mItemSize*(i-1);
+                } else {
+                    _do_destroy(temp, 1);
+                }
+
+                _do_copy(temp, item, 1);
+
+                ssize_t j = i-1;
+                void* next = reinterpret_cast<char*>(array) + mItemSize*(i);                    
+                do {
+                    _do_destroy(next, 1);
+                    _do_copy(next, curr, 1);
+                    next = curr;
+                    --j;
+                    curr = reinterpret_cast<char*>(array) + mItemSize*(j);                    
+                } while (j>=0 && (cmp(curr, temp, state) > 0));
+
+                _do_destroy(next, 1);
+                _do_copy(next, temp, 1);
+            }
+            i++;
+        }
+        
+        if (temp) {
+            _do_destroy(temp, 1);
+            free(temp);
+        }
+    }
+    return NO_ERROR;
+}
+
+void VectorImpl::pop()
+{
+    if (size())
+        removeItemsAt(size()-1, 1);
+}
+
+void VectorImpl::push()
+{
+    push(0);
+}
+
+void VectorImpl::push(const void* item)
+{
+    insertAt(item, size());
+}
+
+ssize_t VectorImpl::add()
+{
+    return add(0);
+}
+
+ssize_t VectorImpl::add(const void* item)
+{
+    return insertAt(item, size());
+}
+
+ssize_t VectorImpl::replaceAt(size_t index)
+{
+    return replaceAt(0, index);
+}
+
+ssize_t VectorImpl::replaceAt(const void* prototype, size_t index)
+{
+    ALOG_ASSERT(index<size(),
+        "[%p] replace: index=%d, size=%d", this, (int)index, (int)size());
+
+    if (index >= size()) {
+        return BAD_INDEX;
+    }
+
+    void* item = editItemLocation(index);
+    if (item != prototype) {
+        if (item == 0)
+            return NO_MEMORY;
+        _do_destroy(item, 1);
+        if (prototype == 0) {
+            _do_construct(item, 1);
+        } else {
+            _do_copy(item, prototype, 1);
+        }
+    }
+    return ssize_t(index);
+}
+
+ssize_t VectorImpl::removeItemsAt(size_t index, size_t count)
+{
+    ALOG_ASSERT((index+count)<=size(),
+        "[%p] remove: index=%d, count=%d, size=%d",
+               this, (int)index, (int)count, (int)size());
+
+    if ((index+count) > size())
+        return BAD_VALUE;
+   _shrink(index, count);
+   return index;
+}
+
+void VectorImpl::finish_vector()
+{
+    release_storage();
+    mStorage = 0;
+    mCount = 0;
+}
+
+void VectorImpl::clear()
+{
+    _shrink(0, mCount);
+}
+
+void* VectorImpl::editItemLocation(size_t index)
+{
+    ALOG_ASSERT(index<capacity(),
+        "[%p] editItemLocation: index=%d, capacity=%d, count=%d",
+        this, (int)index, (int)capacity(), (int)mCount);
+
+    if (index < capacity()) {
+        void* buffer = editArrayImpl();
+        if (buffer) {
+            return reinterpret_cast<char*>(buffer) + index*mItemSize;
+        }
+    }
+    return 0;
+}
+
+const void* VectorImpl::itemLocation(size_t index) const
+{
+    ALOG_ASSERT(index<capacity(),
+        "[%p] itemLocation: index=%d, capacity=%d, count=%d",
+        this, (int)index, (int)capacity(), (int)mCount);
+
+    if (index < capacity()) {
+        const  void* buffer = arrayImpl();
+        if (buffer) {
+            return reinterpret_cast<const char*>(buffer) + index*mItemSize;
+        }
+    }
+    return 0;
+}
+
+ssize_t VectorImpl::setCapacity(size_t new_capacity)
+{
+    size_t current_capacity = capacity();
+    ssize_t amount = new_capacity - size();
+    if (amount <= 0) {
+        // we can't reduce the capacity
+        return current_capacity;
+    } 
+    SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
+    if (sb) {
+        void* array = sb->data();
+        _do_copy(array, mStorage, size());
+        release_storage();
+        mStorage = const_cast<void*>(array);
+    } else {
+        return NO_MEMORY;
+    }
+    return new_capacity;
+}
+
+ssize_t VectorImpl::resize(size_t size) {
+    ssize_t result = NO_ERROR;
+    if (size > mCount) {
+        result = insertAt(mCount, size - mCount);
+    } else if (size < mCount) {
+        result = removeItemsAt(size, mCount - size);
+    }
+    return result < 0 ? result : size;
+}
+
+void VectorImpl::release_storage()
+{
+    if (mStorage) {
+        const SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage);
+        if (sb->release(SharedBuffer::eKeepStorage) == 1) {
+            _do_destroy(mStorage, mCount);
+            SharedBuffer::dealloc(sb);
+        } 
+    }
+}
+
+void* VectorImpl::_grow(size_t where, size_t amount)
+{
+//    ALOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
+//        this, (int)where, (int)amount, (int)mCount, (int)capacity());
+
+    ALOG_ASSERT(where <= mCount,
+            "[%p] _grow: where=%d, amount=%d, count=%d",
+            this, (int)where, (int)amount, (int)mCount); // caller already checked
+
+    const size_t new_size = mCount + amount;
+    if (capacity() < new_size) {
+        const size_t new_capacity = max(kMinVectorCapacity, ((new_size*3)+1)/2);
+//        ALOGV("grow vector %p, new_capacity=%d", this, (int)new_capacity);
+        if ((mStorage) &&
+            (mCount==where) &&
+            (mFlags & HAS_TRIVIAL_COPY) &&
+            (mFlags & HAS_TRIVIAL_DTOR))
+        {
+            const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
+            SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
+            if (sb) {
+                mStorage = sb->data();
+            } else {
+                return NULL;
+            }
+        } else {
+            SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
+            if (sb) {
+                void* array = sb->data();
+                if (where != 0) {
+                    _do_copy(array, mStorage, where);
+                }
+                if (where != mCount) {
+                    const void* from = reinterpret_cast<const uint8_t *>(mStorage) + where*mItemSize;
+                    void* dest = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+                    _do_copy(dest, from, mCount-where);
+                }
+                release_storage();
+                mStorage = const_cast<void*>(array);
+            } else {
+                return NULL;
+            }
+        }
+    } else {
+        void* array = editArrayImpl();
+        if (where != mCount) {
+            const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize;
+            void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+            _do_move_forward(to, from, mCount - where);
+        }
+    }
+    mCount = new_size;
+    void* free_space = const_cast<void*>(itemLocation(where));
+    return free_space;
+}
+
+void VectorImpl::_shrink(size_t where, size_t amount)
+{
+    if (!mStorage)
+        return;
+
+//    ALOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
+//        this, (int)where, (int)amount, (int)mCount, (int)capacity());
+
+    ALOG_ASSERT(where + amount <= mCount,
+            "[%p] _shrink: where=%d, amount=%d, count=%d",
+            this, (int)where, (int)amount, (int)mCount); // caller already checked
+
+    const size_t new_size = mCount - amount;
+    if (new_size*3 < capacity()) {
+        const size_t new_capacity = max(kMinVectorCapacity, new_size*2);
+//        ALOGV("shrink vector %p, new_capacity=%d", this, (int)new_capacity);
+        if ((where == new_size) &&
+            (mFlags & HAS_TRIVIAL_COPY) &&
+            (mFlags & HAS_TRIVIAL_DTOR))
+        {
+            const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
+            SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
+            if (sb) {
+                mStorage = sb->data();
+            } else {
+                return;
+            }
+        } else {
+            SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
+            if (sb) {
+                void* array = sb->data();
+                if (where != 0) {
+                    _do_copy(array, mStorage, where);
+                }
+                if (where != new_size) {
+                    const void* from = reinterpret_cast<const uint8_t *>(mStorage) + (where+amount)*mItemSize;
+                    void* dest = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
+                    _do_copy(dest, from, new_size - where);
+                }
+                release_storage();
+                mStorage = const_cast<void*>(array);
+            } else{
+                return;
+            }
+        }
+    } else {
+        void* array = editArrayImpl();
+        void* to = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
+        _do_destroy(to, amount);
+        if (where != new_size) {
+            const void* from = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+            _do_move_backward(to, from, new_size - where);
+        }
+    }
+    mCount = new_size;
+}
+
+size_t VectorImpl::itemSize() const {
+    return mItemSize;
+}
+
+void VectorImpl::_do_construct(void* storage, size_t num) const
+{
+    if (!(mFlags & HAS_TRIVIAL_CTOR)) {
+        do_construct(storage, num);
+    }
+}
+
+void VectorImpl::_do_destroy(void* storage, size_t num) const
+{
+    if (!(mFlags & HAS_TRIVIAL_DTOR)) {
+        do_destroy(storage, num);
+    }
+}
+
+void VectorImpl::_do_copy(void* dest, const void* from, size_t num) const
+{
+    if (!(mFlags & HAS_TRIVIAL_COPY)) {
+        do_copy(dest, from, num);
+    } else {
+        memcpy(dest, from, num*itemSize());
+    }
+}
+
+void VectorImpl::_do_splat(void* dest, const void* item, size_t num) const {
+    do_splat(dest, item, num);
+}
+
+void VectorImpl::_do_move_forward(void* dest, const void* from, size_t num) const {
+    do_move_forward(dest, from, num);
+}
+
+void VectorImpl::_do_move_backward(void* dest, const void* from, size_t num) const {
+    do_move_backward(dest, from, num);
+}
+
+/*****************************************************************************/
+
+SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags)
+    : VectorImpl(itemSize, flags)
+{
+}
+
+SortedVectorImpl::SortedVectorImpl(const VectorImpl& rhs)
+: VectorImpl(rhs)
+{
+}
+
+SortedVectorImpl::~SortedVectorImpl()
+{
+}
+
+SortedVectorImpl& SortedVectorImpl::operator = (const SortedVectorImpl& rhs)
+{
+    return static_cast<SortedVectorImpl&>( VectorImpl::operator = (static_cast<const VectorImpl&>(rhs)) );
+}
+
+ssize_t SortedVectorImpl::indexOf(const void* item) const
+{
+    return _indexOrderOf(item);
+}
+
+size_t SortedVectorImpl::orderOf(const void* item) const
+{
+    size_t o;
+    _indexOrderOf(item, &o);
+    return o;
+}
+
+ssize_t SortedVectorImpl::_indexOrderOf(const void* item, size_t* order) const
+{
+    // binary search
+    ssize_t err = NAME_NOT_FOUND;
+    ssize_t l = 0;
+    ssize_t h = size()-1;
+    ssize_t mid;
+    const void* a = arrayImpl();
+    const size_t s = itemSize();
+    while (l <= h) {
+        mid = l + (h - l)/2;
+        const void* const curr = reinterpret_cast<const char *>(a) + (mid*s);
+        const int c = do_compare(curr, item);
+        if (c == 0) {
+            err = l = mid;
+            break;
+        } else if (c < 0) {
+            l = mid + 1;
+        } else {
+            h = mid - 1;
+        }
+    }
+    if (order) *order = l;
+    return err;
+}
+
+ssize_t SortedVectorImpl::add(const void* item)
+{
+    size_t order;
+    ssize_t index = _indexOrderOf(item, &order);
+    if (index < 0) {
+        index = VectorImpl::insertAt(item, order, 1);
+    } else {
+        index = VectorImpl::replaceAt(item, index);
+    }
+    return index;
+}
+
+ssize_t SortedVectorImpl::merge(const VectorImpl& vector)
+{
+    // naive merge...
+    if (!vector.isEmpty()) {
+        const void* buffer = vector.arrayImpl();
+        const size_t is = itemSize();
+        size_t s = vector.size();
+        for (size_t i=0 ; i<s ; i++) {
+            ssize_t err = add( reinterpret_cast<const char*>(buffer) + i*is );
+            if (err<0) {
+                return err;
+            }
+        }
+    }
+    return NO_ERROR;
+}
+
+ssize_t SortedVectorImpl::merge(const SortedVectorImpl& vector)
+{
+    // we've merging a sorted vector... nice!
+    ssize_t err = NO_ERROR;
+    if (!vector.isEmpty()) {
+        // first take care of the case where the vectors are sorted together
+        if (do_compare(vector.itemLocation(vector.size()-1), arrayImpl()) <= 0) {
+            err = VectorImpl::insertVectorAt(static_cast<const VectorImpl&>(vector), 0);
+        } else if (do_compare(vector.arrayImpl(), itemLocation(size()-1)) >= 0) {
+            err = VectorImpl::appendVector(static_cast<const VectorImpl&>(vector));
+        } else {
+            // this could be made a little better
+            err = merge(static_cast<const VectorImpl&>(vector));
+        }
+    }
+    return err;
+}
+
+ssize_t SortedVectorImpl::remove(const void* item)
+{
+    ssize_t i = indexOf(item);
+    if (i>=0) {
+        VectorImpl::removeItemsAt(i, 1);
+    }
+    return i;
+}
+
+/*****************************************************************************/
+
+}; // namespace android
+
diff --git a/libutils/misc.cpp b/libutils/misc.cpp
new file mode 100644
index 0000000..58eb499
--- /dev/null
+++ b/libutils/misc.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "misc"
+
+//
+// Miscellaneous utility functions.
+//
+#include <utils/misc.h>
+#include <utils/Log.h>
+
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#if defined(HAVE_PTHREADS)
+# include <pthread.h>
+#endif
+
+#include <utils/Vector.h>
+
+using namespace android;
+
+namespace android {
+
+struct sysprop_change_callback_info {
+    sysprop_change_callback callback;
+    int priority;
+};
+
+#if defined(HAVE_PTHREADS)
+static pthread_mutex_t gSyspropMutex = PTHREAD_MUTEX_INITIALIZER;
+static Vector<sysprop_change_callback_info>* gSyspropList = NULL;
+#endif
+
+void add_sysprop_change_callback(sysprop_change_callback cb, int priority) {
+#if defined(HAVE_PTHREADS)
+    pthread_mutex_lock(&gSyspropMutex);
+    if (gSyspropList == NULL) {
+        gSyspropList = new Vector<sysprop_change_callback_info>();
+    }
+    sysprop_change_callback_info info;
+    info.callback = cb;
+    info.priority = priority;
+    bool added = false;
+    for (size_t i=0; i<gSyspropList->size(); i++) {
+        if (priority >= gSyspropList->itemAt(i).priority) {
+            gSyspropList->insertAt(info, i);
+            added = true;
+            break;
+        }
+    }
+    if (!added) {
+        gSyspropList->add(info);
+    }
+    pthread_mutex_unlock(&gSyspropMutex);
+#endif
+}
+
+void report_sysprop_change() {
+#if defined(HAVE_PTHREADS)
+    pthread_mutex_lock(&gSyspropMutex);
+    Vector<sysprop_change_callback_info> listeners;
+    if (gSyspropList != NULL) {
+        listeners = *gSyspropList;
+    }
+    pthread_mutex_unlock(&gSyspropMutex);
+
+    //ALOGI("Reporting sysprop change to %d listeners", listeners.size());
+    for (size_t i=0; i<listeners.size(); i++) {
+        listeners[i].callback();
+    }
+#endif
+}
+
+}; // namespace android
diff --git a/libutils/primes.py b/libutils/primes.py
new file mode 100755
index 0000000..e161dd8
--- /dev/null
+++ b/libutils/primes.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python2.6
+#
+# Copyright (C) 2011 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.
+#
+
+#
+# Generates a table of prime numbers for use in BasicHashtable.cpp.
+#
+# Each prime is chosen such that it is a little more than twice as large as
+# the previous prime in the table.  This makes it easier to choose a new
+# hashtable size when the underlying array is grown by as nominal factor
+# of two each time.
+#
+
+def is_odd_prime(n):
+  limit = (n - 1) / 2
+  d = 3
+  while d <= limit:
+    if n % d == 0:
+      return False
+    d += 2
+  return True
+
+print "static size_t PRIMES[] = {"
+
+n = 5
+max = 2**31 - 1
+while n < max:
+  print "    %d," % (n)
+  n = n * 2 + 1
+  while not is_odd_prime(n):
+    n += 2
+
+print "    0,"
+print "};"
diff --git a/libutils/tests/Android.mk b/libutils/tests/Android.mk
new file mode 100644
index 0000000..caedaff
--- /dev/null
+++ b/libutils/tests/Android.mk
@@ -0,0 +1,34 @@
+# Build the unit tests.
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# Build the unit tests.
+test_src_files := \
+    BasicHashtable_test.cpp \
+    BlobCache_test.cpp \
+    BitSet_test.cpp \
+    Looper_test.cpp \
+    LruCache_test.cpp \
+    String8_test.cpp \
+    Unicode_test.cpp \
+    Vector_test.cpp
+
+shared_libraries := \
+    libz \
+    liblog \
+    libcutils \
+    libutils \
+    libstlport
+
+static_libraries := \
+    libgtest \
+    libgtest_main
+
+$(foreach file,$(test_src_files), \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+    $(eval LOCAL_SRC_FILES := $(file)) \
+    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+    $(eval include $(BUILD_NATIVE_TEST)) \
+)
diff --git a/libutils/tests/BasicHashtable_test.cpp b/libutils/tests/BasicHashtable_test.cpp
new file mode 100644
index 0000000..7dcf750
--- /dev/null
+++ b/libutils/tests/BasicHashtable_test.cpp
@@ -0,0 +1,577 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#define LOG_TAG "BasicHashtable_test"
+
+#include <utils/BasicHashtable.h>
+#include <cutils/log.h>
+#include <gtest/gtest.h>
+#include <unistd.h>
+
+namespace android {
+
+typedef int SimpleKey;
+typedef int SimpleValue;
+typedef key_value_pair_t<SimpleKey, SimpleValue> SimpleEntry;
+typedef BasicHashtable<SimpleKey, SimpleEntry> SimpleHashtable;
+
+struct ComplexKey {
+    int k;
+
+    explicit ComplexKey(int k) : k(k) {
+        instanceCount += 1;
+    }
+
+    ComplexKey(const ComplexKey& other) : k(other.k) {
+        instanceCount += 1;
+    }
+
+    ~ComplexKey() {
+        instanceCount -= 1;
+    }
+
+    bool operator ==(const ComplexKey& other) const {
+        return k == other.k;
+    }
+
+    bool operator !=(const ComplexKey& other) const {
+        return k != other.k;
+    }
+
+    static ssize_t instanceCount;
+};
+
+ssize_t ComplexKey::instanceCount = 0;
+
+template<> inline hash_t hash_type(const ComplexKey& value) {
+    return hash_type(value.k);
+}
+
+struct ComplexValue {
+    int v;
+
+    explicit ComplexValue(int v) : v(v) {
+        instanceCount += 1;
+    }
+
+    ComplexValue(const ComplexValue& other) : v(other.v) {
+        instanceCount += 1;
+    }
+
+    ~ComplexValue() {
+        instanceCount -= 1;
+    }
+
+    static ssize_t instanceCount;
+};
+
+ssize_t ComplexValue::instanceCount = 0;
+
+typedef key_value_pair_t<ComplexKey, ComplexValue> ComplexEntry;
+typedef BasicHashtable<ComplexKey, ComplexEntry> ComplexHashtable;
+
+class BasicHashtableTest : public testing::Test {
+protected:
+    virtual void SetUp() {
+        ComplexKey::instanceCount = 0;
+        ComplexValue::instanceCount = 0;
+    }
+
+    virtual void TearDown() {
+        ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0));
+    }
+
+    void assertInstanceCount(ssize_t keys, ssize_t values) {
+        if (keys != ComplexKey::instanceCount || values != ComplexValue::instanceCount) {
+            FAIL() << "Expected " << keys << " keys and " << values << " values "
+                    "but there were actually " << ComplexKey::instanceCount << " keys and "
+                    << ComplexValue::instanceCount << " values";
+        }
+    }
+
+public:
+    template <typename TKey, typename TEntry>
+    static void cookieAt(const BasicHashtable<TKey, TEntry>& h, size_t index,
+            bool* collision, bool* present, hash_t* hash) {
+        uint32_t cookie = h.cookieAt(index);
+        *collision = cookie & BasicHashtable<TKey, TEntry>::Bucket::COLLISION;
+        *present = cookie & BasicHashtable<TKey, TEntry>::Bucket::PRESENT;
+        *hash = cookie & BasicHashtable<TKey, TEntry>::Bucket::HASH_MASK;
+    }
+
+    template <typename TKey, typename TEntry>
+    static const void* getBuckets(const BasicHashtable<TKey, TEntry>& h) {
+        return h.mBuckets;
+    }
+};
+
+template <typename TKey, typename TValue>
+static size_t add(BasicHashtable<TKey, key_value_pair_t<TKey, TValue> >& h,
+        const TKey& key, const TValue& value) {
+    return h.add(hash_type(key), key_value_pair_t<TKey, TValue>(key, value));
+}
+
+template <typename TKey, typename TValue>
+static ssize_t find(BasicHashtable<TKey, key_value_pair_t<TKey, TValue> >& h,
+        ssize_t index, const TKey& key) {
+    return h.find(index, hash_type(key), key);
+}
+
+template <typename TKey, typename TValue>
+static bool remove(BasicHashtable<TKey, key_value_pair_t<TKey, TValue> >& h,
+        const TKey& key) {
+    ssize_t index = find(h, -1, key);
+    if (index >= 0) {
+        h.removeAt(index);
+        return true;
+    }
+    return false;
+}
+
+template <typename TEntry>
+static void getKeyValue(const TEntry& entry, int* key, int* value);
+
+template <> void getKeyValue(const SimpleEntry& entry, int* key, int* value) {
+    *key = entry.key;
+    *value = entry.value;
+}
+
+template <> void getKeyValue(const ComplexEntry& entry, int* key, int* value) {
+    *key = entry.key.k;
+    *value = entry.value.v;
+}
+
+template <typename TKey, typename TValue>
+static void dump(BasicHashtable<TKey, key_value_pair_t<TKey, TValue> >& h) {
+    ALOGD("hashtable %p, size=%u, capacity=%u, bucketCount=%u",
+            &h, h.size(), h.capacity(), h.bucketCount());
+    for (size_t i = 0; i < h.bucketCount(); i++) {
+        bool collision, present;
+        hash_t hash;
+        BasicHashtableTest::cookieAt(h, i, &collision, &present, &hash);
+        if (present) {
+            int key, value;
+            getKeyValue(h.entryAt(i), &key, &value);
+            ALOGD("  [%3u] = collision=%d, present=%d, hash=0x%08x, key=%3d, value=%3d, "
+                    "hash_type(key)=0x%08x",
+                    i, collision, present, hash, key, value, hash_type(key));
+        } else {
+            ALOGD("  [%3u] = collision=%d, present=%d",
+                    i, collision, present);
+        }
+    }
+}
+
+TEST_F(BasicHashtableTest, DefaultConstructor_WithDefaultProperties) {
+    SimpleHashtable h;
+
+    EXPECT_EQ(0U, h.size());
+    EXPECT_EQ(3U, h.capacity());
+    EXPECT_EQ(5U, h.bucketCount());
+    EXPECT_EQ(0.75f, h.loadFactor());
+}
+
+TEST_F(BasicHashtableTest, Constructor_WithNonUnityLoadFactor) {
+    SimpleHashtable h(52, 0.8f);
+
+    EXPECT_EQ(0U, h.size());
+    EXPECT_EQ(77U, h.capacity());
+    EXPECT_EQ(97U, h.bucketCount());
+    EXPECT_EQ(0.8f, h.loadFactor());
+}
+
+TEST_F(BasicHashtableTest, Constructor_WithUnityLoadFactorAndExactCapacity) {
+    SimpleHashtable h(46, 1.0f);
+
+    EXPECT_EQ(0U, h.size());
+    EXPECT_EQ(46U, h.capacity()); // must be one less than bucketCount because loadFactor == 1.0f
+    EXPECT_EQ(47U, h.bucketCount());
+    EXPECT_EQ(1.0f, h.loadFactor());
+}
+
+TEST_F(BasicHashtableTest, Constructor_WithUnityLoadFactorAndInexactCapacity) {
+    SimpleHashtable h(42, 1.0f);
+
+    EXPECT_EQ(0U, h.size());
+    EXPECT_EQ(46U, h.capacity()); // must be one less than bucketCount because loadFactor == 1.0f
+    EXPECT_EQ(47U, h.bucketCount());
+    EXPECT_EQ(1.0f, h.loadFactor());
+}
+
+TEST_F(BasicHashtableTest, FindAddFindRemoveFind_OneEntry) {
+    SimpleHashtable h;
+    ssize_t index = find(h, -1, 8);
+    ASSERT_EQ(-1, index);
+
+    index = add(h, 8, 1);
+    ASSERT_EQ(1U, h.size());
+
+    ASSERT_EQ(index, find(h, -1, 8));
+    ASSERT_EQ(8, h.entryAt(index).key);
+    ASSERT_EQ(1, h.entryAt(index).value);
+
+    index = find(h, index, 8);
+    ASSERT_EQ(-1, index);
+
+    ASSERT_TRUE(remove(h, 8));
+    ASSERT_EQ(0U, h.size());
+
+    index = find(h, -1, 8);
+    ASSERT_EQ(-1, index);
+}
+
+TEST_F(BasicHashtableTest, FindAddFindRemoveFind_MultipleEntryWithUniqueKey) {
+    const size_t N = 11;
+
+    SimpleHashtable h;
+    for (size_t i = 0; i < N; i++) {
+        ssize_t index = find(h, -1, int(i));
+        ASSERT_EQ(-1, index);
+
+        index = add(h, int(i), int(i * 10));
+        ASSERT_EQ(i + 1, h.size());
+
+        ASSERT_EQ(index, find(h, -1, int(i)));
+        ASSERT_EQ(int(i), h.entryAt(index).key);
+        ASSERT_EQ(int(i * 10), h.entryAt(index).value);
+
+        index = find(h, index, int(i));
+        ASSERT_EQ(-1, index);
+    }
+
+    for (size_t i = N; --i > 0; ) {
+        ASSERT_TRUE(remove(h, int(i))) << "i = " << i;
+        ASSERT_EQ(i, h.size());
+
+        ssize_t index = find(h, -1, int(i));
+        ASSERT_EQ(-1, index);
+    }
+}
+
+TEST_F(BasicHashtableTest, FindAddFindRemoveFind_MultipleEntryWithDuplicateKey) {
+    const size_t N = 11;
+    const int K = 1;
+
+    SimpleHashtable h;
+    for (size_t i = 0; i < N; i++) {
+        ssize_t index = find(h, -1, K);
+        if (i == 0) {
+            ASSERT_EQ(-1, index);
+        } else {
+            ASSERT_NE(-1, index);
+        }
+
+        add(h, K, int(i));
+        ASSERT_EQ(i + 1, h.size());
+
+        index = -1;
+        int values = 0;
+        for (size_t j = 0; j <= i; j++) {
+            index = find(h, index, K);
+            ASSERT_GE(index, 0);
+            ASSERT_EQ(K, h.entryAt(index).key);
+            values |= 1 << h.entryAt(index).value;
+        }
+        ASSERT_EQ(values, (1 << (i + 1)) - 1);
+
+        index = find(h, index, K);
+        ASSERT_EQ(-1, index);
+    }
+
+    for (size_t i = N; --i > 0; ) {
+        ASSERT_TRUE(remove(h, K)) << "i = " << i;
+        ASSERT_EQ(i, h.size());
+
+        ssize_t index = -1;
+        for (size_t j = 0; j < i; j++) {
+            index = find(h, index, K);
+            ASSERT_GE(index, 0);
+            ASSERT_EQ(K, h.entryAt(index).key);
+        }
+
+        index = find(h, index, K);
+        ASSERT_EQ(-1, index);
+    }
+}
+
+TEST_F(BasicHashtableTest, Clear_WhenAlreadyEmpty_DoesNothing) {
+    SimpleHashtable h;
+    h.clear();
+
+    EXPECT_EQ(0U, h.size());
+    EXPECT_EQ(3U, h.capacity());
+    EXPECT_EQ(5U, h.bucketCount());
+    EXPECT_EQ(0.75f, h.loadFactor());
+}
+
+TEST_F(BasicHashtableTest, Clear_AfterElementsAdded_RemovesThem) {
+    SimpleHashtable h;
+    add(h, 0, 0);
+    add(h, 1, 0);
+    h.clear();
+
+    EXPECT_EQ(0U, h.size());
+    EXPECT_EQ(3U, h.capacity());
+    EXPECT_EQ(5U, h.bucketCount());
+    EXPECT_EQ(0.75f, h.loadFactor());
+}
+
+TEST_F(BasicHashtableTest, Clear_AfterElementsAdded_DestroysThem) {
+    ComplexHashtable h;
+    add(h, ComplexKey(0), ComplexValue(0));
+    add(h, ComplexKey(1), ComplexValue(0));
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2));
+
+    h.clear();
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0));
+
+    EXPECT_EQ(0U, h.size());
+    EXPECT_EQ(3U, h.capacity());
+    EXPECT_EQ(5U, h.bucketCount());
+    EXPECT_EQ(0.75f, h.loadFactor());
+}
+
+TEST_F(BasicHashtableTest, Remove_AfterElementsAdded_DestroysThem) {
+    ComplexHashtable h;
+    add(h, ComplexKey(0), ComplexValue(0));
+    add(h, ComplexKey(1), ComplexValue(0));
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2));
+
+    ASSERT_TRUE(remove(h, ComplexKey(0)));
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(1, 1));
+
+    ASSERT_TRUE(remove(h, ComplexKey(1)));
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0));
+
+    EXPECT_EQ(0U, h.size());
+    EXPECT_EQ(3U, h.capacity());
+    EXPECT_EQ(5U, h.bucketCount());
+    EXPECT_EQ(0.75f, h.loadFactor());
+}
+
+TEST_F(BasicHashtableTest, Destructor_AfterElementsAdded_DestroysThem) {
+    {
+        ComplexHashtable h;
+        add(h, ComplexKey(0), ComplexValue(0));
+        add(h, ComplexKey(1), ComplexValue(0));
+        ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2));
+    } // h is destroyed here
+
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0));
+}
+
+TEST_F(BasicHashtableTest, Next_WhenEmpty_ReturnsMinusOne) {
+    SimpleHashtable h;
+
+    ASSERT_EQ(-1, h.next(-1));
+}
+
+TEST_F(BasicHashtableTest, Next_WhenNonEmpty_IteratesOverAllEntries) {
+    const int N = 88;
+
+    SimpleHashtable h;
+    for (int i = 0; i < N; i++) {
+        add(h, i, i * 10);
+    }
+
+    bool set[N];
+    memset(set, 0, sizeof(bool) * N);
+    int count = 0;
+    for (ssize_t index = -1; (index = h.next(index)) != -1; ) {
+        ASSERT_GE(index, 0);
+        ASSERT_LT(size_t(index), h.bucketCount());
+
+        const SimpleEntry& entry = h.entryAt(index);
+        ASSERT_GE(entry.key, 0);
+        ASSERT_LT(entry.key, N);
+        ASSERT_EQ(false, set[entry.key]);
+        ASSERT_EQ(entry.key * 10, entry.value);
+
+        set[entry.key] = true;
+        count += 1;
+    }
+    ASSERT_EQ(N, count);
+}
+
+TEST_F(BasicHashtableTest, Add_RehashesOnDemand) {
+    SimpleHashtable h;
+    size_t initialCapacity = h.capacity();
+    size_t initialBucketCount = h.bucketCount();
+
+    for (size_t i = 0; i < initialCapacity; i++) {
+        add(h, int(i), 0);
+    }
+
+    EXPECT_EQ(initialCapacity, h.size());
+    EXPECT_EQ(initialCapacity, h.capacity());
+    EXPECT_EQ(initialBucketCount, h.bucketCount());
+
+    add(h, -1, -1);
+
+    EXPECT_EQ(initialCapacity + 1, h.size());
+    EXPECT_GT(h.capacity(), initialCapacity);
+    EXPECT_GT(h.bucketCount(), initialBucketCount);
+    EXPECT_GT(h.bucketCount(), h.capacity());
+}
+
+TEST_F(BasicHashtableTest, Rehash_WhenCapacityAndBucketCountUnchanged_DoesNothing) {
+    ComplexHashtable h;
+    add(h, ComplexKey(0), ComplexValue(0));
+    const void* oldBuckets = getBuckets(h);
+    ASSERT_NE((void*)NULL, oldBuckets);
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(1, 1));
+
+    h.rehash(h.capacity(), h.loadFactor());
+
+    ASSERT_EQ(oldBuckets, getBuckets(h));
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(1, 1));
+}
+
+TEST_F(BasicHashtableTest, Rehash_WhenEmptyAndHasNoBuckets_ButDoesNotAllocateBuckets) {
+    ComplexHashtable h;
+    ASSERT_EQ((void*)NULL, getBuckets(h));
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0));
+
+    h.rehash(9, 1.0f);
+
+    EXPECT_EQ(0U, h.size());
+    EXPECT_EQ(10U, h.capacity());
+    EXPECT_EQ(11U, h.bucketCount());
+    EXPECT_EQ(1.0f, h.loadFactor());
+    EXPECT_EQ((void*)NULL, getBuckets(h));
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0));
+}
+
+TEST_F(BasicHashtableTest, Rehash_WhenEmptyAndHasBuckets_ReleasesBucketsAndSetsCapacity) {
+    ComplexHashtable h(10);
+    add(h, ComplexKey(0), ComplexValue(0));
+    ASSERT_TRUE(remove(h, ComplexKey(0)));
+    ASSERT_NE((void*)NULL, getBuckets(h));
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0));
+
+    h.rehash(0, 0.75f);
+
+    EXPECT_EQ(0U, h.size());
+    EXPECT_EQ(3U, h.capacity());
+    EXPECT_EQ(5U, h.bucketCount());
+    EXPECT_EQ(0.75f, h.loadFactor());
+    EXPECT_EQ((void*)NULL, getBuckets(h));
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0));
+}
+
+TEST_F(BasicHashtableTest, Rehash_WhenLessThanCurrentCapacity_ShrinksBuckets) {
+    ComplexHashtable h(10);
+    add(h, ComplexKey(0), ComplexValue(0));
+    add(h, ComplexKey(1), ComplexValue(1));
+    const void* oldBuckets = getBuckets(h);
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2));
+
+    h.rehash(0, 0.75f);
+
+    EXPECT_EQ(2U, h.size());
+    EXPECT_EQ(3U, h.capacity());
+    EXPECT_EQ(5U, h.bucketCount());
+    EXPECT_EQ(0.75f, h.loadFactor());
+    EXPECT_NE(oldBuckets, getBuckets(h));
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2));
+}
+
+TEST_F(BasicHashtableTest, CopyOnWrite) {
+    ComplexHashtable h1;
+    add(h1, ComplexKey(0), ComplexValue(0));
+    add(h1, ComplexKey(1), ComplexValue(1));
+    const void* originalBuckets = getBuckets(h1);
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2));
+    ssize_t index0 = find(h1, -1, ComplexKey(0));
+    EXPECT_GE(index0, 0);
+
+    // copy constructor acquires shared reference
+    ComplexHashtable h2(h1);
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2));
+    ASSERT_EQ(originalBuckets, getBuckets(h2));
+    EXPECT_EQ(h1.size(), h2.size());
+    EXPECT_EQ(h1.capacity(), h2.capacity());
+    EXPECT_EQ(h1.bucketCount(), h2.bucketCount());
+    EXPECT_EQ(h1.loadFactor(), h2.loadFactor());
+    EXPECT_EQ(index0, find(h2, -1, ComplexKey(0)));
+
+    // operator= acquires shared reference
+    ComplexHashtable h3;
+    h3 = h2;
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2));
+    ASSERT_EQ(originalBuckets, getBuckets(h3));
+    EXPECT_EQ(h1.size(), h3.size());
+    EXPECT_EQ(h1.capacity(), h3.capacity());
+    EXPECT_EQ(h1.bucketCount(), h3.bucketCount());
+    EXPECT_EQ(h1.loadFactor(), h3.loadFactor());
+    EXPECT_EQ(index0, find(h3, -1, ComplexKey(0)));
+
+    // editEntryAt copies shared contents
+    h1.editEntryAt(index0).value.v = 42;
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(4, 4));
+    ASSERT_NE(originalBuckets, getBuckets(h1));
+    EXPECT_EQ(42, h1.entryAt(index0).value.v);
+    EXPECT_EQ(0, h2.entryAt(index0).value.v);
+    EXPECT_EQ(0, h3.entryAt(index0).value.v);
+
+    // clear releases reference to shared contents
+    h2.clear();
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(4, 4));
+    EXPECT_EQ(0U, h2.size());
+    ASSERT_NE(originalBuckets, getBuckets(h2));
+
+    // operator= acquires shared reference, destroys unshared contents
+    h1 = h3;
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2));
+    ASSERT_EQ(originalBuckets, getBuckets(h1));
+    EXPECT_EQ(h3.size(), h1.size());
+    EXPECT_EQ(h3.capacity(), h1.capacity());
+    EXPECT_EQ(h3.bucketCount(), h1.bucketCount());
+    EXPECT_EQ(h3.loadFactor(), h1.loadFactor());
+    EXPECT_EQ(index0, find(h1, -1, ComplexKey(0)));
+
+    // add copies shared contents
+    add(h1, ComplexKey(2), ComplexValue(2));
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(5, 5));
+    ASSERT_NE(originalBuckets, getBuckets(h1));
+    EXPECT_EQ(3U, h1.size());
+    EXPECT_EQ(0U, h2.size());
+    EXPECT_EQ(2U, h3.size());
+
+    // remove copies shared contents
+    h1 = h3;
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2));
+    ASSERT_EQ(originalBuckets, getBuckets(h1));
+    h1.removeAt(index0);
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(3, 3));
+    ASSERT_NE(originalBuckets, getBuckets(h1));
+    EXPECT_EQ(1U, h1.size());
+    EXPECT_EQ(0U, h2.size());
+    EXPECT_EQ(2U, h3.size());
+
+    // rehash copies shared contents
+    h1 = h3;
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2));
+    ASSERT_EQ(originalBuckets, getBuckets(h1));
+    h1.rehash(10, 1.0f);
+    ASSERT_NO_FATAL_FAILURE(assertInstanceCount(4, 4));
+    ASSERT_NE(originalBuckets, getBuckets(h1));
+    EXPECT_EQ(2U, h1.size());
+    EXPECT_EQ(0U, h2.size());
+    EXPECT_EQ(2U, h3.size());
+}
+
+} // namespace android
diff --git a/libutils/tests/BitSet_test.cpp b/libutils/tests/BitSet_test.cpp
new file mode 100644
index 0000000..752e56d
--- /dev/null
+++ b/libutils/tests/BitSet_test.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#define LOG_TAG "BitSet_test"
+
+#include <utils/BitSet.h>
+#include <cutils/log.h>
+#include <gtest/gtest.h>
+#include <unistd.h>
+
+namespace android {
+
+class BitSetTest : public testing::Test {
+protected:
+    BitSet32 b1;
+    BitSet32 b2;
+    virtual void TearDown() {
+        b1.clear();
+        b2.clear();
+    }
+};
+
+
+TEST_F(BitSetTest, BitWiseOr) {
+    b1.markBit(2);
+    b2.markBit(4);
+
+    BitSet32 tmp = b1 | b2;
+    EXPECT_EQ(tmp.count(), 2u);
+    EXPECT_TRUE(tmp.hasBit(2) && tmp.hasBit(4));
+    // Check that the operator is symmetric
+    EXPECT_TRUE((b2 | b1) == (b1 | b2));
+
+    b1 |= b2;
+    EXPECT_EQ(b1.count(), 2u);
+    EXPECT_TRUE(b1.hasBit(2) && b1.hasBit(4));
+    EXPECT_TRUE(b2.hasBit(4) && b2.count() == 1u);
+}
+TEST_F(BitSetTest, BitWiseAnd_Disjoint) {
+    b1.markBit(2);
+    b1.markBit(4);
+    b1.markBit(6);
+
+    BitSet32 tmp = b1 & b2;
+    EXPECT_TRUE(tmp.isEmpty());
+    // Check that the operator is symmetric
+    EXPECT_TRUE((b2 & b1) == (b1 & b2));
+
+    b2 &= b1;
+    EXPECT_TRUE(b2.isEmpty());
+    EXPECT_EQ(b1.count(), 3u);
+    EXPECT_TRUE(b1.hasBit(2) && b1.hasBit(4) && b1.hasBit(6));
+}
+
+TEST_F(BitSetTest, BitWiseAnd_NonDisjoint) {
+    b1.markBit(2);
+    b1.markBit(4);
+    b1.markBit(6);
+    b2.markBit(3);
+    b2.markBit(6);
+    b2.markBit(9);
+
+    BitSet32 tmp = b1 & b2;
+    EXPECT_EQ(tmp.count(), 1u);
+    EXPECT_TRUE(tmp.hasBit(6));
+    // Check that the operator is symmetric
+    EXPECT_TRUE((b2 & b1) == (b1 & b2));
+
+    b1 &= b2;
+    EXPECT_EQ(b1.count(), 1u);
+    EXPECT_EQ(b2.count(), 3u);
+    EXPECT_TRUE(b2.hasBit(3) && b2.hasBit(6) && b2.hasBit(9));
+}
+} // namespace android
diff --git a/libutils/tests/BlobCache_test.cpp b/libutils/tests/BlobCache_test.cpp
new file mode 100644
index 0000000..7202123
--- /dev/null
+++ b/libutils/tests/BlobCache_test.cpp
@@ -0,0 +1,421 @@
+/*
+ ** Copyright 2011, 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 <fcntl.h>
+#include <stdio.h>
+
+#include <gtest/gtest.h>
+
+#include <utils/BlobCache.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class BlobCacheTest : public ::testing::Test {
+protected:
+    enum {
+        MAX_KEY_SIZE = 6,
+        MAX_VALUE_SIZE = 8,
+        MAX_TOTAL_SIZE = 13,
+    };
+
+    virtual void SetUp() {
+        mBC = new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE);
+    }
+
+    virtual void TearDown() {
+        mBC.clear();
+    }
+
+    sp<BlobCache> mBC;
+};
+
+TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+    ASSERT_EQ('e', buf[0]);
+    ASSERT_EQ('f', buf[1]);
+    ASSERT_EQ('g', buf[2]);
+    ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
+    char buf[2] = { 0xee, 0xee };
+    mBC->set("ab", 2, "cd", 2);
+    mBC->set("ef", 2, "gh", 2);
+    ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
+    ASSERT_EQ('c', buf[0]);
+    ASSERT_EQ('d', buf[1]);
+    ASSERT_EQ(size_t(2), mBC->get("ef", 2, buf, 2));
+    ASSERT_EQ('g', buf[0]);
+    ASSERT_EQ('h', buf[1]);
+}
+
+TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
+    char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4));
+    ASSERT_EQ(0xee, buf[0]);
+    ASSERT_EQ('e', buf[1]);
+    ASSERT_EQ('f', buf[2]);
+    ASSERT_EQ('g', buf[3]);
+    ASSERT_EQ('h', buf[4]);
+    ASSERT_EQ(0xee, buf[5]);
+}
+
+TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
+    char buf[3] = { 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
+    ASSERT_EQ(0xee, buf[0]);
+    ASSERT_EQ(0xee, buf[1]);
+    ASSERT_EQ(0xee, buf[2]);
+}
+
+TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    mBC->set("abcd", 4, "ijkl", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+    ASSERT_EQ('i', buf[0]);
+    ASSERT_EQ('j', buf[1]);
+    ASSERT_EQ('k', buf[2]);
+    ASSERT_EQ('l', buf[3]);
+}
+
+TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
+    char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+    ASSERT_EQ('e', buf[0]);
+    ASSERT_EQ('f', buf[1]);
+    ASSERT_EQ('g', buf[2]);
+    ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) {
+    char key[MAX_KEY_SIZE+1];
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    for (int i = 0; i < MAX_KEY_SIZE+1; i++) {
+        key[i] = 'a';
+    }
+    mBC->set(key, MAX_KEY_SIZE+1, "bbbb", 4);
+    ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE+1, buf, 4));
+    ASSERT_EQ(0xee, buf[0]);
+    ASSERT_EQ(0xee, buf[1]);
+    ASSERT_EQ(0xee, buf[2]);
+    ASSERT_EQ(0xee, buf[3]);
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfValueIsTooBig) {
+    char buf[MAX_VALUE_SIZE+1];
+    for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+        buf[i] = 'b';
+    }
+    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
+    for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+        buf[i] = 0xee;
+    }
+    ASSERT_EQ(size_t(0), mBC->get("abcd", 4, buf, MAX_VALUE_SIZE+1));
+    for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+        SCOPED_TRACE(i);
+        ASSERT_EQ(0xee, buf[i]);
+    }
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfKeyValuePairIsTooBig) {
+    // Check a testing assumptions
+    ASSERT_TRUE(MAX_TOTAL_SIZE < MAX_KEY_SIZE + MAX_VALUE_SIZE);
+    ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+    enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE + 1 };
+
+    char key[MAX_KEY_SIZE];
+    char buf[bufSize];
+    for (int i = 0; i < MAX_KEY_SIZE; i++) {
+        key[i] = 'a';
+    }
+    for (int i = 0; i < bufSize; i++) {
+        buf[i] = 'b';
+    }
+
+    mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE);
+    ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
+    char key[MAX_KEY_SIZE];
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    for (int i = 0; i < MAX_KEY_SIZE; i++) {
+        key[i] = 'a';
+    }
+    mBC->set(key, MAX_KEY_SIZE, "wxyz", 4);
+    ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4));
+    ASSERT_EQ('w', buf[0]);
+    ASSERT_EQ('x', buf[1]);
+    ASSERT_EQ('y', buf[2]);
+    ASSERT_EQ('z', buf[3]);
+}
+
+TEST_F(BlobCacheTest, CacheMaxValueSizeSucceeds) {
+    char buf[MAX_VALUE_SIZE];
+    for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+        buf[i] = 'b';
+    }
+    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE);
+    for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+        buf[i] = 0xee;
+    }
+    ASSERT_EQ(size_t(MAX_VALUE_SIZE), mBC->get("abcd", 4, buf,
+            MAX_VALUE_SIZE));
+    for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+        SCOPED_TRACE(i);
+        ASSERT_EQ('b', buf[i]);
+    }
+}
+
+TEST_F(BlobCacheTest, CacheMaxKeyValuePairSizeSucceeds) {
+    // Check a testing assumption
+    ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+    enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE };
+
+    char key[MAX_KEY_SIZE];
+    char buf[bufSize];
+    for (int i = 0; i < MAX_KEY_SIZE; i++) {
+        key[i] = 'a';
+    }
+    for (int i = 0; i < bufSize; i++) {
+        buf[i] = 'b';
+    }
+
+    mBC->set(key, MAX_KEY_SIZE, buf, bufSize);
+    ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
+    char buf[1] = { 0xee };
+    mBC->set("x", 1, "y", 1);
+    ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
+    ASSERT_EQ('y', buf[0]);
+}
+
+TEST_F(BlobCacheTest, CacheSizeDoesntExceedTotalLimit) {
+    for (int i = 0; i < 256; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, "x", 1);
+    }
+    int numCached = 0;
+    for (int i = 0; i < 256; i++) {
+        uint8_t k = i;
+        if (mBC->get(&k, 1, NULL, 0) == 1) {
+            numCached++;
+        }
+    }
+    ASSERT_GE(MAX_TOTAL_SIZE / 2, numCached);
+}
+
+TEST_F(BlobCacheTest, ExceedingTotalLimitHalvesCacheSize) {
+    // Fill up the entire cache with 1 char key/value pairs.
+    const int maxEntries = MAX_TOTAL_SIZE / 2;
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, "x", 1);
+    }
+    // Insert one more entry, causing a cache overflow.
+    {
+        uint8_t k = maxEntries;
+        mBC->set(&k, 1, "x", 1);
+    }
+    // Count the number of entries in the cache.
+    int numCached = 0;
+    for (int i = 0; i < maxEntries+1; i++) {
+        uint8_t k = i;
+        if (mBC->get(&k, 1, NULL, 0) == 1) {
+            numCached++;
+        }
+    }
+    ASSERT_EQ(maxEntries/2 + 1, numCached);
+}
+
+class BlobCacheFlattenTest : public BlobCacheTest {
+protected:
+    virtual void SetUp() {
+        BlobCacheTest::SetUp();
+        mBC2 = new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE);
+    }
+
+    virtual void TearDown() {
+        mBC2.clear();
+        BlobCacheTest::TearDown();
+    }
+
+    void roundTrip() {
+        size_t size = mBC->getFlattenedSize();
+        uint8_t* flat = new uint8_t[size];
+        ASSERT_EQ(OK, mBC->flatten(flat, size));
+        ASSERT_EQ(OK, mBC2->unflatten(flat, size));
+        delete[] flat;
+    }
+
+    sp<BlobCache> mBC2;
+};
+
+TEST_F(BlobCacheFlattenTest, FlattenOneValue) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    roundTrip();
+    ASSERT_EQ(size_t(4), mBC2->get("abcd", 4, buf, 4));
+    ASSERT_EQ('e', buf[0]);
+    ASSERT_EQ('f', buf[1]);
+    ASSERT_EQ('g', buf[2]);
+    ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheFlattenTest, FlattenFullCache) {
+    // Fill up the entire cache with 1 char key/value pairs.
+    const int maxEntries = MAX_TOTAL_SIZE / 2;
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, &k, 1);
+    }
+
+    roundTrip();
+
+    // Verify the deserialized cache
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        uint8_t v = 0xee;
+        ASSERT_EQ(size_t(1), mBC2->get(&k, 1, &v, 1));
+        ASSERT_EQ(k, v);
+    }
+}
+
+TEST_F(BlobCacheFlattenTest, FlattenDoesntChangeCache) {
+    // Fill up the entire cache with 1 char key/value pairs.
+    const int maxEntries = MAX_TOTAL_SIZE / 2;
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, &k, 1);
+    }
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size));
+    delete[] flat;
+
+    // Verify the cache that we just serialized
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        uint8_t v = 0xee;
+        ASSERT_EQ(size_t(1), mBC->get(&k, 1, &v, 1));
+        ASSERT_EQ(k, v);
+    }
+}
+
+TEST_F(BlobCacheFlattenTest, FlattenCatchesBufferTooSmall) {
+    // Fill up the entire cache with 1 char key/value pairs.
+    const int maxEntries = MAX_TOTAL_SIZE / 2;
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, &k, 1);
+    }
+
+    size_t size = mBC->getFlattenedSize() - 1;
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(BAD_VALUE, mBC->flatten(flat, size));
+    delete[] flat;
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size));
+    flat[1] = ~flat[1];
+
+    // Bad magic should cause an error.
+    ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size));
+    delete[] flat;
+
+    // The error should cause the unflatten to result in an empty cache
+    ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheVersion) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size));
+    flat[5] = ~flat[5];
+
+    // Version mismatches shouldn't cause errors, but should not use the
+    // serialized entries
+    ASSERT_EQ(OK, mBC2->unflatten(flat, size));
+    delete[] flat;
+
+    // The version mismatch should cause the unflatten to result in an empty
+    // cache
+    ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheDeviceVersion) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size));
+    flat[10] = ~flat[10];
+
+    // Version mismatches shouldn't cause errors, but should not use the
+    // serialized entries
+    ASSERT_EQ(OK, mBC2->unflatten(flat, size));
+    delete[] flat;
+
+    // The version mismatch should cause the unflatten to result in an empty
+    // cache
+    ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBufferTooSmall) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size));
+
+    // A buffer truncation shouldt cause an error
+    ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1));
+    delete[] flat;
+
+    // The error should cause the unflatten to result in an empty cache
+    ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+} // namespace android
diff --git a/libutils/tests/Looper_test.cpp b/libutils/tests/Looper_test.cpp
new file mode 100644
index 0000000..8bf2ba2
--- /dev/null
+++ b/libutils/tests/Looper_test.cpp
@@ -0,0 +1,693 @@
+//
+// Copyright 2010 The Android Open Source Project
+//
+
+#include <utils/Looper.h>
+#include <utils/Timers.h>
+#include <utils/StopWatch.h>
+#include <gtest/gtest.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "TestHelpers.h"
+
+// # of milliseconds to fudge stopwatch measurements
+#define TIMING_TOLERANCE_MS 25
+
+namespace android {
+
+enum {
+    MSG_TEST1 = 1,
+    MSG_TEST2 = 2,
+    MSG_TEST3 = 3,
+    MSG_TEST4 = 4,
+};
+
+class DelayedWake : public DelayedTask {
+    sp<Looper> mLooper;
+
+public:
+    DelayedWake(int delayMillis, const sp<Looper> looper) :
+        DelayedTask(delayMillis), mLooper(looper) {
+    }
+
+protected:
+    virtual void doTask() {
+        mLooper->wake();
+    }
+};
+
+class DelayedWriteSignal : public DelayedTask {
+    Pipe* mPipe;
+
+public:
+    DelayedWriteSignal(int delayMillis, Pipe* pipe) :
+        DelayedTask(delayMillis), mPipe(pipe) {
+    }
+
+protected:
+    virtual void doTask() {
+        mPipe->writeSignal();
+    }
+};
+
+class CallbackHandler {
+public:
+    void setCallback(const sp<Looper>& looper, int fd, int events) {
+        looper->addFd(fd, 0, events, staticHandler, this);
+    }
+
+protected:
+    virtual ~CallbackHandler() { }
+
+    virtual int handler(int fd, int events) = 0;
+
+private:
+    static int staticHandler(int fd, int events, void* data) {
+        return static_cast<CallbackHandler*>(data)->handler(fd, events);
+    }
+};
+
+class StubCallbackHandler : public CallbackHandler {
+public:
+    int nextResult;
+    int callbackCount;
+
+    int fd;
+    int events;
+
+    StubCallbackHandler(int nextResult) : nextResult(nextResult),
+            callbackCount(0), fd(-1), events(-1) {
+    }
+
+protected:
+    virtual int handler(int fd, int events) {
+        callbackCount += 1;
+        this->fd = fd;
+        this->events = events;
+        return nextResult;
+    }
+};
+
+class StubMessageHandler : public MessageHandler {
+public:
+    Vector<Message> messages;
+
+    virtual void handleMessage(const Message& message) {
+        messages.push(message);
+    }
+};
+
+class LooperTest : public testing::Test {
+protected:
+    sp<Looper> mLooper;
+
+    virtual void SetUp() {
+        mLooper = new Looper(true);
+    }
+
+    virtual void TearDown() {
+        mLooper.clear();
+    }
+};
+
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeout) {
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal timeout";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturns) {
+    mLooper->wake();
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because wake() was called before waiting";
+    EXPECT_EQ(ALOOPER_POLL_WAKE, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because loop was awoken";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturns) {
+    sp<DelayedWake> delayedWake = new DelayedWake(100, mLooper);
+    delayedWake->run();
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal wake delay";
+    EXPECT_EQ(ALOOPER_POLL_WAKE, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because loop was awoken";
+}
+
+TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturns) {
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+}
+
+TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+    EXPECT_EQ(0, handler.callbackCount)
+            << "callback should not have been invoked because FD was not signalled";
+}
+
+TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCallbackAndReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    ASSERT_EQ(OK, pipe.writeSignal());
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should be invoked exactly once";
+    EXPECT_EQ(pipe.receiveFd, handler.fd)
+            << "callback should have received pipe fd as parameter";
+    EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
+            << "callback should have received ALOOPER_EVENT_INPUT as events";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNoSignalledFDs_WaitsForTimeoutAndReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal timeout";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+    EXPECT_EQ(0, handler.callbackCount)
+            << "callback should not have been invoked because FD was not signalled";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_ImmediatelyInvokesCallbackAndReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    pipe.writeSignal();
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should be invoked exactly once";
+    EXPECT_EQ(pipe.receiveFd, handler.fd)
+            << "callback should have received pipe fd as parameter";
+    EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
+            << "callback should have received ALOOPER_EVENT_INPUT as events";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_PromptlyInvokesCallbackAndReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+    sp<DelayedWriteSignal> delayedWriteSignal = new DelayedWriteSignal(100, & pipe);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+    delayedWriteSignal->run();
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal signal delay";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should be invoked exactly once";
+    EXPECT_EQ(pipe.receiveFd, handler.fd)
+            << "callback should have received pipe fd as parameter";
+    EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
+            << "callback should have received ALOOPER_EVENT_INPUT as events";
+}
+
+TEST_F(LooperTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeInvoked) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+    pipe.writeSignal(); // would cause FD to be considered signalled
+    mLooper->removeFd(pipe.receiveFd);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal timeout because FD was no longer registered";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+    EXPECT_EQ(0, handler.callbackCount)
+            << "callback should not be invoked";
+}
+
+TEST_F(LooperTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvokedAgainLater) {
+    Pipe pipe;
+    StubCallbackHandler handler(false);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    // First loop: Callback is registered and FD is signalled.
+    pipe.writeSignal();
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal zero because FD was already signalled";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should be invoked";
+
+    // Second loop: Callback is no longer registered and FD is signalled.
+    pipe.writeSignal();
+
+    stopWatch.reset();
+    result = mLooper->pollOnce(0);
+    elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal zero because timeout was zero";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should not be invoked this time";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonCallbackFdIsSignalled_ReturnsIdent) {
+    const int expectedIdent = 5;
+    void* expectedData = this;
+
+    Pipe pipe;
+
+    pipe.writeSignal();
+    mLooper->addFd(pipe.receiveFd, expectedIdent, ALOOPER_EVENT_INPUT, NULL, expectedData);
+
+    StopWatch stopWatch("pollOnce");
+    int fd;
+    int events;
+    void* data;
+    int result = mLooper->pollOnce(100, &fd, &events, &data);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(expectedIdent, result)
+            << "pollOnce result should be the ident of the FD that was signalled";
+    EXPECT_EQ(pipe.receiveFd, fd)
+            << "pollOnce should have returned the received pipe fd";
+    EXPECT_EQ(ALOOPER_EVENT_INPUT, events)
+            << "pollOnce should have returned ALOOPER_EVENT_INPUT as events";
+    EXPECT_EQ(expectedData, data)
+            << "pollOnce should have returned the data";
+}
+
+TEST_F(LooperTest, AddFd_WhenCallbackAdded_ReturnsOne) {
+    Pipe pipe;
+    int result = mLooper->addFd(pipe.receiveFd, 0, ALOOPER_EVENT_INPUT, NULL, NULL);
+
+    EXPECT_EQ(1, result)
+            << "addFd should return 1 because FD was added";
+}
+
+TEST_F(LooperTest, AddFd_WhenIdentIsNegativeAndCallbackIsNull_ReturnsError) {
+    Pipe pipe;
+    int result = mLooper->addFd(pipe.receiveFd, -1, ALOOPER_EVENT_INPUT, NULL, NULL);
+
+    EXPECT_EQ(-1, result)
+            << "addFd should return -1 because arguments were invalid";
+}
+
+TEST_F(LooperTest, AddFd_WhenNoCallbackAndAllowNonCallbacksIsFalse_ReturnsError) {
+    Pipe pipe;
+    sp<Looper> looper = new Looper(false /*allowNonCallbacks*/);
+    int result = looper->addFd(pipe.receiveFd, 0, 0, NULL, NULL);
+
+    EXPECT_EQ(-1, result)
+            << "addFd should return -1 because arguments were invalid";
+}
+
+TEST_F(LooperTest, RemoveFd_WhenCallbackNotAdded_ReturnsZero) {
+    int result = mLooper->removeFd(1);
+
+    EXPECT_EQ(0, result)
+            << "removeFd should return 0 because FD not registered";
+}
+
+TEST_F(LooperTest, RemoveFd_WhenCallbackAddedThenRemovedTwice_ReturnsOnceFirstTimeAndReturnsZeroSecondTime) {
+    Pipe pipe;
+    StubCallbackHandler handler(false);
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    // First time.
+    int result = mLooper->removeFd(pipe.receiveFd);
+
+    EXPECT_EQ(1, result)
+            << "removeFd should return 1 first time because FD was registered";
+
+    // Second time.
+    result = mLooper->removeFd(pipe.receiveFd);
+
+    EXPECT_EQ(0, result)
+            << "removeFd should return 0 second time because FD was no longer registered";
+}
+
+TEST_F(LooperTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeInvoked) {
+    Pipe pipe;
+    StubCallbackHandler handler1(true);
+    StubCallbackHandler handler2(true);
+
+    handler1.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+    handler2.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); // replace it
+    pipe.writeSignal(); // would cause FD to be considered signalled
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because FD was already signalled";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(0, handler1.callbackCount)
+            << "original handler callback should not be invoked because it was replaced";
+    EXPECT_EQ(1, handler2.callbackCount)
+            << "replacement handler callback should be invoked";
+}
+
+TEST_F(LooperTest, SendMessage_WhenOneMessageIsEnqueue_ShouldInvokeHandlerDuringNextPoll) {
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessage(handler, Message(MSG_TEST1));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was already sent";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+    EXPECT_EQ(size_t(1), handler->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
+            << "handled message";
+}
+
+TEST_F(LooperTest, SendMessage_WhenMultipleMessagesAreEnqueued_ShouldInvokeHandlersInOrderDuringNextPoll) {
+    sp<StubMessageHandler> handler1 = new StubMessageHandler();
+    sp<StubMessageHandler> handler2 = new StubMessageHandler();
+    mLooper->sendMessage(handler1, Message(MSG_TEST1));
+    mLooper->sendMessage(handler2, Message(MSG_TEST2));
+    mLooper->sendMessage(handler1, Message(MSG_TEST3));
+    mLooper->sendMessage(handler1, Message(MSG_TEST4));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was already sent";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+    EXPECT_EQ(size_t(3), handler1->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler1->messages[0].what)
+            << "handled message";
+    EXPECT_EQ(MSG_TEST3, handler1->messages[1].what)
+            << "handled message";
+    EXPECT_EQ(MSG_TEST4, handler1->messages[2].what)
+            << "handled message";
+    EXPECT_EQ(size_t(1), handler2->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST2, handler2->messages[0].what)
+            << "handled message";
+}
+
+TEST_F(LooperTest, SendMessageDelayed_WhenSentToTheFuture_ShouldInvokeHandlerAfterDelayTime) {
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessageDelayed(ms2ns(100), handler, Message(MSG_TEST1));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "first poll should end quickly because next message timeout was computed";
+    EXPECT_EQ(ALOOPER_POLL_WAKE, result)
+            << "pollOnce result should be ALOOPER_POLL_WAKE due to wakeup";
+    EXPECT_EQ(size_t(0), handler->messages.size())
+            << "no message handled yet";
+
+    result = mLooper->pollOnce(1000);
+    elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_EQ(size_t(1), handler->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
+            << "handled message";
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "second poll should end around the time of the delayed message dispatch";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+
+    result = mLooper->pollOnce(100);
+    elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(100 + 100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "third poll should timeout";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT because there were no messages left";
+}
+
+TEST_F(LooperTest, SendMessageDelayed_WhenSentToThePast_ShouldInvokeHandlerDuringNextPoll) {
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessageDelayed(ms2ns(-1000), handler, Message(MSG_TEST1));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was already sent";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+    EXPECT_EQ(size_t(1), handler->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
+            << "handled message";
+}
+
+TEST_F(LooperTest, SendMessageDelayed_WhenSentToThePresent_ShouldInvokeHandlerDuringNextPoll) {
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessageDelayed(0, handler, Message(MSG_TEST1));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was already sent";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+    EXPECT_EQ(size_t(1), handler->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
+            << "handled message";
+}
+
+TEST_F(LooperTest, SendMessageAtTime_WhenSentToTheFuture_ShouldInvokeHandlerAfterDelayTime) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessageAtTime(now + ms2ns(100), handler, Message(MSG_TEST1));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "first poll should end quickly because next message timeout was computed";
+    EXPECT_EQ(ALOOPER_POLL_WAKE, result)
+            << "pollOnce result should be ALOOPER_POLL_WAKE due to wakeup";
+    EXPECT_EQ(size_t(0), handler->messages.size())
+            << "no message handled yet";
+
+    result = mLooper->pollOnce(1000);
+    elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_EQ(size_t(1), handler->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
+            << "handled message";
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "second poll should end around the time of the delayed message dispatch";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+
+    result = mLooper->pollOnce(100);
+    elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(100 + 100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "third poll should timeout";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT because there were no messages left";
+}
+
+TEST_F(LooperTest, SendMessageAtTime_WhenSentToThePast_ShouldInvokeHandlerDuringNextPoll) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessageAtTime(now - ms2ns(1000), handler, Message(MSG_TEST1));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was already sent";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+    EXPECT_EQ(size_t(1), handler->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
+            << "handled message";
+}
+
+TEST_F(LooperTest, SendMessageAtTime_WhenSentToThePresent_ShouldInvokeHandlerDuringNextPoll) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessageAtTime(now, handler, Message(MSG_TEST1));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was already sent";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+    EXPECT_EQ(size_t(1), handler->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
+            << "handled message";
+}
+
+TEST_F(LooperTest, RemoveMessage_WhenRemovingAllMessagesForHandler_ShouldRemoveThoseMessage) {
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessage(handler, Message(MSG_TEST1));
+    mLooper->sendMessage(handler, Message(MSG_TEST2));
+    mLooper->sendMessage(handler, Message(MSG_TEST3));
+    mLooper->removeMessages(handler);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was sent so looper was awoken";
+    EXPECT_EQ(ALOOPER_POLL_WAKE, result)
+            << "pollOnce result should be ALOOPER_POLL_WAKE because looper was awoken";
+    EXPECT_EQ(size_t(0), handler->messages.size())
+            << "no messages to handle";
+
+    result = mLooper->pollOnce(0);
+
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT because there was nothing to do";
+    EXPECT_EQ(size_t(0), handler->messages.size())
+            << "no messages to handle";
+}
+
+TEST_F(LooperTest, RemoveMessage_WhenRemovingSomeMessagesForHandler_ShouldRemoveThoseMessage) {
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessage(handler, Message(MSG_TEST1));
+    mLooper->sendMessage(handler, Message(MSG_TEST2));
+    mLooper->sendMessage(handler, Message(MSG_TEST3));
+    mLooper->sendMessage(handler, Message(MSG_TEST4));
+    mLooper->removeMessages(handler, MSG_TEST3);
+    mLooper->removeMessages(handler, MSG_TEST1);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was sent so looper was awoken";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because two messages were sent";
+    EXPECT_EQ(size_t(2), handler->messages.size())
+            << "no messages to handle";
+    EXPECT_EQ(MSG_TEST2, handler->messages[0].what)
+            << "handled message";
+    EXPECT_EQ(MSG_TEST4, handler->messages[1].what)
+            << "handled message";
+
+    result = mLooper->pollOnce(0);
+
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT because there was nothing to do";
+    EXPECT_EQ(size_t(2), handler->messages.size())
+            << "no more messages to handle";
+}
+
+} // namespace android
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
new file mode 100644
index 0000000..e573952
--- /dev/null
+++ b/libutils/tests/LruCache_test.cpp
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <utils/JenkinsHash.h>
+#include <utils/LruCache.h>
+#include <cutils/log.h>
+#include <gtest/gtest.h>
+
+namespace android {
+
+typedef int SimpleKey;
+typedef const char* StringValue;
+
+struct ComplexKey {
+    int k;
+
+    explicit ComplexKey(int k) : k(k) {
+        instanceCount += 1;
+    }
+
+    ComplexKey(const ComplexKey& other) : k(other.k) {
+        instanceCount += 1;
+    }
+
+    ~ComplexKey() {
+        instanceCount -= 1;
+    }
+
+    bool operator ==(const ComplexKey& other) const {
+        return k == other.k;
+    }
+
+    bool operator !=(const ComplexKey& other) const {
+        return k != other.k;
+    }
+
+    static ssize_t instanceCount;
+};
+
+ssize_t ComplexKey::instanceCount = 0;
+
+template<> inline hash_t hash_type(const ComplexKey& value) {
+    return hash_type(value.k);
+}
+
+struct ComplexValue {
+    int v;
+
+    explicit ComplexValue(int v) : v(v) {
+        instanceCount += 1;
+    }
+
+    ComplexValue(const ComplexValue& other) : v(other.v) {
+        instanceCount += 1;
+    }
+
+    ~ComplexValue() {
+        instanceCount -= 1;
+    }
+
+    static ssize_t instanceCount;
+};
+
+ssize_t ComplexValue::instanceCount = 0;
+
+typedef LruCache<ComplexKey, ComplexValue> ComplexCache;
+
+class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> {
+public:
+    EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { }
+    ~EntryRemovedCallback() {}
+    void operator()(SimpleKey& k, StringValue& v) {
+        callbackCount += 1;
+        lastKey = k;
+        lastValue = v;
+    }
+    ssize_t callbackCount;
+    SimpleKey lastKey;
+    StringValue lastValue;
+};
+
+class LruCacheTest : public testing::Test {
+protected:
+    virtual void SetUp() {
+        ComplexKey::instanceCount = 0;
+        ComplexValue::instanceCount = 0;
+    }
+
+    virtual void TearDown() {
+        ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0));
+    }
+
+    void assertInstanceCount(ssize_t keys, ssize_t values) {
+        if (keys != ComplexKey::instanceCount || values != ComplexValue::instanceCount) {
+            FAIL() << "Expected " << keys << " keys and " << values << " values "
+                    "but there were actually " << ComplexKey::instanceCount << " keys and "
+                    << ComplexValue::instanceCount << " values";
+        }
+    }
+};
+
+TEST_F(LruCacheTest, Empty) {
+    LruCache<SimpleKey, StringValue> cache(100);
+
+    EXPECT_EQ(NULL, cache.get(0));
+    EXPECT_EQ(0u, cache.size());
+}
+
+TEST_F(LruCacheTest, Simple) {
+    LruCache<SimpleKey, StringValue> cache(100);
+
+    cache.put(1, "one");
+    cache.put(2, "two");
+    cache.put(3, "three");
+    EXPECT_STREQ("one", cache.get(1));
+    EXPECT_STREQ("two", cache.get(2));
+    EXPECT_STREQ("three", cache.get(3));
+    EXPECT_EQ(3u, cache.size());
+}
+
+TEST_F(LruCacheTest, MaxCapacity) {
+    LruCache<SimpleKey, StringValue> cache(2);
+
+    cache.put(1, "one");
+    cache.put(2, "two");
+    cache.put(3, "three");
+    EXPECT_EQ(NULL, cache.get(1));
+    EXPECT_STREQ("two", cache.get(2));
+    EXPECT_STREQ("three", cache.get(3));
+    EXPECT_EQ(2u, cache.size());
+}
+
+TEST_F(LruCacheTest, RemoveLru) {
+    LruCache<SimpleKey, StringValue> cache(100);
+
+    cache.put(1, "one");
+    cache.put(2, "two");
+    cache.put(3, "three");
+    cache.removeOldest();
+    EXPECT_EQ(NULL, cache.get(1));
+    EXPECT_STREQ("two", cache.get(2));
+    EXPECT_STREQ("three", cache.get(3));
+    EXPECT_EQ(2u, cache.size());
+}
+
+TEST_F(LruCacheTest, GetUpdatesLru) {
+    LruCache<SimpleKey, StringValue> cache(100);
+
+    cache.put(1, "one");
+    cache.put(2, "two");
+    cache.put(3, "three");
+    EXPECT_STREQ("one", cache.get(1));
+    cache.removeOldest();
+    EXPECT_STREQ("one", cache.get(1));
+    EXPECT_EQ(NULL, cache.get(2));
+    EXPECT_STREQ("three", cache.get(3));
+    EXPECT_EQ(2u, cache.size());
+}
+
+uint32_t hash_int(int x) {
+    return JenkinsHashWhiten(JenkinsHashMix(0, x));
+}
+
+TEST_F(LruCacheTest, StressTest) {
+    const size_t kCacheSize = 512;
+    LruCache<SimpleKey, StringValue> cache(512);
+    const size_t kNumKeys = 16 * 1024;
+    const size_t kNumIters = 100000;
+    char* strings[kNumKeys];
+
+    for (size_t i = 0; i < kNumKeys; i++) {
+        strings[i] = (char *)malloc(16);
+        sprintf(strings[i], "%d", i);
+    }
+
+    srandom(12345);
+    int hitCount = 0;
+    for (size_t i = 0; i < kNumIters; i++) {
+        int index = random() % kNumKeys;
+        uint32_t key = hash_int(index);
+        const char *val = cache.get(key);
+        if (val != NULL) {
+            EXPECT_EQ(strings[index], val);
+            hitCount++;
+        } else {
+            cache.put(key, strings[index]);
+        }
+    }
+    size_t expectedHitCount = kNumIters * kCacheSize / kNumKeys;
+    EXPECT_LT(int(expectedHitCount * 0.9), hitCount);
+    EXPECT_GT(int(expectedHitCount * 1.1), hitCount);
+    EXPECT_EQ(kCacheSize, cache.size());
+
+    for (size_t i = 0; i < kNumKeys; i++) {
+        free((void *)strings[i]);
+    }
+}
+
+TEST_F(LruCacheTest, NoLeak) {
+    ComplexCache cache(100);
+
+    cache.put(ComplexKey(0), ComplexValue(0));
+    cache.put(ComplexKey(1), ComplexValue(1));
+    EXPECT_EQ(2, cache.size());
+    assertInstanceCount(2, 3);  // the null value counts as an instance
+}
+
+TEST_F(LruCacheTest, Clear) {
+    ComplexCache cache(100);
+
+    cache.put(ComplexKey(0), ComplexValue(0));
+    cache.put(ComplexKey(1), ComplexValue(1));
+    EXPECT_EQ(2, cache.size());
+    assertInstanceCount(2, 3);
+    cache.clear();
+    assertInstanceCount(0, 1);
+}
+
+TEST_F(LruCacheTest, ClearNoDoubleFree) {
+    {
+        ComplexCache cache(100);
+
+        cache.put(ComplexKey(0), ComplexValue(0));
+        cache.put(ComplexKey(1), ComplexValue(1));
+        EXPECT_EQ(2, cache.size());
+        assertInstanceCount(2, 3);
+        cache.removeOldest();
+        cache.clear();
+        assertInstanceCount(0, 1);
+    }
+    assertInstanceCount(0, 0);
+}
+
+TEST_F(LruCacheTest, ClearReuseOk) {
+    ComplexCache cache(100);
+
+    cache.put(ComplexKey(0), ComplexValue(0));
+    cache.put(ComplexKey(1), ComplexValue(1));
+    EXPECT_EQ(2, cache.size());
+    assertInstanceCount(2, 3);
+    cache.clear();
+    assertInstanceCount(0, 1);
+    cache.put(ComplexKey(0), ComplexValue(0));
+    cache.put(ComplexKey(1), ComplexValue(1));
+    EXPECT_EQ(2, cache.size());
+    assertInstanceCount(2, 3);
+}
+
+TEST_F(LruCacheTest, Callback) {
+    LruCache<SimpleKey, StringValue> cache(100);
+    EntryRemovedCallback callback;
+    cache.setOnEntryRemovedListener(&callback);
+
+    cache.put(1, "one");
+    cache.put(2, "two");
+    cache.put(3, "three");
+    EXPECT_EQ(3, cache.size());
+    cache.removeOldest();
+    EXPECT_EQ(1, callback.callbackCount);
+    EXPECT_EQ(1, callback.lastKey);
+    EXPECT_STREQ("one", callback.lastValue);
+}
+
+TEST_F(LruCacheTest, CallbackOnClear) {
+    LruCache<SimpleKey, StringValue> cache(100);
+    EntryRemovedCallback callback;
+    cache.setOnEntryRemovedListener(&callback);
+
+    cache.put(1, "one");
+    cache.put(2, "two");
+    cache.put(3, "three");
+    EXPECT_EQ(3, cache.size());
+    cache.clear();
+    EXPECT_EQ(3, callback.callbackCount);
+}
+
+}
diff --git a/libutils/tests/String8_test.cpp b/libutils/tests/String8_test.cpp
new file mode 100644
index 0000000..c42c68d
--- /dev/null
+++ b/libutils/tests/String8_test.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#define LOG_TAG "String8_test"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+class String8Test : public testing::Test {
+protected:
+    virtual void SetUp() {
+    }
+
+    virtual void TearDown() {
+    }
+};
+
+TEST_F(String8Test, Cstr) {
+    String8 tmp("Hello, world!");
+
+    EXPECT_STREQ(tmp.string(), "Hello, world!");
+}
+
+TEST_F(String8Test, OperatorPlus) {
+    String8 src1("Hello, ");
+
+    // Test adding String8 + const char*
+    const char* ccsrc2 = "world!";
+    String8 dst1 = src1 + ccsrc2;
+    EXPECT_STREQ(dst1.string(), "Hello, world!");
+    EXPECT_STREQ(src1.string(), "Hello, ");
+    EXPECT_STREQ(ccsrc2, "world!");
+
+    // Test adding String8 + String8
+    String8 ssrc2("world!");
+    String8 dst2 = src1 + ssrc2;
+    EXPECT_STREQ(dst2.string(), "Hello, world!");
+    EXPECT_STREQ(src1.string(), "Hello, ");
+    EXPECT_STREQ(ssrc2.string(), "world!");
+}
+
+TEST_F(String8Test, OperatorPlusEquals) {
+    String8 src1("My voice");
+
+    // Testing String8 += String8
+    String8 src2(" is my passport.");
+    src1 += src2;
+    EXPECT_STREQ(src1.string(), "My voice is my passport.");
+    EXPECT_STREQ(src2.string(), " is my passport.");
+
+    // Adding const char* to the previous string.
+    const char* src3 = " Verify me.";
+    src1 += src3;
+    EXPECT_STREQ(src1.string(), "My voice is my passport. Verify me.");
+    EXPECT_STREQ(src2.string(), " is my passport.");
+    EXPECT_STREQ(src3, " Verify me.");
+}
+
+}
diff --git a/libutils/tests/TestHelpers.h b/libutils/tests/TestHelpers.h
new file mode 100644
index 0000000..d8e985e
--- /dev/null
+++ b/libutils/tests/TestHelpers.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 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 TESTHELPERS_H
+#define TESTHELPERS_H
+
+#include <utils/threads.h>
+
+namespace android {
+
+class Pipe {
+public:
+    int sendFd;
+    int receiveFd;
+
+    Pipe() {
+        int fds[2];
+        ::pipe(fds);
+
+        receiveFd = fds[0];
+        sendFd = fds[1];
+    }
+
+    ~Pipe() {
+        if (sendFd != -1) {
+            ::close(sendFd);
+        }
+
+        if (receiveFd != -1) {
+            ::close(receiveFd);
+        }
+    }
+
+    status_t writeSignal() {
+        ssize_t nWritten = ::write(sendFd, "*", 1);
+        return nWritten == 1 ? 0 : -errno;
+    }
+
+    status_t readSignal() {
+        char buf[1];
+        ssize_t nRead = ::read(receiveFd, buf, 1);
+        return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno;
+    }
+};
+
+class DelayedTask : public Thread {
+    int mDelayMillis;
+
+public:
+    DelayedTask(int delayMillis) : mDelayMillis(delayMillis) { }
+
+protected:
+    virtual ~DelayedTask() { }
+
+    virtual void doTask() = 0;
+
+    virtual bool threadLoop() {
+        usleep(mDelayMillis * 1000);
+        doTask();
+        return false;
+    }
+};
+
+} // namespace android
+
+#endif // TESTHELPERS_H
diff --git a/libutils/tests/Unicode_test.cpp b/libutils/tests/Unicode_test.cpp
new file mode 100644
index 0000000..18c130c
--- /dev/null
+++ b/libutils/tests/Unicode_test.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#define LOG_TAG "Unicode_test"
+#include <utils/Log.h>
+#include <utils/Unicode.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+class UnicodeTest : public testing::Test {
+protected:
+    virtual void SetUp() {
+    }
+
+    virtual void TearDown() {
+    }
+};
+
+TEST_F(UnicodeTest, UTF8toUTF16ZeroLength) {
+    ssize_t measured;
+
+    const uint8_t str[] = { };
+
+    measured = utf8_to_utf16_length(str, 0);
+    EXPECT_EQ(0, measured)
+            << "Zero length input should return zero length output.";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16ASCIILength) {
+    ssize_t measured;
+
+    // U+0030 or ASCII '0'
+    const uint8_t str[] = { 0x30 };
+
+    measured = utf8_to_utf16_length(str, sizeof(str));
+    EXPECT_EQ(1, measured)
+            << "ASCII glyphs should have a length of 1 char16_t";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16Plane1Length) {
+    ssize_t measured;
+
+    // U+2323 SMILE
+    const uint8_t str[] = { 0xE2, 0x8C, 0xA3 };
+
+    measured = utf8_to_utf16_length(str, sizeof(str));
+    EXPECT_EQ(1, measured)
+            << "Plane 1 glyphs should have a length of 1 char16_t";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16SurrogateLength) {
+    ssize_t measured;
+
+    // U+10000
+    const uint8_t str[] = { 0xF0, 0x90, 0x80, 0x80 };
+
+    measured = utf8_to_utf16_length(str, sizeof(str));
+    EXPECT_EQ(2, measured)
+            << "Surrogate pairs should have a length of 2 char16_t";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16TruncatedUTF8) {
+    ssize_t measured;
+
+    // Truncated U+2323 SMILE
+    // U+2323 SMILE
+    const uint8_t str[] = { 0xE2, 0x8C };
+
+    measured = utf8_to_utf16_length(str, sizeof(str));
+    EXPECT_EQ(-1, measured)
+            << "Truncated UTF-8 should return -1 to indicate invalid";
+}
+
+TEST_F(UnicodeTest, UTF8toUTF16Normal) {
+    const uint8_t str[] = {
+        0x30, // U+0030, 1 UTF-16 character
+        0xC4, 0x80, // U+0100, 1 UTF-16 character
+        0xE2, 0x8C, 0xA3, // U+2323, 1 UTF-16 character
+        0xF0, 0x90, 0x80, 0x80, // U+10000, 2 UTF-16 character
+    };
+
+    char16_t output[1 + 1 + 1 + 2 + 1]; // Room for NULL
+
+    utf8_to_utf16(str, sizeof(str), output);
+
+    EXPECT_EQ(0x0030, output[0])
+            << "should be U+0030";
+    EXPECT_EQ(0x0100, output[1])
+            << "should be U+0100";
+    EXPECT_EQ(0x2323, output[2])
+            << "should be U+2323";
+    EXPECT_EQ(0xD800, output[3])
+            << "should be first half of surrogate U+10000";
+    EXPECT_EQ(0xDC00, output[4])
+            << "should be second half of surrogate U+10000";
+    EXPECT_EQ(NULL, output[5])
+            << "should be NULL terminated";
+}
+
+}
diff --git a/libutils/tests/Vector_test.cpp b/libutils/tests/Vector_test.cpp
new file mode 100644
index 0000000..d29c054
--- /dev/null
+++ b/libutils/tests/Vector_test.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#define LOG_TAG "Vector_test"
+
+#include <utils/Vector.h>
+#include <cutils/log.h>
+#include <gtest/gtest.h>
+#include <unistd.h>
+
+namespace android {
+
+class VectorTest : public testing::Test {
+protected:
+    virtual void SetUp() {
+    }
+
+    virtual void TearDown() {
+    }
+
+public:
+};
+
+
+TEST_F(VectorTest, CopyOnWrite_CopyAndAddElements) {
+
+    Vector<int> vector;
+    Vector<int> other;
+    vector.setCapacity(8);
+
+    vector.add(1);
+    vector.add(2);
+    vector.add(3);
+
+    EXPECT_EQ(vector.size(), 3);
+
+    // copy the vector
+    other = vector;
+
+    EXPECT_EQ(other.size(), 3);
+
+    // add an element to the first vector
+    vector.add(4);
+
+    // make sure the sizes are correct
+    EXPECT_EQ(vector.size(), 4);
+    EXPECT_EQ(other.size(), 3);
+
+    // add an element to the copy
+    other.add(5);
+
+    // make sure the sizes are correct
+    EXPECT_EQ(vector.size(), 4);
+    EXPECT_EQ(other.size(), 4);
+
+    // make sure the content of both vectors are correct
+    EXPECT_EQ(vector[3], 4);
+    EXPECT_EQ(other[3], 5);
+}
+
+
+} // namespace android
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 6040bd9..a325692 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -90,10 +90,6 @@
 # Logged when the supplicant switches to a new state
 50023 wifi_supplicant_state_changed (supplicant_state|1|5)
 
-# Do not change these names without updating tag in:
-#//device/dalvik/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.c
-51000 socket_stats (send|1|2),(recv|1|2),(ip|1|5),(port|1|5),(close|1|5)
-
 # Database operation samples.
 # db: the filename of the database
 # sql: the executed query (without query args)
@@ -110,22 +106,7 @@
 60003 view_use_drawing_cache (View drawn using bitmap cache|1|5)
 
 # graphics timestamp
-60100 sf_app_dequeue_before (buffer|1),(identity|1),(time|2)
-60101 sf_app_dequeue_after (buffer|1),(identity|1),(time|2)
-60102 sf_app_lock_before (buffer|1),(identity|1),(time|2)
-60103 sf_app_lock_after (buffer|1),(identity|1),(time|2)
-60104 sf_app_queue (buffer|1),(identity|1),(time|2)
-60105 sf_repaint (buffer|1),(time|2)
-60106 sf_composition_complete (buffer|1),(time|2)
-60107 sf_unlock_clients (buffer|1),(time|2)
-60108 sf_swapbuffers (buffer|1),(time|2)
-60109 sf_repaint_done (buffer|1),(time|2)
-60110 sf_fb_post_before (buffer|1),(time|2)
-60111 sf_fb_post_after (buffer|1),(time|2)
-60112 sf_fb_dequeue_before (buffer|1),(time|2)
-60113 sf_fb_dequeue_after (buffer|1),(time|2)
-60114 sf_fb_lock_before (buffer|1),(time|2)
-60115 sf_fb_lock_after (buffer|1),(time|2)
+# 60100 - 60199 reserved for surfaceflinger
 
 # 0 for screen off, 1 for screen on, 2 for key-guard done
 70000 screen_toggled (screen_state|1|5)
@@ -151,7 +132,7 @@
 80310 bionic_event_resolver_wrong_query (uid|1)
 
 # libcore failure logging
-90100 cert_pin_failure (certs|4)
+90100 exp_det_cert_pin_failure (certs|4)
 
 # NOTE - the range 1000000-2000000 is reserved for partners and others who
 # want to define their own log tags without conflicting with the core platform.
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index d3b5ed0..d44c679 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1,10 +1,10 @@
 // Copyright 2006 The Android Open Source Project
 
-#include <cutils/logger.h>
-#include <cutils/logd.h>
+#include <log/logger.h>
+#include <log/logd.h>
+#include <log/logprint.h>
+#include <log/event_tag_map.h>
 #include <cutils/sockets.h>
-#include <cutils/logprint.h>
-#include <cutils/event_tag_map.h>
 
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h
index 8087f0a..4307a30 100644
--- a/logwrapper/include/logwrap/logwrap.h
+++ b/logwrapper/include/logwrap/logwrap.h
@@ -44,11 +44,15 @@
  *           send a signal twice to signal the caller (once for the child, and
  *           once for the caller)
  *   log_target: Specify where to log the output of the child, either LOG_NONE,
- *           LOG_ALOG (for the Android system log) or LOG_KLOG (for the kernel
- *           log).
+ *           LOG_ALOG (for the Android system log), LOG_KLOG (for the kernel
+ *           log), or LOG_FILE (and you need to specify a pathname in the
+ *           file_path argument, otherwise pass NULL).  These are bit fields,
+ *           and can be OR'ed together to log to multiple places.
  *   abbreviated: If true, capture up to the first 100 lines and last 4K of
  *           output from the child.  The abbreviated output is not dumped to
  *           the specified log until the child has exited.
+ *   file_path: if log_target has the LOG_FILE bit set, then this parameter
+ *           must be set to the pathname of the file to log to.
  *
  * Return value:
  *   0 when logwrap successfully run the child process and captured its status
@@ -58,13 +62,14 @@
  *
  */
 
-/* Values for the log_target parameter android_fork_exec_ext() */
+/* Values for the log_target parameter android_fork_execvp_ext() */
 #define LOG_NONE        0
 #define LOG_ALOG        1
 #define LOG_KLOG        2
+#define LOG_FILE        4
 
 int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
-        int log_target, bool abbreviated);
+        int log_target, bool abbreviated, char *file_path);
 
 /* Similar to above, except abbreviated logging is not available, and if logwrap
  * is true, logging is to the Android system log, and if false, there is no
@@ -74,10 +79,9 @@
                                      bool ignore_int_quit, bool logwrap)
 {
     return android_fork_execvp_ext(argc, argv, status, ignore_int_quit,
-                                   (logwrap ? LOG_ALOG : LOG_NONE), false);
+                                   (logwrap ? LOG_ALOG : LOG_NONE), false, NULL);
 }
 
-
 __END_DECLS
 
 #endif /* __LIBS_LOGWRAP_H */
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 01cc9a1..4ca1db4 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -93,6 +93,7 @@
     char klog_fmt[MAX_KLOG_TAG * 2];
     char *btag;
     bool abbreviated;
+    FILE *fp;
     struct abbr_buf a_buf;
 };
 
@@ -158,11 +159,15 @@
 
 /* Log directly to the specified log */
 static void do_log_line(struct log_info *log_info, char *line) {
-    if (log_info->log_target == LOG_KLOG) {
+    if (log_info->log_target & LOG_KLOG) {
         klog_write(6, log_info->klog_fmt, line);
-    } else if (log_info->log_target == LOG_ALOG) {
+    }
+    if (log_info->log_target & LOG_ALOG) {
         ALOG(LOG_INFO, log_info->btag, "%s", line);
     }
+    if (log_info->log_target & LOG_FILE) {
+        fprintf(log_info->fp, "%s\n", line);
+    }
 }
 
 /* Log to either the abbreviated buf, or directly to the specified log
@@ -290,7 +295,7 @@
 }
 
 static int parent(const char *tag, int parent_read, pid_t pid,
-        int *chld_sts, int log_target, bool abbreviated) {
+        int *chld_sts, int log_target, bool abbreviated, char *file_path) {
     int status = 0;
     char buffer[4096];
     struct pollfd poll_fds[] = {
@@ -300,6 +305,7 @@
         },
     };
     int rc = 0;
+    int fd;
 
     struct log_info log_info;
 
@@ -309,8 +315,6 @@
     bool found_child = false;
     char tmpbuf[256];
 
-    log_info.log_target = log_target;
-    log_info.abbreviated = abbreviated;
     log_info.btag = basename(tag);
     if (!log_info.btag) {
         log_info.btag = (char*) tag;
@@ -323,11 +327,30 @@
         init_abbr_buf(&log_info.a_buf);
     }
 
-    if (log_target == LOG_KLOG) {
+    if (log_target & LOG_KLOG) {
         snprintf(log_info.klog_fmt, sizeof(log_info.klog_fmt),
                  "<6>%.*s: %%s", MAX_KLOG_TAG, log_info.btag);
     }
 
+    if ((log_target & LOG_FILE) && !file_path) {
+        /* No file_path specified, clear the LOG_FILE bit */
+        log_target &= ~LOG_FILE;
+    }
+
+    if (log_target & LOG_FILE) {
+        fd = open(file_path, O_WRONLY | O_CREAT, 0664);
+        if (fd < 0) {
+            ERROR("Cannot log to file %s\n", file_path);
+            log_target &= ~LOG_FILE;
+        } else {
+            lseek(fd, 0, SEEK_END);
+            log_info.fp = fdopen(fd, "a");
+        }
+    }
+
+    log_info.log_target = log_target;
+    log_info.abbreviated = abbreviated;
+
     while (!found_child) {
         if (TEMP_FAILURE_RETRY(poll(poll_fds, ARRAY_SIZE(poll_fds), -1)) < 0) {
             ERROR("poll failed\n");
@@ -432,6 +455,9 @@
 
 err_waitpid:
 err_poll:
+    if (log_target & LOG_FILE) {
+        fclose(log_info.fp); /* Also closes underlying fd */
+    }
     if (abbreviated) {
         free_abbr_buf(&log_info.a_buf);
     }
@@ -451,7 +477,7 @@
 }
 
 int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
-        int log_target, bool abbreviated) {
+        int log_target, bool abbreviated, char *file_path) {
     pid_t pid;
     int parent_ptty;
     int child_ptty;
@@ -523,7 +549,8 @@
             sigaction(SIGQUIT, &ignact, &quitact);
         }
 
-        rc = parent(argv[0], parent_ptty, pid, status, log_target, abbreviated);
+        rc = parent(argv[0], parent_ptty, pid, status, log_target,
+                    abbreviated, file_path);
     }
 
     if (ignore_int_quit) {
diff --git a/logwrapper/logwrapper.c b/logwrapper/logwrapper.c
index d1c6240..d0d8d14 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -80,7 +80,7 @@
     }
 
     rc = android_fork_execvp_ext(argc, &argv[0], &status, true,
-                                 log_target, abbreviated);
+                                 log_target, abbreviated, NULL);
     if (!rc) {
         if (WIFEXITED(status))
             rc = WEXITSTATUS(status);
diff --git a/reboot/Android.mk b/reboot/Android.mk
new file mode 100644
index 0000000..4db0c1e
--- /dev/null
+++ b/reboot/Android.mk
@@ -0,0 +1,12 @@
+# Copyright 2013 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= reboot.c
+
+LOCAL_SHARED_LIBRARIES:= libcutils
+
+LOCAL_MODULE:= reboot
+
+include $(BUILD_EXECUTABLE)
diff --git a/reboot/reboot.c b/reboot/reboot.c
new file mode 100644
index 0000000..d9a4227
--- /dev/null
+++ b/reboot/reboot.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2013 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <cutils/properties.h>
+#include <cutils/android_reboot.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+    int ret;
+    size_t prop_len;
+    char property_val[PROPERTY_VALUE_MAX];
+    const char *cmd = "reboot";
+    char *optarg = "";
+
+    opterr = 0;
+    do {
+        int c;
+
+        c = getopt(argc, argv, "p");
+
+        if (c == EOF) {
+            break;
+        }
+
+        switch (c) {
+        case 'p':
+            cmd = "shutdown";
+            break;
+        case '?':
+            fprintf(stderr, "usage: %s [-p] [rebootcommand]\n", argv[0]);
+            exit(EXIT_FAILURE);
+        }
+    } while (1);
+
+    if(argc > optind + 1) {
+        fprintf(stderr, "%s: too many arguments\n", argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    if (argc > optind)
+        optarg = argv[optind];
+
+    prop_len = snprintf(property_val, sizeof(property_val), "%s,%s", cmd, optarg);
+    if (prop_len >= sizeof(property_val)) {
+        fprintf(stderr, "reboot command too long: %s\n", optarg);
+        exit(EXIT_FAILURE);
+    }
+
+    ret = property_set(ANDROID_RB_PROPERTY, property_val);
+    if(ret < 0) {
+        perror("reboot");
+        exit(EXIT_FAILURE);
+    }
+
+    // Don't return early. Give the reboot command time to take effect
+    // to avoid messing up scripts which do "adb shell reboot && adb wait-for-device"
+    while(1) { pause(); }
+
+    fprintf(stderr, "Done\n");
+    return 0;
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 3417f54..2c16084 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -1,55 +1,38 @@
 LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
 
-# files that live under /system/etc/...
-
-copy_from := \
-	etc/hosts
-
-
-copy_to := $(addprefix $(TARGET_OUT)/,$(copy_from))
-copy_from := $(addprefix $(LOCAL_PATH)/,$(copy_from))
-
-$(copy_to) : PRIVATE_MODULE := system_etcdir
-$(copy_to) : $(TARGET_OUT)/% : $(LOCAL_PATH)/% | $(ACP)
-	$(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(copy_to)
-
-
-# files that live under /...
-
+#######################################
+# init.rc
 # 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)
-$(INSTALLED_RAMDISK_TARGET): $(file)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := init.rc
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
+
+include $(BUILD_PREBUILT)
 endif
+#######################################
+# init.environ.rc
 
-file := $(TARGET_ROOT_OUT)/ueventd.rc
-$(file) : $(LOCAL_PATH)/ueventd.rc | $(ACP)
-	$(transform-prebuilt-to-target)
-ALL_PREBUILT += $(file)
-$(INSTALLED_RAMDISK_TARGET): $(file)
+include $(CLEAR_VARS)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE := init.environ.rc
+LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
 
-# init.usb.rc is handled by build/target/product/core.rc
-
-
+# Put it here instead of in init.rc module definition,
+# because init.rc is conditionally included.
+#
 # create some directories (some are mount points)
-DIRS := $(addprefix $(TARGET_ROOT_OUT)/, \
-		sbin \
-		dev \
-		proc \
-		sys \
-		system \
-		data \
-	) \
-	$(TARGET_OUT_DATA)
+LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
+    sbin dev proc sys system data)
 
-$(DIRS):
-	@echo Directory: $@
-	@mkdir -p $@
+include $(BUILD_SYSTEM)/base_rules.mk
 
-ALL_PREBUILT += $(DIRS)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in
+	@echo "Generate: $< -> $@"
+	@mkdir -p $(dir $@)
+	$(hide) sed -e 's?%BOOTCLASSPATH%?$(PRODUCT_BOOTCLASSPATH)?g' $< >$@
+
+#######################################
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
new file mode 100644
index 0000000..d2f74c0
--- /dev/null
+++ b/rootdir/init.environ.rc.in
@@ -0,0 +1,12 @@
+# set up the global environment
+on init
+    export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
+    export LD_LIBRARY_PATH /vendor/lib:/system/lib
+    export ANDROID_BOOTLOGO 1
+    export ANDROID_ROOT /system
+    export ANDROID_ASSETS /system/app
+    export ANDROID_DATA /data
+    export ANDROID_STORAGE /storage
+    export ASEC_MOUNTPOINT /mnt/asec
+    export LOOP_MOUNTPOINT /mnt/obb
+    export BOOTCLASSPATH %BOOTCLASSPATH%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 7735029..400c09e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -4,6 +4,7 @@
 # This is a common source of Android security bugs.
 #
 
+import /init.environ.rc
 import /init.usb.rc
 import /init.${ro.hardware}.rc
 import /init.trace.rc
@@ -30,18 +31,6 @@
 
 loglevel 3
 
-# setup the global environment
-    export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
-    export LD_LIBRARY_PATH /vendor/lib:/system/lib
-    export ANDROID_BOOTLOGO 1
-    export ANDROID_ROOT /system
-    export ANDROID_ASSETS /system/app
-    export ANDROID_DATA /data
-    export ANDROID_STORAGE /storage
-    export ASEC_MOUNTPOINT /mnt/asec
-    export LOOP_MOUNTPOINT /mnt/obb
-    export BOOTCLASSPATH /system/framework/core.jar:/system/framework/conscrypt.jar:/system/framework/okhttp.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar
-
 # Backward compatibility
     symlink /system/etc /etc
     symlink /sys/kernel/debug /d
@@ -55,6 +44,19 @@
     mount cgroup none /acct cpuacct
     mkdir /acct/uid
 
+# Create cgroup mount point for memory
+    mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
+    mkdir /sys/fs/cgroup/memory 0750 root system
+    mount cgroup none /sys/fs/cgroup/memory memory
+    write /sys/fs/cgroup/memory/memory.move_charge_at_immigrate 1
+    chown root system /sys/fs/cgroup/memory/tasks
+    chmod 0660 /sys/fs/cgroup/memory/tasks
+    mkdir /sys/fs/cgroup/memory/sw 0750 root system
+    write /sys/fs/cgroup/memory/sw/memory.swappiness 100
+    write /sys/fs/cgroup/memory/sw/memory.move_charge_at_immigrate 1
+    chown root system /sys/fs/cgroup/memory/sw/tasks
+    chmod 0660 /sys/fs/cgroup/memory/sw/tasks
+
     mkdir /system
     mkdir /data 0771 system system
     mkdir /cache 0770 system cache
@@ -62,12 +64,11 @@
 
     # See storage config details at http://source.android.com/tech/storage/
     mkdir /mnt/shell 0700 shell shell
-    mkdir /storage 0050 root sdcard_r
+    mkdir /mnt/media_rw 0700 media_rw media_rw
+    mkdir /storage 0751 root sdcard_r
 
     # Directory for putting things only root should see.
     mkdir /mnt/secure 0700 root root
-    # Create private mountpoint so we can MS_MOVE from staging
-    mount tmpfs tmpfs /mnt/secure mode=0700,uid=0,gid=0
 
     # Directory for staging bindmounts
     mkdir /mnt/secure/staging 0700 root root
@@ -134,12 +135,15 @@
 # This is needed by any process that uses socket tagging.
     chmod 0644 /dev/xt_qtaguid
 
+# Create location for fs_mgr to store abbreviated output from filesystem
+# checker programs.
+    mkdir /dev/fscklogs 0770 root system
+
 on post-fs
     # once everything is setup, no need to modify /
     mount rootfs rootfs / ro remount
     # mount shared so changes propagate into child namespaces
     mount rootfs rootfs / shared rec
-    mount tmpfs tmpfs /mnt/secure private rec
 
     # We chown/chmod /cache again so because mount is run as root + defaults
     chown system cache /cache
@@ -178,6 +182,9 @@
     # We restorecon /data in case the userdata partition has been reset.
     restorecon /data
 
+    # Avoid predictable entropy pool. Carry over entropy from previous boot.
+    copy /data/system/entropy.dat /dev/urandom
+
     # Create dump dir and collect dumps.
     # Do this before we mount cache so eventually we can use cache for
     # storing dumps on platforms which do not have a dedicated dump partition.
@@ -366,9 +373,6 @@
     setprop net.tcp.buffersize.gprs    4092,8760,11680,4096,8760,11680
     setprop net.tcp.buffersize.evdo    4094,87380,262144,4096,16384,262144
 
-# Set this property so surfaceflinger is not started by system_init
-    setprop system_init.startsurfaceflinger 0
-
     class_start core
     class_start main
 
@@ -398,6 +402,13 @@
     class_reset late_start
     class_reset main
 
+on property:sys.powerctl=*
+    powerctl ${sys.powerctl}
+
+# system server cannot write to /proc/sys files, so proxy it through init
+on property:sys.sysctl.extra_free_kbytes=*
+    write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}
+
 ## Daemon processes to be run by init.
 ##
 service ueventd /sbin/ueventd
@@ -405,6 +416,16 @@
     critical
     seclabel u:r:ueventd:s0
 
+service healthd /sbin/healthd
+    class core
+    critical
+    seclabel u:r:healthd:s0
+
+service healthd-charger /sbin/healthd -n
+    class charger
+    critical
+    seclabel u:r:healthd:s0
+
 service console /system/bin/sh
     class core
     console
@@ -431,6 +452,7 @@
     user system
     group system
     critical
+    onrestart restart healthd
     onrestart restart zygote
     onrestart restart media
     onrestart restart surfaceflinger
diff --git a/run-as/package.c b/run-as/package.c
index 27fc1eb..901e9e3 100644
--- a/run-as/package.c
+++ b/run-as/package.c
@@ -90,7 +90,7 @@
      */
 
     oldegid = getegid();
-    if (setegid(AID_SYSTEM) < 0) {
+    if (setegid(AID_PACKAGE_INFO) < 0) {
         return NULL;
     }
 
@@ -111,7 +111,7 @@
         goto EXIT;
 
     /* Ensure that the file is owned by the system user */
-    if ((st.st_uid != AID_SYSTEM) || (st.st_gid != AID_SYSTEM)) {
+    if ((st.st_uid != AID_SYSTEM) || (st.st_gid != AID_PACKAGE_INFO)) {
         goto EXIT;
     }
 
diff --git a/run-as/run-as.c b/run-as/run-as.c
index 3c0ecc4..cc05e63 100644
--- a/run-as/run-as.c
+++ b/run-as/run-as.c
@@ -36,9 +36,9 @@
 /*
  *  WARNING WARNING WARNING WARNING
  *
- *  This program runs as set-uid root on Android production devices.
- *  Be very conservative when modifying it to avoid any serious
- *  security issue. Keep in mind the following:
+ *  This program runs with CAP_SETUID and CAP_SETGID capabilities on Android
+ *  production devices. Be very conservative when modifying it to avoid any
+ *  serious security issue. Keep in mind the following:
  *
  *  - This program should only run for the 'root' or 'shell' users
  *
@@ -61,14 +61,19 @@
  *
  *   run-as <package-name> <command> <args>
  *
- *  The 'run-as' binary is setuid, but will check the following:
+ *  The 'run-as' binary is installed with CAP_SETUID and CAP_SETGID file
+ *  capabilities, but will check the following:
  *
  *  - that it is invoked from the 'shell' or 'root' user (abort otherwise)
  *  - that '<package-name>' is the name of an installed and debuggable package
  *  - that the package's data directory is well-formed (see package.c)
  *
- *  If so, it will cd to the package's data directory, drop to the application's
- *  user id / group id then run the command there.
+ *  If so, it will drop to the application's user id / group id, cd to the
+ *  package's data directory, then run the command there.
+ *
+ *  NOTE: In the future it might not be possible to cd to the package's data
+ *  directory under that package's user id / group id, in which case this
+ *  utility will need to be changed accordingly.
  *
  *  This can be useful for a number of different things on production devices:
  *
@@ -141,19 +146,6 @@
         return 1;
     }
 
-    /* then move to it */
-    {
-        int ret;
-        do {
-            ret = chdir(info.dataDir);
-        } while (ret < 0 && errno == EINTR);
-
-        if (ret < 0) {
-            panic("Could not cd to package's data directory: %s\n", strerror(errno));
-            return 1;
-        }
-    }
-
     /* Ensure that we change all real/effective/saved IDs at the
      * same time to avoid nasty surprises.
      */
@@ -168,6 +160,19 @@
         return 1;
     }
 
+    /* cd into the data directory */
+    {
+        int ret;
+        do {
+            ret = chdir(info.dataDir);
+        } while (ret < 0 && errno == EINTR);
+
+        if (ret < 0) {
+            panic("Could not cd to package's data directory: %s\n", strerror(errno));
+            return 1;
+        }
+    }
+
     /* User specified command for exec. */
     if (argc >= 3 ) {
         if (execvp(argv[2], argv+2) < 0) {
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index fb04d6d..4630db9 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -6,6 +6,6 @@
 LOCAL_MODULE:= sdcard
 LOCAL_CFLAGS := -Wall -Wno-unused-parameter
 
-LOCAL_SHARED_LIBRARIES := libc
+LOCAL_SHARED_LIBRARIES := libc libcutils
 
 include $(BUILD_EXECUTABLE)
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index bff6e67..05fbfba 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -30,6 +30,11 @@
 #include <pthread.h>
 #include <sys/time.h>
 #include <sys/resource.h>
+#include <sys/inotify.h>
+
+#include <cutils/fs.h>
+#include <cutils/hashmap.h>
+#include <cutils/multiuser.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -57,6 +62,30 @@
  * - if an op that returns a fuse_entry fails writing the reply to the
  * kernel, you must rollback the refcount to reflect the reference the
  * kernel did not actually acquire
+ *
+ * This daemon can also derive custom filesystem permissions based on directory
+ * structure when requested. These custom permissions support several features:
+ *
+ * - Apps can access their own files in /Android/data/com.example/ without
+ * requiring any additional GIDs.
+ * - Separate permissions for protecting directories like Pictures and Music.
+ * - Multi-user separation on the same physical device.
+ *
+ * The derived permissions look like this:
+ *
+ * rwxrwx--x root:sdcard_rw     /
+ * rwxrwx--- root:sdcard_pics   /Pictures
+ * rwxrwx--- root:sdcard_av     /Music
+ *
+ * rwxrwx--x root:sdcard_rw     /Android
+ * rwxrwx--x root:sdcard_rw     /Android/data
+ * rwxrwx--- u0_a12:sdcard_rw   /Android/data/com.example
+ * rwxrwx--x root:sdcard_rw     /Android/obb/
+ * rwxrwx--- u0_a12:sdcard_rw   /Android/obb/com.example
+ *
+ * rwxrwx--- root:sdcard_all    /Android/user
+ * rwxrwx--x root:sdcard_rw     /Android/user/10
+ * rwxrwx--- u10_a12:sdcard_rw  /Android/user/10/Android/data/com.example
  */
 
 #define FUSE_TRACE 0
@@ -89,6 +118,39 @@
  * or that a reply has already been written. */
 #define NO_STATUS 1
 
+/* Path to system-provided mapping of package name to appIds */
+static const char* const kPackagesListFile = "/data/system/packages.list";
+
+/* Supplementary groups to execute with */
+static const gid_t kGroups[1] = { AID_PACKAGE_INFO };
+
+/* Permission mode for a specific node. Controls how file permissions
+ * are derived for children nodes. */
+typedef enum {
+    /* Nothing special; this node should just inherit from its parent. */
+    PERM_INHERIT,
+    /* This node is one level above a normal root; used for legacy layouts
+     * which use the first level to represent user_id. */
+    PERM_LEGACY_PRE_ROOT,
+    /* This node is "/" */
+    PERM_ROOT,
+    /* This node is "/Android" */
+    PERM_ANDROID,
+    /* This node is "/Android/data" */
+    PERM_ANDROID_DATA,
+    /* This node is "/Android/obb" */
+    PERM_ANDROID_OBB,
+    /* This node is "/Android/user" */
+    PERM_ANDROID_USER,
+} perm_t;
+
+/* Permissions structure to derive */
+typedef enum {
+    DERIVE_NONE,
+    DERIVE_LEGACY,
+    DERIVE_UNIFIED,
+} derive_t;
+
 struct handle {
     int fd;
 };
@@ -102,6 +164,13 @@
     __u64 nid;
     __u64 gen;
 
+    /* State derived based on current position in hierarchy. */
+    perm_t perm;
+    userid_t userid;
+    uid_t uid;
+    gid_t gid;
+    mode_t mode;
+
     struct node *next;          /* per-dir sibling list */
     struct node *child;         /* first contained file by this dir */
     struct node *parent;        /* containing directory */
@@ -114,16 +183,44 @@
      * namelen for both fields.
      */
     char *actual_name;
+
+    /* If non-null, an exact underlying path that should be grafted into this
+     * position. Used to support things like OBB. */
+    char* graft_path;
+    size_t graft_pathlen;
 };
 
+static int str_hash(void *key) {
+    return hashmapHash(key, strlen(key));
+}
+
+/** Test if two string keys are equal ignoring case */
+static bool str_icase_equals(void *keyA, void *keyB) {
+    return strcasecmp(keyA, keyB) == 0;
+}
+
+static int int_hash(void *key) {
+    return (int) key;
+}
+
+static bool int_equals(void *keyA, void *keyB) {
+    return keyA == keyB;
+}
+
 /* Global data structure shared by all fuse handlers. */
 struct fuse {
     pthread_mutex_t lock;
 
     __u64 next_generation;
     int fd;
+    derive_t derive;
+    bool split_perms;
+    gid_t write_gid;
     struct node root;
-    char rootpath[PATH_MAX];
+    char obbpath[PATH_MAX];
+
+    Hashmap* package_to_appid;
+    Hashmap* appid_with_rw;
 };
 
 /* Private data used by a single fuse handler. */
@@ -208,15 +305,26 @@
  * Populates 'buf' with the path and returns the length of the path on success,
  * or returns -1 if the path is too long for the provided buffer.
  */
-static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize)
-{
-    size_t namelen = node->namelen;
+static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) {
+    const char* name;
+    size_t namelen;
+    if (node->graft_path) {
+        name = node->graft_path;
+        namelen = node->graft_pathlen;
+    } else if (node->actual_name) {
+        name = node->actual_name;
+        namelen = node->namelen;
+    } else {
+        name = node->name;
+        namelen = node->namelen;
+    }
+
     if (bufsize < namelen + 1) {
         return -1;
     }
 
     ssize_t pathlen = 0;
-    if (node->parent) {
+    if (node->parent && node->graft_path == NULL) {
         pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 2);
         if (pathlen < 0) {
             return -1;
@@ -224,7 +332,6 @@
         buf[pathlen++] = '/';
     }
 
-    const char* name = node->actual_name ? node->actual_name : node->name;
     memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
     return pathlen + namelen;
 }
@@ -258,7 +365,7 @@
         struct dirent* entry;
         DIR* dir = opendir(path);
         if (!dir) {
-            ERROR("opendir %s failed: %s", path, strerror(errno));
+            ERROR("opendir %s failed: %s\n", path, strerror(errno));
             return actual;
         }
         while ((entry = readdir(dir))) {
@@ -273,9 +380,9 @@
     return actual;
 }
 
-static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, __u64 nid)
+static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, const struct node* node)
 {
-    attr->ino = nid;
+    attr->ino = node->nid;
     attr->size = s->st_size;
     attr->blocks = s->st_blocks;
     attr->atime = s->st_atime;
@@ -287,19 +394,169 @@
     attr->mode = s->st_mode;
     attr->nlink = s->st_nlink;
 
-        /* force permissions to something reasonable:
-         * world readable
-         * writable by the sdcard group
-         */
-    if (attr->mode & 0100) {
-        attr->mode = (attr->mode & (~0777)) | 0775;
-    } else {
-        attr->mode = (attr->mode & (~0777)) | 0664;
+    attr->uid = node->uid;
+    attr->gid = node->gid;
+
+    /* Filter requested mode based on underlying file, and
+     * pass through file type. */
+    int owner_mode = s->st_mode & 0700;
+    int filtered_mode = node->mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
+    attr->mode = (attr->mode & S_IFMT) | filtered_mode;
+}
+
+static int touch(char* path, mode_t mode) {
+    int fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, mode);
+    if (fd == -1) {
+        if (errno == EEXIST) {
+            return 0;
+        } else {
+            ERROR("Failed to open(%s): %s\n", path, strerror(errno));
+            return -1;
+        }
+    }
+    close(fd);
+    return 0;
+}
+
+static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
+        struct node *node) {
+    appid_t appid;
+
+    /* By default, each node inherits from its parent */
+    node->perm = PERM_INHERIT;
+    node->userid = parent->userid;
+    node->uid = parent->uid;
+    node->gid = parent->gid;
+    node->mode = parent->mode;
+
+    if (fuse->derive == DERIVE_NONE) {
+        return;
     }
 
-        /* all files owned by root.sdcard */
-    attr->uid = 0;
-    attr->gid = AID_SDCARD_RW;
+    /* Derive custom permissions based on parent and current node */
+    switch (parent->perm) {
+    case PERM_INHERIT:
+        /* Already inherited above */
+        break;
+    case PERM_LEGACY_PRE_ROOT:
+        /* Legacy internal layout places users at top level */
+        node->perm = PERM_ROOT;
+        node->userid = strtoul(node->name, NULL, 10);
+        break;
+    case PERM_ROOT:
+        /* Assume masked off by default. */
+        node->mode = 0770;
+        if (!strcasecmp(node->name, "Android")) {
+            /* App-specific directories inside; let anyone traverse */
+            node->perm = PERM_ANDROID;
+            node->mode = 0771;
+        } else if (fuse->split_perms) {
+            if (!strcasecmp(node->name, "DCIM")
+                    || !strcasecmp(node->name, "Pictures")) {
+                node->gid = AID_SDCARD_PICS;
+            } else if (!strcasecmp(node->name, "Alarms")
+                    || !strcasecmp(node->name, "Movies")
+                    || !strcasecmp(node->name, "Music")
+                    || !strcasecmp(node->name, "Notifications")
+                    || !strcasecmp(node->name, "Podcasts")
+                    || !strcasecmp(node->name, "Ringtones")) {
+                node->gid = AID_SDCARD_AV;
+            }
+        }
+        break;
+    case PERM_ANDROID:
+        if (!strcasecmp(node->name, "data")) {
+            /* App-specific directories inside; let anyone traverse */
+            node->perm = PERM_ANDROID_DATA;
+            node->mode = 0771;
+        } else if (!strcasecmp(node->name, "obb")) {
+            /* App-specific directories inside; let anyone traverse */
+            node->perm = PERM_ANDROID_OBB;
+            node->mode = 0771;
+            /* Single OBB directory is always shared */
+            node->graft_path = fuse->obbpath;
+            node->graft_pathlen = strlen(fuse->obbpath);
+        } else if (!strcasecmp(node->name, "user")) {
+            /* User directories must only be accessible to system, protected
+             * by sdcard_all. Zygote will bind mount the appropriate user-
+             * specific path. */
+            node->perm = PERM_ANDROID_USER;
+            node->gid = AID_SDCARD_ALL;
+            node->mode = 0770;
+        }
+        break;
+    case PERM_ANDROID_DATA:
+    case PERM_ANDROID_OBB:
+        appid = (appid_t) hashmapGet(fuse->package_to_appid, node->name);
+        if (appid != 0) {
+            node->uid = multiuser_get_uid(parent->userid, appid);
+        }
+        node->mode = 0770;
+        break;
+    case PERM_ANDROID_USER:
+        /* Root of a secondary user */
+        node->perm = PERM_ROOT;
+        node->userid = strtoul(node->name, NULL, 10);
+        node->gid = AID_SDCARD_R;
+        node->mode = 0771;
+        break;
+    }
+}
+
+/* Return if the calling UID holds sdcard_rw. */
+static bool get_caller_has_rw_locked(struct fuse* fuse, const struct fuse_in_header *hdr) {
+    /* No additional permissions enforcement */
+    if (fuse->derive == DERIVE_NONE) {
+        return true;
+    }
+
+    appid_t appid = multiuser_get_app_id(hdr->uid);
+    return hashmapContainsKey(fuse->appid_with_rw, (void*) appid);
+}
+
+/* Kernel has already enforced everything we returned through
+ * derive_permissions_locked(), so this is used to lock down access
+ * even further, such as enforcing that apps hold sdcard_rw. */
+static bool check_caller_access_to_name(struct fuse* fuse,
+        const struct fuse_in_header *hdr, const struct node* parent_node,
+        const char* name, int mode, bool has_rw) {
+    /* Always block security-sensitive files at root */
+    if (parent_node && parent_node->perm == PERM_ROOT) {
+        if (!strcasecmp(name, "autorun.inf")
+                || !strcasecmp(name, ".android_secure")
+                || !strcasecmp(name, "android_secure")) {
+            return false;
+        }
+    }
+
+    /* No additional permissions enforcement */
+    if (fuse->derive == DERIVE_NONE) {
+        return true;
+    }
+
+    /* Root always has access; access for any other UIDs should always
+     * be controlled through packages.list. */
+    if (hdr->uid == 0) {
+        return true;
+    }
+
+    /* If asking to write, verify that caller either owns the
+     * parent or holds sdcard_rw. */
+    if (mode & W_OK) {
+        if (parent_node && hdr->uid == parent_node->uid) {
+            return true;
+        }
+
+        return has_rw;
+    }
+
+    /* No extra permissions to enforce */
+    return true;
+}
+
+static bool check_caller_access_to_node(struct fuse* fuse,
+        const struct fuse_in_header *hdr, const struct node* node, int mode, bool has_rw) {
+    return check_caller_access_to_name(fuse, hdr, node->parent, node->name, mode, has_rw);
 }
 
 struct node *create_node_locked(struct fuse* fuse,
@@ -330,6 +587,8 @@
     node->namelen = namelen;
     node->nid = ptr_to_id(node);
     node->gen = fuse->next_generation++;
+
+    derive_permissions_locked(fuse, parent, node);
     acquire_node_locked(node);
     add_node_to_parent_locked(node, parent);
     return node;
@@ -422,18 +681,56 @@
     return child;
 }
 
-static void fuse_init(struct fuse *fuse, int fd, const char *source_path)
-{
+static void fuse_init(struct fuse *fuse, int fd, const char *source_path,
+        gid_t write_gid, derive_t derive, bool split_perms) {
     pthread_mutex_init(&fuse->lock, NULL);
 
     fuse->fd = fd;
     fuse->next_generation = 0;
+    fuse->derive = derive;
+    fuse->split_perms = split_perms;
+    fuse->write_gid = write_gid;
 
     memset(&fuse->root, 0, sizeof(fuse->root));
     fuse->root.nid = FUSE_ROOT_ID; /* 1 */
     fuse->root.refcount = 2;
     fuse->root.namelen = strlen(source_path);
     fuse->root.name = strdup(source_path);
+    fuse->root.userid = 0;
+    fuse->root.uid = AID_ROOT;
+
+    /* Set up root node for various modes of operation */
+    switch (derive) {
+    case DERIVE_NONE:
+        /* Traditional behavior that treats entire device as being accessible
+         * to sdcard_rw, and no permissions are derived. */
+        fuse->root.perm = PERM_ROOT;
+        fuse->root.mode = 0775;
+        fuse->root.gid = AID_SDCARD_RW;
+        break;
+    case DERIVE_LEGACY:
+        /* Legacy behavior used to support internal multiuser layout which
+         * places user_id at the top directory level, with the actual roots
+         * just below that. Shared OBB path is also at top level. */
+        fuse->root.perm = PERM_LEGACY_PRE_ROOT;
+        fuse->root.mode = 0771;
+        fuse->root.gid = AID_SDCARD_R;
+        fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
+        fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
+        snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/obb", source_path);
+        fs_prepare_dir(fuse->obbpath, 0775, getuid(), getgid());
+        break;
+    case DERIVE_UNIFIED:
+        /* Unified multiuser layout which places secondary user_id under
+         * /Android/user and shared OBB path under /Android/obb. */
+        fuse->root.perm = PERM_ROOT;
+        fuse->root.mode = 0771;
+        fuse->root.gid = AID_SDCARD_R;
+        fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
+        fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
+        snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/Android/obb", source_path);
+        break;
+    }
 }
 
 static void fuse_status(struct fuse *fuse, __u64 unique, int err)
@@ -485,7 +782,7 @@
         return -ENOMEM;
     }
     memset(&out, 0, sizeof(out));
-    attr_from_stat(&out.attr, &s, node->nid);
+    attr_from_stat(&out.attr, &s, node);
     out.attr_valid = 10;
     out.entry_valid = 10;
     out.nodeid = node->nid;
@@ -495,7 +792,7 @@
     return NO_STATUS;
 }
 
-static int fuse_reply_attr(struct fuse* fuse, __u64 unique, __u64 nid,
+static int fuse_reply_attr(struct fuse* fuse, __u64 unique, const struct node* node,
         const char* path)
 {
     struct fuse_attr_out out;
@@ -505,7 +802,7 @@
         return -errno;
     }
     memset(&out, 0, sizeof(out));
-    attr_from_stat(&out.attr, &s, nid);
+    attr_from_stat(&out.attr, &s, node);
     out.attr_valid = 10;
     fuse_reply(fuse, unique, &out, sizeof(out));
     return NO_STATUS;
@@ -530,6 +827,10 @@
             child_path, sizeof(child_path), 1))) {
         return -ENOENT;
     }
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, R_OK, false)) {
+        return -EACCES;
+    }
+
     return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
 }
 
@@ -567,17 +868,23 @@
     if (!node) {
         return -ENOENT;
     }
-    return fuse_reply_attr(fuse, hdr->unique, hdr->nodeid, path);
+    if (!check_caller_access_to_node(fuse, hdr, node, R_OK, false)) {
+        return -EACCES;
+    }
+
+    return fuse_reply_attr(fuse, hdr->unique, node, path);
 }
 
 static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
 {
+    bool has_rw;
     struct node* node;
     char path[PATH_MAX];
     struct timespec times[2];
 
     pthread_mutex_lock(&fuse->lock);
+    has_rw = get_caller_has_rw_locked(fuse, hdr);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
     TRACE("[%d] SETATTR fh=%llx valid=%x @ %llx (%s)\n", handler->token,
             req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
@@ -586,6 +893,9 @@
     if (!node) {
         return -ENOENT;
     }
+    if (!check_caller_access_to_node(fuse, hdr, node, W_OK, has_rw)) {
+        return -EACCES;
+    }
 
     /* XXX: incomplete implementation on purpose.
      * chmod/chown should NEVER be implemented.*/
@@ -625,18 +935,20 @@
             return -errno;
         }
     }
-    return fuse_reply_attr(fuse, hdr->unique, hdr->nodeid, path);
+    return fuse_reply_attr(fuse, hdr->unique, node, path);
 }
 
 static int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
 {
+    bool has_rw;
     struct node* parent_node;
     char parent_path[PATH_MAX];
     char child_path[PATH_MAX];
     const char* actual_name;
 
     pthread_mutex_lock(&fuse->lock);
+    has_rw = get_caller_has_rw_locked(fuse, hdr);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
     TRACE("[%d] MKNOD %s 0%o @ %llx (%s)\n", handler->token,
@@ -647,6 +959,9 @@
             child_path, sizeof(child_path), 1))) {
         return -ENOENT;
     }
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK, has_rw)) {
+        return -EACCES;
+    }
     __u32 mode = (req->mode & (~0777)) | 0664;
     if (mknod(child_path, mode, req->rdev) < 0) {
         return -errno;
@@ -657,12 +972,14 @@
 static int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
 {
+    bool has_rw;
     struct node* parent_node;
     char parent_path[PATH_MAX];
     char child_path[PATH_MAX];
     const char* actual_name;
 
     pthread_mutex_lock(&fuse->lock);
+    has_rw = get_caller_has_rw_locked(fuse, hdr);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
     TRACE("[%d] MKDIR %s 0%o @ %llx (%s)\n", handler->token,
@@ -673,21 +990,45 @@
             child_path, sizeof(child_path), 1))) {
         return -ENOENT;
     }
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK, has_rw)) {
+        return -EACCES;
+    }
     __u32 mode = (req->mode & (~0777)) | 0775;
     if (mkdir(child_path, mode) < 0) {
         return -errno;
     }
+
+    /* When creating /Android/data and /Android/obb, mark them as .nomedia */
+    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "data")) {
+        char nomedia[PATH_MAX];
+        snprintf(nomedia, PATH_MAX, "%s/.nomedia", child_path);
+        if (touch(nomedia, 0664) != 0) {
+            ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
+            return -ENOENT;
+        }
+    }
+    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
+        char nomedia[PATH_MAX];
+        snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->obbpath);
+        if (touch(nomedia, 0664) != 0) {
+            ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
+            return -ENOENT;
+        }
+    }
+
     return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
 }
 
 static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const char* name)
 {
+    bool has_rw;
     struct node* parent_node;
     char parent_path[PATH_MAX];
     char child_path[PATH_MAX];
 
     pthread_mutex_lock(&fuse->lock);
+    has_rw = get_caller_has_rw_locked(fuse, hdr);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
     TRACE("[%d] UNLINK %s @ %llx (%s)\n", handler->token,
@@ -698,6 +1039,9 @@
             child_path, sizeof(child_path), 1)) {
         return -ENOENT;
     }
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK, has_rw)) {
+        return -EACCES;
+    }
     if (unlink(child_path) < 0) {
         return -errno;
     }
@@ -707,11 +1051,13 @@
 static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const char* name)
 {
+    bool has_rw;
     struct node* parent_node;
     char parent_path[PATH_MAX];
     char child_path[PATH_MAX];
 
     pthread_mutex_lock(&fuse->lock);
+    has_rw = get_caller_has_rw_locked(fuse, hdr);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
     TRACE("[%d] RMDIR %s @ %llx (%s)\n", handler->token,
@@ -722,6 +1068,9 @@
             child_path, sizeof(child_path), 1)) {
         return -ENOENT;
     }
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK, has_rw)) {
+        return -EACCES;
+    }
     if (rmdir(child_path) < 0) {
         return -errno;
     }
@@ -732,6 +1081,7 @@
         const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
         const char* old_name, const char* new_name)
 {
+    bool has_rw;
     struct node* old_parent_node;
     struct node* new_parent_node;
     struct node* child_node;
@@ -743,6 +1093,7 @@
     int res;
 
     pthread_mutex_lock(&fuse->lock);
+    has_rw = get_caller_has_rw_locked(fuse, hdr);
     old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             old_parent_path, sizeof(old_parent_path));
     new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
@@ -755,6 +1106,14 @@
         res = -ENOENT;
         goto lookup_error;
     }
+    if (!check_caller_access_to_name(fuse, hdr, old_parent_node, old_name, W_OK, has_rw)) {
+        res = -EACCES;
+        goto lookup_error;
+    }
+    if (!check_caller_access_to_name(fuse, hdr, new_parent_node, new_name, W_OK, has_rw)) {
+        res = -EACCES;
+        goto lookup_error;
+    }
     child_node = lookup_child_by_name_locked(old_parent_node, old_name);
     if (!child_node || get_node_path_locked(child_node,
             old_child_path, sizeof(old_child_path)) < 0) {
@@ -800,15 +1159,28 @@
     return res;
 }
 
+static int open_flags_to_access_mode(int open_flags) {
+    if ((open_flags & O_ACCMODE) == O_RDONLY) {
+        return R_OK;
+    } else if ((open_flags & O_ACCMODE) == O_WRONLY) {
+        return W_OK;
+    } else {
+        /* Probably O_RDRW, but treat as default to be safe */
+        return R_OK | W_OK;
+    }
+}
+
 static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const struct fuse_open_in* req)
 {
+    bool has_rw;
     struct node* node;
     char path[PATH_MAX];
     struct fuse_open_out out;
     struct handle *h;
 
     pthread_mutex_lock(&fuse->lock);
+    has_rw = get_caller_has_rw_locked(fuse, hdr);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
     TRACE("[%d] OPEN 0%o @ %llx (%s)\n", handler->token,
             req->flags, hdr->nodeid, node ? node->name : "?");
@@ -817,6 +1189,10 @@
     if (!node) {
         return -ENOENT;
     }
+    if (!check_caller_access_to_node(fuse, hdr, node,
+            open_flags_to_access_mode(req->flags), has_rw)) {
+        return -EACCES;
+    }
     h = malloc(sizeof(*h));
     if (!h) {
         return -ENOMEM;
@@ -961,6 +1337,9 @@
     if (!node) {
         return -ENOENT;
     }
+    if (!check_caller_access_to_node(fuse, hdr, node, R_OK, false)) {
+        return -EACCES;
+    }
     h = malloc(sizeof(*h));
     if (!h) {
         return -ENOMEM;
@@ -972,6 +1351,8 @@
         return -errno;
     }
     out.fh = ptr_to_id(h);
+    out.open_flags = 0;
+    out.padding = 0;
     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
     return NO_STATUS;
 }
@@ -1206,6 +1587,123 @@
     return NULL;
 }
 
+static bool remove_str_to_int(void *key, void *value, void *context) {
+    Hashmap* map = context;
+    hashmapRemove(map, key);
+    free(key);
+    return true;
+}
+
+static bool remove_int_to_null(void *key, void *value, void *context) {
+    Hashmap* map = context;
+    hashmapRemove(map, key);
+    return true;
+}
+
+static int read_package_list(struct fuse *fuse) {
+    pthread_mutex_lock(&fuse->lock);
+
+    hashmapForEach(fuse->package_to_appid, remove_str_to_int, fuse->package_to_appid);
+    hashmapForEach(fuse->appid_with_rw, remove_int_to_null, fuse->appid_with_rw);
+
+    FILE* file = fopen(kPackagesListFile, "r");
+    if (!file) {
+        ERROR("failed to open package list: %s\n", strerror(errno));
+        pthread_mutex_unlock(&fuse->lock);
+        return -1;
+    }
+
+    char buf[512];
+    while (fgets(buf, sizeof(buf), file) != NULL) {
+        char package_name[512];
+        int appid;
+        char gids[512];
+
+        if (sscanf(buf, "%s %d %*d %*s %*s %s", package_name, &appid, gids) == 3) {
+            char* package_name_dup = strdup(package_name);
+            hashmapPut(fuse->package_to_appid, package_name_dup, (void*) appid);
+
+            char* token = strtok(gids, ",");
+            while (token != NULL) {
+                if (strtoul(token, NULL, 10) == fuse->write_gid) {
+                    hashmapPut(fuse->appid_with_rw, (void*) appid, (void*) 1);
+                    break;
+                }
+                token = strtok(NULL, ",");
+            }
+        }
+    }
+
+    TRACE("read_package_list: found %d packages, %d with write_gid\n",
+            hashmapSize(fuse->package_to_appid),
+            hashmapSize(fuse->appid_with_rw));
+    fclose(file);
+    pthread_mutex_unlock(&fuse->lock);
+    return 0;
+}
+
+static void watch_package_list(struct fuse* fuse) {
+    struct inotify_event *event;
+    char event_buf[512];
+
+    int nfd = inotify_init();
+    if (nfd < 0) {
+        ERROR("inotify_init failed: %s\n", strerror(errno));
+        return;
+    }
+
+    bool active = false;
+    while (1) {
+        if (!active) {
+            int res = inotify_add_watch(nfd, kPackagesListFile, IN_DELETE_SELF);
+            if (res == -1) {
+                if (errno == ENOENT || errno == EACCES) {
+                    /* Framework may not have created yet, sleep and retry */
+                    ERROR("missing packages.list; retrying\n");
+                    sleep(3);
+                    continue;
+                } else {
+                    ERROR("inotify_add_watch failed: %s\n", strerror(errno));
+                    return;
+                }
+            }
+
+            /* Watch above will tell us about any future changes, so
+             * read the current state. */
+            if (read_package_list(fuse) == -1) {
+                ERROR("read_package_list failed: %s\n", strerror(errno));
+                return;
+            }
+            active = true;
+        }
+
+        int event_pos = 0;
+        int res = read(nfd, event_buf, sizeof(event_buf));
+        if (res < (int) sizeof(*event)) {
+            if (errno == EINTR)
+                continue;
+            ERROR("failed to read inotify event: %s\n", strerror(errno));
+            return;
+        }
+
+        while (res >= (int) sizeof(*event)) {
+            int event_size;
+            event = (struct inotify_event *) (event_buf + event_pos);
+
+            TRACE("inotify event: %08x\n", event->mask);
+            if ((event->mask & IN_IGNORED) == IN_IGNORED) {
+                /* Previously watched file was deleted, probably due to move
+                 * that swapped in new data; re-arm the watch and read. */
+                active = false;
+            }
+
+            event_size = sizeof(*event) + event->len;
+            res -= event_size;
+            event_pos += event_size;
+        }
+    }
+}
+
 static int ignite_fuse(struct fuse* fuse, int num_threads)
 {
     struct fuse_handler* handlers;
@@ -1213,7 +1711,7 @@
 
     handlers = malloc(num_threads * sizeof(struct fuse_handler));
     if (!handlers) {
-        ERROR("cannot allocate storage for threads");
+        ERROR("cannot allocate storage for threads\n");
         return -ENOMEM;
     }
 
@@ -1222,16 +1720,25 @@
         handlers[i].token = i;
     }
 
-    for (i = 1; i < num_threads; i++) {
+    /* When deriving permissions, this thread is used to process inotify events,
+     * otherwise it becomes one of the FUSE handlers. */
+    i = (fuse->derive == DERIVE_NONE) ? 1 : 0;
+    for (; i < num_threads; i++) {
         pthread_t thread;
         int res = pthread_create(&thread, NULL, start_handler, &handlers[i]);
         if (res) {
-            ERROR("failed to start thread #%d, error=%d", i, res);
+            ERROR("failed to start thread #%d, error=%d\n", i, res);
             goto quit;
         }
     }
-    handle_fuse_requests(&handlers[0]);
-    ERROR("terminated prematurely");
+
+    if (fuse->derive == DERIVE_NONE) {
+        handle_fuse_requests(&handlers[0]);
+    } else {
+        watch_package_list(fuse);
+    }
+
+    ERROR("terminated prematurely\n");
 
     /* don't bother killing all of the other threads or freeing anything,
      * should never get here anyhow */
@@ -1241,14 +1748,21 @@
 
 static int usage()
 {
-    ERROR("usage: sdcard [-t<threads>] <source_path> <dest_path> <uid> <gid>\n"
-            "    -t<threads>: specify number of threads to use, default -t%d\n"
+    ERROR("usage: sdcard [OPTIONS] <source_path> <dest_path>\n"
+            "    -u: specify UID to run as\n"
+            "    -g: specify GID to run as\n"
+            "    -w: specify GID required to write (default sdcard_rw, requires -d or -l)\n"
+            "    -t: specify number of threads to use (default %d)\n"
+            "    -d: derive file permissions based on path\n"
+            "    -l: derive file permissions based on legacy internal layout\n"
+            "    -s: split derived permissions for pics, av\n"
             "\n", DEFAULT_NUM_THREADS);
     return 1;
 }
 
-static int run(const char* source_path, const char* dest_path, uid_t uid, gid_t gid,
-        int num_threads) {
+static int run(const char* source_path, const char* dest_path, uid_t uid,
+        gid_t gid, gid_t write_gid, int num_threads, derive_t derive,
+        bool split_perms) {
     int fd;
     char opts[256];
     int res;
@@ -1259,7 +1773,7 @@
 
     fd = open("/dev/fuse", O_RDWR);
     if (fd < 0){
-        ERROR("cannot open fuse device (error %d)\n", errno);
+        ERROR("cannot open fuse device: %s\n", strerror(errno));
         return -1;
     }
 
@@ -1269,23 +1783,29 @@
 
     res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV, opts);
     if (res < 0) {
-        ERROR("cannot mount fuse filesystem (error %d)\n", errno);
+        ERROR("cannot mount fuse filesystem: %s\n", strerror(errno));
+        goto error;
+    }
+
+    res = setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups);
+    if (res < 0) {
+        ERROR("cannot setgroups: %s\n", strerror(errno));
         goto error;
     }
 
     res = setgid(gid);
     if (res < 0) {
-        ERROR("cannot setgid (error %d)\n", errno);
+        ERROR("cannot setgid: %s\n", strerror(errno));
         goto error;
     }
 
     res = setuid(uid);
     if (res < 0) {
-        ERROR("cannot setuid (error %d)\n", errno);
+        ERROR("cannot setuid: %s\n", strerror(errno));
         goto error;
     }
 
-    fuse_init(&fuse, fd, source_path);
+    fuse_init(&fuse, fd, source_path, write_gid, derive, split_perms);
 
     umask(0);
     res = ignite_fuse(&fuse, num_threads);
@@ -1305,34 +1825,53 @@
     const char *dest_path = NULL;
     uid_t uid = 0;
     gid_t gid = 0;
+    gid_t write_gid = AID_SDCARD_RW;
     int num_threads = DEFAULT_NUM_THREADS;
+    derive_t derive = DERIVE_NONE;
+    bool split_perms = false;
     int i;
     struct rlimit rlim;
 
-    for (i = 1; i < argc; i++) {
+    int opt;
+    while ((opt = getopt(argc, argv, "u:g:w:t:dls")) != -1) {
+        switch (opt) {
+            case 'u':
+                uid = strtoul(optarg, NULL, 10);
+                break;
+            case 'g':
+                gid = strtoul(optarg, NULL, 10);
+                break;
+            case 'w':
+                write_gid = strtoul(optarg, NULL, 10);
+                break;
+            case 't':
+                num_threads = strtoul(optarg, NULL, 10);
+                break;
+            case 'd':
+                derive = DERIVE_UNIFIED;
+                break;
+            case 'l':
+                derive = DERIVE_LEGACY;
+                break;
+            case 's':
+                split_perms = true;
+                break;
+            case '?':
+            default:
+                return usage();
+        }
+    }
+
+    for (i = optind; i < argc; i++) {
         char* arg = argv[i];
-        if (!strncmp(arg, "-t", 2))
-            num_threads = strtoul(arg + 2, 0, 10);
-        else if (!source_path)
+        if (!source_path) {
             source_path = arg;
-        else if (!dest_path)
+        } else if (!dest_path) {
             dest_path = arg;
-        else if (!uid) {
-            char* endptr = NULL;
-            errno = 0;
-            uid = strtoul(arg, &endptr, 10);
-            if (*endptr != '\0' || errno != 0) {
-                ERROR("Invalid uid");
-                return usage();
-            }
+        } else if (!uid) {
+            uid = strtoul(arg, NULL, 10);
         } else if (!gid) {
-            char* endptr = NULL;
-            errno = 0;
-            gid = strtoul(arg, &endptr, 10);
-            if (*endptr != '\0' || errno != 0) {
-                ERROR("Invalid gid");
-                return usage();
-            }
+            gid = strtoul(arg, NULL, 10);
         } else {
             ERROR("too many arguments\n");
             return usage();
@@ -1355,6 +1894,10 @@
         ERROR("number of threads must be at least 1\n");
         return usage();
     }
+    if (split_perms && derive == DERIVE_NONE) {
+        ERROR("cannot split permissions without deriving\n");
+        return usage();
+    }
 
     rlim.rlim_cur = 8192;
     rlim.rlim_max = 8192;
@@ -1362,6 +1905,6 @@
         ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
     }
 
-    res = run(source_path, dest_path, uid, gid, num_threads);
+    res = run(source_path, dest_path, uid, gid, write_gid, num_threads, derive, split_perms);
     return res < 0 ? 1 : 0;
 }
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index c764690..75ce53f 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -16,7 +16,6 @@
 	rm \
 	mkdir \
 	rmdir \
-	reboot \
 	getevent \
 	sendevent \
 	date \
@@ -66,7 +65,11 @@
 	runcon \
 	getsebool \
 	setsebool \
-	load_policy
+	load_policy \
+	swapon \
+	swapoff \
+	mkswap \
+	readlink
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
 TOOLS += r
diff --git a/toolbox/log.c b/toolbox/log.c
index f30e6a7..2f020a8 100644
--- a/toolbox/log.c
+++ b/toolbox/log.c
@@ -30,7 +30,7 @@
  */
 
 #include <stdio.h>
-#include <cutils/logd.h>
+#include <log/logd.h>
 #include <ctype.h>
 #include <sys/socket.h>
 #include <sys/types.h>
@@ -130,8 +130,8 @@
     buffer[0] = '\0';
     
     for (i = optind ; i < argc ; i++) {
-        strncat(buffer, argv[i], sizeof(buffer)-1);
-        strncat(buffer, " ", sizeof(buffer)-1);
+        strlcat(buffer, argv[i], sizeof(buffer)-1);
+        strlcat(buffer, " ", sizeof(buffer)-1);
     }
 
     if(buffer[0] == 0) {
diff --git a/toolbox/lsof.c b/toolbox/lsof.c
index 376a642..113c120 100644
--- a/toolbox/lsof.c
+++ b/toolbox/lsof.c
@@ -54,7 +54,7 @@
     ssize_t parent_length;
 };
 
-void print_header()
+static void print_header()
 {
     printf("%-9s %5s %10s %4s %9s %18s %9s %10s %s\n",
             "COMMAND",
@@ -68,12 +68,12 @@
             "NAME");
 }
 
-void print_type(char *type, struct pid_info_t* info)
+static void print_type(char *type, struct pid_info_t* info)
 {
     static ssize_t link_dest_size;
     static char link_dest[PATH_MAX];
 
-    strncat(info->path, type, sizeof(info->path));
+    strlcat(info->path, type, sizeof(info->path));
     if ((link_dest_size = readlink(info->path, link_dest, sizeof(link_dest)-1)) < 0) {
         if (errno == ENOENT)
             goto out;
@@ -96,7 +96,7 @@
 }
 
 // Prints out all file that have been memory mapped
-void print_maps(struct pid_info_t* info)
+static void print_maps(struct pid_info_t* info)
 {
     FILE *maps;
     char buffer[PATH_MAX + 100];
@@ -107,7 +107,7 @@
     long int inode;
     char file[PATH_MAX];
 
-    strncat(info->path, "maps", sizeof(info->path));
+    strlcat(info->path, "maps", sizeof(info->path));
 
     maps = fopen(info->path, "r");
     if (!maps)
@@ -131,10 +131,10 @@
 }
 
 // Prints out all open file descriptors
-void print_fds(struct pid_info_t* info)
+static void print_fds(struct pid_info_t* info)
 {
     static char* fd_path = "fd/";
-    strncat(info->path, fd_path, sizeof(info->path));
+    strlcat(info->path, fd_path, sizeof(info->path));
 
     int previous_length = info->parent_length;
     info->parent_length += strlen(fd_path);
@@ -163,7 +163,7 @@
     info->path[info->parent_length] = '\0';
 }
 
-void lsof_dumpinfo(pid_t pid)
+static void lsof_dumpinfo(pid_t pid)
 {
     int fd;
     struct pid_info_t info;
@@ -187,7 +187,7 @@
     }
 
     // Read the command line information; each argument is terminated with NULL.
-    strncat(info.path, "cmdline", sizeof(info.path));
+    strlcat(info.path, "cmdline", sizeof(info.path));
     fd = open(info.path, O_RDONLY);
     if (fd < 0) {
         fprintf(stderr, "Couldn't read %s\n", info.path);
diff --git a/toolbox/mkswap.c b/toolbox/mkswap.c
new file mode 100644
index 0000000..1710ef6
--- /dev/null
+++ b/toolbox/mkswap.c
@@ -0,0 +1,94 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <asm/page.h>
+#include <sys/swap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/* XXX This needs to be obtained from kernel headers. See b/9336527 */
+struct linux_swap_header {
+    char            bootbits[1024]; /* Space for disklabel etc. */
+    uint32_t        version;
+    uint32_t        last_page;
+    uint32_t        nr_badpages;
+    unsigned char   sws_uuid[16];
+    unsigned char   sws_volume[16];
+    uint32_t        padding[117];
+    uint32_t        badpages[1];
+};
+
+#define MAGIC_SWAP_HEADER     "SWAPSPACE2"
+#define MAGIC_SWAP_HEADER_LEN 10
+#define MIN_PAGES             10
+
+int mkswap_main(int argc, char **argv)
+{
+    int err = 0;
+    int fd;
+    ssize_t len;
+    off_t swap_size;
+    int pagesize;
+    struct linux_swap_header sw_hdr;
+
+    if (argc != 2) {
+        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
+        return -EINVAL;
+    }
+
+    fd = open(argv[1], O_WRONLY);
+    if (fd < 0) {
+        err = errno;
+        fprintf(stderr, "Cannot open %s\n", argv[1]);
+        return err;
+    }
+
+    pagesize = getpagesize();
+    /* Determine the length of the swap file */
+    swap_size = lseek(fd, 0, SEEK_END);
+    if (swap_size < MIN_PAGES * pagesize) {
+        fprintf(stderr, "Swap file needs to be at least %dkB\n",
+            (MIN_PAGES * pagesize) >> 10);
+        err = -ENOSPC;
+        goto err;
+    }
+    if (lseek(fd, 0, SEEK_SET)) {
+        err = errno;
+        fprintf(stderr, "Can't seek to the beginning of the file\n");
+        goto err;
+    }
+
+    memset(&sw_hdr, 0, sizeof(sw_hdr));
+    sw_hdr.version = 1;
+    sw_hdr.last_page = (swap_size / pagesize) - 1;
+
+    len = write(fd, &sw_hdr, sizeof(sw_hdr));
+    if (len != sizeof(sw_hdr)) {
+        err = errno;
+        fprintf(stderr, "Failed to write swap header into %s\n", argv[1]);
+        goto err;
+    }
+
+    /* Write the magic header */
+    if (lseek(fd, pagesize - MAGIC_SWAP_HEADER_LEN, SEEK_SET) < 0) {
+        err = errno;
+        fprintf(stderr, "Failed to seek into %s\n", argv[1]);
+        goto err;
+    }
+
+    len = write(fd, MAGIC_SWAP_HEADER, MAGIC_SWAP_HEADER_LEN);
+    if (len != MAGIC_SWAP_HEADER_LEN) {
+        err = errno;
+        fprintf(stderr, "Failed to write magic swap header into %s\n", argv[1]);
+        goto err;
+    }
+
+    if (fsync(fd) < 0) {
+        err = errno;
+        fprintf(stderr, "Failed to sync %s\n", argv[1]);
+        goto err;
+    }
+err:
+    close(fd);
+    return err;
+}
diff --git a/toolbox/mount.c b/toolbox/mount.c
index bcda2a2..66ae8b1 100644
--- a/toolbox/mount.c
+++ b/toolbox/mount.c
@@ -138,6 +138,24 @@
 	return rwflag;
 }
 
+/*
+ * Mark the given block device as read-write, using the BLKROSET ioctl.
+ */
+static void fs_set_blk_rw(const char *blockdev)
+{
+    int fd;
+    int OFF = 0;
+
+    fd = open(blockdev, O_RDONLY);
+    if (fd < 0) {
+        // should never happen
+        return;
+    }
+
+    ioctl(fd, BLKROSET, &OFF);
+    close(fd);
+}
+
 static char *progname;
 
 static struct extra_opts extra;
@@ -179,6 +197,10 @@
         dev = loopdev;
     }
 
+    if ((rwflag & MS_RDONLY) == 0) {
+        fs_set_blk_rw(dev);
+    }
+
 	while ((s = strsep(&type, ",")) != NULL) {
 retry:
 		if (mount(dev, dir, s, rwflag, data) == -1) {
diff --git a/toolbox/readlink.c b/toolbox/readlink.c
new file mode 100644
index 0000000..d114e20
--- /dev/null
+++ b/toolbox/readlink.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static int skip_newline, quiet_errors, canonicalize;
+
+static void usage(char* name) {
+    fprintf(stderr, "Usage: %s [OPTION]... FILE\n", name);
+}
+
+int readlink_main(int argc, char* argv[]) {
+    int c;
+    while ((c = getopt(argc, argv, "nfqs")) != -1) {
+        switch (c) {
+        case 'n':
+            skip_newline = 1;
+            break;
+        case 'f':
+            canonicalize = 1;
+            break;
+        case 'q':
+        case 's':
+            quiet_errors = 1;
+            break;
+        case '?':
+        default:
+            usage(argv[0]);
+            return EXIT_FAILURE;
+        }
+    }
+    int index = optind;
+    if (argc - index != 1) {
+        usage(argv[0]);
+        return EXIT_FAILURE;
+    }
+
+    char name[PATH_MAX+1];
+    if (canonicalize) {
+        if(!realpath(argv[optind], name)) {
+            if (!quiet_errors) {
+                perror("readlink");
+            }
+            return EXIT_FAILURE;
+        }
+    } else {
+        ssize_t len = readlink(argv[1], name, PATH_MAX);
+
+        if (len < 0) {
+            if (!quiet_errors) {
+                perror("readlink");
+            }
+            return EXIT_FAILURE;
+        }
+        name[len] = '\0';
+    }
+
+    fputs(name, stdout);
+    if (!skip_newline) {
+        fputs("\n", stdout);
+    }
+
+    return EXIT_SUCCESS;
+}
diff --git a/toolbox/reboot.c b/toolbox/reboot.c
deleted file mode 100644
index f8546de..0000000
--- a/toolbox/reboot.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <cutils/android_reboot.h>
-#include <unistd.h>
-
-int reboot_main(int argc, char *argv[])
-{
-    int ret;
-    int nosync = 0;
-    int poweroff = 0;
-    int flags = 0;
-
-    opterr = 0;
-    do {
-        int c;
-
-        c = getopt(argc, argv, "np");
-        
-        if (c == EOF) {
-            break;
-        }
-        
-        switch (c) {
-        case 'n':
-            nosync = 1;
-            break;
-        case 'p':
-            poweroff = 1;
-            break;
-        case '?':
-            fprintf(stderr, "usage: %s [-n] [-p] [rebootcommand]\n", argv[0]);
-            exit(EXIT_FAILURE);
-        }
-    } while (1);
-
-    if(argc > optind + 1) {
-        fprintf(stderr, "%s: too many arguments\n", argv[0]);
-        exit(EXIT_FAILURE);
-    }
-
-    if(nosync)
-        /* also set NO_REMOUNT_RO as remount ro includes an implicit sync */
-        flags = ANDROID_RB_FLAG_NO_SYNC | ANDROID_RB_FLAG_NO_REMOUNT_RO;
-
-    if(poweroff)
-        ret = android_reboot(ANDROID_RB_POWEROFF, flags, 0);
-    else if(argc > optind)
-        ret = android_reboot(ANDROID_RB_RESTART2, flags, argv[optind]);
-    else
-        ret = android_reboot(ANDROID_RB_RESTART, flags, 0);
-    if(ret < 0) {
-        perror("reboot");
-        exit(EXIT_FAILURE);
-    }
-    fprintf(stderr, "reboot returned\n");
-    return 0;
-}
diff --git a/toolbox/rm.c b/toolbox/rm.c
index 3a24bec..957b586 100644
--- a/toolbox/rm.c
+++ b/toolbox/rm.c
@@ -45,8 +45,10 @@
             continue;
         sprintf(dn, "%s/%s", name, de->d_name);
         if (unlink_recursive(dn, flags) < 0) {
-            fail = 1;
-            break;
+            if (!(flags & OPT_FORCE)) {
+                fail = 1;
+                break;
+            }
         }
         errno = 0;
     }
@@ -71,6 +73,7 @@
     int ret;
     int i, c;
     int flags = 0;
+    int something_failed = 0;
 
     if (argc < 2)
         return usage();
@@ -103,17 +106,21 @@
             ret = unlink_recursive(argv[i], flags);
         } else {
             ret = unlink(argv[i]);
-            if (errno == ENOENT && (flags & OPT_FORCE)) {
-                return 0;
+            if (ret < 0 && errno == ENOENT && (flags & OPT_FORCE)) {
+                continue;
             }
         }
 
         if (ret < 0) {
             fprintf(stderr, "rm failed for %s, %s\n", argv[i], strerror(errno));
-            return -1;
+            if (!(flags & OPT_FORCE)) {
+                return -1;
+            } else {
+                something_failed = 1;
+            }
         }
     }
 
-    return 0;
+    return something_failed;
 }
 
diff --git a/toolbox/swapoff.c b/toolbox/swapoff.c
new file mode 100644
index 0000000..8f14158
--- /dev/null
+++ b/toolbox/swapoff.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <asm/page.h>
+#include <sys/swap.h>
+
+int swapoff_main(int argc, char **argv)
+{
+    int err = 0;
+
+    if (argc != 2) {
+        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
+        return -EINVAL;
+    }
+
+    err = swapoff(argv[1]);
+    if (err) {
+        fprintf(stderr, "swapoff failed for %s\n", argv[1]);
+    }
+
+    return err;
+}
diff --git a/toolbox/swapon.c b/toolbox/swapon.c
new file mode 100644
index 0000000..afa6868
--- /dev/null
+++ b/toolbox/swapon.c
@@ -0,0 +1,73 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <asm/page.h>
+#include <sys/swap.h>
+
+/* XXX These need to be obtained from kernel headers. See b/9336527 */
+#define SWAP_FLAG_PREFER        0x8000
+#define SWAP_FLAG_PRIO_MASK     0x7fff
+#define SWAP_FLAG_PRIO_SHIFT    0
+#define SWAP_FLAG_DISCARD       0x10000
+
+void usage(char *name)
+{
+    fprintf(stderr, "Usage: %s [-p prio] <filename>\n"
+        "        prio must be between 0 and %d\n", name, SWAP_FLAG_PRIO_MASK);
+}
+
+int parse_prio(char *prio_str)
+{
+    unsigned long p = strtoul(prio_str, NULL, 10);
+
+    return (p > SWAP_FLAG_PRIO_MASK)? -1 : (int)p;
+}
+
+int swapon_main(int argc, char **argv)
+{
+    int err = 0;
+    int flags = 0;
+    int prio;
+
+    opterr = 0;
+    do {
+        int c = getopt(argc, argv, "hp:");
+        if (c == -1)
+            break;
+
+        switch (c) {
+            case 'p':
+                if (optarg != NULL)
+                    prio = parse_prio(optarg);
+                else
+                    prio = -1;
+
+                if (prio < 0) {
+                    usage(argv[0]);
+                    return -EINVAL;
+                }
+                flags |= SWAP_FLAG_PREFER;
+                flags |= (prio << SWAP_FLAG_PRIO_SHIFT) & SWAP_FLAG_PRIO_MASK;
+                break;
+            case 'h':
+                usage(argv[0]);
+                return 0;
+            case '?':
+                fprintf(stderr, "unknown option: %c\n", optopt);
+                return -EINVAL;
+        }
+    } while (1);
+
+    if (optind != argc - 1) {
+        usage(argv[0]);
+        return -EINVAL;
+    }
+
+    err = swapon(argv[argc - 1], flags);
+    if (err) {
+        fprintf(stderr, "swapon failed for %s\n", argv[argc - 1]);
+    }
+
+    return err;
+}
diff --git a/toolbox/touch.c b/toolbox/touch.c
index b8ab310..52ddf2a 100644
--- a/toolbox/touch.c
+++ b/toolbox/touch.c
@@ -5,13 +5,40 @@
 #include <sys/stat.h>
 #include <stdlib.h>
 #include <fcntl.h>
+#include <time.h>
 
 static void usage(void)
 {
-        fprintf(stderr, "touch: usage: touch [-alm] [-t time_t] <file>\n");
+        fprintf(stderr, "touch: usage: touch [-alm] [-t YYYYMMDD[.hhmmss]] <file>\n");
         exit(1);
 }
 
+static time_t parse_time(char *s)
+{
+    struct tm tm;
+    int day = atoi(s);
+    int hour = 0;
+
+    while (*s && *s != '.') {
+        s++;
+    }
+
+    if (*s) {
+        s++;
+        hour = atoi(s);
+    }
+
+    tm.tm_year = day / 10000 - 1900;
+    tm.tm_mon = (day % 10000) / 100 - 1;
+    tm.tm_mday = day % 100;
+    tm.tm_hour = hour / 10000;
+    tm.tm_min = (hour % 10000) / 100;
+    tm.tm_sec = hour % 100;
+    tm.tm_isdst = -1;
+
+    return mktime(&tm);
+}
+
 int touch_main(int argc, char *argv[])
 {
         int i, fd, aflag = 0, mflag = 0, debug = 0, flags = 0;
@@ -31,9 +58,9 @@
                     case 't':
                         if ((i+1) >= argc)
                             usage();
-                        specified_time.tv_sec = atol(argv[++i]);
-                        if (specified_time.tv_sec == 0) {
-                            fprintf(stderr, "touch: invalid time_t\n");
+                        specified_time.tv_sec = parse_time(argv[++i]);
+                        if (specified_time.tv_sec == -1) {
+                            fprintf(stderr, "touch: invalid timestamp specified\n");
                             exit(1);
                         }
                         specified_time.tv_nsec = 0;