Merge "ueventd: fix a busy loop while reading uevents"
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..41270f9 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>
@@ -561,7 +562,7 @@
         break;
 
     case A_OPEN: /* OPEN(local-id, 0, "destination") */
-        if (t->online) {
+        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
             char *name = (char*) p->data;
             name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
             s = create_local_service_socket(name);
@@ -577,28 +578,50 @@
         break;
 
     case A_OKAY: /* READY(local-id, remote-id, "") */
-        if (t->online) {
-            if((s = find_local_socket(p->msg.arg1))) {
+        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
+            if((s = find_local_socket(p->msg.arg1, 0))) {
                 if(s->peer == 0) {
+                    /* On first READY message, create the connection. */
                     s->peer = create_remote_socket(p->msg.arg0, t);
                     s->peer->peer = s;
+                    s->ready(s);
+                } else if (s->peer->id == p->msg.arg0) {
+                    /* Other READY messages must use the same local-id */
+                    s->ready(s);
+                } else {
+                    D("Invalid A_OKAY(%d,%d), expected A_OKAY(%d,%d) on transport %s\n",
+                      p->msg.arg0, p->msg.arg1, s->peer->id, p->msg.arg1, t->serial);
                 }
-                s->ready(s);
             }
         }
         break;
 
-    case A_CLSE: /* CLOSE(local-id, remote-id, "") */
-        if (t->online) {
-            if((s = find_local_socket(p->msg.arg1))) {
-                s->close(s);
+    case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */
+        if (t->online && p->msg.arg1 != 0) {
+            if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
+                /* According to protocol.txt, p->msg.arg0 might be 0 to indicate
+                 * a failed OPEN only. However, due to a bug in previous ADB
+                 * versions, CLOSE(0, remote-id, "") was also used for normal
+                 * CLOSE() operations.
+                 *
+                 * This is bad because it means a compromised adbd could
+                 * send packets to close connections between the host and
+                 * other devices. To avoid this, only allow this if the local
+                 * socket has a peer on the same transport.
+                 */
+                if (p->msg.arg0 == 0 && s->peer && s->peer->transport != t) {
+                    D("Invalid A_CLSE(0, %u) from transport %s, expected transport %s\n",
+                      p->msg.arg1, t->serial, s->peer->transport->serial);
+                } else {
+                    s->close(s);
+                }
             }
         }
         break;
 
-    case A_WRTE:
-        if (t->online) {
-            if((s = find_local_socket(p->msg.arg1))) {
+    case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
+        if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
+            if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
                 unsigned rid = p->msg.arg0;
                 p->len = p->msg.data_length;
 
@@ -1199,7 +1222,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 +1324,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 +1353,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 +1410,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 +1470,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..c85b02a 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -122,16 +122,19 @@
         */
     void (*ready)(asocket *s);
 
+        /* shutdown is called by the peer before it goes away.
+        ** the socket should not do any further calls on its peer.
+        ** Always followed by a call to close. Optional, i.e. can be NULL.
+        */
+    void (*shutdown)(asocket *s);
+
         /* close is called by the peer when it has gone away.
         ** we are not allowed to make any further calls on the
         ** peer once our close method is called.
         */
     void (*close)(asocket *s);
 
-        /* socket-type-specific extradata */
-    void *extra;
-
-    	/* A socket is bound to atransport */
+        /* A socket is bound to atransport */
     atransport *transport;
 };
 
@@ -236,7 +239,7 @@
 
 void print_packet(const char *label, apacket *p);
 
-asocket *find_local_socket(unsigned id);
+asocket *find_local_socket(unsigned local_id, unsigned remote_id);
 void install_local_socket(asocket *s);
 void remove_socket(asocket *s);
 void close_all_sockets(atransport *t);
@@ -292,7 +295,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..7f54ad9 100644
--- a/adb/sockets.c
+++ b/adb/sockets.c
@@ -59,17 +59,22 @@
     .prev = &local_socket_closing_list,
 };
 
-asocket *find_local_socket(unsigned id)
+// Parse the global list of sockets to find one with id |local_id|.
+// If |peer_id| is not 0, also check that it is connected to a peer
+// with id |peer_id|. Returns an asocket handle on success, NULL on failure.
+asocket *find_local_socket(unsigned local_id, unsigned peer_id)
 {
     asocket *s;
     asocket *result = NULL;
 
     adb_mutex_lock(&socket_list_lock);
     for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
-        if (s->id == id) {
+        if (s->id != local_id)
+            continue;
+        if (peer_id == 0 || (s->peer && s->peer->id == peer_id)) {
             result = s;
-            break;
         }
+        break;
     }
     adb_mutex_unlock(&socket_list_lock);
 
@@ -91,6 +96,11 @@
     adb_mutex_lock(&socket_list_lock);
 
     s->id = local_socket_next_id++;
+
+    // Socket ids should never be 0.
+    if (local_socket_next_id == 0)
+      local_socket_next_id = 1;
+
     insert_local_socket(s, &local_socket_list);
 
     adb_mutex_unlock(&socket_list_lock);
@@ -230,6 +240,12 @@
     if(s->peer) {
         D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n",
           s->id, s->peer->id, s->peer->fd);
+        /* Note: it's important to call shutdown before disconnecting from
+         * the peer, this ensures that remote sockets can still get the id
+         * of the local socket they're connected to, to send a CLOSE()
+         * protocol event. */
+        if (s->peer->shutdown)
+          s->peer->shutdown(s->peer);
         s->peer->peer = 0;
         // tweak to avoid deadlock
         if (s->peer->close == local_socket_close) {
@@ -397,6 +413,7 @@
     s->fd = fd;
     s->enqueue = local_socket_enqueue;
     s->ready = local_socket_ready;
+    s->shutdown = NULL;
     s->close = local_socket_close;
     install_local_socket(s);
 
@@ -485,21 +502,29 @@
     send_packet(p, s->transport);
 }
 
-static void remote_socket_close(asocket *s)
+static void remote_socket_shutdown(asocket *s)
 {
-    D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n",
+    D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d\n",
       s->id, s->fd, s->peer?s->peer->fd:-1);
     apacket *p = get_apacket();
     p->msg.command = A_CLSE;
     if(s->peer) {
         p->msg.arg0 = s->peer->id;
+    }
+    p->msg.arg1 = s->id;
+    send_packet(p, s->transport);
+}
+
+static void remote_socket_close(asocket *s)
+{
+    if (s->peer) {
         s->peer->peer = 0;
         D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n",
           s->id, s->peer->id, s->peer->fd);
         s->peer->close(s->peer);
     }
-    p->msg.arg1 = s->id;
-    send_packet(p, s->transport);
+    D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n",
+      s->id, s->fd, s->peer?s->peer->fd:-1);
     D("RS(%d): closed\n", s->id);
     remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
     free(s);
@@ -519,15 +544,24 @@
     free(s);
 }
 
+/* Create an asocket to exchange packets with a remote service through transport
+  |t|. Where |id| is the socket id of the corresponding service on the other
+   side of the transport (it is allocated by the remote side and _cannot_ be 0).
+   Returns a new non-NULL asocket handle. */
 asocket *create_remote_socket(unsigned id, atransport *t)
 {
-    asocket *s = calloc(1, sizeof(aremotesocket));
-    adisconnect*  dis = &((aremotesocket*)s)->disconnect;
+    asocket* s;
+    adisconnect* dis;
+
+    if (id == 0) fatal("invalid remote socket id (0)");
+    s = calloc(1, sizeof(aremotesocket));
+    dis = &((aremotesocket*)s)->disconnect;
 
     if (s == NULL) fatal("cannot allocate socket");
     s->id = id;
     s->enqueue = remote_socket_enqueue;
     s->ready = remote_socket_ready;
+    s->shutdown = remote_socket_shutdown;
     s->close = remote_socket_close;
     s->transport = t;
 
@@ -562,6 +596,7 @@
 static void local_socket_ready_notify(asocket *s)
 {
     s->ready = local_socket_ready;
+    s->shutdown = NULL;
     s->close = local_socket_close;
     adb_write(s->fd, "OKAY", 4);
     s->ready(s);
@@ -573,6 +608,7 @@
 static void local_socket_close_notify(asocket *s)
 {
     s->ready = local_socket_ready;
+    s->shutdown = NULL;
     s->close = local_socket_close;
     sendfailmsg(s->fd, "closed");
     s->close(s);
@@ -767,6 +803,7 @@
         adb_write(s->peer->fd, "OKAY", 4);
 
         s->peer->ready = local_socket_ready;
+        s->peer->shutdown = NULL;
         s->peer->close = local_socket_close;
         s->peer->peer = s2;
         s2->peer = s->peer;
@@ -806,6 +843,7 @@
         ** tear down
         */
     s->peer->ready = local_socket_ready_notify;
+    s->peer->shutdown = NULL;
     s->peer->close = local_socket_close_notify;
     s->peer->peer = 0;
         /* give him our transport and upref it */
@@ -844,29 +882,24 @@
     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));
     if (s == NULL) fatal("cannot allocate socket");
     s->enqueue = smart_socket_enqueue;
     s->ready = smart_socket_ready;
+    s->shutdown = NULL;
     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/adf/Android.mk b/adf/Android.mk
new file mode 100644
index 0000000..64d486e
--- /dev/null
+++ b/adf/Android.mk
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+LOCAL_PATH := $(my-dir)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/adf/libadf/Android.mk b/adf/libadf/Android.mk
new file mode 100644
index 0000000..908aa6c
--- /dev/null
+++ b/adf/libadf/Android.mk
@@ -0,0 +1,23 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := adf.c
+LOCAL_MODULE := libadf
+LOCAL_MODULE_TAGS := optional
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
+include $(BUILD_STATIC_LIBRARY)
diff --git a/adf/libadf/adf.c b/adf/libadf/adf.c
new file mode 100644
index 0000000..871629e
--- /dev/null
+++ b/adf/libadf/adf.c
@@ -0,0 +1,810 @@
+/*
+ * 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <linux/limits.h>
+
+#include <sys/ioctl.h>
+
+#include <adf/adf.h>
+
+#define ADF_BASE_PATH "/dev/"
+
+static ssize_t adf_find_nodes(const char *pattern, adf_id_t **ids)
+{
+    DIR *dir;
+    struct dirent *dirent;
+    size_t n = 0;
+    ssize_t ret;
+    adf_id_t *ids_ret = NULL;
+
+    dir = opendir(ADF_BASE_PATH);
+    if (!dir)
+        return -errno;
+
+    errno = 0;
+    while ((dirent = readdir(dir))) {
+        adf_id_t id;
+        int matched = sscanf(dirent->d_name, pattern, &id);
+
+        if (matched < 0) {
+            ret = -errno;
+            goto done;
+        } else if (matched != 1) {
+            continue;
+        }
+
+        adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
+        if (!new_ids) {
+            ret = -ENOMEM;
+            goto done;
+        }
+
+        ids_ret = new_ids;
+        ids_ret[n] = id;
+        n++;
+    }
+    if (errno)
+        ret = -errno;
+    else
+        ret = n;
+
+done:
+    closedir(dir);
+    if (ret < 0)
+        free(ids_ret);
+    else
+        *ids = ids_ret;
+    return ret;
+}
+
+ssize_t adf_devices(adf_id_t **ids)
+{
+    return adf_find_nodes("adf%u", ids);
+}
+
+int adf_device_open(adf_id_t id, int flags, struct adf_device *dev)
+{
+    char filename[64];
+    int err;
+
+    dev->id = id;
+
+    snprintf(filename, sizeof(filename), ADF_BASE_PATH "adf%u", id);
+    dev->fd = open(filename, flags);
+    if (dev->fd < 0)
+        return -errno;
+
+    return 0;
+}
+
+void adf_device_close(struct adf_device *dev)
+{
+    if (dev->fd >= 0)
+        close(dev->fd);
+}
+
+int adf_get_device_data(struct adf_device *dev, struct adf_device_data *data)
+{
+    int err;
+    int ret = 0;
+
+    memset(data, 0, sizeof(*data));
+
+    err = ioctl(dev->fd, ADF_GET_DEVICE_DATA, data);
+    if (err < 0)
+        return -ENOMEM;
+
+    if (data->n_attachments) {
+        data->attachments = malloc(sizeof(data->attachments[0]) *
+                data->n_attachments);
+        if (!data->attachments)
+            return -ENOMEM;
+    }
+
+    if (data->n_allowed_attachments) {
+        data->allowed_attachments =
+                malloc(sizeof(data->allowed_attachments[0]) *
+                        data->n_allowed_attachments);
+        if (!data->allowed_attachments) {
+            ret = -ENOMEM;
+            goto done;
+        }
+    }
+
+    if (data->custom_data_size) {
+        data->custom_data = malloc(data->custom_data_size);
+        if (!data->custom_data) {
+            ret = -ENOMEM;
+            goto done;
+        }
+    }
+
+    err = ioctl(dev->fd, ADF_GET_DEVICE_DATA, data);
+    if (err < 0)
+        ret = -errno;
+
+done:
+    if (ret < 0)
+        adf_free_device_data(data);
+    return ret;
+}
+
+void adf_free_device_data(struct adf_device_data *data)
+{
+    free(data->attachments);
+    free(data->allowed_attachments);
+    free(data->custom_data);
+}
+
+int adf_device_post(struct adf_device *dev,
+        adf_id_t *interfaces, size_t n_interfaces,
+        struct adf_buffer_config *bufs, size_t n_bufs,
+        void *custom_data, size_t custom_data_size)
+{
+    int err;
+    struct adf_post_config data;
+
+    memset(&data, 0, sizeof(data));
+    data.interfaces = interfaces;
+    data.n_interfaces = n_interfaces;
+    data.bufs = bufs;
+    data.n_bufs = n_bufs;
+    data.custom_data = custom_data;
+    data.custom_data_size = custom_data_size;
+
+    err = ioctl(dev->fd, ADF_POST_CONFIG, &data);
+    if (err < 0)
+        return -errno;
+
+    return (int)data.complete_fence;
+}
+
+static int adf_device_attachment(struct adf_device *dev,
+        adf_id_t overlay_engine, adf_id_t interface, bool attach)
+{
+    int err;
+    struct adf_attachment_config data;
+
+    memset(&data, 0, sizeof(data));
+    data.overlay_engine = overlay_engine;
+    data.interface = interface;
+
+    err = ioctl(dev->fd, attach ? ADF_ATTACH : ADF_DETACH, &data);
+    if (err < 0)
+        return -errno;
+
+    return 0;
+}
+
+int adf_device_attach(struct adf_device *dev, adf_id_t overlay_engine,
+                      adf_id_t interface)
+{
+   return adf_device_attachment(dev, overlay_engine, interface, true);
+}
+
+int adf_device_detach(struct adf_device *dev, adf_id_t overlay_engine,
+                      adf_id_t interface)
+{
+   return adf_device_attachment(dev, overlay_engine, interface, false);
+}
+
+ssize_t adf_interfaces(struct adf_device *dev, adf_id_t **interfaces)
+{
+    char pattern[64];
+
+    snprintf(pattern, sizeof(pattern), "adf-interface%u.%%u", dev->id);
+    return adf_find_nodes(pattern, interfaces);
+}
+
+ssize_t adf_interfaces_for_overlay_engine(struct adf_device *dev,
+        adf_id_t overlay_engine, adf_id_t **interfaces)
+{
+    struct adf_device_data data;
+    ssize_t n = 0;
+    ssize_t ret;
+    adf_id_t *ids_ret = NULL;
+
+    ret = adf_get_device_data(dev, &data);
+    if (ret < 0)
+        return ret;
+
+    size_t i;
+    for (i = 0; i < data.n_allowed_attachments; i++) {
+        if (data.allowed_attachments[i].overlay_engine != overlay_engine)
+            continue;
+
+        adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
+        if (!new_ids) {
+            ret = -ENOMEM;
+            goto done;
+        }
+
+        ids_ret = new_ids;
+        ids_ret[n] = data.allowed_attachments[i].interface;
+        n++;
+    }
+
+    ret = n;
+
+done:
+    adf_free_device_data(&data);
+    if (ret < 0)
+        free(ids_ret);
+    else
+        *interfaces = ids_ret;
+    return ret;
+}
+
+static ssize_t adf_interfaces_filter(struct adf_device *dev,
+        adf_id_t *in, size_t n_in, adf_id_t **out,
+        bool (*filter)(struct adf_interface_data *data, __u32 match),
+        __u32 match)
+{
+    size_t n = 0;
+    ssize_t ret;
+    adf_id_t *ids_ret = NULL;
+
+    size_t i;
+    for (i = 0; i < n_in; i++) {
+        int fd = adf_interface_open(dev, in[i], O_RDONLY);
+        if (fd < 0) {
+            ret = fd;
+            goto done;
+        }
+
+        struct adf_interface_data data;
+        ret = adf_get_interface_data(fd, &data);
+        close(fd);
+        if (ret < 0)
+            goto done;
+
+        if (!filter(&data, match))
+            continue;
+
+        adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
+        if (!new_ids) {
+            ret = -ENOMEM;
+            goto done;
+        }
+
+        ids_ret = new_ids;
+        ids_ret[n] = in[i];
+        n++;
+    }
+
+    ret = n;
+
+done:
+    if (ret < 0)
+        free(ids_ret);
+    else
+        *out = ids_ret;
+    return ret;
+}
+
+static bool adf_interface_type_filter(struct adf_interface_data *data,
+        __u32 type)
+{
+    return data->type == (enum adf_interface_type)type;
+}
+
+ssize_t adf_interfaces_filter_by_type(struct adf_device *dev,
+        enum adf_interface_type type,
+        adf_id_t *in, size_t n_in, adf_id_t **out)
+{
+    return adf_interfaces_filter(dev, in, n_in, out, adf_interface_type_filter,
+            type);
+}
+
+static bool adf_interface_flags_filter(struct adf_interface_data *data,
+        __u32 flag)
+{
+    return !!(data->flags & flag);
+}
+
+ssize_t adf_interfaces_filter_by_flag(struct adf_device *dev, __u32 flag,
+        adf_id_t *in, size_t n_in, adf_id_t **out)
+{
+    return adf_interfaces_filter(dev, in, n_in, out, adf_interface_flags_filter,
+            flag);
+}
+
+int adf_interface_open(struct adf_device *dev, adf_id_t id, int flags)
+{
+    char filename[64];
+
+    snprintf(filename, sizeof(filename), ADF_BASE_PATH "adf-interface%u.%u",
+            dev->id, id);
+
+    int fd = open(filename, flags);
+    if (fd < 0)
+        return -errno;
+    return fd;
+}
+
+int adf_get_interface_data(int fd, struct adf_interface_data *data)
+{
+    int err;
+    int ret = 0;
+
+    memset(data, 0, sizeof(*data));
+
+    err = ioctl(fd, ADF_GET_INTERFACE_DATA, data);
+    if (err < 0)
+        return -errno;
+
+    if (data->n_available_modes) {
+        data->available_modes = malloc(sizeof(data->available_modes[0]) *
+                data->n_available_modes);
+        if (!data->available_modes)
+            return -ENOMEM;
+    }
+
+    if (data->custom_data_size) {
+        data->custom_data = malloc(data->custom_data_size);
+        if (!data->custom_data) {
+            ret = -ENOMEM;
+            goto done;
+        }
+    }
+
+    err = ioctl(fd, ADF_GET_INTERFACE_DATA, data);
+    if (err < 0)
+        ret = -errno;
+
+done:
+    if (ret < 0)
+        adf_free_interface_data(data);
+    return ret;
+}
+
+void adf_free_interface_data(struct adf_interface_data *data)
+{
+    free(data->available_modes);
+    free(data->custom_data);
+}
+
+int adf_interface_blank(int fd, __u8 mode)
+{
+    int err = ioctl(fd, ADF_BLANK, mode);
+    if (err < 0)
+        return -errno;
+    return 0;
+}
+
+int adf_interface_set_mode(int fd, struct drm_mode_modeinfo *mode)
+{
+    int err = ioctl(fd, ADF_SET_MODE, mode);
+    if (err < 0)
+        return -errno;
+    return 0;
+}
+
+int adf_interface_simple_buffer_alloc(int fd, __u32 w, __u32 h,
+        __u32 format, __u32 *offset, __u32 *pitch)
+{
+    int err;
+    struct adf_simple_buffer_alloc data;
+
+    memset(&data, 0, sizeof(data));
+    data.w = w;
+    data.h = h;
+    data.format = format;
+
+    err = ioctl(fd, ADF_SIMPLE_BUFFER_ALLOC, &data);
+    if (err < 0)
+        return -errno;
+
+    *offset = data.offset;
+    *pitch = data.pitch;
+    return (int)data.fd;
+}
+
+int adf_interface_simple_post(int fd, __u32 overlay_engine,
+        __u32 w, __u32 h, __u32 format, int buf_fd, __u32 offset,
+        __u32 pitch, int acquire_fence)
+{
+    int ret;
+    struct adf_simple_post_config data;
+
+    memset(&data, 0, sizeof(data));
+    data.buf.overlay_engine = overlay_engine;
+    data.buf.w = w;
+    data.buf.h = h;
+    data.buf.format = format;
+    data.buf.fd[0] = buf_fd;
+    data.buf.offset[0] = offset;
+    data.buf.pitch[0] = pitch;
+    data.buf.n_planes = 1;
+    data.buf.acquire_fence = acquire_fence;
+
+    ret = ioctl(fd, ADF_SIMPLE_POST_CONFIG, &data);
+    if (ret < 0)
+        return -errno;
+
+    return (int)data.complete_fence;
+}
+
+ssize_t adf_overlay_engines(struct adf_device *dev, adf_id_t **overlay_engines)
+{
+    char pattern[64];
+
+    snprintf(pattern, sizeof(pattern), "adf-overlay-engine%u.%%u", dev->id);
+    return adf_find_nodes(pattern, overlay_engines);
+}
+
+ssize_t adf_overlay_engines_for_interface(struct adf_device *dev,
+        adf_id_t interface, adf_id_t **overlay_engines)
+{
+    struct adf_device_data data;
+    ssize_t n = 0;
+    ssize_t ret;
+    adf_id_t *ids_ret = NULL;
+
+    ret = adf_get_device_data(dev, &data);
+    if (ret < 0)
+        return ret;
+
+    size_t i;
+    for (i = 0; i < data.n_allowed_attachments; i++) {
+        if (data.allowed_attachments[i].interface != interface)
+            continue;
+
+        adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
+        if (!new_ids) {
+            ret = -ENOMEM;
+            goto done;
+        }
+
+        ids_ret = new_ids;
+        ids_ret[n] = data.allowed_attachments[i].overlay_engine;
+        n++;
+    }
+
+    ret = n;
+
+done:
+    adf_free_device_data(&data);
+    if (ret < 0)
+        free(ids_ret);
+    else
+        *overlay_engines = ids_ret;
+    return ret;
+}
+
+static ssize_t adf_overlay_engines_filter(struct adf_device *dev,
+        adf_id_t *in, size_t n_in, adf_id_t **out,
+        bool (*filter)(struct adf_overlay_engine_data *data, void *cookie),
+        void *cookie)
+{
+    size_t n = 0;
+    ssize_t ret;
+    adf_id_t *ids_ret = NULL;
+
+    size_t i;
+    for (i = 0; i < n_in; i++) {
+        int fd = adf_overlay_engine_open(dev, in[i], O_RDONLY);
+        if (fd < 0) {
+            ret = fd;
+            goto done;
+        }
+
+        struct adf_overlay_engine_data data;
+        ret = adf_get_overlay_engine_data(fd, &data);
+        close(fd);
+        if (ret < 0)
+            goto done;
+
+        if (!filter(&data, cookie))
+            continue;
+
+        adf_id_t *new_ids = realloc(ids_ret, (n + 1) * sizeof(ids_ret[0]));
+        if (!new_ids) {
+            ret = -ENOMEM;
+            goto done;
+        }
+
+        ids_ret = new_ids;
+        ids_ret[n] = in[i];
+        n++;
+    }
+
+    ret = n;
+
+done:
+    if (ret < 0)
+        free(ids_ret);
+    else
+        *out = ids_ret;
+    return ret;
+}
+
+struct format_filter_cookie {
+    const __u32 *formats;
+    size_t n_formats;
+};
+
+static bool adf_overlay_engine_format_filter(
+        struct adf_overlay_engine_data *data, void *cookie)
+{
+    struct format_filter_cookie *c = cookie;
+    size_t i;
+    for (i = 0; i < data->n_supported_formats; i++) {
+        size_t j;
+        for (j = 0; j < c->n_formats; j++)
+            if (data->supported_formats[i] == c->formats[j])
+                return true;
+    }
+    return false;
+}
+
+ssize_t adf_overlay_engines_filter_by_format(struct adf_device *dev,
+        const __u32 *formats, size_t n_formats, adf_id_t *in, size_t n_in,
+        adf_id_t **out)
+{
+    struct format_filter_cookie cookie = { formats, n_formats };
+    return adf_overlay_engines_filter(dev, in, n_in, out,
+            adf_overlay_engine_format_filter, &cookie);
+}
+
+int adf_overlay_engine_open(struct adf_device *dev, adf_id_t id, int flags)
+{
+    char filename[64];
+
+    snprintf(filename, sizeof(filename),
+            ADF_BASE_PATH "adf-overlay-engine%u.%u", dev->id, id);
+
+    int fd = open(filename, flags);
+    if (fd < 0)
+        return -errno;
+    return fd;
+}
+
+int adf_get_overlay_engine_data(int fd, struct adf_overlay_engine_data *data)
+{
+    int err;
+    int ret = 0;
+
+    memset(data, 0, sizeof(*data));
+
+    err = ioctl(fd, ADF_GET_OVERLAY_ENGINE_DATA, data);
+    if (err < 0)
+        return -errno;
+
+    if (data->n_supported_formats) {
+        data->supported_formats = malloc(sizeof(data->supported_formats[0]) *
+              data->n_supported_formats);
+        if (!data->supported_formats)
+            return -ENOMEM;
+    }
+
+    if (data->custom_data_size) {
+      data->custom_data = malloc(data->custom_data_size);
+      if (!data->custom_data) {
+          ret = -ENOMEM;
+          goto done;
+      }
+    }
+
+    err = ioctl(fd, ADF_GET_OVERLAY_ENGINE_DATA, data);
+    if (err < 0)
+        ret = -errno;
+
+done:
+    if (ret < 0)
+        adf_free_overlay_engine_data(data);
+    return ret;
+}
+
+void adf_free_overlay_engine_data(struct adf_overlay_engine_data *data)
+{
+    free(data->supported_formats);
+    free(data->custom_data);
+}
+
+bool adf_overlay_engine_supports_format(int fd, __u32 format)
+{
+    struct adf_overlay_engine_data data;
+    bool ret = false;
+    size_t i;
+
+    int err = adf_get_overlay_engine_data(fd, &data);
+    if (err < 0)
+        return false;
+
+    for (i = 0; i < data.n_supported_formats; i++) {
+        if (data.supported_formats[i] == format) {
+            ret = true;
+            break;
+        }
+    }
+
+    adf_free_overlay_engine_data(&data);
+    return ret;
+}
+
+int adf_set_event(int fd, enum adf_event_type type, bool enabled)
+{
+    struct adf_set_event data;
+
+    data.type = type;
+    data.enabled = enabled;
+
+    int err = ioctl(fd, ADF_SET_EVENT, &data);
+    if (err < 0)
+        return -errno;
+    return 0;
+}
+
+int adf_read_event(int fd, struct adf_event **event)
+{
+    struct adf_event header;
+    struct {
+        struct adf_event base;
+        uint8_t data[0];
+    } *event_ret;
+    size_t data_size;
+    int ret = 0;
+
+    int err = read(fd, &header, sizeof(header));
+    if (err < 0)
+        return -errno;
+    if ((size_t)err < sizeof(header))
+        return -EIO;
+    if (header.length < sizeof(header))
+        return -EIO;
+
+    event_ret = malloc(header.length);
+    if (!event_ret)
+        return -ENOMEM;
+    data_size = header.length - sizeof(header);
+
+    memcpy(event_ret, &header, sizeof(header));
+    ssize_t read_size = read(fd, &event_ret->data, data_size);
+    if (read_size < 0) {
+        ret = -errno;
+        goto done;
+    }
+    if ((size_t)read_size < data_size) {
+        ret = -EIO;
+        goto done;
+    }
+
+    *event = &event_ret->base;
+
+done:
+    if (ret < 0)
+        free(event_ret);
+    return ret;
+}
+
+void adf_format_str(__u32 format, char buf[ADF_FORMAT_STR_SIZE])
+{
+    buf[0] = format & 0xFF;
+    buf[1] = (format >> 8) & 0xFF;
+    buf[2] = (format >> 16) & 0xFF;
+    buf[3] = (format >> 24) & 0xFF;
+    buf[4] = '\0';
+}
+
+static bool adf_find_simple_post_overlay_engine(struct adf_device *dev,
+        const __u32 *formats, size_t n_formats,
+        adf_id_t interface, adf_id_t *overlay_engine)
+{
+    adf_id_t *engs;
+    ssize_t n_engs = adf_overlay_engines_for_interface(dev, interface, &engs);
+
+    if (n_engs <= 0)
+        return false;
+
+    adf_id_t *filtered_engs;
+    ssize_t n_filtered_engs = adf_overlay_engines_filter_by_format(dev,
+            formats, n_formats, engs, n_engs, &filtered_engs);
+    free(engs);
+
+    if (n_filtered_engs <= 0)
+        return false;
+
+    *overlay_engine = filtered_engs[0];
+    free(filtered_engs);
+    return true;
+}
+
+static const __u32 any_rgb_format[] = {
+    DRM_FORMAT_C8,
+    DRM_FORMAT_RGB332,
+    DRM_FORMAT_BGR233,
+    DRM_FORMAT_XRGB1555,
+    DRM_FORMAT_XBGR1555,
+    DRM_FORMAT_RGBX5551,
+    DRM_FORMAT_BGRX5551,
+    DRM_FORMAT_ARGB1555,
+    DRM_FORMAT_ABGR1555,
+    DRM_FORMAT_RGBA5551,
+    DRM_FORMAT_BGRA5551,
+    DRM_FORMAT_RGB565,
+    DRM_FORMAT_BGR565,
+    DRM_FORMAT_RGB888,
+    DRM_FORMAT_BGR888,
+    DRM_FORMAT_XRGB8888,
+    DRM_FORMAT_XBGR8888,
+    DRM_FORMAT_RGBX8888,
+    DRM_FORMAT_BGRX8888,
+    DRM_FORMAT_XRGB2101010,
+    DRM_FORMAT_XBGR2101010,
+    DRM_FORMAT_RGBX1010102,
+    DRM_FORMAT_BGRX1010102,
+    DRM_FORMAT_ARGB2101010,
+    DRM_FORMAT_ABGR2101010,
+    DRM_FORMAT_RGBA1010102,
+    DRM_FORMAT_BGRA1010102,
+    DRM_FORMAT_ARGB8888,
+    DRM_FORMAT_ABGR8888,
+    DRM_FORMAT_RGBA8888,
+    DRM_FORMAT_BGRA8888,
+};
+
+int adf_find_simple_post_configuration(struct adf_device *dev,
+        const __u32 *formats, size_t n_formats,
+        adf_id_t *interface, adf_id_t *overlay_engine)
+{
+    adf_id_t *intfs;
+    ssize_t n_intfs = adf_interfaces(dev, &intfs);
+
+    if (n_intfs < 0)
+        return n_intfs;
+    else if (!n_intfs)
+        return -ENODEV;
+
+    adf_id_t *primary_intfs;
+    ssize_t n_primary_intfs = adf_interfaces_filter_by_flag(dev,
+            ADF_INTF_FLAG_PRIMARY, intfs, n_intfs, &primary_intfs);
+    free(intfs);
+
+    if (n_primary_intfs < 0)
+        return n_primary_intfs;
+    else if (!n_primary_intfs)
+        return -ENODEV;
+
+    if (!formats) {
+        formats = any_rgb_format;
+        n_formats = sizeof(any_rgb_format) / sizeof(any_rgb_format[0]);
+    }
+
+    bool found = false;
+    ssize_t i = 0;
+    for (i = 0; i < n_primary_intfs; i++) {
+        found = adf_find_simple_post_overlay_engine(dev, formats, n_formats,
+                primary_intfs[i], overlay_engine);
+        if (found) {
+            *interface = primary_intfs[i];
+            break;
+        }
+    }
+    free(primary_intfs);
+
+    if (!found)
+        return -ENODEV;
+
+    return 0;
+}
diff --git a/adf/libadf/include/adf/adf.h b/adf/libadf/include/adf/adf.h
new file mode 100644
index 0000000..b6bda34
--- /dev/null
+++ b/adf/libadf/include/adf/adf.h
@@ -0,0 +1,250 @@
+/*
+ * 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 _LIBADF_ADF_H_
+#define _LIBADF_ADF_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <video/adf.h>
+
+typedef __u32 adf_id_t;
+
+struct adf_device {
+    adf_id_t id;
+    int fd;
+};
+
+__BEGIN_DECLS
+
+/**
+ * Enumerates all ADF devices.
+ *
+ * Returns the number of ADF devices, and sets ids to a list of device IDs.
+ * The caller must free() the returned list of device IDs.
+ *
+ * On error, returns -errno.
+ */
+ssize_t adf_devices(adf_id_t **ids);
+
+/**
+ * Opens an ADF device.
+ *
+ * On error, returns -errno.
+ */
+int adf_device_open(adf_id_t id, int flags, struct adf_device *dev);
+/**
+ * Closes an ADF device.
+ */
+void adf_device_close(struct adf_device *dev);
+/**
+ * Reads the ADF device data.
+ *
+ * adf_get_device_data() allocates buffers inside data, which the caller
+ * must free by calling adf_free_device_data().  On error, returns -errno.
+ */
+int adf_get_device_data(struct adf_device *dev, struct adf_device_data *data);
+/**
+ * Frees the device data returned by adf_get_device_data().
+ */
+void adf_free_device_data(struct adf_device_data *data);
+
+/**
+ * Atomically posts a new display configuration to the specified interfaces.
+ *
+ * Returns a sync fence fd that will fire when the configuration is removed
+ * from the screen.  On error, returns -errno.
+ */
+int adf_device_post(struct adf_device *dev,
+        adf_id_t *interfaces, size_t n_interfaces,
+        struct adf_buffer_config *bufs, size_t n_bufs,
+        void *custom_data, size_t custom_data_size);
+/**
+ * Attaches the specified interface and overlay engine.
+ */
+int adf_device_attach(struct adf_device *dev, adf_id_t overlay_engine,
+                      adf_id_t interface);
+/**
+ * Detaches the specified interface and overlay engine.
+ */
+int adf_device_detach(struct adf_device *dev, adf_id_t overlay_engine,
+                      adf_id_t interface);
+
+/**
+ * Enumerates all interfaces belonging to an ADF device.
+ *
+ * The caller must free() the returned list of interface IDs.
+ */
+ssize_t adf_interfaces(struct adf_device *dev, adf_id_t **interfaces);
+
+/**
+ * Enumerates all interfaces which can be attached to the specified overlay
+ * engine.
+ *
+ * The caller must free() the returned list of interface IDs.
+ */
+ssize_t adf_interfaces_for_overlay_engine(struct adf_device *dev,
+        adf_id_t overlay_engine, adf_id_t **interfaces);
+/**
+ * Filters a list of interfaces by type.
+ *
+ * Returns the number of matching interfaces, and sets out to a list of matching
+ * interface IDs.  The caller must free() the returned list of interface IDs.
+ *
+ * On error, returns -errno.
+ */
+ssize_t adf_interfaces_filter_by_type(struct adf_device *dev,
+        enum adf_interface_type type,
+        adf_id_t *in, size_t n_in, adf_id_t **out);
+/**
+ * Filters a list of interfaces by flag.
+ *
+ * The caller must free() the returned list of interface IDs.
+ */
+ssize_t adf_interfaces_filter_by_flag(struct adf_device *dev, __u32 flag,
+        adf_id_t *in, size_t n_in, adf_id_t **out);
+
+/**
+ * Opens an ADF interface.
+ *
+ * Returns a file descriptor.  The caller must close() the fd when done.
+ * On error, returns -errno.
+ */
+int adf_interface_open(struct adf_device *dev, adf_id_t id, int flags);
+/**
+ * Reads the interface data.
+ *
+ * adf_get_interface_data() allocates buffers inside data, which the caller
+ * must free by calling adf_free_interface_data().  On error, returns -errno.
+ */
+int adf_get_interface_data(int fd, struct adf_interface_data *data);
+/**
+ * Frees the interface data returned by adf_get_interface_data().
+ */
+void adf_free_interface_data(struct adf_interface_data *data);
+
+/**
+ * Sets the interface's DPMS mode.
+ */
+int adf_interface_blank(int fd, __u8 mode);
+/**
+ * Sets the interface's display mode.
+ */
+int adf_interface_set_mode(int fd, struct drm_mode_modeinfo *mode);
+/**
+ * Allocates a single-plane RGB buffer of the specified size and format.
+ *
+ * Returns a dma-buf fd.  On error, returns -errno.
+ */
+int adf_interface_simple_buffer_alloc(int fd, __u32 w, __u32 h,
+        __u32 format, __u32 *offset, __u32 *pitch);
+/**
+ * Posts a single-plane RGB buffer to the display using the specified
+ * overlay engine.
+ *
+ * Returns a sync fence fd that will fire when the buffer is removed
+ * from the screen.  On error, returns -errno.
+ */
+int adf_interface_simple_post(int fd, adf_id_t overlay_engine,
+        __u32 w, __u32 h, __u32 format, int buf_fd, __u32 offset,
+        __u32 pitch, int acquire_fence);
+
+/**
+ * Enumerates all overlay engines belonging to an ADF device.
+ *
+ * The caller must free() the returned list of overlay engine IDs.
+ */
+ssize_t adf_overlay_engines(struct adf_device *dev, adf_id_t **overlay_engines);
+
+/**
+ * Enumerates all overlay engines which can be attached to the specified
+ * interface.
+ *
+ * The caller must free() the returned list of overlay engine IDs.
+ */
+ssize_t adf_overlay_engines_for_interface(struct adf_device *dev,
+        adf_id_t interface, adf_id_t **overlay_engines);
+/**
+ * Filters a list of overlay engines by supported buffer format.
+ *
+ * Returns the overlay engines which support at least one of the specified
+ * formats.  The caller must free() the returned list of overlay engine IDs.
+ */
+ssize_t adf_overlay_engines_filter_by_format(struct adf_device *dev,
+        const __u32 *formats, size_t n_formats, adf_id_t *in, size_t n_in,
+        adf_id_t **out);
+
+/**
+ * Opens an ADF overlay engine.
+ *
+ * Returns a file descriptor.  The caller must close() the fd when done.
+ * On error, returns -errno.
+ */
+int adf_overlay_engine_open(struct adf_device *dev, adf_id_t id, int flags);
+/**
+ * Reads the overlay engine data.
+ *
+ * adf_get_overlay_engine_data() allocates buffers inside data, which the caller
+ * must free by calling adf_free_overlay_engine_data().  On error, returns
+ * -errno.
+ */
+int adf_get_overlay_engine_data(int fd, struct adf_overlay_engine_data *data);
+/**
+ * Frees the overlay engine data returned by adf_get_overlay_engine_data().
+ */
+void adf_free_overlay_engine_data(struct adf_overlay_engine_data *data);
+
+/**
+ * Returns whether the overlay engine supports the specified format.
+ */
+bool adf_overlay_engine_supports_format(int fd, __u32 format);
+
+/**
+ * Subscribes or unsubscribes from the specified hardware event.
+ */
+int adf_set_event(int fd, enum adf_event_type type, bool enabled);
+/**
+ * Reads one event from the fd, blocking if needed.
+ *
+ * The caller must free() the returned buffer.  On error, returns -errno.
+ */
+int adf_read_event(int fd, struct adf_event **event);
+
+#define ADF_FORMAT_STR_SIZE 5
+/**
+ * Converts an ADF/DRM fourcc format to its string representation.
+ */
+void adf_format_str(__u32 format, char buf[ADF_FORMAT_STR_SIZE]);
+
+/**
+ * Finds an appropriate interface and overlay engine for a simple post.
+ *
+ * Specifically, finds the primary interface, and an overlay engine
+ * that can be attached to the primary interface and supports one of the
+ * specified formats.  The caller may pass a NULL formats list, to indicate that
+ * any RGB format is acceptable.
+ *
+ * On error, returns -errno.
+ */
+int adf_find_simple_post_configuration(struct adf_device *dev,
+        const __u32 *formats, size_t n_formats,
+        adf_id_t *interface, adf_id_t *overlay_engine);
+
+__END_DECLS
+
+#endif /* _LIBADF_ADF_H_ */
diff --git a/adf/libadfhwc/Android.mk b/adf/libadfhwc/Android.mk
new file mode 100644
index 0000000..acea322
--- /dev/null
+++ b/adf/libadfhwc/Android.mk
@@ -0,0 +1,25 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := adfhwc.cpp
+LOCAL_MODULE := libadfhwc
+LOCAL_MODULE_TAGS := optional
+LOCAL_STATIC_LIBRARIES := libadf liblog libutils
+LOCAL_CFLAGS += -DLOG_TAG=\"adfhwc\"
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
+include $(BUILD_STATIC_LIBRARY)
diff --git a/adf/libadfhwc/adfhwc.cpp b/adf/libadfhwc/adfhwc.cpp
new file mode 100644
index 0000000..dee3cae
--- /dev/null
+++ b/adf/libadfhwc/adfhwc.cpp
@@ -0,0 +1,293 @@
+/*
+ * 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 <fcntl.h>
+#include <poll.h>
+#include <pthread.h>
+#include <sys/resource.h>
+
+#include <adf/adf.h>
+#include <adfhwc/adfhwc.h>
+
+#include <cutils/log.h>
+#include <utils/Vector.h>
+
+struct adf_hwc_helper {
+    adf_hwc_event_callbacks const *event_cb;
+    void *event_cb_data;
+
+    pthread_t event_thread;
+
+    android::Vector<int> intf_fds;
+    android::Vector<drm_mode_modeinfo> display_configs;
+};
+
+template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; }
+
+int adf_eventControl(struct adf_hwc_helper *dev, int disp, int event,
+        int enabled)
+{
+    if (enabled != !!enabled)
+        return -EINVAL;
+
+    if ((size_t)disp >= dev->intf_fds.size())
+        return -EINVAL;
+
+    switch (event) {
+    case HWC_EVENT_VSYNC:
+        return adf_set_event(dev->intf_fds[disp], ADF_EVENT_VSYNC, enabled);
+    }
+
+    return -EINVAL;
+}
+
+static inline int32_t dpi(uint16_t res, uint16_t size_mm)
+{
+    if (size_mm)
+        return 1000 * (res * 25.4f) / size_mm;
+    return 0;
+}
+
+int adf_blank(struct adf_hwc_helper *dev, int disp, int blank)
+{
+    if ((size_t)disp >= dev->intf_fds.size())
+        return -EINVAL;
+
+    uint8_t dpms_mode = blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON;
+    return adf_interface_blank(dev->intf_fds[disp], dpms_mode);
+}
+
+int adf_query_display_types_supported(struct adf_hwc_helper *dev, int *value)
+{
+    *value = 0;
+    if (dev->intf_fds.size() > 0)
+        *value |= HWC_DISPLAY_PRIMARY_BIT;
+    if (dev->intf_fds.size() > 1)
+        *value |= HWC_DISPLAY_EXTERNAL_BIT;
+
+    return 0;
+}
+
+int adf_getDisplayConfigs(struct adf_hwc_helper *dev, int disp,
+        uint32_t *configs, size_t *numConfigs)
+{
+    if ((size_t)disp >= dev->intf_fds.size())
+        return -EINVAL;
+
+    adf_interface_data data;
+    int err = adf_get_interface_data(dev->intf_fds[disp], &data);
+    if (err < 0) {
+        ALOGE("failed to get ADF interface data: %s", strerror(err));
+        return err;
+    }
+
+    if (!data.hotplug_detect)
+        return -ENODEV;
+
+    android::Vector<drm_mode_modeinfo *> unique_configs;
+    unique_configs.push_back(&data.current_mode);
+    for (size_t i = 0; i < data.n_available_modes; i++)
+        if (memcmp(&data.available_modes[i], &data.current_mode,
+                sizeof(data.current_mode)))
+            unique_configs.push_back(&data.available_modes[i]);
+
+    for (size_t i = 0; i < min(*numConfigs, unique_configs.size()); i++) {
+        configs[i] = dev->display_configs.size();
+        dev->display_configs.push_back(*unique_configs[i]);
+    }
+    *numConfigs = unique_configs.size();
+
+    adf_free_interface_data(&data);
+    return 0;
+}
+
+static int32_t adf_display_attribute(const adf_interface_data &data,
+        const drm_mode_modeinfo &mode, const uint32_t attribute)
+{
+    switch (attribute) {
+    case HWC_DISPLAY_VSYNC_PERIOD:
+        if (mode.vrefresh)
+            return 1000000000 / mode.vrefresh;
+        return 0;
+
+    case HWC_DISPLAY_WIDTH:
+        return mode.hdisplay;
+
+    case HWC_DISPLAY_HEIGHT:
+        return mode.vdisplay;
+
+    case HWC_DISPLAY_DPI_X:
+        return dpi(mode.hdisplay, data.width_mm);
+
+    case HWC_DISPLAY_DPI_Y:
+        return dpi(mode.vdisplay, data.height_mm);
+
+    default:
+        ALOGE("unknown display attribute %u", attribute);
+        return -EINVAL;
+    }
+}
+
+int adf_getDisplayAttributes(struct adf_hwc_helper *dev, int disp,
+        uint32_t config, const uint32_t *attributes, int32_t *values)
+{
+    if ((size_t)disp >= dev->intf_fds.size())
+        return -EINVAL;
+
+    if (config >= dev->display_configs.size())
+        return -EINVAL;
+
+    adf_interface_data data;
+    int err = adf_get_interface_data(dev->intf_fds[disp], &data);
+    if (err < 0) {
+        ALOGE("failed to get ADF interface data: %s", strerror(err));
+        return err;
+    }
+
+    for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++)
+        values[i] = adf_display_attribute(data, dev->display_configs[config],
+                attributes[i]);
+
+    adf_free_interface_data(&data);
+    return 0;
+}
+
+static void handle_adf_event(struct adf_hwc_helper *dev, int disp)
+{
+    adf_event *event;
+    int err = adf_read_event(dev->intf_fds[disp], &event);
+    if (err < 0) {
+        ALOGE("error reading event from display %d: %s", disp, strerror(err));
+        return;
+    }
+
+    void *vsync_temp;
+    adf_vsync_event *vsync;
+    adf_hotplug_event *hotplug;
+
+    switch (event->type) {
+    case ADF_EVENT_VSYNC:
+        vsync_temp = event;
+        vsync = static_cast<adf_vsync_event *>(vsync_temp);
+        // casting directly to adf_vsync_event * makes g++ warn about
+        // potential alignment issues that don't apply here
+        dev->event_cb->vsync(dev->event_cb_data, disp, vsync->timestamp);
+        break;
+    case ADF_EVENT_HOTPLUG:
+        hotplug = reinterpret_cast<adf_hotplug_event *>(event);
+        dev->event_cb->hotplug(dev->event_cb_data, disp, hotplug->connected);
+        break;
+    default:
+        if (event->type < ADF_EVENT_DEVICE_CUSTOM)
+            ALOGW("unrecognized event type %u", event->type);
+        else if (!dev->event_cb || !dev->event_cb->custom_event)
+            ALOGW("unhandled event type %u", event->type);
+        else
+            dev->event_cb->custom_event(dev->event_cb_data, disp, event);
+    }
+    free(event);
+}
+
+static void *adf_event_thread(void *data)
+{
+    adf_hwc_helper *dev = static_cast<adf_hwc_helper *>(data);
+
+    setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+
+    pollfd *fds = new pollfd[dev->intf_fds.size()];
+    for (size_t i = 0; i < dev->intf_fds.size(); i++) {
+        fds[i].fd = dev->intf_fds[i];
+        fds[i].events = POLLIN | POLLPRI;
+    }
+
+    while (true) {
+        int err = poll(fds, dev->intf_fds.size(), -1);
+
+        if (err > 0) {
+            for (size_t i = 0; i < dev->intf_fds.size(); i++)
+                if (fds[i].revents & (POLLIN | POLLPRI))
+                    handle_adf_event(dev, i);
+        }
+        else if (err == -1) {
+            if (errno == EINTR)
+                break;
+            ALOGE("error in event thread: %s", strerror(errno));
+        }
+    }
+
+    delete [] fds;
+    return NULL;
+}
+
+int adf_hwc_open(int *intf_fds, size_t n_intfs,
+        const struct adf_hwc_event_callbacks *event_cb, void *event_cb_data,
+        struct adf_hwc_helper **dev)
+{
+    if (!n_intfs)
+        return -EINVAL;
+
+    adf_hwc_helper *dev_ret = new adf_hwc_helper;
+    dev_ret->event_cb = event_cb;
+    dev_ret->event_cb_data = event_cb_data;
+
+    int ret;
+
+    for (size_t i = 0; i < n_intfs; i++) {
+        int dup_intf_fd = dup(intf_fds[i]);
+        if (dup_intf_fd < 0) {
+            ALOGE("failed to dup interface fd: %s", strerror(errno));
+            ret = -errno;
+            goto err;
+        }
+
+        dev_ret->intf_fds.push_back(dup_intf_fd);
+
+        ret = adf_set_event(dup_intf_fd, ADF_EVENT_HOTPLUG, 1);
+        if (ret < 0 && ret != -EINVAL) {
+            ALOGE("failed to enable hotplug event on display %u: %s",
+                    i, strerror(errno));
+            goto err;
+        }
+    }
+
+    ret = pthread_create(&dev_ret->event_thread, NULL, adf_event_thread,
+            dev_ret);
+    if (ret) {
+        ALOGE("failed to create event thread: %s", strerror(ret));
+        goto err;
+    }
+
+    *dev = dev_ret;
+    return 0;
+
+err:
+    for (size_t i = 0; i < dev_ret->intf_fds.size(); i++)
+        close(dev_ret->intf_fds[i]);
+
+    delete dev_ret;
+    return ret;
+}
+
+void adf_hwc_close(struct adf_hwc_helper *dev)
+{
+    pthread_kill(dev->event_thread, SIGTERM);
+    pthread_join(dev->event_thread, NULL);
+
+    for (size_t i = 0; i < dev->intf_fds.size(); i++)
+        close(dev->intf_fds[i]);
+
+    delete dev;
+}
diff --git a/adf/libadfhwc/include/adfhwc/adfhwc.h b/adf/libadfhwc/include/adfhwc/adfhwc.h
new file mode 100644
index 0000000..71e7624
--- /dev/null
+++ b/adf/libadfhwc/include/adfhwc/adfhwc.h
@@ -0,0 +1,129 @@
+/*
+ * 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 _LIBADFHWC_ADFHWC_H_
+#define _LIBADFHWC_ADFHWC_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <video/adf.h>
+
+#include <hardware/hwcomposer.h>
+
+struct adf_hwc_helper;
+
+struct adf_hwc_event_callbacks {
+    /**
+     * Called on vsync (required)
+     */
+    void (*vsync)(void *data, int disp, uint64_t timestamp);
+    /**
+     * Called on hotplug (required)
+     */
+    void (*hotplug)(void *data, int disp, bool connected);
+    /**
+     * Called on hardware-custom ADF events (optional)
+     */
+    void (*custom_event)(void *data, int disp, struct adf_event *event);
+};
+
+/**
+ * Converts HAL pixel formats to equivalent ADF/DRM format FourCCs.
+ */
+static inline uint32_t adf_fourcc_for_hal_pixel_format(int format)
+{
+    switch (format) {
+    case HAL_PIXEL_FORMAT_RGBA_8888:
+        return DRM_FORMAT_RGBA8888;
+    case HAL_PIXEL_FORMAT_RGBX_8888:
+        return DRM_FORMAT_RGBX8888;
+    case HAL_PIXEL_FORMAT_RGB_888:
+        return DRM_FORMAT_RGB888;
+    case HAL_PIXEL_FORMAT_RGB_565:
+        return DRM_FORMAT_RGB565;
+    case HAL_PIXEL_FORMAT_BGRA_8888:
+        return DRM_FORMAT_BGRA8888;
+    case HAL_PIXEL_FORMAT_YV12:
+        return DRM_FORMAT_YVU420;
+    case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+        return DRM_FORMAT_NV16;
+    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+        return DRM_FORMAT_NV21;
+    case HAL_PIXEL_FORMAT_YCbCr_422_I:
+        return DRM_FORMAT_YUYV;
+    default:
+        return 0;
+    }
+}
+
+/**
+ * Converts HAL display types to equivalent ADF interface flags.
+ */
+static inline uint32_t adf_hwc_interface_flag_for_disp(int disp)
+{
+    switch (disp) {
+    case HWC_DISPLAY_PRIMARY:
+        return ADF_INTF_FLAG_PRIMARY;
+    case HWC_DISPLAY_EXTERNAL:
+        return ADF_INTF_FLAG_EXTERNAL;
+    default:
+        return 0;
+    }
+}
+
+__BEGIN_DECLS
+
+/**
+ * Create a HWC helper for the specified ADF interfaces.
+ *
+ * intf_fds must be indexed by HWC display type: e.g.,
+ * intf_fds[HWC_DISPLAY_PRIMARY] is the fd for the primary display
+ * interface.  n_intfs must be >= 1.
+ *
+ * The caller retains ownership of the fds in intf_fds and must close()
+ * them when they are no longer needed.
+ *
+ * On error, returns -errno.
+ */
+int adf_hwc_open(int *intf_fds, size_t n_intfs,
+        const struct adf_hwc_event_callbacks *event_cb, void *event_cb_data,
+        struct adf_hwc_helper **dev);
+
+/**
+ * Destroys a HWC helper.
+ */
+void adf_hwc_close(struct adf_hwc_helper *dev);
+
+/**
+ * Generic implementations of common HWC ops.
+ *
+ * The HWC should not point its ops directly at these helpers.  Instead, the HWC
+ * should provide stub ops which call these helpers after converting the
+ * hwc_composer_device_1* to a struct adf_hwc_helper*.
+ */
+int adf_eventControl(struct adf_hwc_helper *dev, int disp, int event,
+        int enabled);
+int adf_blank(struct adf_hwc_helper *dev, int disp, int blank);
+int adf_query_display_types_supported(struct adf_hwc_helper *dev, int *value);
+int adf_getDisplayConfigs(struct adf_hwc_helper *dev, int disp,
+        uint32_t *configs, size_t *numConfigs);
+int adf_getDisplayAttributes(struct adf_hwc_helper *dev, int disp,
+        uint32_t config, const uint32_t *attributes, int32_t *values);
+
+__END_DECLS
+
+#endif /* _LIBADFHWC_ADFHWC_H_ */
diff --git a/debuggerd/arm/machine.c b/debuggerd/arm/machine.c
index 6bcd07e..4ab6026 100644
--- a/debuggerd/arm/machine.c
+++ b/debuggerd/arm/machine.c
@@ -15,18 +15,15 @@
 ** limitations under the License.
 */
 
-#include <stddef.h>
+#include <errno.h>
 #include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <sys/types.h>
 #include <sys/ptrace.h>
-
-#include <corkscrew/ptrace.h>
-
-#include <linux/user.h>
+#include <sys/types.h>
+#include <sys/user.h>
 
 #include "../utility.h"
 #include "../machine.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/mips/machine.c b/debuggerd/mips/machine.c
index e06a50c..489f3c5 100644
--- a/debuggerd/mips/machine.c
+++ b/debuggerd/mips/machine.c
@@ -26,7 +26,7 @@
 
 #include <corkscrew/ptrace.h>
 
-#include <linux/user.h>
+#include <sys/user.h>
 
 #include "../utility.h"
 #include "../machine.h"
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..0f32dbf
--- /dev/null
+++ b/fastbootd/Android.mk
@@ -0,0 +1,104 @@
+# 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_C_INCLUDES := \
+    external/openssl/include \
+    external/mdnsresponder/mDNSShared \
+    $(LOCAL_PATH)/include \
+    external/zlib/ \
+
+LOCAL_SRC_FILES := \
+    config.c \
+    commands.c \
+    commands/boot.c \
+    commands/flash.c \
+    commands/partitions.c \
+    commands/virtual_partitions.c \
+    fastbootd.c \
+    protocol.c \
+    network_discovery.c \
+    socket_client.c \
+    secure.c \
+    transport.c \
+    transport_socket.c \
+    trigger.c \
+    usb_linux_client.c \
+    utils.c \
+
+LOCAL_MODULE := fastbootd
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter -DFLASH_CERT
+LOCAL_LDFLAGS := -ldl
+
+LOCAL_SHARED_LIBRARIES := \
+    libhardware \
+    libcrypto \
+    libhardware_legacy \
+    libmdnssd
+
+LOCAL_STATIC_LIBRARIES := \
+    libsparse_static \
+    libc \
+    libcutils \
+    libz
+
+#LOCAL_FORCE_STATIC_EXECUTABLE := true
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+    external/zlib/
+
+LOCAL_SRC_FILES := \
+    commands/partitions.c \
+    other/gptedit.c \
+    utils.c
+
+LOCAL_MODULE := gptedit
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
+
+LOCAL_STATIC_LIBRARIES := \
+    libsparse_static \
+    libc \
+    libcutils \
+    libz
+
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/include \
+
+LOCAL_STATIC_LIBRARIES := \
+    $(EXTRA_STATIC_LIBS) \
+    libcutils
+
+LOCAL_SRC_FILES := \
+    other/vendor_trigger.c
+
+LOCAL_MODULE := libvendortrigger.default
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
+
+
+include $(BUILD_SHARED_LIBRARY)
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..d8a601f
--- /dev/null
+++ b/fastbootd/commands.c
@@ -0,0 +1,408 @@
+/*
+ * 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 <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/reboot.h>
+#include <fcntl.h>
+
+#include "bootimg.h"
+#include "commands/boot.h"
+#include "commands/flash.h"
+#include "commands/partitions.h"
+#include "commands/virtual_partitions.h"
+#include "debug.h"
+#include "protocol.h"
+#include "trigger.h"
+#include "utils.h"
+
+#define ATAGS_LOCATION "/proc/atags"
+
+static void cmd_boot(struct protocol_handle *phandle, const char *arg)
+{
+    int sz, atags_sz, new_atags_sz;
+    int rv;
+    unsigned kernel_actual;
+    unsigned ramdisk_actual;
+    unsigned second_actual;
+    void *kernel_ptr;
+    void *ramdisk_ptr;
+    void *second_ptr;
+    struct boot_img_hdr *hdr;
+    char *ptr = NULL;
+    char *atags_ptr = NULL;
+    char *new_atags = NULL;
+    int data_fd = 0;
+
+    D(DEBUG, "cmd_boot %s\n", arg);
+
+    if (phandle->download_fd < 0) {
+        fastboot_fail(phandle, "no kernel file");
+        return;
+    }
+
+    atags_ptr = read_atags(ATAGS_LOCATION, &atags_sz);
+    if (atags_ptr == NULL) {
+        fastboot_fail(phandle, "atags read error");
+        goto error;
+    }
+
+    // TODO: With cms we can also verify partition name included as
+    // cms signed attribute
+    if (flash_validate_certificate(phandle->download_fd, &data_fd) != 1) {
+        fastboot_fail(phandle, "Access forbiden you need the certificate");
+        return;
+    }
+
+    sz = get_file_size(data_fd);
+
+    ptr = (char *) mmap(NULL, sz, PROT_READ,
+                        MAP_POPULATE | MAP_PRIVATE, data_fd, 0);
+
+    hdr = (struct boot_img_hdr *) ptr;
+
+    if (ptr == MAP_FAILED) {
+        fastboot_fail(phandle, "internal fastbootd error");
+        goto error;
+    }
+
+    if ((size_t) sz < sizeof(*hdr)) {
+        fastboot_fail(phandle, "invalid bootimage header");
+        goto error;
+    }
+
+    kernel_actual = ROUND_TO_PAGE(hdr->kernel_size, hdr->page_size);
+    ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, hdr->page_size);
+    second_actual = ROUND_TO_PAGE(hdr->second_size, hdr->page_size);
+
+    new_atags = (char *) create_atags((unsigned *) atags_ptr, atags_sz, hdr, &new_atags_sz);
+
+    if (new_atags == NULL) {
+        fastboot_fail(phandle, "atags generate error");
+        goto error;
+    }
+    if (new_atags_sz > 0x4000) {
+        fastboot_fail(phandle, "atags file to large");
+        goto error;
+    }
+
+    if ((int) (hdr->page_size + kernel_actual + ramdisk_actual) < sz) {
+        fastboot_fail(phandle, "incomplete bootimage");
+        goto error;
+    }
+
+    kernel_ptr = (void *)((unsigned) ptr + hdr->page_size);
+    ramdisk_ptr = (void *)((unsigned) kernel_ptr + kernel_actual);
+    second_ptr = (void *)((unsigned) ramdisk_ptr + ramdisk_actual);
+
+    D(INFO, "preparing to boot");
+    // Prepares boot physical address. Addresses from header are ignored
+    rv = prepare_boot_linux(hdr->kernel_addr, kernel_ptr, kernel_actual,
+                            hdr->ramdisk_addr, ramdisk_ptr, ramdisk_actual,
+                            hdr->second_addr, second_ptr, second_actual,
+                            hdr->tags_addr, new_atags, ROUND_TO_PAGE(new_atags_sz, hdr->page_size));
+    if (rv < 0) {
+        fastboot_fail(phandle, "kexec prepare failed");
+        goto error;
+    }
+
+    fastboot_okay(phandle, "");
+
+    free(atags_ptr);
+    munmap(ptr, sz);
+    free(new_atags);
+    close(data_fd);
+
+    D(INFO, "Kexec going to reboot");
+    reboot(LINUX_REBOOT_CMD_KEXEC);
+
+    fastboot_fail(phandle, "reboot error");
+
+    return;
+
+error:
+
+    if (atags_ptr != NULL)
+        free(atags_ptr);
+    if (ptr != NULL)
+        munmap(ptr, sz);
+
+}
+
+static void cmd_erase(struct protocol_handle *phandle, const char *arg)
+{
+    int partition_fd;
+    char path[PATH_MAX];
+    D(DEBUG, "cmd_erase %s\n", arg);
+
+    if (flash_find_entry(arg, path, PATH_MAX)) {
+        fastboot_fail(phandle, "partition table doesn't exist");
+        return;
+    }
+
+    if (path == NULL) {
+        fastboot_fail(phandle, "Couldn't find partition");
+        return;
+    }
+
+    partition_fd = flash_get_partiton(path);
+    if (partition_fd < 0) {
+        fastboot_fail(phandle, "partiton file does not exists");
+    }
+
+    if (flash_erase(partition_fd)) {
+        fastboot_fail(phandle, "failed to erase partition");
+        flash_close(partition_fd);
+        return;
+    }
+
+    if (flash_close(partition_fd) < 0) {
+        D(ERR, "could not close device %s", strerror(errno));
+        fastboot_fail(phandle, "failed to erase partition");
+        return;
+    }
+    fastboot_okay(phandle, "");
+}
+
+static int GPT_header_location() {
+    const char *location_str = fastboot_getvar("gpt_sector");
+    char *str;
+    int location;
+
+    if (!strcmp("", location_str)) {
+        D(INFO, "GPT location not specified using second sector");
+        return 1;
+    }
+    else {
+        location = strtoul(location_str, &str, 10);
+        D(INFO, "GPT location specified as %d", location);
+
+        if (*str != '\0')
+            return -1;
+
+        return location - 1;
+    }
+}
+
+static void cmd_gpt_layout(struct protocol_handle *phandle, const char *arg) {
+    struct GPT_entry_table *oldtable;
+    int location;
+    struct GPT_content content;
+    const char *device;
+    device = fastboot_getvar("blockdev");
+
+    if (!strcmp(device, "")) {
+        fastboot_fail(phandle, "blockdev not defined in config file");
+        return;
+    }
+
+    //TODO: add same verification as in cmd_flash
+    if (phandle->download_fd < 0) {
+        fastboot_fail(phandle, "no layout file");
+        return;
+    }
+
+    location = GPT_header_location();
+    oldtable = GPT_get_device(device, location);
+
+    GPT_default_content(&content, oldtable);
+    if (oldtable == NULL)
+        D(WARN, "Could not get old gpt table");
+    else
+        GPT_release_device(oldtable);
+
+    if (!GPT_parse_file(phandle->download_fd, &content)) {
+        fastboot_fail(phandle, "Could not parse partition config file");
+        return;
+    }
+
+    if (trigger_gpt_layout(&content)) {
+        fastboot_fail(phandle, "Vendor forbids this opperation");
+        GPT_release_content(&content);
+        return;
+    }
+
+    if (!GPT_write_content(device, &content)) {
+        fastboot_fail(phandle, "Unable to write gpt file");
+        GPT_release_content(&content);
+        return;
+    }
+
+    GPT_release_content(&content);
+    fastboot_okay(phandle, "");
+}
+
+static void cmd_flash(struct protocol_handle *phandle, const char *arg)
+{
+    int partition;
+    uint64_t sz;
+    char data[BOOT_MAGIC_SIZE];
+    char path[PATH_MAX];
+    ssize_t header_sz = 0;
+    int data_fd = 0;
+
+    D(DEBUG, "cmd_flash %s\n", arg);
+
+    if (try_handle_virtual_partition(phandle, arg)) {
+        return;
+    }
+
+    if (phandle->download_fd < 0) {
+        fastboot_fail(phandle, "no kernel file");
+        return;
+    }
+
+    if (flash_find_entry(arg, path, PATH_MAX)) {
+        fastboot_fail(phandle, "partition table doesn't exist");
+        return;
+    }
+
+    if (flash_validate_certificate(phandle->download_fd, &data_fd) != 1) {
+        fastboot_fail(phandle, "Access forbiden you need certificate");
+        return;
+    }
+
+    // TODO: Maybe its goot idea to check whether the partition is bootable
+    if (!strcmp(arg, "boot") || !strcmp(arg, "recovery")) {
+        if (read_data_once(data_fd, data, BOOT_MAGIC_SIZE) < BOOT_MAGIC_SIZE) {
+            fastboot_fail(phandle, "incoming data read error, cannot read boot header");
+            return;
+        }
+        if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
+            fastboot_fail(phandle, "image is not a boot image");
+            return;
+        }
+    }
+
+    partition = flash_get_partiton(path);
+
+    sz = get_file_size64(data_fd);
+
+    sz -= header_sz;
+
+    if (sz > get_file_size64(partition)) {
+        flash_close(partition);
+        D(WARN, "size of file too large");
+        fastboot_fail(phandle, "size of file too large");
+        return;
+    }
+
+    D(INFO, "writing %lld bytes to '%s'\n", sz, arg);
+
+    if (flash_write(partition, phandle->download_fd, sz, header_sz)) {
+        fastboot_fail(phandle, "flash write failure");
+        return;
+    }
+    D(INFO, "partition '%s' updated\n", arg);
+
+    flash_close(partition);
+    close(data_fd);
+
+    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) {
+        fastboot_fail(phandle, "download failed");
+        return;
+    }
+
+    fastboot_okay(phandle, "");
+}
+
+static void cmd_oem(struct protocol_handle *phandle, const char *arg) {
+    const char *response = "";
+
+    //TODO: Maybe it should get download descriptor also
+    if (trigger_oem_cmd(arg, &response))
+        fastboot_fail(phandle, response);
+    else
+        fastboot_okay(phandle, response);
+}
+
+void commands_init()
+{
+    virtual_partition_register("partition-table", cmd_gpt_layout);
+
+    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_register("oem", cmd_oem);
+    //fastboot_publish("version", "0.5");
+    //fastboot_publish("product", "swordfish");
+    //fastboot_publish("kernel", "lk");
+}
diff --git a/fastbootd/commands/boot.c b/fastbootd/commands/boot.c
new file mode 100644
index 0000000..8da9a28
--- /dev/null
+++ b/fastbootd/commands/boot.c
@@ -0,0 +1,254 @@
+/*
+ * 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 <sys/syscall.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "boot.h"
+#include "debug.h"
+#include "utils.h"
+#include "bootimg.h"
+
+
+#define KEXEC_ARM_ATAGS_OFFSET  0x1000
+#define KEXEC_ARM_ZIMAGE_OFFSET 0x8000
+
+#define MEMORY_SIZE 0x0800000
+#define START_ADDRESS 0x44000000
+#define KERNEL_START (START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET)
+
+#define ATAG_NONE_TYPE      0x00000000
+#define ATAG_CORE_TYPE      0x54410001
+#define ATAG_RAMDISK_TYPE   0x54410004
+#define ATAG_INITRD2_TYPE   0x54420005
+#define ATAG_CMDLINE_TYPE   0x54410009
+
+#define MAX_ATAG_SIZE 0x4000
+
+struct atag_info {
+    unsigned size;
+    unsigned type;
+};
+
+struct atag_initrd2 {
+    unsigned start;
+    unsigned size;
+};
+
+struct atag_cmdline {
+    char cmdline[0];
+};
+
+struct atag {
+    struct atag_info info;
+    union {
+        struct atag_initrd2 initrd2;
+        struct atag_cmdline cmdline;
+    } data;
+};
+
+
+long kexec_load(unsigned int entry, unsigned long nr_segments,
+                struct kexec_segment *segment, unsigned long flags) {
+   return syscall(__NR_kexec_load, entry, nr_segments, segment, flags);
+}
+
+/*
+ * Prepares arguments for kexec
+ * Kernel address is not set into kernel_phys
+ * Ramdisk is set to position relative to kernel
+ */
+int prepare_boot_linux(unsigned kernel_phys, void *kernel_addr, int kernel_size,
+                       unsigned ramdisk_phys, void *ramdisk_addr, int ramdisk_size,
+                       unsigned second_phys, void *second_addr, int second_size,
+                       unsigned atags_phys, void *atags_addr, int atags_size) {
+    struct kexec_segment segment[4];
+    int segment_count = 2;
+    unsigned entry = START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET;
+    int rv;
+    int page_size = getpagesize();
+
+    segment[0].buf = kernel_addr;
+    segment[0].bufsz = kernel_size;
+    segment[0].mem = (void *) KERNEL_START;
+    segment[0].memsz = ROUND_TO_PAGE(kernel_size, page_size);
+
+    if (kernel_size > MEMORY_SIZE - KEXEC_ARM_ZIMAGE_OFFSET) {
+        D(INFO, "Kernel image too big");
+        return -1;
+    }
+
+    segment[1].buf = atags_addr;
+    segment[1].bufsz = atags_size;
+    segment[1].mem = (void *) (START_ADDRESS + KEXEC_ARM_ATAGS_OFFSET);
+    segment[1].memsz = ROUND_TO_PAGE(atags_size, page_size);
+
+    D(INFO, "Ramdisk size is %d", ramdisk_size);
+
+    if (ramdisk_size != 0) {
+        segment[segment_count].buf = ramdisk_addr;
+        segment[segment_count].bufsz = ramdisk_size;
+        segment[segment_count].mem = (void *) (KERNEL_START + ramdisk_phys - kernel_phys);
+        segment[segment_count].memsz = ROUND_TO_PAGE(ramdisk_phys, page_size);
+        ++segment_count;
+    }
+
+    D(INFO, "Ramdisk size is %d", ramdisk_size);
+    if (second_size != 0) {
+        segment[segment_count].buf = second_addr;
+        segment[segment_count].bufsz = second_size;
+        segment[segment_count].mem = (void *) (KERNEL_START + second_phys - kernel_phys);
+        segment[segment_count].memsz = ROUND_TO_PAGE(second_size, page_size);
+        entry = second_phys;
+        ++segment_count;
+    }
+
+    rv = kexec_load(entry, segment_count, segment, KEXEC_ARCH_DEFAULT);
+
+    if (rv != 0) {
+        D(INFO, "Kexec_load returned non-zero exit code: %s\n", strerror(errno));
+        return -1;
+    }
+
+    return 1;
+
+}
+
+unsigned *create_atags(unsigned *atags_position, int atag_size, const struct boot_img_hdr *hdr, int *size) {
+    struct atag *current_tag = (struct atag *) atags_position;
+    unsigned *current_tag_raw = atags_position;
+    unsigned *new_atags = malloc(ROUND_TO_PAGE(atag_size + BOOT_ARGS_SIZE * sizeof(char),
+                                               hdr->page_size));
+    //This pointer will point into the beggining of buffer free space
+    unsigned *natags_raw_buff = new_atags;
+    int new_atags_size = 0;
+    int current_size;
+    int cmdl_length;
+
+    // copy tags from current atag file
+    while (current_tag->info.type != ATAG_NONE_TYPE) {
+        switch (current_tag->info.type) {
+            case ATAG_CMDLINE_TYPE:
+            case ATAG_RAMDISK_TYPE:
+            case ATAG_INITRD2_TYPE: break;
+            default:
+                memcpy((void *)natags_raw_buff, (void *)current_tag_raw, current_tag->info.size * sizeof(unsigned));
+                natags_raw_buff += current_tag->info.size;
+                new_atags_size += current_tag->info.size;
+        }
+
+        current_tag_raw += current_tag->info.size;
+        current_tag = (struct atag *) current_tag_raw;
+
+        if (current_tag_raw >= atags_position + atag_size) {
+            D(ERR, "Critical error in atags");
+            return NULL;
+        }
+    }
+
+    // set INITRD2 tag
+    if (hdr->ramdisk_size > 0) {
+        current_size = (sizeof(struct atag_info) + sizeof(struct atag_initrd2)) / sizeof(unsigned);
+        *((struct atag *) natags_raw_buff) = (struct atag) {
+            .info = {
+                .size = current_size,
+                .type = ATAG_INITRD2_TYPE
+            },
+            .data = {
+                .initrd2 = (struct atag_initrd2) {
+                    .start = hdr->ramdisk_addr,
+                    .size = hdr->ramdisk_size
+                }
+            }
+        };
+
+        new_atags_size += current_size;
+        natags_raw_buff += current_size;
+    }
+
+    // set ATAG_CMDLINE
+    cmdl_length = strnlen((char *) hdr->cmdline, BOOT_ARGS_SIZE - 1);
+    current_size = sizeof(struct atag_info) + (1 + cmdl_length);
+    current_size = (current_size + sizeof(unsigned) - 1) / sizeof(unsigned);
+    *((struct atag *) natags_raw_buff) = (struct atag) {
+        .info = {
+            .size = current_size,
+            .type = ATAG_CMDLINE_TYPE
+        },
+    };
+
+    //copy cmdline and ensure that there is null character
+    memcpy(((struct atag *) natags_raw_buff)->data.cmdline.cmdline,
+           (char *) hdr->cmdline, cmdl_length);
+    ((struct atag *) natags_raw_buff)->data.cmdline.cmdline[cmdl_length] = '\0';
+
+    new_atags_size += current_size;
+    natags_raw_buff += current_size;
+
+    // set ATAG_NONE
+    *((struct atag *) natags_raw_buff) = (struct atag) {
+        .info = {
+            .size = 0,
+            .type = ATAG_NONE_TYPE
+        },
+    };
+    new_atags_size += sizeof(struct atag_info) / sizeof(unsigned);
+    natags_raw_buff += sizeof(struct atag_info) / sizeof(unsigned);
+
+    *size = new_atags_size * sizeof(unsigned);
+    return new_atags;
+}
+
+char *read_atags(const char * path, int *atags_sz) {
+    int afd = -1;
+    char *atags_ptr = NULL;
+
+    afd = open(path, O_RDONLY);
+    if (afd < 0) {
+        D(ERR, "wrong atags file");
+        return 0;
+    }
+
+    atags_ptr = (char *) malloc(MAX_ATAG_SIZE);
+    if (atags_ptr == NULL) {
+        D(ERR, "insufficient memory");
+        return 0;
+    }
+
+    *atags_sz = read(afd, atags_ptr, MAX_ATAG_SIZE);
+
+    close(afd);
+    return atags_ptr;
+}
+
diff --git a/fastbootd/commands/boot.h b/fastbootd/commands/boot.h
new file mode 100644
index 0000000..901c38a
--- /dev/null
+++ b/fastbootd/commands/boot.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef __FASTBOOT_BOOT_H
+#define __FASTBOOT_BOOT_H
+
+#include <sys/cdefs.h>
+#include <linux/kexec.h>
+
+#include "bootimg.h"
+
+#define KEXEC_TYPE_DEFAULT 0
+#define KEXEC_TYPE_CRASH   1
+
+int prepare_boot_linux(unsigned, void *, int, unsigned, void *, int,
+                       unsigned, void *, int, unsigned, void *, int);
+unsigned *create_atags(unsigned *, int, const struct boot_img_hdr *, int *);
+long kexec_load(unsigned int, unsigned long, struct kexec_segment *, unsigned long);
+char *read_atags(const char *, int *);
+
+#endif /* _SYS_KEXEC_H */
+
diff --git a/fastbootd/commands/flash.c b/fastbootd/commands/flash.c
new file mode 100644
index 0000000..0954217
--- /dev/null
+++ b/fastbootd/commands/flash.c
@@ -0,0 +1,161 @@
+/*
+ * 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 <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "flash.h"
+#include "protocol.h"
+#include "debug.h"
+#include "utils.h"
+#include "commands/partitions.h"
+
+#ifdef FLASH_CERT
+#include "secure.h"
+#endif
+
+#define ALLOWED_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-."
+#define BUFFER_SIZE 1024 * 1024
+#define MIN(a, b) (a > b ? b : a)
+
+
+int flash_find_entry(const char *name, char *out, size_t outlen)
+{
+//TODO: Assumption: All the partitions has they unique name
+
+    const char *path = fastboot_getvar("device-directory");
+    size_t length;
+    if (strcmp(path, "") == 0) {
+        D(ERR, "device-directory: not defined in config file");
+        return -1;
+    }
+
+    length = strspn(name, ALLOWED_CHARS);
+    if (length != strlen(name)) {
+        D(ERR, "Not allowed char in name: %c", name[length]);
+        return -1;
+    }
+
+    if (snprintf(out, outlen, "%s%s", path, name) >= (int) outlen) {
+        D(ERR, "Too long path to partition file");
+        return -1;
+    }
+
+    if (access(out, F_OK ) == -1) {
+        D(ERR, "could not find partition file %s", name);
+        return -1;
+    }
+
+    return 0;
+}
+
+int flash_erase(int fd)
+{
+    int64_t size;
+    size = get_block_device_size(fd);
+    D(DEBUG, "erase %llu data from %d\n", size, fd);
+
+    return wipe_block_device(fd, size);
+}
+
+int flash_write(int partition_fd, int data_fd, ssize_t size, ssize_t skip)
+{
+    ssize_t written = 0;
+    struct GPT_mapping input;
+    struct GPT_mapping output;
+
+    while (written < size) {
+        int current_size = MIN(size - written, BUFFER_SIZE);
+
+        if (gpt_mmap(&input, written + skip, current_size, data_fd)) {
+            D(ERR, "Error in writing data, unable to map data file %d at %d size %d", size, skip, current_size);
+            return -1;
+        }
+        if (gpt_mmap(&output, written, current_size, partition_fd)) {
+            D(ERR, "Error in writing data, unable to map output partition");
+            return -1;
+        }
+
+        memcpy(output.ptr, input.ptr, current_size);
+
+        gpt_unmap(&input);
+        gpt_unmap(&output);
+
+        written += current_size;
+    }
+
+    return 0;
+}
+
+#ifdef FLASH_CERT
+
+int flash_validate_certificate(int signed_fd, int *data_fd) {
+    int ret = 0;
+    const char *cert_path;
+    X509_STORE *store = NULL;
+    CMS_ContentInfo *content_info;
+    BIO *content;
+
+    cert_path = fastboot_getvar("certificate-path");
+    if (!strcmp(cert_path, "")) {
+        D(ERR, "could not find cert-key value in config file");
+        goto finish;
+    }
+
+    store = cert_store_from_path(cert_path);
+    if (store == NULL) {
+        D(ERR, "unable to create certification store");
+        goto finish;
+    }
+
+    if (cert_read(signed_fd, &content_info, &content)) {
+        D(ERR, "reading data failed");
+        goto finish;
+    }
+
+    ret = cert_verify(content, content_info, store, data_fd);
+    cert_release(content, content_info);
+
+    return ret;
+
+finish:
+    if (store != NULL)
+        cert_release_store(store);
+
+    return ret;
+}
+
+#else
+int flash_validate_certificate(int signed_fd, int *data_fd) {
+    return 1;
+}
+#endif
diff --git a/fastbootd/commands/flash.h b/fastbootd/commands/flash.h
new file mode 100644
index 0000000..5a64cab
--- /dev/null
+++ b/fastbootd/commands/flash.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#ifndef _FASTBOOTD_ERASE_H
+#define _FASTBOOTD_ERASE_H
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include "debug.h"
+
+int flash_find_entry(const char *, char *, size_t);
+int flash_erase(int fd);
+
+static inline int flash_get_partiton(const char *path) {
+    return open(path, O_RDWR);
+}
+
+static inline int flash_close(int fd) {
+    return close(fd);
+}
+
+int flash_write(int partition, int data, ssize_t size, ssize_t skip);
+
+static inline ssize_t read_data_once(int fd, char *buffer, ssize_t size) {
+    ssize_t readcount = 0;
+    ssize_t len;
+
+    while ((len = TEMP_FAILURE_RETRY(read(fd, (void *) &buffer[readcount], size - readcount))) > 0) {
+        readcount += len;
+    }
+    if (len < 0) {
+        D(ERR, "Read error:%s", strerror(errno));
+        return len;
+    }
+
+    return readcount;
+}
+
+int flash_validate_certificate(int signed_fd, int *data_fd);
+
+#endif
+
diff --git a/fastbootd/commands/partitions.c b/fastbootd/commands/partitions.c
new file mode 100644
index 0000000..de80ea3
--- /dev/null
+++ b/fastbootd/commands/partitions.c
@@ -0,0 +1,771 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <endian.h>
+#include <zlib.h>
+#include <linux/hdreg.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <cutils/config_utils.h>
+
+#include "partitions.h"
+#include "debug.h"
+#include "utils.h"
+#include "protocol.h"
+
+#define BLKRRPART  _IO(0x12,95) /* re-read partition table */
+#define BLKSSZGET  _IO(0x12,104)
+
+#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
+#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
+#define ALIGN_DOWN(x, y) ((y) * ((x) / (y)))
+
+
+const uint8_t partition_type_uuid[16] = {
+    0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
+    0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7,
+};
+
+//TODO: There is assumption that we are using little endian
+
+static void GPT_entry_clear(struct GPT_entry_raw *entry)
+{
+    memset(entry, 0, sizeof(*entry));
+}
+
+/*
+ * returns mapped location to choosen area
+ * mapped_ptr is pointer to whole area mapped (it can be bigger then requested)
+ */
+int gpt_mmap(struct GPT_mapping *mapping, uint64_t location, int size, int fd)
+{
+    unsigned int location_diff = location & ~PAGE_MASK;
+
+    mapping->size = ALIGN(size + location_diff, PAGE_SIZE);
+
+    uint64_t sz = get_file_size64(fd);
+    if (sz < size + location) {
+        D(ERR, "the location of mapping area is outside of the device size %lld", sz);
+        return 1;
+    }
+    location = ALIGN_DOWN(location, PAGE_SIZE);
+
+    mapping->map_ptr = mmap64(NULL, mapping->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, location);
+
+    if (mapping->map_ptr == MAP_FAILED) {
+        mapping->ptr = MAP_FAILED;
+        D(ERR, "map failed %d", (int) mapping->map_ptr);
+        return 1;
+    }
+
+    mapping->ptr = (void *)((char *) mapping->map_ptr + location_diff);
+    return 0;
+}
+
+void gpt_unmap(struct GPT_mapping *mapping) {
+    munmap(mapping->map_ptr, mapping->size);
+}
+
+
+#define LBA_ADDR(table, value)   ((uint64_t) (table)->sector_size * (value))
+
+int GPT_map_from_content(struct GPT_entry_table *table, const struct GPT_content *content)
+{
+
+    // Mapping header
+    if (gpt_mmap(&table->header_map, LBA_ADDR(table, content->header.current_lba),
+                 table->sector_size, table->fd)) {
+        D(ERR, "unable to map header:%s\n", strerror(errno));
+        goto error_header;
+    }
+
+    table->header = (struct GPT_header *) table->header_map.ptr;
+
+    table->partition_table_size = ROUND_UP(content->header.entries_count * sizeof(*table->entries),
+                                           table->sector_size);
+
+    // Mapping entry table
+    if (gpt_mmap(&table->entries_map, LBA_ADDR(table, content->header.entries_lba),
+                 table->partition_table_size, table->fd)) {
+        D(ERR, "unable to map entries");
+        goto error_signature;
+    }
+
+    table->entries = (struct GPT_entry_raw *) table->entries_map.ptr;
+
+    // Mapping secondary header
+    if (gpt_mmap(&table->sec_header_map, LBA_ADDR(table, content->header.backup_lba),
+                 table->sector_size, table->fd)) {
+        D(ERR, "unable to map backup gpt header");
+        goto error_sec_header;
+    }
+
+    // Mapping secondary entries table
+    if (gpt_mmap(&table->sec_entries_map,
+                 LBA_ADDR(table, content->header.backup_lba) - table->partition_table_size,
+                 table->partition_table_size, table->fd)) {
+        D(ERR, "unable to map secondary gpt table");
+        goto error_sec_entries;
+    }
+
+    table->second_header = (struct GPT_header *) table->sec_header_map.ptr;
+    table->second_entries = (struct GPT_entry_raw *) table->sec_entries_map.ptr;
+    table->second_valid = strcmp("EFI PART", (char *) table->second_header->signature) == 0;
+
+    return 0;
+
+error_sec_entries:
+    gpt_unmap(&table->sec_header_map);
+error_sec_header:
+    gpt_unmap(&table->entries_map);
+error_signature:
+    gpt_unmap(&table->header_map);
+error_header:
+    return 1;
+}
+
+int GPT_map(struct GPT_entry_table *table, unsigned header_lba)
+{
+    struct GPT_content content;
+    struct GPT_mapping mapping;
+    struct GPT_header *header;
+
+    if (gpt_mmap(&mapping, LBA_ADDR(table, header_lba), table->sector_size, table->fd)) {
+        D(ERR, "unable to map header: %s", strerror(errno));
+        goto error_header;
+    }
+
+    header = (struct GPT_header *) mapping.ptr;
+
+    if (strcmp("EFI PART", (char *) header->signature)) {
+        D(ERR, "GPT entry not valid");
+        goto error_signature;
+    }
+
+    content.header = *header;
+
+    gpt_unmap(&mapping);
+
+    return GPT_map_from_content(table, &content);
+
+error_signature:
+    gpt_unmap(&table->header_map);
+error_header:
+    return 1;
+}
+
+struct GPT_entry_table* GPT_get_device(const char *path, unsigned header_lba)
+{
+    struct GPT_entry_table *table;
+    size_t sector_bytes;
+
+    table = (struct GPT_entry_table *) malloc(sizeof(*table));
+    table->fd = open(path, O_RDWR);
+
+    if (table->fd < 0) {
+        D(ERR, "unable to open file %s:%s\n", path, strerror(errno));
+        return NULL;
+    }
+
+    if (!ioctl(table->fd, BLKSSZGET, &sector_bytes)) {
+        table->sector_size = (unsigned) sector_bytes;
+        D(INFO, "Got sector size %d", table->sector_size);
+    } else {
+        D(WARN, "unable to get sector size, assuming 512");
+        table->sector_size = 512;
+    }
+
+    if (GPT_map(table, header_lba)) {
+        D(ERR, "Could not map gpt");
+        return NULL;
+    }
+
+    return table;
+}
+
+static struct GPT_entry_table* GPT_get_from_content(const char *path, const struct GPT_content *content)
+{
+    struct GPT_entry_table *table;
+    size_t sector_bytes;
+
+    table = (struct GPT_entry_table *) malloc(sizeof(*table));
+    table->fd = open(path, O_RDWR);
+
+    if (table->fd < 0) {
+        D(ERR, "unable to open file %s:%s\n", path, strerror(errno));
+        return NULL;
+    }
+
+    if (!ioctl(table->fd, BLKSSZGET, &sector_bytes)) {
+        table->sector_size = (unsigned) sector_bytes;
+        D(INFO, "Got sector size %d", table->sector_size);
+    } else {
+        D(WARN, "unable to get sector size %s, assuming 512", strerror(errno));
+        table->sector_size = 512;
+    }
+
+    if (GPT_map_from_content(table, content)) {
+        D(ERR, "Could not map gpt");
+        return NULL;
+    }
+
+    return table;
+}
+
+
+void GPT_release_device(struct GPT_entry_table *table)
+{
+    gpt_unmap(&table->header_map);
+    gpt_unmap(&table->entries_map);
+    gpt_unmap(&table->sec_header_map);
+    gpt_unmap(&table->sec_entries_map);
+    close(table->fd);
+    free(table);
+}
+
+static int GPT_check_overlap(struct GPT_entry_table *table, struct GPT_entry_raw *entry);
+static int GPT_check_overlap_except(struct GPT_entry_table *table,
+                                    struct GPT_entry_raw *entry,
+                                    struct GPT_entry_raw *exclude);
+
+void GPT_edit_entry(struct GPT_entry_table *table,
+                    struct GPT_entry_raw *old_entry,
+                    struct GPT_entry_raw *new_entry)
+{
+    struct GPT_entry_raw *current_entry = GPT_get_pointer(table, old_entry);
+
+    if (GPT_check_overlap_except(table, new_entry, current_entry)) {
+        D(ERR, "Couldn't add overlaping partition");
+        return;
+    }
+
+    if (current_entry == NULL) {
+        D(ERR, "Couldn't find entry");
+        return;
+    }
+
+    *current_entry = *new_entry;
+}
+
+int GPT_delete_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry)
+{
+    struct GPT_entry_raw *raw = GPT_get_pointer(table, entry);
+
+    if (raw == NULL) {
+        D(ERR, "could not find entry");
+        return 1;
+    }
+    D(DEBUG, "Deleting gpt entry '%s'\n", raw->partition_guid);
+
+    // Entry in the middle of table may become empty
+    GPT_entry_clear(raw);
+
+    return 0;
+}
+
+void GPT_add_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry)
+{
+    unsigned i;
+    int inserted = 0;
+    if (GPT_check_overlap(table, entry)) {
+        D(ERR, "Couldn't add overlaping partition");
+        return;
+    }
+
+    if (GPT_get_pointer(table, entry) != NULL) {
+        D(WARN, "Add entry fault, this entry already exists");
+        return;
+    }
+
+    struct GPT_entry_raw *entries = table->entries;
+
+    for (i = 0; i < table->header->entries_count; ++i) {
+        if (!entries[i].type_guid[0]) {
+            inserted = 1;
+            D(DEBUG, "inserting");
+            memcpy(&entries[i], entry, sizeof(entries[i]));
+            break;
+        }
+    }
+
+    if (!inserted) {
+        D(ERR, "Unable to find empty partion entry");
+    }
+}
+
+struct GPT_entry_raw *GPT_get_pointer_by_UTFname(struct GPT_entry_table *table, const uint16_t *name);
+
+struct GPT_entry_raw *GPT_get_pointer(struct GPT_entry_table *table, struct GPT_entry_raw *entry)
+{
+    if (entry->partition_guid[0] != 0)
+        return GPT_get_pointer_by_guid(table, (const char *) entry->partition_guid);
+    else if (entry->name[0] != 0)
+        return GPT_get_pointer_by_UTFname(table, entry->name);
+
+    D(WARN, "Name or guid needed to find entry");
+    return NULL;
+}
+
+struct GPT_entry_raw *GPT_get_pointer_by_guid(struct GPT_entry_table *table, const char *name)
+{
+    int current = (int) table->header->entries_count;
+
+    for (current = current - 1; current >= 0; --current) {
+        if (strncmp((char *) name,
+                    (char *) table->entries[current].partition_guid, 16) == 0) {
+                return &table->entries[current];
+        }
+    }
+
+    return NULL;
+}
+
+int strncmp_UTF16_char(const uint16_t *s1, const char *s2, size_t n)
+{
+    if (n == 0)
+        return (0);
+    do {
+        if (((*s1) & 127) != *s2++)
+            return (((unsigned char) ((*s1) & 127)) - *(unsigned char *)--s2);
+        if (*s1++ == 0)
+            break;
+    } while (--n != 0);
+    return (0);
+}
+
+int strncmp_UTF16(const uint16_t *s1, const uint16_t *s2, size_t n)
+{
+    if (n == 0)
+        return (0);
+    do {
+        if ((*s1) != *s2++)
+            return (*s1 - *--s2);
+        if (*s1++ == 0)
+            break;
+    } while (--n != 0);
+    return (0);
+}
+
+struct GPT_entry_raw *GPT_get_pointer_by_name(struct GPT_entry_table *table, const char *name)
+{
+    int count = (int) table->header->entries_count;
+    int current;
+
+    for (current = 0; current < count; ++current) {
+        if (strncmp_UTF16_char(table->entries[current].name,
+                         (char *) name, 16) == 0) {
+                    return &table->entries[current];
+        }
+    }
+
+    return NULL;
+}
+
+struct GPT_entry_raw *GPT_get_pointer_by_UTFname(struct GPT_entry_table *table, const uint16_t *name)
+{
+    int count = (int) table->header->entries_count;
+    int current;
+
+    for (current = 0; current < count; ++current) {
+        if (strncmp_UTF16(table->entries[current].name,
+                          name, GPT_NAMELEN) == 0) {
+                return &table->entries[current];
+        }
+    }
+
+    return NULL;
+}
+
+void GPT_sync(struct GPT_entry_table *table)
+{
+    uint32_t crc;
+
+    //calculate crc32
+    crc = crc32(0, Z_NULL, 0);
+    crc = crc32(crc, (void*) table->entries, table->header->entries_count * sizeof(*table->entries));
+    table->header->partition_array_checksum = crc;
+
+    table->header->header_checksum = 0;
+    crc = crc32(0, Z_NULL, 0);
+    crc = crc32(crc, (void*) table->header, table->header->header_size);
+    table->header->header_checksum = crc;
+
+    //sync secondary partion
+    if (table->second_valid) {
+        memcpy((void *)table->second_entries, (void *) table->entries, table->partition_table_size);
+        memcpy((void *)table->second_header, (void *)table->header, sizeof(*table->header));
+    }
+
+    if(!ioctl(table->fd, BLKRRPART, NULL)) {
+        D(WARN, "Unable to force kernel to refresh partition table");
+    }
+}
+
+void GPT_to_UTF16(uint16_t *to, const char *from, int n)
+{
+    int i;
+    for (i = 0; i < (n - 1) && (to[i] = from[i]) != '\0'; ++i);
+    to[i] = '\0';
+}
+
+void GPT_from_UTF16(char *to, const uint16_t *from, int n)
+{
+    int i;
+    for (i = 0; i < (n - 1) && (to[i] = from[i] & 127) != '\0'; ++i);
+    to[i] = '\0';
+}
+
+static int GPT_check_overlap_except(struct GPT_entry_table *table,
+                                    struct GPT_entry_raw *entry,
+                                    struct GPT_entry_raw *exclude) {
+    int current = (int) table->header->entries_count;
+    int dontcheck;
+    struct GPT_entry_raw *current_entry;
+    if (entry->last_lba < entry->first_lba) {
+        D(WARN, "Start address have to be less than end address");
+        return 1;
+    }
+
+    for (current = current - 1; current >= 0; --current) {
+        current_entry = &table->entries[current];
+        dontcheck = strncmp((char *) entry->partition_guid,
+                           (char *) current_entry->partition_guid , 16) == 0;
+        dontcheck |= current_entry->type_guid[0] == 0;
+        dontcheck |= current_entry == exclude;
+
+        if (!dontcheck && ((entry->last_lba >= current_entry->first_lba &&
+                            entry->first_lba < current_entry->last_lba ))) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static int GPT_check_overlap(struct GPT_entry_table *table, struct GPT_entry_raw *entry)
+{
+    return GPT_check_overlap_except(table, entry, NULL);
+}
+
+static char *get_key_value(char *ptr, char **key, char **value)
+{
+    *key = ptr;
+    ptr = strchr(ptr, '=');
+
+    if (ptr == NULL)
+        return NULL;
+
+    *ptr++ = '\0';
+    *value = ptr;
+    ptr = strchr(ptr, ';');
+
+    if (ptr == NULL)
+        ptr = *value + strlen(*value);
+    else
+        *ptr = '\0';
+
+    *key = strip(*key);
+    *value = strip(*value);
+
+    return ptr;
+}
+
+//TODO: little endian?
+static int add_key_value(const char *key, const char *value, struct GPT_entry_raw *entry)
+{
+    char *endptr;
+    if (!strcmp(key, "type")) {
+        strncpy((char *) entry->type_guid, value, 16);
+        entry->type_guid[15] = 0;
+    }
+    else if (!strcmp(key, "guid")) {
+        strncpy((char *) entry->partition_guid, value, 16);
+        entry->type_guid[15] = 0;
+    }
+    else if (!strcmp(key, "firstlba")) {
+        entry->first_lba = strtoul(value, &endptr, 10);
+        if (*endptr != '\0') goto error;
+    }
+    else if (!strcmp(key, "lastlba")) {
+        entry->last_lba = strtoul(value, &endptr, 10);
+        if (*endptr != '\0') goto error;
+    }
+    else if (!strcmp(key, "flags")) {
+        entry->flags = strtoul(value, &endptr, 16);
+        if (*endptr != '\0') goto error;
+    }
+    else if (!strcmp(key, "name")) {
+        GPT_to_UTF16(entry->name, value, GPT_NAMELEN);
+    }
+    else {
+        goto error;
+    }
+
+    return 0;
+
+error:
+    D(ERR, "Could not find key or parse value: %s,%s", key, value);
+    return 1;
+}
+
+int GPT_parse_entry(char *string, struct GPT_entry_raw *entry)
+{
+    char *ptr = string;
+    char *key, *value;
+
+    while ((ptr = get_key_value(ptr, &key, &value)) != NULL) {
+        if (add_key_value(key, value, entry)) {
+            D(WARN, "key or value not valid: %s %s", key, value);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+void entry_set_guid(int n, uint8_t *guid)
+{
+    int fd;
+    fd = open("/dev/urandom", O_RDONLY);
+    read(fd, guid, 16);
+    close(fd);
+
+    //rfc4122
+    guid[8] = (guid[8] & 0x3F) | 0x80;
+    guid[7] = (guid[7] & 0x0F) | 0x40;
+}
+
+void GPT_default_content(struct GPT_content *content, struct GPT_entry_table *table)
+{
+    if (table != NULL) {
+        memcpy(&content->header, table->header, sizeof(content->header));
+        content->header.header_size = sizeof(content->header);
+        content->header.entry_size = sizeof(struct GPT_entry_raw);
+    }
+    else {
+        D(WARN, "Could not locate old gpt table, using default values");
+        memset(&content->header, 0, sizeof(content->header) / sizeof(int));
+        content->header = (struct GPT_header) {
+            .revision = 0x10000,
+            .header_size = sizeof(content->header),
+            .header_checksum = 0,
+            .reserved_zeros = 0,
+            .current_lba = 1,
+            .backup_lba = 1,
+            .entry_size = sizeof(struct GPT_entry_raw),
+            .partition_array_checksum = 0
+        };
+        strncpy((char *)content->header.signature, "EFI PART", 8);
+        strncpy((char *)content->header.disk_guid, "ANDROID MMC DISK", 16);
+    }
+}
+
+static int get_config_uint64(cnode *node, uint64_t *ptr, const char *name)
+{
+    const char *tmp;
+    uint64_t val;
+    char *endptr;
+    if ((tmp = config_str(node, name, NULL))) {
+        val = strtoull(tmp, &endptr, 10);
+        if (*endptr != '\0') {
+            D(WARN, "Value for %s is not a number: %s", name, tmp);
+            return 1;
+        }
+        *ptr = val;
+        return 0;
+    }
+    return 1;
+}
+
+static int get_config_string(cnode *node, char *ptr, int max_len, const char *name)
+{
+    size_t begin, end;
+    const char *value = config_str(node, name, NULL);
+    if (!value)
+        return -1;
+
+    begin = strcspn(value, "\"") + 1;
+    end = strcspn(&value[begin], "\"");
+
+    if ((int) end > max_len) {
+        D(WARN, "Identifier \"%s\" too long", value);
+        return -1;
+    }
+
+    strncpy(ptr, &value[begin], end);
+    if((int) end < max_len)
+        ptr[end] = 0;
+    return 0;
+}
+
+static void GPT_parse_header(cnode *node, struct GPT_content *content)
+{
+    get_config_uint64(node, &content->header.current_lba, "header_lba");
+    get_config_uint64(node, &content->header.backup_lba, "backup_lba");
+    get_config_uint64(node, &content->header.first_usable_lba, "first_lba");
+    get_config_uint64(node, &content->header.last_usable_lba, "last_lba");
+    get_config_uint64(node, &content->header.entries_lba, "entries_lba");
+    get_config_string(node, (char *) content->header.disk_guid, 16, "guid");
+}
+
+static int GPT_parse_partitions(cnode *node, struct GPT_content *content)
+{
+    cnode *current;
+    int i;
+    uint64_t partition_size;
+    struct GPT_entry_raw *entry;
+    for (i = 0, current = node->first_child; current; current = current->next, ++i) {
+        entry = &content->entries[i];
+        entry_set_guid(i, content->entries[i].partition_guid);
+        memcpy(&content->entries[i].type_guid, partition_type_uuid, 16);
+        if (get_config_uint64(current, &entry->first_lba, "first_lba")) {
+            D(ERR, "first_lba not specified");
+            return 1;
+        }
+        if (get_config_uint64(current, &partition_size, "partition_size")) {
+            D(ERR, "partition_size not specified");
+            return 1;
+        }
+        if (config_str(current, "system", NULL)) {
+            entry->flags |= GPT_FLAG_SYSTEM;
+        }
+        if (config_str(current, "bootable", NULL)) {
+            entry->flags |= GPT_FLAG_BOOTABLE;
+        }
+        if (config_str(current, "readonly", NULL)) {
+            entry->flags |= GPT_FLAG_READONLY;
+        }
+        if (config_str(current, "automount", NULL)) {
+            entry->flags |= GPT_FLAG_DOAUTOMOUNT;
+        }
+
+        get_config_uint64(current, &content->entries[i].flags, "flags");
+        content->entries[i].last_lba = content->entries[i].first_lba + partition_size - 1;
+        GPT_to_UTF16(content->entries[i].name, current->name, 16);
+    }
+    return 0;
+}
+
+static inline int cnode_count(cnode *node)
+{
+    int i;
+    cnode *current;
+    for (i = 0, current = node->first_child; current; current = current->next, ++i)
+        ;
+    return i;
+}
+
+
+static int GPT_parse_cnode(cnode *root, struct GPT_content *content)
+{
+    cnode *partnode;
+
+    if (!(partnode = config_find(root, "partitions"))) {
+        D(ERR, "Could not find partition table");
+        return 0;
+    }
+
+    GPT_parse_header(root, content);
+
+    content->header.entries_count = cnode_count(partnode);
+    content->entries = malloc(content->header.entries_count * sizeof(struct GPT_entry_raw));
+
+    if (GPT_parse_partitions(partnode, content)) {
+        D(ERR, "Could not parse partitions");
+        return 0;
+    }
+
+    return 1;
+}
+
+int GPT_parse_file(int fd, struct GPT_content *content)
+{
+    char *data;
+    int size;
+    int ret;
+    cnode *root = config_node("", "");
+
+    size = get_file_size(fd);
+    data = (char *) mmap(NULL, size + 1, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+
+    if (data == NULL) {
+        if (size == 0)
+            D(ERR, "config file empty");
+        else
+            D(ERR, "Out of memory");
+        return 0;
+    }
+
+    data[size - 1] = 0;
+    config_load(root, data);
+
+    if (root->first_child == NULL) {
+        D(ERR, "Could not read config file");
+        return 0;
+    }
+
+    ret = GPT_parse_cnode(root, content);
+    munmap(data, size);
+    return ret;
+}
+
+void GPT_release_content(struct GPT_content *content)
+{
+    free(content->entries);
+}
+
+int GPT_write_content(const char *device, struct GPT_content *content)
+{
+    struct GPT_entry_table *maptable;
+
+    maptable = GPT_get_from_content(device, content);
+    if (maptable == NULL) {
+        D(ERR, "could not map device");
+        return 0;
+    }
+
+    memcpy(maptable->header, &content->header, sizeof(*maptable->header));
+    memcpy(maptable->entries, content->entries,
+           content->header.entries_count * sizeof(*maptable->entries));
+
+    GPT_sync(maptable);
+    GPT_release_device(maptable);
+
+    return 1;
+}
+
diff --git a/fastbootd/commands/partitions.h b/fastbootd/commands/partitions.h
new file mode 100644
index 0000000..9a6a88d
--- /dev/null
+++ b/fastbootd/commands/partitions.h
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+
+#ifndef __FASTBOOTD_PATITIONS_
+#define __FASTBOOTD_PATITIONS_
+
+#include <stdint.h>
+
+#define GPT_ENTRIES 128
+#define GPT_NAMELEN 36
+
+#define GPT_FLAG_SYSTEM (1ULL << 0)
+#define GPT_FLAG_BOOTABLE (1ULL << 2)
+#define GPT_FLAG_READONLY (1ULL << 60)
+#define GPT_FLAG_DOAUTOMOUNT (1ULL << 63)
+
+// it should be passed in little endian order
+struct GPT_entry_raw {
+    uint8_t type_guid[16];
+    uint8_t partition_guid[16];
+    uint64_t first_lba; // little endian
+    uint64_t last_lba;
+    uint64_t flags;
+    uint16_t name[GPT_NAMELEN]; // UTF-16 LE
+};
+
+struct GPT_mapping {
+    void *map_ptr;
+    void *ptr;
+    unsigned size;
+};
+
+struct GPT_entry_table {
+    int fd;
+
+    struct GPT_mapping header_map;
+    struct GPT_mapping entries_map;
+    struct GPT_mapping sec_header_map;
+    struct GPT_mapping sec_entries_map;
+
+    struct GPT_header *header;
+    struct GPT_entry_raw *entries;
+    struct GPT_header *second_header;
+    struct GPT_entry_raw *second_entries;
+
+    unsigned sector_size;
+    unsigned partition_table_size;
+    int second_valid;
+};
+
+struct GPT_header {
+    uint8_t signature[8];
+    uint32_t revision;
+    uint32_t header_size;
+    uint32_t header_checksum;
+    uint32_t reserved_zeros;
+    uint64_t current_lba;
+    uint64_t backup_lba;
+    uint64_t first_usable_lba;
+    uint64_t last_usable_lba;
+    uint8_t disk_guid[16];
+    uint64_t entries_lba;
+    uint32_t entries_count;
+    uint32_t entry_size;
+    uint32_t partition_array_checksum;
+    // the rest should be filled with zeros
+} __attribute__((packed));
+
+struct GPT_content {
+    struct GPT_header header;
+    struct GPT_entry_raw *entries;
+};
+
+
+struct GPT_entry_table* GPT_get_device(const char *, unsigned lba);
+
+void GPT_release_device(struct GPT_entry_table *);
+
+void GPT_edit_entry(struct GPT_entry_table *table,
+                    struct GPT_entry_raw *old_entry,
+                    struct GPT_entry_raw *new_entry);
+
+int GPT_delete_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry);
+
+void GPT_add_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry);
+
+struct GPT_entry_raw *GPT_get_pointer(struct GPT_entry_table *table, struct GPT_entry_raw *entry);
+struct GPT_entry_raw *GPT_get_pointer_by_guid(struct GPT_entry_table *, const char *);
+struct GPT_entry_raw *GPT_get_pointer_by_name(struct GPT_entry_table *, const char *);
+
+//Use after every edit operation
+void GPT_sync();
+
+void GPT_to_UTF16(uint16_t *, const char *, int );
+void GPT_from_UTF16(char *, const uint16_t *, int);
+
+int GPT_parse_entry(char *string, struct GPT_entry_raw *entry);
+
+void GPT_default_content(struct GPT_content *content, struct GPT_entry_table *table);
+
+void GPT_release_content(struct GPT_content *content);
+
+int GPT_parse_file(int fd, struct GPT_content *content);
+
+int GPT_write_content(const char *device, struct GPT_content *content);
+
+int gpt_mmap(struct GPT_mapping *mapping, uint64_t location, int size, int fd);
+
+void gpt_unmap(struct GPT_mapping *mapping);
+
+#endif
diff --git a/fastbootd/commands/virtual_partitions.c b/fastbootd/commands/virtual_partitions.c
new file mode 100644
index 0000000..813f485
--- /dev/null
+++ b/fastbootd/commands/virtual_partitions.c
@@ -0,0 +1,65 @@
+/*
+ * 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 "commands/virtual_partitions.h"
+#include "debug.h"
+
+static struct virtual_partition *partitions = NULL;
+
+int try_handle_virtual_partition(struct protocol_handle *handle, const char *arg)
+{
+    struct virtual_partition *current;
+
+    for (current = partitions; current != NULL; current = current->next) {
+        if (!strcmp(current->name, arg)) {
+            current->handler(handle, arg);
+        }
+    }
+
+    return 0;
+}
+
+void virtual_partition_register(
+        const char * name,
+        void (*handler)(struct protocol_handle *phandle, const char *arg))
+{
+    struct virtual_partition *new;
+    new = malloc(sizeof(*new));
+    if (new) {
+        new->name = name;
+        new->handler = handler;
+        new->next = partitions;
+        partitions = new;
+    }
+    else {
+        D(ERR, "Out of memory");
+    }
+}
diff --git a/fastbootd/commands/virtual_partitions.h b/fastbootd/commands/virtual_partitions.h
new file mode 100644
index 0000000..88df71e
--- /dev/null
+++ b/fastbootd/commands/virtual_partitions.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#ifndef FASTBOOTD_VIRTUAL_PARTITIONS_H
+#define FASTBOOTD_VIRTUAL_PARTITIONS_H
+
+#include "protocol.h"
+
+struct virtual_partition {
+    struct virtual_partition *next;
+    const char *name;
+    void (*handler)(struct protocol_handle *phandle, const char *arg);
+};
+
+int try_handle_virtual_partition(struct protocol_handle *handle, const char *arg);
+
+void virtual_partition_register(
+        const char * name,
+        void (*handler)(struct protocol_handle *phandle, const char *arg));
+
+#endif
diff --git a/fastbootd/config.c b/fastbootd/config.c
new file mode 100644
index 0000000..fe6da69
--- /dev/null
+++ b/fastbootd/config.c
@@ -0,0 +1,145 @@
+/*
+ * 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 "utils.h"
+
+#include "debug.h"
+
+// TODO: change config path
+#define CONFIG_PATH "/data/fastboot.cfg"
+
+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..2b51b33
--- /dev/null
+++ b/fastbootd/fastbootd.c
@@ -0,0 +1,100 @@
+/*
+ * 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 <getopt.h>
+#include <stdlib.h>
+
+#include "debug.h"
+#include "trigger.h"
+#include "socket_client.h"
+#include "secure.h"
+
+unsigned int debug_level = DEBUG;
+
+void commands_init();
+void usb_init();
+void config_init();
+int transport_socket_init();
+int network_discovery_init();
+void ssh_server_start();
+
+int main(int argc, char **argv)
+{
+    int socket_client = 0;
+    int c;
+    int network = 1;
+
+    klog_init();
+    klog_set_level(6);
+
+    const struct option longopts[] = {
+        {"socket", no_argument, 0, 'S'},
+        {"nonetwork", no_argument, 0, 'n'},
+        {0, 0, 0, 0}
+    };
+
+    while (1) {
+        c = getopt_long(argc, argv, "Sn", longopts, NULL);
+        /* Alphabetical cases */
+        if (c < 0)
+            break;
+        switch (c) {
+        case 'S':
+            socket_client = 1;
+            break;
+        case 'n':
+            network = 0;
+            break;
+        case '?':
+            return 1;
+        default:
+            return 0;
+        }
+    }
+
+    (void)argc;
+    (void)argv;
+
+    klog_init();
+    klog_set_level(6);
+
+    if (socket_client) {
+        //TODO: Shouldn't we change current tty into raw mode?
+        run_socket_client();
+    }
+    else {
+        cert_init_crypto();
+        config_init();
+        load_trigger();
+        commands_init();
+        usb_init();
+
+        if (network) {
+            if (!transport_socket_init())
+                exit(1);
+            ssh_server_start();
+            network_discovery_init();
+        }
+
+        while (1) {
+            sleep(1);
+        }
+    }
+    return 0;
+}
diff --git a/fastbootd/include/vendor_trigger.h b/fastbootd/include/vendor_trigger.h
new file mode 100644
index 0000000..51204fa
--- /dev/null
+++ b/fastbootd/include/vendor_trigger.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#ifndef __VENDOR_TRIGGER_H_
+#define __VENDOR_TRIGGER_H_
+
+#define TRIGGER_MODULE_ID "fastbootd"
+#include <hardware/hardware.h>
+
+__BEGIN_DECLS
+
+struct GPT_entry_raw;
+struct GPT_content;
+
+/*
+ * Structer with function pointers may become longer in the future
+ */
+
+struct vendor_trigger_t {
+    struct hw_device_t common;
+
+    /*
+     * This function runs at the beggining and shoud never be changed
+     *
+     * version is number parameter indicating version on the fastbootd side
+     * libversion is version indicateing version of the library version
+     *
+     * returns 0 if it can cooperate with the current version and 1 in opposite
+     */
+    int (*check_version)(const int version, int *libversion);
+
+
+    /*
+     * Return value -1 forbid the action from the vendor site and sets errno
+     */
+    int (* gpt_layout)(struct GPT_content *);
+    int (* oem_cmd)(const char *arg, const char **response);
+};
+
+__END_DECLS
+
+#endif
diff --git a/fastbootd/network_discovery.c b/fastbootd/network_discovery.c
new file mode 100644
index 0000000..1cd3e48
--- /dev/null
+++ b/fastbootd/network_discovery.c
@@ -0,0 +1,118 @@
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <dns_sd.h>
+#include <cutils/properties.h>
+#include <unistd.h>
+
+#include "debug.h"
+#include "network_discovery.h"
+#include "utils.h"
+
+#define MDNS_SERVICE_NAME "mdnsd"
+#define MDNS_SERVICE_STATUS "init.svc.mdnsd"
+#define FASTBOOTD_TYPE "_fastbootd._tcp"
+#define FASTBOOTD_DOMAIN "local."
+#define FASTBOOTD_NAME "fastbootd"
+
+
+static void reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags, DNSServiceErrorType errorCode,
+    const char *name, const char *regtype, const char *domain, void *context)
+{
+    (void)sdref;    // Unused
+    (void)flags;    // Unused
+    (void)context;  // Unused
+    if (errorCode == kDNSServiceErr_ServiceNotRunning) {
+        fprintf(stderr, "Error code %d\n", errorCode);
+    }
+
+
+    printf("Got a reply for service %s.%s%s: ", name, regtype, domain);
+
+    if (errorCode == kDNSServiceErr_NoError)
+    {
+        if (flags & kDNSServiceFlagsAdd)
+            printf("Name now registered and active\n");
+        else
+            printf("Name registration removed\n");
+        if (errorCode == kDNSServiceErr_NameConflict)
+            printf("Name in use, please choose another\n");
+        else
+            printf("Error %d\n", errorCode);
+
+        if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
+    }
+}
+
+static int register_service() {
+    DNSServiceRef sdref = NULL;
+    const char *domain = FASTBOOTD_DOMAIN;
+    const char *type = FASTBOOTD_TYPE;
+    const char *host = NULL;
+    char name[PROP_VALUE_MAX];
+    uint16_t port = 22;
+    int flags = 0;
+    DNSServiceErrorType result;
+    property_get("ro.serialno", name, "");
+    if (!strcmp(name, "")) {
+        D(ERR, "No property serialno");
+        return -1;
+    }
+
+    result = DNSServiceRegister(&sdref, flags, kDNSServiceInterfaceIndexAny,
+                       name, type, domain, host, port,
+                       0, NULL, reg_reply, NULL);
+    if (result != kDNSServiceErr_NoError) {
+        D(ERR, "Unable to register service");
+        return -1;
+    }
+    return 0;
+}
+
+
+int network_discovery_init()
+{
+    D(INFO, "Starting discovery");
+    if (service_start(MDNS_SERVICE_NAME)) {
+        D(ERR, "Unable to start discovery");
+        return -1;
+    }
+
+    if (register_service()) {
+        D(ERR, "Unable to register service");
+        return -1;
+    }
+
+    return 0;
+}
+
diff --git a/fastbootd/network_discovery.h b/fastbootd/network_discovery.h
new file mode 100644
index 0000000..75fda63
--- /dev/null
+++ b/fastbootd/network_discovery.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef _FASTBOOTD_NETWORK_DISCOVERY_H
+#define _FASTBOOTD_NETWORK_DISCOVERY_H
+
+int network_discovery_init();
+
+#endif
diff --git a/fastbootd/other/gptedit.c b/fastbootd/other/gptedit.c
new file mode 100644
index 0000000..16d34a5
--- /dev/null
+++ b/fastbootd/other/gptedit.c
@@ -0,0 +1,302 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#include <cutils/klog.h>
+
+#include "commands/partitions.h"
+#include "debug.h"
+
+unsigned int debug_level = DEBUG;
+//TODO: add tool to generate config file
+
+void usage() {
+    fprintf(stderr,
+            "usage: test_gpt [ <option> ] <file>\n"
+            "\n"
+            "options:\n"
+            "  -p                                       print partitions\n"
+            "  -c                                       print config file\n"
+            "  -a                                       adds new partition\n"
+            "  -d                                       deletes partition (-o needed)\n"
+            "\n"
+            "  -n name@startlba,endlba                  new partition detail\n"
+            "  -o                                       old partition name\n"
+            "  -t                                       type guid\n"
+            "  -g                                       partition guid\n"
+            "  -l gpt_location                          specyfies gpt secto\n"
+    );
+
+}
+
+void printGPT(struct GPT_entry_table *table);
+void addGPT(struct GPT_entry_table *table, const char *arg, const char *guid, const char *tguid);
+void deleteGPT(struct GPT_entry_table *table, const char *name);
+void configPrintGPT(struct GPT_entry_table *table);
+
+int main(int argc, char *argv[]) {
+    int print_cmd = 0;
+    int config_cmd = 0;
+    int add_cmd = 0;
+    int del_cmd = 0;
+    int sync_cmd = 0;
+    int c;
+    const char *new_partition = NULL;
+    const char *old_partition = NULL;
+    const char *type_guid = NULL;
+    const char *partition_guid = NULL;
+    unsigned gpt_location = 1;
+
+    klog_init();
+    klog_set_level(6);
+
+    const struct option longopts[] = {
+        {"print", no_argument, 0, 'p'},
+        {"config-print", no_argument, 0, 'c'},
+        {"add", no_argument, 0, 'a'},
+        {"del", no_argument, 0, 'd'},
+        {"new", required_argument, 0, 'n'},
+        {"old", required_argument, 0, 'o'},
+        {"type", required_argument, 0, 't'},
+        {"sync", required_argument, 0, 's'},
+        {"guid", required_argument, 0, 'g'},
+        {"location", required_argument, 0, 'l'},
+        {0, 0, 0, 0}
+    };
+
+    while (1) {
+        c = getopt_long(argc, argv, "pcadt:g:n:o:sl:", longopts, NULL);
+        /* Alphabetical cases */
+        if (c < 0)
+            break;
+        switch (c) {
+        case 'p':
+            print_cmd = 1;
+            break;
+        case 'c':
+            config_cmd = 1;
+            break;
+        case 'a':
+            add_cmd = 1;
+            break;
+        case 'd':
+            del_cmd = 1;
+            break;
+        case 'n':
+            new_partition = optarg;
+            break;
+        case 'o':
+            old_partition = optarg;
+            break;
+        case 't':
+            type_guid = optarg;
+        case 'g':
+            partition_guid = optarg;
+            break;
+        case 's':
+            sync_cmd = 1;
+            break;
+        case 'l':
+            gpt_location = strtoul(optarg, NULL, 10);
+            fprintf(stderr, "Got offset as %d", gpt_location);
+            break;
+        case '?':
+            return 1;
+        default:
+            abort();
+        }
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    if (argc < 1) {
+        usage();
+        return 1;
+    }
+
+    const char *path = argv[0];
+    struct GPT_entry_table *table = GPT_get_device(path, gpt_location);
+    if (table == NULL) {
+        fprintf(stderr, "unable to get GPT table from %s\n", path);
+        return 1;
+    }
+
+    if (add_cmd)
+        addGPT(table, new_partition, partition_guid, type_guid);
+    if (del_cmd)
+        deleteGPT(table, old_partition);
+    if (print_cmd)
+        printGPT(table);
+    if (config_cmd)
+        configPrintGPT(table);
+    if (sync_cmd)
+        GPT_sync(table);
+
+    GPT_release_device(table);
+
+    return 0;
+}
+
+void printGPT(struct GPT_entry_table *table) {
+    struct GPT_entry_raw *entry = table->entries;
+    unsigned n, m;
+    char name[GPT_NAMELEN + 1];
+
+    printf("ptn  start block   end block     name\n");
+    printf("---- ------------- -------------\n");
+
+    for (n = 0; n < table->header->entries_count; n++, entry++) {
+        if (entry->type_guid[0] == 0)
+            continue;
+        for (m = 0; m < GPT_NAMELEN; m++) {
+            name[m] = entry->name[m] & 127;
+        }
+        name[m] = 0;
+        printf("#%03d %13lld %13lld %s\n",
+            n + 1, entry->first_lba, entry->last_lba, name);
+    }
+}
+
+void configPrintGPT(struct GPT_entry_table *table) {
+    struct GPT_entry_raw *entry = table->entries;
+    unsigned n, m;
+    char name[GPT_NAMELEN + 1];
+    char temp_guid[17];
+    temp_guid[16] = 0;
+
+    printf("header_lba %lld\n", table->header->current_lba);
+    printf("backup_lba %lld\n", table->header->backup_lba);
+    printf("first_lba %lld\n", table->header->first_usable_lba);
+    printf("last_lba %lld\n", table->header->last_usable_lba);
+    printf("entries_lba %lld\n", table->header->entries_lba);
+    snprintf(temp_guid, 17, "%s", table->header->disk_guid);
+    printf("guid \"%s\"", temp_guid);
+
+    printf("\npartitions {\n");
+
+    for (n = 0; n < table->header->entries_count; n++, entry++) {
+        uint64_t size = entry->last_lba - entry->first_lba + 1;
+
+        if (entry->type_guid[0] == 0)
+            continue;
+        for (m = 0; m < GPT_NAMELEN; m++) {
+            name[m] = entry->name[m] & 127;
+        }
+        name[m] = 0;
+
+        printf("    %s {\n", name);
+        snprintf(temp_guid, 17, "%s", entry->partition_guid);
+        printf("        guid \"%s\"\n", temp_guid);
+        printf("        first_lba %lld\n", entry->first_lba);
+        printf("        partition_size %lld\n", size);
+        if (entry->flags & GPT_FLAG_SYSTEM)
+            printf("        system\n");
+        if (entry->flags & GPT_FLAG_BOOTABLE)
+            printf("        bootable\n");
+        if (entry->flags & GPT_FLAG_READONLY)
+            printf("        readonly\n");
+        if (entry->flags & GPT_FLAG_DOAUTOMOUNT)
+            printf("        automount\n");
+        printf("    }\n\n");
+    }
+    printf("}\n");
+}
+
+void addGPT(struct GPT_entry_table *table, const char *str  , const char *guid, const char *tguid) {
+    char *c, *c2;
+    char *arg = malloc(strlen(str));
+    char *name = arg;
+    unsigned start, end;
+    strcpy(arg, str);
+    if (guid == NULL || tguid == NULL) {
+        fprintf(stderr, "Type guid and partion guid needed");
+        free(arg);
+        return;
+    }
+
+    c = strchr(arg, '@');
+
+    if (c == NULL) {
+        fprintf(stderr, "Wrong entry format");
+        free(arg);
+        return;
+    }
+
+    *c++ = '\0';
+
+    c2 = strchr(c, ',');
+
+    if (c2 == NULL) {
+        fprintf(stderr, "Wrong entry format");
+        free(arg);
+        return;
+    }
+
+    start = strtoul(c, NULL, 10);
+    *c2++ = '\0';
+    end = strtoul(c2, NULL, 10);
+
+    struct GPT_entry_raw data;
+    strncpy((char *)data.partition_guid, guid, 15);
+    data.partition_guid[15] = '\0';
+    strncpy((char *)data.type_guid, tguid, 15);
+    data.type_guid[15] = '\0';
+    GPT_to_UTF16(data.name, name, GPT_NAMELEN);
+    data.first_lba = start;
+    data.last_lba = end;
+
+    fprintf(stderr, "Adding (%d,%d) %s as, [%s, %s]", start, end, name, (char *) data.type_guid, (char *) data.partition_guid);
+    GPT_add_entry(table, &data);
+    free(arg);
+}
+
+void deleteGPT(struct GPT_entry_table *table, const char *name) {
+    struct GPT_entry_raw *entry;
+
+    if (name == NULL) {
+        fprintf(stderr, "Need partition name");
+        return;
+    }
+
+    entry = GPT_get_pointer_by_name(table, name);
+
+    if (!entry) {
+        fprintf(stderr, "Unable to find partition: %s", name);
+        return;
+    }
+    GPT_delete_entry(table, entry);
+}
+
diff --git a/fastbootd/other/partitions.sample.cfg b/fastbootd/other/partitions.sample.cfg
new file mode 100644
index 0000000..49562cf
--- /dev/null
+++ b/fastbootd/other/partitions.sample.cfg
@@ -0,0 +1,60 @@
+
+header_lba 1
+backup_lba 101
+first_lba 43
+last_lba 100
+entries_lba 2
+
+partitions {
+    #You can generate this as output from gptedit -c
+    SOS {
+        first_lba 28672
+        partition_size 16384
+    }
+
+    DTB {
+        first_lba 45056
+        partition_size 8192
+    }
+
+    LNX {
+        first_lba 53248
+        partition_size 16384
+    }
+
+    APP {
+        first_lba 69632
+        partition_size 1048576
+    }
+
+    CAC {
+        first_lba 1118208
+        partition_size 1572864
+    }
+
+    MSC {
+        first_lba 2691072
+        partition_size 4096
+    }
+
+    USP {
+        first_lba 2695168
+        partition_size 65536
+    }
+
+    MDA {
+        first_lba 2760704
+        partition_size 4096
+    }
+
+    FCT {
+        first_lba 2764800
+        partition_size 32768
+    }
+
+    UDA {
+        first_lba 2797568
+        partition_size 27975680
+    }
+}
+
diff --git a/fastbootd/other/sign/src/SignImg.java b/fastbootd/other/sign/src/SignImg.java
new file mode 100644
index 0000000..338d427
--- /dev/null
+++ b/fastbootd/other/sign/src/SignImg.java
@@ -0,0 +1,181 @@
+package signtool;
+
+import java.io.*;
+import java.util.Properties;
+import java.util.ArrayList;
+
+import javax.mail.internet.*;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.activation.MailcapCommandMap;
+import javax.activation.CommandMap;
+
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.cert.X509Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateEncodingException;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.cms.CMSProcessableByteArray;
+import org.bouncycastle.cms.CMSSignedGenerator;
+import org.bouncycastle.cms.CMSSignedDataGenerator;
+import org.bouncycastle.cms.CMSSignedGenerator;
+import org.bouncycastle.cms.CMSProcessable;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.CMSTypedData;
+import org.bouncycastle.cert.jcajce.JcaCertStore;
+import org.bouncycastle.util.Store;
+import org.bouncycastle.asn1.ASN1InputStream;    
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.ASN1Object;
+
+
+public class SignImg {
+
+    /* It reads private key in pkcs#8 formate
+     * Conversion:
+     * openssl pkcs8 -topk8 -nocrypt -outform DER < inkey.pem > outkey.pk8
+     */
+    private static PrivateKey getPrivateKey(String path) throws IOException, FileNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException {
+        File file = new File(path);
+        FileInputStream fis = new FileInputStream(file);
+        byte[] data = new byte[(int)file.length()];
+        fis.read(data);
+        fis.close();
+
+        PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(data);
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        PrivateKey privateKey = kf.generatePrivate(kspec);
+
+        return privateKey;
+    }
+
+    private static MimeBodyPart getContent(String path) throws IOException, FileNotFoundException, MessagingException {
+        MimeBodyPart body = new MimeBodyPart();
+
+        File file = new File(path);
+        FileInputStream fis = new FileInputStream(file);
+        byte[] data = new byte[(int)file.length()];
+        fis.read(data);
+        fis.close();
+
+        body.setContent(data, "application/octet-stream");
+
+        return body;
+    }
+
+    private static CMSProcessableByteArray getCMSContent(String path) throws IOException, FileNotFoundException, MessagingException {
+        File file = new File(path);
+        FileInputStream fis = new FileInputStream(file);
+        byte[] data = new byte[(int)file.length()];
+        fis.read(data);
+        fis.close();
+        CMSProcessableByteArray cms = new CMSProcessableByteArray(data);
+
+        return cms;
+    }
+
+    private static X509Certificate readCert(String path) throws IOException, FileNotFoundException, CertificateException {
+        File file = new File(path);
+        FileInputStream is = new FileInputStream(file);
+
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        Certificate cert = cf.generateCertificate(is);
+        is.close();
+
+        return (X509Certificate) cert;
+    }
+
+    private static void save(MimeBodyPart content, String path) throws IOException, FileNotFoundException, MessagingException {
+        File file = new File(path);
+        FileOutputStream os = new FileOutputStream(file);
+
+        content.writeTo(os);
+
+        os.close();
+    }
+
+    private static Store certToStore(X509Certificate certificate) throws CertificateEncodingException {
+        ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
+        certList.add(certificate);
+        return new JcaCertStore(certList);
+    }
+
+    public static void setDefaultMailcap()
+    {
+        MailcapCommandMap _mailcap =
+            (MailcapCommandMap)CommandMap.getDefaultCommandMap();
+
+        _mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
+        _mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
+        _mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
+        _mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
+        _mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");
+
+        CommandMap.setDefaultCommandMap(_mailcap);
+    } 
+
+    public static void main(String[] args) {
+        try {
+            if (args.length < 4) {
+                System.out.println("Usage: signimg data private_key certificate output");
+                return;
+            }
+            System.out.println("Signing the image");
+            setDefaultMailcap();
+
+            Security.addProvider(new BouncyCastleProvider());
+
+            PrivateKey key = getPrivateKey(args[1]);
+            System.out.println("File read sucessfully");
+
+            CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
+
+            CMSTypedData body = getCMSContent(args[0]);
+            System.out.println("Content read sucessfully");
+
+            X509Certificate cert = (X509Certificate) readCert(args[2]);
+            System.out.println("Certificate read sucessfully");
+
+            ContentSigner sha256Signer = new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(key);
+
+            Store certs = certToStore(cert);
+
+            generator.addCertificates(certs);
+            generator.addSignerInfoGenerator(
+                          new JcaSignerInfoGeneratorBuilder(
+                                new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
+                          .build(sha256Signer, cert));
+
+            CMSSignedData signed = generator.generate(body, true);
+            System.out.println("Signed");
+
+            Properties props = System.getProperties();
+            Session session = Session.getDefaultInstance(props, null);
+            
+            File file = new File(args[3]);
+            FileOutputStream os = new FileOutputStream(file);
+
+            ASN1InputStream asn1 = new ASN1InputStream(signed.getEncoded());
+            ByteArrayOutputStream out = new ByteArrayOutputStream(); 
+            DEROutputStream dOut = new DEROutputStream(os); 
+            dOut.writeObject(ASN1Object.fromByteArray(signed.getEncoded()));
+
+        }
+        catch (Exception ex) {
+            System.out.println("Exception during programm execution: " + ex.getMessage());
+        }
+    }
+}
diff --git a/fastbootd/other/vendor_trigger.c b/fastbootd/other/vendor_trigger.c
new file mode 100644
index 0000000..101959b
--- /dev/null
+++ b/fastbootd/other/vendor_trigger.c
@@ -0,0 +1,96 @@
+/*
+ * 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 "vendor_trigger.h"
+#include "debug.h"
+
+unsigned int debug_level = DEBUG;
+
+static const int version = 1;
+
+int check_version(const int fastboot_version, int *libversion) {
+    *libversion = version;
+    return !(fastboot_version == version);
+}
+
+int gpt_layout(struct GPT_content *table) {
+    D(DEBUG, "message from libvendor");
+    return 0;
+}
+
+int oem_cmd(const char *arg, const char **response) {
+    D(DEBUG, "message from libvendor, oem catched request %s", arg);
+    return 0;
+}
+
+static int close_triggers(struct vendor_trigger_t *dev)
+{
+    if (dev)
+        free(dev);
+
+    return 0;
+}
+
+static int open_triggers(const struct hw_module_t *module, char const *name,
+                         struct hw_device_t **device) {
+    struct vendor_trigger_t *dev = malloc(sizeof(struct vendor_trigger_t));
+    klog_init();
+    klog_set_level(6);
+
+    memset(dev, 0, sizeof(*dev));
+    dev->common.module = (struct hw_module_t *) module;
+    dev->common.close  = (int (*)(struct hw_device_t *)) close_triggers;
+
+    dev->gpt_layout = gpt_layout;
+    dev->oem_cmd = oem_cmd;
+
+    *device = (struct hw_device_t *) dev;
+
+    return 0;
+}
+
+
+static struct hw_module_methods_t trigger_module_methods = {
+    .open = open_triggers,
+};
+
+struct hw_module_t HAL_MODULE_INFO_SYM = {
+    .tag = HARDWARE_MODULE_TAG,
+    .version_major = 1,
+    .version_minor = 0,
+    .id = TRIGGER_MODULE_ID,
+    .name = "vendor trigger library for fastbootd",
+    .author = "Google, Inc.",
+    .methods = &trigger_module_methods,
+};
+
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/secure.c b/fastbootd/secure.c
new file mode 100644
index 0000000..a657ad4
--- /dev/null
+++ b/fastbootd/secure.c
@@ -0,0 +1,169 @@
+/*
+ * 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 <openssl/pem.h>
+#include <openssl/engine.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pem.h>
+#include <openssl/cms.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "secure.h"
+#include "debug.h"
+#include "utils.h"
+
+
+void cert_init_crypto() {
+    CRYPTO_malloc_init();
+    ERR_load_crypto_strings();
+    OpenSSL_add_all_algorithms();
+    ENGINE_load_builtin_engines();
+}
+
+X509_STORE *cert_store_from_path(const char *path) {
+
+    X509_STORE *store;
+    struct stat st;
+    X509_LOOKUP *lookup;
+
+    if (stat(path, &st)) {
+        D(ERR, "Unable to stat cert path");
+        goto error;
+    }
+
+    if (!(store = X509_STORE_new())) {
+        goto error;
+    }
+
+    if (S_ISDIR(st.st_mode)) {
+        lookup = X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
+        if (lookup == NULL)
+            goto error;
+        if (!X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM)) {
+            D(ERR, "Error loading cert directory %s", path);
+            goto error;
+        }
+    }
+    else if(S_ISREG(st.st_mode)) {
+        lookup = X509_STORE_add_lookup(store,X509_LOOKUP_file());
+        if (lookup == NULL)
+            goto error;
+        if (!X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM)) {
+            D(ERR, "Error loading cert directory %s", path);
+            goto error;
+        }
+    }
+    else {
+        D(ERR, "cert path is not directory or regular file");
+        goto error;
+    }
+
+    return store;
+
+error:
+    return NULL;
+}
+
+
+int cert_read(int fd, CMS_ContentInfo **content, BIO **output) {
+    BIO *input;
+    *output = NULL;
+
+
+    input = BIO_new_fd(fd, BIO_NOCLOSE);
+    if (input == NULL) {
+        D(ERR, "Unable to open input");
+        goto error;
+    }
+
+    //TODO:
+    // read with d2i_CMS_bio to support DER
+    // with java or just encode data with base64
+    *content = SMIME_read_CMS(input, output);
+    if (*content == NULL) {
+        unsigned long err = ERR_peek_last_error();
+        D(ERR, "Unable to parse input file: %s", ERR_lib_error_string(err));
+        goto error_read;
+    }
+
+    BIO_free(input);
+
+    return 0;
+
+error_read:
+    BIO_free(input);
+error:
+    return 1;
+}
+
+int cert_verify(BIO *content, CMS_ContentInfo *content_info, X509_STORE *store, int *out_fd) {
+    BIO *output_temp;
+    int ret;
+
+    *out_fd = create_temp_file();
+    if (*out_fd < 0) {
+        D(ERR, "unable to create temporary file");
+        return -1;
+    }
+
+    output_temp = BIO_new_fd(*out_fd, BIO_NOCLOSE);
+    if (output_temp == NULL) {
+        D(ERR, "unable to create temporary bio");
+        close(*out_fd);
+        return -1;
+    }
+
+    ret = CMS_verify(content_info, NULL ,store, content, output_temp, 0);
+
+    if (ret == 0) {
+        char buf[256];
+        unsigned long err = ERR_peek_last_error();
+        D(ERR, "Verification failed with reason: %s, %s", ERR_lib_error_string(err),  ERR_error_string(err, buf));
+        D(ERR, "Data used: content %d", (int) content);
+    }
+
+    ERR_clear_error();
+    ERR_remove_state(0);
+
+    BIO_free(output_temp);
+
+    return ret;
+}
+
+void cert_release(BIO *content, CMS_ContentInfo *info) {
+    BIO_free(content);
+    CMS_ContentInfo_free(info);
+}
+
diff --git a/fastbootd/secure.h b/fastbootd/secure.h
new file mode 100644
index 0000000..878a643
--- /dev/null
+++ b/fastbootd/secure.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef _FASTBOOTD_SECURE_H
+#define _FASTBOOTD_SECURE_H
+
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pem.h>
+#include <openssl/cms.h>
+
+void cert_init_crypto();
+
+X509_STORE *cert_store_from_path(const char*stream);
+
+static inline void cert_release_store(X509_STORE *store) {
+    X509_STORE_free(store);
+}
+
+int cert_read(int fd, CMS_ContentInfo **content, BIO **output);
+int cert_verify(BIO *content, CMS_ContentInfo *content_info, X509_STORE *store, int *out_fd);
+void cert_release(BIO *content, CMS_ContentInfo *info);
+
+#endif
diff --git a/fastbootd/socket_client.c b/fastbootd/socket_client.c
new file mode 100644
index 0000000..da636db
--- /dev/null
+++ b/fastbootd/socket_client.c
@@ -0,0 +1,94 @@
+/*
+ * 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 <stdio.h>
+#include <cutils/sockets.h>
+#include <poll.h>
+#include <unistd.h>
+
+#include "utils.h"
+
+#define BUFFER_SIZE 256
+
+#define STDIN_FD 0
+#define STDOUT_FD 1
+#define STDERR_FD 2
+
+void run_socket_client() {
+    int fd;
+    char buffer[BUFFER_SIZE];
+    int n;
+    struct pollfd fds[2];
+
+    fd = socket_local_client("fastbootd",
+                         ANDROID_SOCKET_NAMESPACE_RESERVED,
+                         SOCK_STREAM);
+
+    if (fd < 0) {
+        fprintf(stderr, "ERROR: Unable to open fastbootd socket\n");
+        return;
+    }
+
+    fds[0].fd = STDIN_FD;
+    fds[0].events = POLLIN;
+    fds[1].fd = fd;
+    fds[1].events = POLLIN;
+
+    while(true) {
+        if (poll(fds, 2, -1) <= 0) {
+            fprintf(stderr, "ERROR: socket error");
+            return;
+        }
+
+        if (fds[0].revents & POLLIN) {
+            if ((n = read(STDIN_FD, buffer, BUFFER_SIZE)) < 0) {
+                goto error;
+            }
+
+            if (bulk_write(fd, buffer, n) < 0) {
+                goto error;
+            }
+        }
+
+        if (fds[1].revents & POLLIN) {
+            if ((n = read(fd, buffer, BUFFER_SIZE)) < 0) {
+                goto error;
+            }
+
+            if (bulk_write(STDOUT_FD, buffer, n) < 0) {
+                goto error;
+            }
+        }
+    }
+
+error:
+    fprintf(stderr, "Transport error\n");
+}
diff --git a/fastbootd/socket_client.h b/fastbootd/socket_client.h
new file mode 100644
index 0000000..4481ff2
--- /dev/null
+++ b/fastbootd/socket_client.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef _FASTBOOTD_SOCKET_CLIENT_H
+#define _FASTBOOTD_SOCKET_CLIENT_H
+
+void run_socket_client();
+
+#endif
diff --git a/fastbootd/transport.c b/fastbootd/transport.c
new file mode 100644
index 0000000..19a705c
--- /dev/null
+++ b/fastbootd/transport.c
@@ -0,0 +1,150 @@
+/*
+ * 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;
+            //TODO: multiple threads
+            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/transport_socket.c b/fastbootd/transport_socket.c
new file mode 100644
index 0000000..ff0f3bd
--- /dev/null
+++ b/fastbootd/transport_socket.c
@@ -0,0 +1,154 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <cutils/sockets.h>
+
+#include "debug.h"
+#include "transport.h"
+#include "utils.h"
+
+
+#define container_of(ptr, type, member) \
+    ((type*)((char*)(ptr) - offsetof(type, member)))
+
+#define SOCKET_WORKING 0
+#define SOCKET_STOPPED -1
+
+
+struct socket_transport {
+    struct transport transport;
+
+    int fd;
+};
+
+struct socket_handle {
+    struct transport_handle handle;
+
+    int fd;
+};
+
+void socket_close(struct transport_handle *thandle)
+{
+    struct socket_handle * handle = container_of(thandle, struct socket_handle, handle);
+    close(handle->fd);
+}
+
+struct transport_handle *socket_connect(struct transport *transport)
+{
+    struct socket_handle *handle = calloc(sizeof(struct socket_handle), 1);
+    struct socket_transport *socket_transport = container_of(transport, struct socket_transport, transport);
+    struct sockaddr addr;
+    socklen_t alen = sizeof(addr);
+
+    handle->fd = accept(socket_transport->fd, &addr, &alen);
+
+    if (handle->fd < 0) {
+        D(WARN, "socket connect error");
+        return NULL;
+    }
+
+    D(DEBUG, "[ socket_thread - registering device ]");
+    return &handle->handle;
+}
+
+ssize_t socket_write(struct transport_handle *thandle, const void *data, size_t len)
+{
+    ssize_t ret;
+    struct socket_handle *handle = container_of(thandle, struct socket_handle, handle);
+
+    D(DEBUG, "about to write (fd=%d, len=%d)", handle->fd, len);
+    ret = bulk_write(handle->fd, data, len);
+    if (ret < 0) {
+        D(ERR, "ERROR: fd = %d, ret = %zd", handle->fd, ret);
+        return -1;
+    }
+    D(DEBUG, "[ socket_write done fd=%d ]", handle->fd);
+    return ret;
+}
+
+ssize_t socket_read(struct transport_handle *thandle, void *data, size_t len)
+{
+    ssize_t ret;
+    struct socket_handle *handle = container_of(thandle, struct socket_handle, handle);
+
+    D(DEBUG, "about to read (fd=%d, len=%d)", handle->fd, len);
+    ret = bulk_read(handle->fd, data, len);
+    if (ret < 0) {
+        D(ERR, "ERROR: fd = %d, ret = %zd", handle->fd, ret);
+        return -1;
+    }
+    D(DEBUG, "[ socket_read done fd=%d ret=%zd]", handle->fd, ret);
+    return ret;
+}
+
+static int listen_socket_init(struct socket_transport *socket_transport)
+{
+    int s = android_get_control_socket("fastbootd");
+
+    if (s < 0) {
+        D(WARN, "android_get_control_socket(fastbootd): %s\n", strerror(errno));
+        return 0;
+    }
+
+    if (listen(s, 4) < 0) {
+        D(WARN, "listen(control socket): %s\n", strerror(errno));
+        return 0;
+    }
+
+    socket_transport->fd = s;
+
+    return 1;
+}
+
+
+int transport_socket_init()
+{
+    struct socket_transport *socket_transport = malloc(sizeof(struct socket_transport));
+
+    socket_transport->transport.connect = socket_connect;
+    socket_transport->transport.close = socket_close;
+    socket_transport->transport.read = socket_read;
+    socket_transport->transport.write = socket_write;
+
+    if (!listen_socket_init(socket_transport)) {
+        D(ERR, "socket transport init failed");
+        free(socket_transport);
+        return 0;
+    }
+
+    transport_register(&socket_transport->transport);
+    return 1;
+}
+
diff --git a/fastbootd/trigger.c b/fastbootd/trigger.c
new file mode 100644
index 0000000..e63e64d
--- /dev/null
+++ b/fastbootd/trigger.c
@@ -0,0 +1,90 @@
+/*
+ * 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 <dlfcn.h>
+
+#include <hardware/hardware.h>
+#include "debug.h"
+#include "trigger.h"
+#include "protocol.h"
+#include "vendor_trigger.h"
+
+static const int version = 1;
+
+static struct vendor_trigger_t *triggers = NULL;
+
+int load_trigger() {
+    int err;
+    hw_module_t* module;
+    hw_device_t* device;
+    int libversion;
+
+    err = hw_get_module(TRIGGER_MODULE_ID, (hw_module_t const**)&module);
+
+    if (err == 0) {
+        err = module->methods->open(module, NULL, &device);
+
+        if (err == 0) {
+            triggers = (struct vendor_trigger_t *) device;
+        } else {
+            D(WARN, "Libvendor load error");
+            return 1;
+        }
+    }
+    else {
+        D(WARN, "Libvendor not load: %s", strerror(-err));
+        return 0;
+    }
+
+    if (triggers->check_version != NULL &&
+        triggers->check_version(version, &libversion)) {
+
+        triggers = NULL;
+        D(ERR, "Library report incompability");
+        return 1;
+    }
+    D(INFO, "libvendortrigger loaded");
+
+    return 0;
+}
+
+int trigger_oem_cmd(const char *arg, const char **response) {
+    if (triggers != NULL && triggers->oem_cmd != NULL)
+        return triggers->oem_cmd(arg, response);
+    return 0;
+}
+
+int trigger_gpt_layout(struct GPT_content *table) {
+    if (triggers != NULL && triggers->gpt_layout != NULL)
+        return triggers->gpt_layout(table);
+    return 0;
+}
+
diff --git a/fastbootd/trigger.h b/fastbootd/trigger.h
new file mode 100644
index 0000000..404acb4
--- /dev/null
+++ b/fastbootd/trigger.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef __FASTBOOTD_TRIGGER_H_
+#define __FASTBOOTD_TRIGGER_H_
+
+#include "commands/partitions.h"
+#include "vendor_trigger.h"
+
+int load_trigger();
+
+/* same as in struct triggers */
+
+int trigger_gpt_layout(struct GPT_content *table);
+int trigger_oem_cmd(const char *arg, const char **response);
+
+#endif
diff --git a/fastbootd/usb_linux_client.c b/fastbootd/usb_linux_client.c
new file mode 100644
index 0000000..7a8e46f
--- /dev/null
+++ b/fastbootd/usb_linux_client.c
@@ -0,0 +1,308 @@
+/*
+ * 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"
+#include "utils.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 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 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;
+}
+
+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/fastbootd/utils.c b/fastbootd/utils.c
new file mode 100644
index 0000000..fe3f0f8
--- /dev/null
+++ b/fastbootd/utils.c
@@ -0,0 +1,260 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <stdlib.h>
+#include <cutils/properties.h>
+
+#include "utils.h"
+#include "debug.h"
+
+#ifndef BLKDISCARD
+#define BLKDISCARD _IO(0x12,119)
+#endif
+
+#ifndef BLKSECDISCARD
+#define BLKSECDISCARD _IO(0x12,125)
+#endif
+
+#define READ_BUF_SIZE (16*1024)
+
+int get_stream_size(FILE *stream) {
+    int size;
+    fseek(stream, 0, SEEK_END);
+    size = ftell(stream);
+    fseek(stream, 0, SEEK_SET);
+    return size;
+}
+
+uint64_t get_block_device_size(int fd)
+{
+    uint64_t size = 0;
+    int ret;
+
+    ret = ioctl(fd, BLKGETSIZE64, &size);
+
+    if (ret)
+        return 0;
+
+    return size;
+}
+
+uint64_t get_file_size(int fd)
+{
+    struct stat buf;
+    int ret;
+    int64_t computed_size;
+
+    ret = fstat(fd, &buf);
+    if (ret)
+        return 0;
+
+    if (S_ISREG(buf.st_mode))
+        computed_size = buf.st_size;
+    else if (S_ISBLK(buf.st_mode))
+        computed_size = get_block_device_size(fd);
+    else
+        computed_size = 0;
+
+    return computed_size;
+}
+
+uint64_t get_file_size64(int fd)
+{
+    struct stat64 buf;
+    int ret;
+    uint64_t computed_size;
+
+    ret = fstat64(fd, &buf);
+    if (ret)
+        return 0;
+
+    if (S_ISREG(buf.st_mode))
+        computed_size = buf.st_size;
+    else if (S_ISBLK(buf.st_mode))
+        computed_size = get_block_device_size(fd);
+    else
+        computed_size = 0;
+
+    return computed_size;
+}
+
+
+char *strip(char *str)
+{
+    int n;
+
+    n = strspn(str, " \t");
+    str += n;
+    n = strcspn(str, " \t");
+    str[n] = '\0';
+
+    return str;
+}
+
+int wipe_block_device(int fd, int64_t len)
+{
+    uint64_t range[2];
+    int ret;
+
+    range[0] = 0;
+    range[1] = len;
+    ret = ioctl(fd, BLKSECDISCARD, &range);
+    if (ret < 0) {
+        range[0] = 0;
+        range[1] = len;
+        ret = ioctl(fd, BLKDISCARD, &range);
+        if (ret < 0) {
+            D(WARN, "Discard failed\n");
+            return 1;
+        } else {
+            D(WARN, "Wipe via secure discard failed, used discard instead\n");
+            return 0;
+        }
+    }
+
+    return 0;
+}
+
+int create_temp_file() {
+    char tempname[] = "/dev/fastboot_data_XXXXXX";
+    int fd;
+
+    fd = mkstemp(tempname);
+    if (fd < 0)
+        return -1;
+
+    unlink(tempname);
+
+    return fd;
+}
+
+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_write 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;
+}
+
+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;
+}
+
+#define NAP_TIME 200  // 200 ms between polls
+static int wait_for_property(const char *name, const char *desired_value, int maxwait)
+{
+    char value[PROPERTY_VALUE_MAX] = {'\0'};
+    int maxnaps = (maxwait * 1000) / NAP_TIME;
+
+    if (maxnaps < 1) {
+        maxnaps = 1;
+    }
+
+    while (maxnaps-- > 0) {
+        usleep(NAP_TIME * 1000);
+        if (property_get(name, value, NULL)) {
+            if (desired_value == NULL || strcmp(value, desired_value) == 0) {
+                return 0;
+            }
+        }
+    }
+    return -1; /* failure */
+}
+
+int service_start(const char *service_name)
+{
+    int result = 0;
+    char property_value[PROPERTY_VALUE_MAX];
+
+    property_get(service_name, property_value, "");
+    if (strcmp("running", property_value) != 0) {
+        D(INFO, "Starting %s", service_name);
+        property_set("ctl.start", service_name);
+        if (wait_for_property(service_name, "running", 5))
+            result = -1;
+    }
+
+    return result;
+}
+
+int service_stop(const char *service_name)
+{
+    int result = 0;
+
+    D(INFO, "Stopping MDNSD");
+    property_set("ctl.stop", service_name);
+    if (wait_for_property(service_name, "stopped", 5))
+        result = -1;
+
+    return result;
+}
+
+int ssh_server_start()
+{
+    return service_start("sshd");
+}
diff --git a/fastbootd/utils.h b/fastbootd/utils.h
new file mode 100644
index 0000000..3d98699
--- /dev/null
+++ b/fastbootd/utils.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef _FASTBOOT_UTLIS_H
+#define _FASTBOOT_UTILS_H
+
+#include <stdio.h>
+
+int get_stream_size(FILE *);
+
+char *strip(char *str);
+
+uint64_t get_file_size64(int fd);
+uint64_t get_file_size(int fd);
+uint64_t get_block_device_size(int fd);
+int wipe_block_device(int fd, int64_t len);
+int create_temp_file();
+ssize_t bulk_read(int bulk_out, char *buf, size_t length);
+ssize_t bulk_write(int bulk_in, const char *buf, size_t length);
+int service_start(const char *service_name);
+int service_stop(const char *service_name);
+int ssh_server_start();
+
+#define ROUND_TO_PAGE(address,pagesize) ((address + pagesize - 1) & (~(pagesize - 1)))
+
+#define ROUND_UP(number,size) (((number + size - 1) / size) * size)
+
+#endif
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/private/pixelflinger/ggl_context.h b/include/private/pixelflinger/ggl_context.h
index 4864d5a..d43655c 100644
--- a/include/private/pixelflinger/ggl_context.h
+++ b/include/private/pixelflinger/ggl_context.h
@@ -121,7 +121,7 @@
 template<> struct CTA<true> { };
 
 #define GGL_CONTEXT(con, c)         context_t *con = static_cast<context_t *>(c)
-#define GGL_OFFSETOF(field)         int(&(((context_t*)0)->field))
+#define GGL_OFFSETOF(field)         uintptr_t(&(((context_t*)0)->field))
 #define GGL_INIT_PROC(p, f)         p.f = ggl_ ## f;
 #define GGL_BETWEEN(x, L, H)        (uint32_t((x)-(L)) <= ((H)-(L)))
 
@@ -340,16 +340,18 @@
 
 struct surface_t {
     union {
-        GGLSurface      s;
+        GGLSurface          s;
+        // Keep the following struct field types in line with the corresponding
+        // GGLSurface fields to avoid mismatches leading to errors.
         struct {
-        uint32_t            reserved;
-        uint32_t			width;
-        uint32_t			height;
-        int32_t             stride;
-        uint8_t*			data;	
-        uint8_t				format;
-        uint8_t				dirty;
-        uint8_t				pad[2];
+            GGLsizei        reserved;
+            GGLuint         width;
+            GGLuint         height;
+            GGLint          stride;
+            GGLubyte*       data;
+            GGLubyte        format;
+            GGLubyte        dirty;
+            GGLubyte        pad[2];
         };
     };
     void                (*read) (const surface_t* s, context_t* c,
@@ -480,7 +482,7 @@
     uint32_t    width;
     uint32_t    height;
     uint32_t    stride;
-    int32_t     data;
+    uintptr_t   data;
     int32_t     dsdx;
     int32_t     dtdx;
     int32_t     spill[2];
diff --git a/include/private/pixelflinger/ggl_fixed.h b/include/private/pixelflinger/ggl_fixed.h
index 217ec04..d0493f3 100644
--- a/include/private/pixelflinger/ggl_fixed.h
+++ b/include/private/pixelflinger/ggl_fixed.h
@@ -457,6 +457,69 @@
     return u.res;
 }
 
+#elif defined(__aarch64__)
+
+// inline AArch64 implementations
+
+inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift) CONST;
+inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift)
+{
+    GGLfixed result;
+    GGLfixed round;
+
+    asm("mov    %x[round], #1                        \n"
+        "lsl    %x[round], %x[round], %x[shift]      \n"
+        "lsr    %x[round], %x[round], #1             \n"
+        "smaddl %x[result], %w[x], %w[y],%x[round]   \n"
+        "lsr    %x[result], %x[result], %x[shift]    \n"
+        : [round]"=&r"(round), [result]"=&r"(result) \
+        : [x]"r"(x), [y]"r"(y), [shift] "r"(shift)   \
+        :
+       );
+    return result;
+}
+inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST;
+inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a, int shift)
+{
+    GGLfixed result;
+    asm("smull  %x[result], %w[x], %w[y]                     \n"
+        "lsr    %x[result], %x[result], %x[shift]            \n"
+        "add    %w[result], %w[result], %w[a]                \n"
+        : [result]"=&r"(result)                               \
+        : [x]"r"(x), [y]"r"(y), [a]"r"(a), [shift] "r"(shift) \
+        :
+        );
+    return result;
+}
+
+inline GGLfixed gglMulSubx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST;
+inline GGLfixed gglMulSubx(GGLfixed x, GGLfixed y, GGLfixed a, int shift)
+{
+
+    GGLfixed result;
+    int rshift;
+
+    asm("smull  %x[result], %w[x], %w[y]                     \n"
+        "lsr    %x[result], %x[result], %x[shift]            \n"
+        "sub    %w[result], %w[result], %w[a]                \n"
+        : [result]"=&r"(result)                               \
+        : [x]"r"(x), [y]"r"(y), [a]"r"(a), [shift] "r"(shift) \
+        :
+        );
+    return result;
+}
+inline int64_t gglMulii(int32_t x, int32_t y) CONST;
+inline int64_t gglMulii(int32_t x, int32_t y)
+{
+    int64_t res;
+    asm("smull  %x0, %w1, %w2 \n"
+        : "=r"(res)
+        : "%r"(x), "r"(y)
+        :
+        );
+    return res;
+}
+
 #else // ----------------------------------------------------------------------
 
 inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST;
@@ -498,7 +561,7 @@
 inline int32_t gglClz(int32_t x) CONST;
 inline int32_t gglClz(int32_t x)
 {
-#if (defined(__arm__) && !defined(__thumb__)) || defined(__mips__)
+#if (defined(__arm__) && !defined(__thumb__)) || defined(__mips__) || defined(__aarch64__)
     return __builtin_clz(x);
 #else
     if (!x) return 32;
@@ -554,6 +617,8 @@
     // clamps to zero in one instruction, but gcc won't generate it and
     // replace it by a cmp + movlt (it's quite amazing actually).
     asm("bic %0, %1, %1, asr #31\n" : "=r"(c) : "r"(c));
+#elif defined(__aarch64__)
+    asm("bic %w0, %w1, %w1, asr #31\n" : "=r"(c) : "r"(c));
 #else
     c &= ~(c>>31);
 #endif
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/sysutils/NetlinkEvent.h b/include/sysutils/NetlinkEvent.h
index 25a56f7..c0a9418 100644
--- a/include/sysutils/NetlinkEvent.h
+++ b/include/sysutils/NetlinkEvent.h
@@ -34,6 +34,9 @@
     const static int NlActionChange;
     const static int NlActionLinkDown;
     const static int NlActionLinkUp;
+    const static int NlActionAddressUpdated;
+    const static int NlActionAddressRemoved;
+    const static int NlActionRdnss;
 
     NetlinkEvent();
     virtual ~NetlinkEvent();
@@ -49,6 +52,8 @@
  protected:
     bool parseBinaryNetlinkMessage(char *buffer, int size);
     bool parseAsciiNetlinkMessage(char *buffer, int size);
+    bool parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr, int rtasize);
+    bool parseNdUserOptMessage(struct nduseroptmsg *msg, int optsize);
 };
 
 #endif
diff --git a/include/sysutils/NetlinkListener.h b/include/sysutils/NetlinkListener.h
index beb8bda..6e52c3b 100644
--- a/include/sysutils/NetlinkListener.h
+++ b/include/sysutils/NetlinkListener.h
@@ -21,7 +21,7 @@
 class NetlinkEvent;
 
 class NetlinkListener : public SocketListener {
-    char mBuffer[64 * 1024];
+    char mBuffer[64 * 1024] __attribute__((aligned(4)));
     int mFormat;
 
 public:
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..15c9891
--- /dev/null
+++ b/include/utils/Looper.h
@@ -0,0 +1,477 @@
+/*
+ * 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 <sys/epoll.h>
+
+namespace android {
+
+/*
+ * NOTE: Since Looper is used to implement the NDK ALooper, the Looper
+ * enums and the signature of Looper_callbackFunc need to align with
+ * that implementation.
+ */
+
+/**
+ * For callback-based event loops, this is the prototype of the function
+ * that is called when a file descriptor event occurs.
+ * It is given the file descriptor it is associated with,
+ * a bitmask of the poll events that were triggered (typically 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.
+ */
+typedef int (*Looper_callbackFunc)(int fd, int events, void* data);
+
+/**
+ * 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 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 Looper_callbackFunc function pointer.
+ */
+class SimpleLooperCallback : public LooperCallback {
+protected:
+    virtual ~SimpleLooperCallback();
+
+public:
+    SimpleLooperCallback(Looper_callbackFunc callback);
+    virtual int handleEvent(int fd, int events, void* data);
+
+private:
+    Looper_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 RefBase {
+protected:
+    virtual ~Looper();
+
+public:
+    enum {
+        /**
+         * Result from Looper_pollOnce() and Looper_pollAll():
+         * The poll was awoken using wake() before the timeout expired
+         * and no callbacks were executed and no other file descriptors were ready.
+         */
+        POLL_WAKE = -1,
+
+        /**
+         * Result from Looper_pollOnce() and Looper_pollAll():
+         * One or more callbacks were executed.
+         */
+        POLL_CALLBACK = -2,
+
+        /**
+         * Result from Looper_pollOnce() and Looper_pollAll():
+         * The timeout expired.
+         */
+        POLL_TIMEOUT = -3,
+
+        /**
+         * Result from Looper_pollOnce() and Looper_pollAll():
+         * An error occurred.
+         */
+        POLL_ERROR = -4,
+    };
+
+    /**
+     * Flags for file descriptor events that a looper can monitor.
+     *
+     * These flag bits can be combined to monitor multiple events at once.
+     */
+    enum {
+        /**
+         * The file descriptor is available for read operations.
+         */
+        EVENT_INPUT = 1 << 0,
+
+        /**
+         * The file descriptor is available for write operations.
+         */
+        EVENT_OUTPUT = 1 << 1,
+
+        /**
+         * The file descriptor has encountered an error condition.
+         *
+         * The looper always sends notifications about errors; it is not necessary
+         * to specify this event flag in the requested event set.
+         */
+        EVENT_ERROR = 1 << 2,
+
+        /**
+         * The file descriptor was hung up.
+         * For example, indicates that the remote end of a pipe or socket was closed.
+         *
+         * The looper always sends notifications about hangups; it is not necessary
+         * to specify this event flag in the requested event set.
+         */
+        EVENT_HANGUP = 1 << 3,
+
+        /**
+         * The file descriptor is invalid.
+         * For example, the file descriptor was closed prematurely.
+         *
+         * The looper always sends notifications about invalid file descriptors; it is not necessary
+         * to specify this event flag in the requested event set.
+         */
+        EVENT_INVALID = 1 << 4,
+    };
+
+    enum {
+        /**
+         * Option for Looper_prepare: this looper will accept calls to
+         * Looper_addFd() that do not have a callback (that is provide NULL
+         * for the callback).  In this case the caller of Looper_pollOnce()
+         * or Looper_pollAll() MUST check the return from these functions to
+         * discover when data is available on such fds and process it.
+         */
+        PREPARE_ALLOW_NON_CALLBACKS = 1<<0
+    };
+
+    /**
+     * 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 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 POLL_CALLBACK if one or more callbacks were invoked.
+     *
+     * Returns POLL_TIMEOUT if there was no data before the given
+     * timeout expired.
+     *
+     * Returns 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 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 POLL_CALLBACK if providing a non-NULL callback.
+     * "events" are the poll events to wake up on.  Typically this is 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 Looper_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, Looper_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 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/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h
new file mode 100644
index 0000000..1877494
--- /dev/null
+++ b/include/ziparchive/zip_archive.h
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+/*
+ * Read-only access to Zip archives, with minimal heap allocation.
+ */
+#ifndef LIBZIPARCHIVE_ZIPARCHIVE_H_
+#define LIBZIPARCHIVE_ZIPARCHIVE_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Compat.h>
+
+__BEGIN_DECLS
+
+/* Zip compression methods we support */
+enum {
+  kCompressStored     = 0,        // no compression
+  kCompressDeflated   = 8,        // standard deflate
+};
+
+struct ZipEntryName {
+  const char* name;
+  uint16_t name_length;
+};
+
+/*
+ * Represents information about a zip entry in a zip file.
+ */
+struct ZipEntry {
+  // Compression method: One of kCompressStored or
+  // kCompressDeflated.
+  uint16_t method;
+
+  // Modification time. The zipfile format specifies
+  // that the first two little endian bytes contain the time
+  // and the last two little endian bytes contain the date.
+  uint32_t mod_time;
+
+  // 1 if this entry contains a data descriptor segment, 0
+  // otherwise.
+  uint8_t has_data_descriptor;
+
+  // Crc32 value of this ZipEntry. This information might
+  // either be stored in the local file header or in a special
+  // Data descriptor footer at the end of the file entry.
+  uint32_t crc32;
+
+  // Compressed length of this ZipEntry. Might be present
+  // either in the local file header or in the data descriptor
+  // footer.
+  uint32_t compressed_length;
+
+  // Uncompressed length of this ZipEntry. Might be present
+  // either in the local file header or in the data descriptor
+  // footer.
+  uint32_t uncompressed_length;
+
+  // The offset to the start of data for this ZipEntry.
+  off64_t offset;
+};
+
+typedef void* ZipArchiveHandle;
+
+/*
+ * Open a Zip archive, and sets handle to the value of the opaque
+ * handle for the file. This handle must be released by calling
+ * CloseArchive with this handle.
+ *
+ * Returns 0 on success, and negative values on failure.
+ */
+int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle);
+
+/*
+ * Like OpenArchive, but takes a file descriptor open for reading
+ * at the start of the file.  The descriptor must be mappable (this does
+ * not allow access to a stream).
+ *
+ * Sets handle to the value of the opaque handle for this file descriptor.
+ * This handle must be released by calling CloseArchive with this handle.
+ *
+ * This function maps and scans the central directory and builds a table
+ * of entries for future lookups.
+ *
+ * "debugFileName" will appear in error messages, but is not otherwise used.
+ *
+ * Returns 0 on success, and negative values on failure.
+ */
+int32_t OpenArchiveFd(const int fd, const char* debugFileName,
+                      ZipArchiveHandle *handle);
+
+/*
+ * Close archive, releasing resources associated with it. This will
+ * unmap the central directory of the zipfile and free all internal
+ * data structures associated with the file. It is an error to use
+ * this handle for any further operations without an intervening
+ * call to one of the OpenArchive variants.
+ */
+void CloseArchive(ZipArchiveHandle handle);
+
+/*
+ * Find an entry in the Zip archive, by name. |entryName| must be a null
+ * terminated string, and |data| must point to a writeable memory location.
+ *
+ * Returns 0 if an entry is found, and populates |data| with information
+ * about this entry. Returns negative values otherwise.
+ *
+ * It's important to note that |data->crc32|, |data->compLen| and
+ * |data->uncompLen| might be set to values from the central directory
+ * if this file entry contains a data descriptor footer. To verify crc32s
+ * and length, a call to VerifyCrcAndLengths must be made after entry data
+ * has been processed.
+ */
+int32_t FindEntry(const ZipArchiveHandle handle, const char* entryName,
+                  ZipEntry* data);
+
+/*
+ * Start iterating over all entries of a zip file. The order of iteration
+ * is not guaranteed to be the same as the order of elements
+ * in the central directory but is stable for a given zip file. |cookie|
+ * must point to a writeable memory location, and will be set to the value
+ * of an opaque cookie which can be used to make one or more calls to
+ * Next.
+ *
+ * This method also accepts an optional prefix to restrict iteration to
+ * entry names that start with |prefix|.
+ *
+ * Returns 0 on success and negative values on failure.
+ */
+int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
+                       const char* prefix);
+
+/*
+ * Advance to the next element in the zipfile in iteration order.
+ *
+ * Returns 0 on success, -1 if there are no more elements in this
+ * archive and lower negative values on failure.
+ */
+int32_t Next(void* cookie, ZipEntry* data, ZipEntryName *name);
+
+/*
+ * Uncompress and write an entry to an open file identified by |fd|.
+ * |entry->uncompressed_length| bytes will be written to the file at
+ * its current offset, and the file will be truncated at the end of
+ * the uncompressed data.
+ *
+ * Returns 0 on success and negative values on failure.
+ */
+int32_t ExtractEntryToFile(ZipArchiveHandle handle, ZipEntry* entry, int fd);
+
+/**
+ * Uncompress a given zip entry to the memory region at |begin| and of
+ * size |size|. This size is expected to be the same as the *declared*
+ * uncompressed length of the zip entry. It is an error if the *actual*
+ * number of uncompressed bytes differs from this number.
+ *
+ * Returns 0 on success and negative values on failure.
+ */
+int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry,
+                        uint8_t* begin, uint32_t size);
+
+int GetFileDescriptor(const ZipArchiveHandle handle);
+
+const char* ErrorCodeString(int32_t error_code);
+
+__END_DECLS
+
+#endif  // LIBZIPARCHIVE_ZIPARCHIVE_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/devices.c b/init/devices.c
index af88c5f..f7df453 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -44,6 +44,7 @@
 #include <cutils/uevent.h>
 
 #include "devices.h"
+#include "ueventd_parser.h"
 #include "util.h"
 #include "log.h"
 
@@ -530,8 +531,11 @@
     name++;
 
     /* too-long names would overrun our buffer */
-    if(strlen(name) > len)
+    if(strlen(name) > len) {
+        ERROR("DEVPATH=%s exceeds %u-character limit on filename; ignoring event\n",
+                name, len);
         return NULL;
+    }
 
     return name;
 }
@@ -557,37 +561,76 @@
             uevent->major, uevent->minor, links);
 }
 
+#define DEVPATH_LEN 96
+
+static bool assemble_devpath(char *devpath, const char *dirname,
+        const char *devname)
+{
+    int s = snprintf(devpath, DEVPATH_LEN, "%s/%s", dirname, devname);
+    if (s < 0) {
+        ERROR("failed to assemble device path (%s); ignoring event\n",
+                strerror(errno));
+        return false;
+    } else if (s >= DEVPATH_LEN) {
+        ERROR("%s/%s exceeds %u-character limit on path; ignoring event\n",
+                dirname, devname, DEVPATH_LEN);
+        return false;
+    }
+    return true;
+}
+
+static void mkdir_recursive_for_devpath(const char *devpath)
+{
+    char dir[DEVPATH_LEN];
+    char *slash;
+
+    strcpy(dir, devpath);
+    slash = strrchr(dir, '/');
+    *slash = '\0';
+    mkdir_recursive(dir, 0755);
+}
+
 static void handle_generic_device_event(struct uevent *uevent)
 {
     char *base;
     const char *name;
-    char devpath[96] = {0};
+    char devpath[DEVPATH_LEN] = {0};
     char **links = NULL;
 
     name = parse_device_name(uevent, 64);
     if (!name)
         return;
 
-    if (!strncmp(uevent->subsystem, "usb", 3)) {
+    struct ueventd_subsystem *subsystem =
+            ueventd_subsystem_find_by_name(uevent->subsystem);
+
+    if (subsystem) {
+        const char *devname;
+
+        switch (subsystem->devname_src) {
+        case DEVNAME_UEVENT_DEVNAME:
+            devname = uevent->device_name;
+            break;
+
+        case DEVNAME_UEVENT_DEVPATH:
+            devname = name;
+            break;
+
+        default:
+            ERROR("%s subsystem's devpath option is not set; ignoring event\n",
+                    uevent->subsystem);
+            return;
+        }
+
+        if (!assemble_devpath(devpath, subsystem->dirname, devname))
+            return;
+        mkdir_recursive_for_devpath(devpath);
+    } else if (!strncmp(uevent->subsystem, "usb", 3)) {
          if (!strcmp(uevent->subsystem, "usb")) {
             if (uevent->device_name) {
-                /*
-                 * create device node provided by kernel if present
-                 * see drivers/base/core.c
-                 */
-                char *p = devpath;
-                snprintf(devpath, sizeof(devpath), "/dev/%s", uevent->device_name);
-                /* skip leading /dev/ */
-                p += 5;
-                /* build directories */
-                while (*p) {
-                    if (*p == '/') {
-                        *p = 0;
-                        make_dir(devpath, 0755);
-                        *p = '/';
-                    }
-                    p++;
-                }
+                if (!assemble_devpath(devpath, "/dev", uevent->device_name))
+                    return;
+                mkdir_recursive_for_devpath(devpath);
              }
              else {
                  /* This imitates the file system that would be created
diff --git a/init/init.c b/init/init.c
index c497d78..ab52749 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>
 
@@ -220,6 +221,9 @@
             }
 
             rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
+            if (rc == 0 && !strcmp(scon, mycon)) {
+                ERROR("Warning!  Service %s needs a SELinux domain defined; please fix!\n", svc->name);
+            }
             freecon(mycon);
             freecon(fcon);
             if (rc < 0) {
@@ -556,6 +560,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 +1040,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 +1055,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..f49e698 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -60,7 +60,7 @@
 #define KEYWORD(symbol, flags, nargs, func) \
     [ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
 
-struct {
+static struct {
     const char *name;
     int (*func)(int nargs, char **args);
     unsigned char nargs;
@@ -76,7 +76,7 @@
 #define kw_func(kw) (keyword_info[kw].func)
 #define kw_nargs(kw) (keyword_info[kw].nargs)
 
-int lookup_keyword(const char *s)
+static int lookup_keyword(const char *s)
 {
     switch (*s++) {
     case '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;
@@ -167,7 +170,7 @@
     return K_UNKNOWN;
 }
 
-void parse_line_no_op(struct parse_state *state, int nargs, char **args)
+static void parse_line_no_op(struct parse_state *state, int nargs, char **args)
 {
 }
 
@@ -290,7 +293,7 @@
     return -1;
 }
 
-void parse_import(struct parse_state *state, int nargs, char **args)
+static void parse_import(struct parse_state *state, int nargs, char **args)
 {
     struct listnode *import_list = state->priv;
     struct import *import;
@@ -315,7 +318,7 @@
     INFO("found import '%s', adding to import list", import->filename);
 }
 
-void parse_new_section(struct parse_state *state, int kw,
+static void parse_new_section(struct parse_state *state, int kw,
                        int nargs, char **args)
 {
     printf("[ %s %s ]\n", args[0],
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/parser.h b/init/parser.h
index 0a5802a..a58272a 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -33,7 +33,6 @@
     void *priv;
 };
 
-int lookup_keyword(const char *s);
 void DUMP(void);
 int next_token(struct parse_state *state);
 void parse_error(struct parse_state *state, const char *fmt, ...);
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/init/signal_handler.c b/init/signal_handler.c
index d31ad63..7e8e1a7 100644
--- a/init/signal_handler.c
+++ b/init/signal_handler.c
@@ -57,7 +57,15 @@
 
     svc = service_find_by_pid(pid);
     if (!svc) {
-        ERROR("untracked pid %d exited\n", pid);
+        if (WIFEXITED(status)) {
+            ERROR("untracked pid %d exited with status %d\n", pid, WEXITSTATUS(status));
+        } else if (WIFSIGNALED(status)) {
+            ERROR("untracked pid %d killed by signal %d\n", pid, WTERMSIG(status));
+        } else if (WIFSTOPPED(status)) {
+            ERROR("untracked pid %d stopped by signal %d\n", pid, WSTOPSIG(status));
+        } else {
+            ERROR("untracked pid %d state changed\n", pid);
+        }
         return 0;
     }
 
diff --git a/init/ueventd.h b/init/ueventd.h
index 9066e47..0a454c5 100644
--- a/init/ueventd.h
+++ b/init/ueventd.h
@@ -17,6 +17,21 @@
 #ifndef _INIT_UEVENTD_H_
 #define _INIT_UEVENTD_H_
 
+#include <cutils/list.h>
+#include <sys/types.h>
+
+struct ueventd_subsystem {
+    struct listnode slist;
+
+    const char *name;
+    enum {
+        DEVNAME_UNKNOWN = 0,
+        DEVNAME_UEVENT_DEVNAME,
+        DEVNAME_UEVENT_DEVPATH,
+    } devname_src;
+    const char *dirname;
+};
+
 int ueventd_main(int argc, char **argv);
 
 #endif
diff --git a/init/ueventd_keywords.h b/init/ueventd_keywords.h
new file mode 100644
index 0000000..88e8f01
--- /dev/null
+++ b/init/ueventd_keywords.h
@@ -0,0 +1,15 @@
+#ifndef KEYWORD
+#define __MAKE_KEYWORD_ENUM__
+#define KEYWORD(symbol, flags, nargs) K_##symbol,
+enum {
+    K_UNKNOWN,
+#endif
+    KEYWORD(subsystem,      SECTION,    1)
+    KEYWORD(devname,        OPTION,     1)
+    KEYWORD(dirname,        OPTION,     1)
+#ifdef __MAKE_KEYWORD_ENUM__
+    KEYWORD_COUNT,
+};
+#undef __MAKE_KEYWORD_ENUM__
+#undef KEYWORD
+#endif
diff --git a/init/ueventd_parser.c b/init/ueventd_parser.c
index 3e60df5..e447006 100644
--- a/init/ueventd_parser.c
+++ b/init/ueventd_parser.c
@@ -14,18 +14,189 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
+#include <errno.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <stdarg.h>
+#include <stdlib.h>
 #include <string.h>
 
+#include "ueventd.h"
 #include "ueventd_parser.h"
 #include "parser.h"
 #include "log.h"
 #include "util.h"
 
+static list_declare(subsystem_list);
+
 static void parse_line_device(struct parse_state *state, int nargs, char **args);
 
+#define SECTION 0x01
+#define OPTION  0x02
+
+#include "ueventd_keywords.h"
+
+#define KEYWORD(symbol, flags, nargs) \
+    [ K_##symbol ] = { #symbol, nargs + 1, flags, },
+
+static struct {
+    const char *name;
+    unsigned char nargs;
+    unsigned char flags;
+} keyword_info[KEYWORD_COUNT] = {
+    [ K_UNKNOWN ] = { "unknown", 0, 0 },
+#include "ueventd_keywords.h"
+};
+#undef KEYWORD
+
+#define kw_is(kw, type) (keyword_info[kw].flags & (type))
+#define kw_nargs(kw) (keyword_info[kw].nargs)
+
+static int lookup_keyword(const char *s)
+{
+    switch (*s++) {
+    case 'd':
+        if (!strcmp(s, "evname")) return K_devname;
+        if (!strcmp(s, "irname")) return K_dirname;
+        break;
+    case 's':
+        if (!strcmp(s, "ubsystem")) return K_subsystem;
+        break;
+    }
+    return K_UNKNOWN;
+}
+
+static void parse_line_no_op(struct parse_state *state __attribute__((unused)),
+        int nargs __attribute__((unused)), char **args  __attribute__((unused)))
+{
+}
+
+static int valid_name(const char *name)
+{
+    while (*name) {
+        if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
+            return 0;
+        }
+        name++;
+    }
+    return 1;
+}
+
+struct ueventd_subsystem *ueventd_subsystem_find_by_name(const char *name)
+{
+    struct listnode *node;
+    struct ueventd_subsystem *s;
+
+    list_for_each(node, &subsystem_list) {
+        s = node_to_item(node, struct ueventd_subsystem, slist);
+        if (!strcmp(s->name, name)) {
+            return s;
+        }
+    }
+    return 0;
+}
+
+static void *parse_subsystem(struct parse_state *state,
+        int nargs __attribute__((unused)), char **args)
+{
+    struct ueventd_subsystem *s;
+
+    if (!valid_name(args[1])) {
+        parse_error(state, "invalid subsystem name '%s'\n", args[1]);
+        return 0;
+    }
+
+    s = ueventd_subsystem_find_by_name(args[1]);
+    if (s) {
+        parse_error(state, "ignored duplicate definition of subsystem '%s'\n",
+                args[1]);
+        return 0;
+    }
+
+    s = calloc(1, sizeof(*s));
+    if (!s) {
+        parse_error(state, "out of memory\n");
+        return 0;
+    }
+    s->name = args[1];
+    s->dirname = "/dev";
+    list_add_tail(&subsystem_list, &s->slist);
+    return s;
+}
+
+static void parse_line_subsystem(struct parse_state *state, int nargs,
+        char **args)
+{
+    struct ueventd_subsystem *s = state->context;
+    int kw;
+
+    if (nargs == 0) {
+        return;
+    }
+
+    kw = lookup_keyword(args[0]);
+    switch (kw) {
+    case K_devname:
+        if (!strcmp(args[1], "uevent_devname"))
+            s->devname_src = DEVNAME_UEVENT_DEVNAME;
+        else if (!strcmp(args[1], "uevent_devpath"))
+            s->devname_src = DEVNAME_UEVENT_DEVPATH;
+        else
+            parse_error(state, "invalid devname '%s'\n", args[1]);
+        break;
+
+    case K_dirname:
+        if (args[1][0] == '/')
+            s->dirname = args[1];
+        else
+            parse_error(state, "dirname '%s' does not start with '/'\n",
+                    args[1]);
+        break;
+
+    default:
+        parse_error(state, "invalid option '%s'\n", args[0]);
+    }
+}
+
+static void parse_new_section(struct parse_state *state, int kw,
+                       int nargs, char **args)
+{
+    printf("[ %s %s ]\n", args[0],
+           nargs > 1 ? args[1] : "");
+
+    switch(kw) {
+    case K_subsystem:
+        state->context = parse_subsystem(state, nargs, args);
+        if (state->context) {
+            state->parse_line = parse_line_subsystem;
+            return;
+        }
+        break;
+    }
+    state->parse_line = parse_line_no_op;
+}
+
+static void parse_line(struct parse_state *state, char **args, int nargs)
+{
+    int kw = lookup_keyword(args[0]);
+    int kw_nargs = kw_nargs(kw);
+
+    if (nargs < kw_nargs) {
+        parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
+            kw_nargs > 2 ? "arguments" : "argument");
+        return;
+    }
+
+    if (kw_is(kw, SECTION)) {
+        parse_new_section(state, kw, nargs, args);
+    } else if (kw_is(kw, OPTION)) {
+        state->parse_line(state, nargs, args);
+    } else {
+        parse_line_device(state, nargs, args);
+    }
+}
+
 static void parse_config(const char *fn, char *s)
 {
     struct parse_state state;
@@ -36,18 +207,19 @@
     state.line = 1;
     state.ptr = s;
     state.nexttoken = 0;
-    state.parse_line = parse_line_device;
+    state.parse_line = parse_line_no_op;
     for (;;) {
         int token = next_token(&state);
         switch (token) {
         case T_EOF:
-            state.parse_line(&state, 0, 0);
+            parse_line(&state, args, nargs);
             return;
         case T_NEWLINE:
             if (nargs) {
-                state.parse_line(&state, nargs, args);
+                parse_line(&state, args, nargs);
                 nargs = 0;
             }
+            state.line++;
             break;
         case T_TEXT:
             if (nargs < UEVENTD_PARSER_MAXARGS) {
@@ -69,7 +241,8 @@
     return 0;
 }
 
-static void parse_line_device(struct parse_state* state, int nargs, char **args)
+static void parse_line_device(struct parse_state *state __attribute__((unused)),
+        int nargs, char **args)
 {
     set_device_permission(nargs, args);
 }
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
index 3684285..907cc49 100644
--- a/init/ueventd_parser.h
+++ b/init/ueventd_parser.h
@@ -17,9 +17,12 @@
 #ifndef _INIT_UEVENTD_PARSER_H_
 #define _INIT_UEVENTD_PARSER_H_
 
+#include "ueventd.h"
+
 #define UEVENTD_PARSER_MAXARGS 5
 
 int ueventd_parse_config_file(const char *fn);
 void set_device_permission(int nargs, char **args);
+struct ueventd_subsystem *ueventd_subsystem_find_by_name(const char *name);
 
 #endif
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..aef3054 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -16,6 +16,7 @@
 
 #include <unistd.h>
 #include <sys/reboot.h>
+#include <sys/syscall.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -105,11 +106,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:
@@ -121,7 +119,7 @@
             break;
 
         case ANDROID_RB_RESTART2:
-            ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+            ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
                            LINUX_REBOOT_CMD_RESTART2, arg);
             break;
 
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/libdiskconfig/config_mbr.c b/libdiskconfig/config_mbr.c
index b89d382..7641b29 100644
--- a/libdiskconfig/config_mbr.c
+++ b/libdiskconfig/config_mbr.c
@@ -88,7 +88,7 @@
         /* DO NOT DEREFERENCE */
         struct pc_boot_record *mbr = (void *)PC_MBR_DISK_OFFSET; 
         /* grab the offset in mbr where to write this partition entry. */
-        item->offset = (loff_t)((uint32_t)((uint8_t *)(&mbr->ptable[pnum])));
+        item->offset = (loff_t)((uintptr_t)((uint8_t *)(&mbr->ptable[pnum])));
     }
 
     pentry = (struct pc_partition *) &item->data;
diff --git a/libion/Android.mk b/libion/Android.mk
index 5121fee..e5d495b 100644
--- a/libion/Android.mk
+++ b/libion/Android.mk
@@ -5,11 +5,16 @@
 LOCAL_MODULE := libion
 LOCAL_MODULE_TAGS := optional
 LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
 include $(BUILD_SHARED_LIBRARY)
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := ion.c ion_test.c
 LOCAL_MODULE := iontest
 LOCAL_MODULE_TAGS := optional tests
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
 LOCAL_SHARED_LIBRARIES := liblog
 include $(BUILD_EXECUTABLE)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/include/ion/ion.h b/libion/include/ion/ion.h
similarity index 72%
rename from include/ion/ion.h
rename to libion/include/ion/ion.h
index 018c0a1..f47793d 100644
--- a/include/ion/ion.h
+++ b/libion/include/ion/ion.h
@@ -21,22 +21,25 @@
 #ifndef __SYS_CORE_ION_H
 #define __SYS_CORE_ION_H
 
+#include <sys/types.h>
 #include <linux/ion.h>
 
 __BEGIN_DECLS
 
+struct ion_handle;
+
 int ion_open();
 int ion_close(int fd);
 int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask,
-	      unsigned int flags, struct ion_handle **handle);
+              unsigned int flags, ion_user_handle_t *handle);
 int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask,
-		 unsigned int flags, int *handle_fd);
+              unsigned int flags, int *handle_fd);
 int ion_sync_fd(int fd, int handle_fd);
-int ion_free(int fd, struct ion_handle *handle);
-int ion_map(int fd, struct ion_handle *handle, size_t length, int prot,
+int ion_free(int fd, ion_user_handle_t handle);
+int ion_map(int fd, ion_user_handle_t handle, size_t length, int prot,
             int flags, off_t offset, unsigned char **ptr, int *map_fd);
-int ion_share(int fd, struct ion_handle *handle, int *share_fd);
-int ion_import(int fd, int share_fd, struct ion_handle **handle);
+int ion_share(int fd, ion_user_handle_t handle, int *share_fd);
+int ion_import(int fd, int share_fd, ion_user_handle_t *handle);
 
 __END_DECLS
 
diff --git a/libion/ion.c b/libion/ion.c
index 020c35b..80bdc2a 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -32,119 +32,139 @@
 
 int ion_open()
 {
-        int fd = open("/dev/ion", O_RDWR);
-        if (fd < 0)
-                ALOGE("open /dev/ion failed!\n");
-        return fd;
+    int fd = open("/dev/ion", O_RDWR);
+    if (fd < 0)
+        ALOGE("open /dev/ion failed!\n");
+    return fd;
 }
 
 int ion_close(int fd)
 {
-        return close(fd);
+    int ret = close(fd);
+    if (ret < 0)
+        return -errno;
+    return ret;
 }
 
 static int ion_ioctl(int fd, int req, void *arg)
 {
-        int ret = ioctl(fd, req, arg);
-        if (ret < 0) {
-                ALOGE("ioctl %x failed with code %d: %s\n", req,
-                       ret, strerror(errno));
-                return -errno;
-        }
-        return ret;
+    int ret = ioctl(fd, req, arg);
+    if (ret < 0) {
+        ALOGE("ioctl %x failed with code %d: %s\n", req,
+              ret, strerror(errno));
+        return -errno;
+    }
+    return ret;
 }
 
 int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask,
-	      unsigned int flags, struct ion_handle **handle)
+              unsigned int flags, ion_user_handle_t *handle)
 {
-        int ret;
-        struct ion_allocation_data data = {
-                .len = len,
-                .align = align,
-		.heap_mask = heap_mask,
-                .flags = flags,
-        };
+    int ret;
+    struct ion_allocation_data data = {
+        .len = len,
+        .align = align,
+        .heap_id_mask = heap_mask,
+        .flags = flags,
+    };
 
-        ret = ion_ioctl(fd, ION_IOC_ALLOC, &data);
-        if (ret < 0)
-                return ret;
-        *handle = data.handle;
+    if (handle == NULL)
+        return -EINVAL;
+
+    ret = ion_ioctl(fd, ION_IOC_ALLOC, &data);
+    if (ret < 0)
         return ret;
+    *handle = data.handle;
+    return ret;
 }
 
-int ion_free(int fd, struct ion_handle *handle)
+int ion_free(int fd, ion_user_handle_t handle)
 {
-        struct ion_handle_data data = {
-                .handle = handle,
-        };
-        return ion_ioctl(fd, ION_IOC_FREE, &data);
+    struct ion_handle_data data = {
+        .handle = handle,
+    };
+    return ion_ioctl(fd, ION_IOC_FREE, &data);
 }
 
-int ion_map(int fd, struct ion_handle *handle, size_t length, int prot,
+int ion_map(int fd, ion_user_handle_t handle, size_t length, int prot,
             int flags, off_t offset, unsigned char **ptr, int *map_fd)
 {
-        struct ion_fd_data data = {
-                .handle = handle,
-        };
+    int ret;
+    struct ion_fd_data data = {
+        .handle = handle,
+    };
 
-        int ret = ion_ioctl(fd, ION_IOC_MAP, &data);
-        if (ret < 0)
-                return ret;
-        *map_fd = data.fd;
-        if (*map_fd < 0) {
-                ALOGE("map ioctl returned negative fd\n");
-                return -EINVAL;
-        }
-        *ptr = mmap(NULL, length, prot, flags, *map_fd, offset);
-        if (*ptr == MAP_FAILED) {
-                ALOGE("mmap failed: %s\n", strerror(errno));
-                return -errno;
-        }
+    if (map_fd == NULL)
+        return -EINVAL;
+    if (ptr == NULL)
+        return -EINVAL;
+
+    ret = ion_ioctl(fd, ION_IOC_MAP, &data);
+    if (ret < 0)
         return ret;
+    *map_fd = data.fd;
+    if (*map_fd < 0) {
+        ALOGE("map ioctl returned negative fd\n");
+        return -EINVAL;
+    }
+    *ptr = mmap(NULL, length, prot, flags, *map_fd, offset);
+    if (*ptr == MAP_FAILED) {
+        ALOGE("mmap failed: %s\n", strerror(errno));
+        return -errno;
+    }
+    return ret;
 }
 
-int ion_share(int fd, struct ion_handle *handle, int *share_fd)
+int ion_share(int fd, ion_user_handle_t handle, int *share_fd)
 {
-        int map_fd;
-        struct ion_fd_data data = {
-                .handle = handle,
-        };
+    int map_fd;
+    int ret;
+    struct ion_fd_data data = {
+        .handle = handle,
+    };
 
-        int ret = ion_ioctl(fd, ION_IOC_SHARE, &data);
-        if (ret < 0)
-                return ret;
-        *share_fd = data.fd;
-        if (*share_fd < 0) {
-                ALOGE("share ioctl returned negative fd\n");
-                return -EINVAL;
-        }
+    if (share_fd == NULL)
+        return -EINVAL;
+
+    ret = ion_ioctl(fd, ION_IOC_SHARE, &data);
+    if (ret < 0)
         return ret;
+    *share_fd = data.fd;
+    if (*share_fd < 0) {
+        ALOGE("share ioctl returned negative fd\n");
+        return -EINVAL;
+    }
+    return ret;
 }
 
 int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask,
-		 unsigned int flags, int *handle_fd) {
-	struct ion_handle *handle;
-	int ret;
+                 unsigned int flags, int *handle_fd) {
+    ion_user_handle_t handle;
+    int ret;
 
-	ret = ion_alloc(fd, len, align, heap_mask, flags, &handle);
-	if (ret < 0)
-		return ret;
-	ret = ion_share(fd, handle, handle_fd);
-	ion_free(fd, handle);
-	return ret;
+    ret = ion_alloc(fd, len, align, heap_mask, flags, &handle);
+    if (ret < 0)
+        return ret;
+    ret = ion_share(fd, handle, handle_fd);
+    ion_free(fd, handle);
+    return ret;
 }
 
-int ion_import(int fd, int share_fd, struct ion_handle **handle)
+int ion_import(int fd, int share_fd, ion_user_handle_t *handle)
 {
-        struct ion_fd_data data = {
-                .fd = share_fd,
-        };
+    int ret;
+    struct ion_fd_data data = {
+        .fd = share_fd,
+    };
 
-        int ret = ion_ioctl(fd, ION_IOC_IMPORT, &data);
-        if (ret < 0)
-                return ret;
-        *handle = data.handle;
+    if (handle == NULL)
+        return -EINVAL;
+
+    ret = ion_ioctl(fd, ION_IOC_IMPORT, &data);
+    if (ret < 0)
         return ret;
+    *handle = data.handle;
+    return ret;
 }
 
 int ion_sync_fd(int fd, int handle_fd)
diff --git a/libion/ion_test.c b/libion/ion_test.c
index 0caaa2a..12163e9 100644
--- a/libion/ion_test.c
+++ b/libion/ion_test.c
@@ -1,3 +1,19 @@
+/*
+ *   Copyright 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.
+ */
+
 #include <errno.h>
 #include <fcntl.h>
 #include <getopt.h>
@@ -13,7 +29,6 @@
 
 #include <ion/ion.h>
 #include <linux/ion.h>
-#include <linux/omap_ion.h>
 
 size_t len = 1024*1024, align = 0;
 int prot = PROT_READ | PROT_WRITE;
@@ -23,256 +38,250 @@
 int test = -1;
 size_t stride;
 
-int _ion_alloc_test(int *fd, struct ion_handle **handle)
+int _ion_alloc_test(int *fd, ion_user_handle_t *handle)
 {
-	int ret;
+    int ret;
 
-	*fd = ion_open();
-	if (*fd < 0)
-		return *fd;
+    *fd = ion_open();
+    if (*fd < 0)
+        return *fd;
 
-	ret = ion_alloc(*fd, len, align, heap_mask, alloc_flags, handle);
+    ret = ion_alloc(*fd, len, align, heap_mask, alloc_flags, handle);
 
-	if (ret)
-		printf("%s failed: %s\n", __func__, strerror(ret));
-	return ret;
+    if (ret)
+        printf("%s failed: %s\n", __func__, strerror(ret));
+    return ret;
 }
 
 void ion_alloc_test()
 {
-	int fd, ret;
-	struct ion_handle *handle;
+    int fd, ret;
+    ion_user_handle_t handle;
 
-	if(_ion_alloc_test(&fd, &handle))
-			return;
+    if(_ion_alloc_test(&fd, &handle))
+        return;
 
-	ret = ion_free(fd, handle);
-	if (ret) {
-		printf("%s failed: %s %p\n", __func__, strerror(ret), handle);
-		return;
-	}
-	ion_close(fd);
-	printf("ion alloc test: passed\n");
+    ret = ion_free(fd, handle);
+    if (ret) {
+        printf("%s failed: %s %p\n", __func__, strerror(ret), handle);
+        return;
+    }
+    ion_close(fd);
+    printf("ion alloc test: passed\n");
 }
 
 void ion_map_test()
 {
-	int fd, map_fd, ret;
-	size_t i;
-	struct ion_handle *handle;
-	unsigned char *ptr;
+    int fd, map_fd, ret;
+    size_t i;
+    ion_user_handle_t handle;
+    unsigned char *ptr;
 
-	if(_ion_alloc_test(&fd, &handle))
-		return;
+    if(_ion_alloc_test(&fd, &handle))
+        return;
 
-	ret = ion_map(fd, handle, len, prot, map_flags, 0, &ptr, &map_fd);
-	if (ret)
-		return;
+    ret = ion_map(fd, handle, len, prot, map_flags, 0, &ptr, &map_fd);
+    if (ret)
+        return;
 
-	for (i = 0; i < len; i++) {
-		ptr[i] = (unsigned char)i;
-	}
-	for (i = 0; i < len; i++)
-		if (ptr[i] != (unsigned char)i)
-			printf("%s failed wrote %d read %d from mapped "
-			       "memory\n", __func__, i, ptr[i]);
-	/* clean up properly */
-	ret = ion_free(fd, handle);
-	ion_close(fd);
-	munmap(ptr, len);
-	close(map_fd);
+    for (i = 0; i < len; i++) {
+        ptr[i] = (unsigned char)i;
+    }
+    for (i = 0; i < len; i++)
+        if (ptr[i] != (unsigned char)i)
+            printf("%s failed wrote %zu read %d from mapped "
+                   "memory\n", __func__, i, ptr[i]);
+    /* clean up properly */
+    ret = ion_free(fd, handle);
+    ion_close(fd);
+    munmap(ptr, len);
+    close(map_fd);
 
-	_ion_alloc_test(&fd, &handle);
-	close(fd);
+    _ion_alloc_test(&fd, &handle);
+    close(fd);
 
 #if 0
-	munmap(ptr, len);
-	close(map_fd);
-	ion_close(fd);
+    munmap(ptr, len);
+    close(map_fd);
+    ion_close(fd);
 
-	_ion_alloc_test(len, align, flags, &fd, &handle);
-	close(map_fd);
-	ret = ion_map(fd, handle, len, prot, flags, 0, &ptr, &map_fd);
-	/* don't clean up */
+    _ion_alloc_test(len, align, flags, &fd, &handle);
+    close(map_fd);
+    ret = ion_map(fd, handle, len, prot, flags, 0, &ptr, &map_fd);
+    /* don't clean up */
 #endif
 }
 
 void ion_share_test()
 
 {
-	struct ion_handle *handle;
-	int sd[2];
-	int num_fd = 1;
-	struct iovec count_vec = {
-		.iov_base = &num_fd,
-		.iov_len = sizeof num_fd,
-	};
-	char buf[CMSG_SPACE(sizeof(int))];
-	socketpair(AF_UNIX, SOCK_STREAM, 0, sd);
-	if (fork()) {
-		struct msghdr msg = {
-			.msg_control = buf,
-			.msg_controllen = sizeof buf,
-			.msg_iov = &count_vec,
-			.msg_iovlen = 1,
-		};
+    ion_user_handle_t handle;
+    int sd[2];
+    int num_fd = 1;
+    struct iovec count_vec = {
+        .iov_base = &num_fd,
+        .iov_len = sizeof num_fd,
+    };
+    char buf[CMSG_SPACE(sizeof(int))];
+    socketpair(AF_UNIX, SOCK_STREAM, 0, sd);
+    if (fork()) {
+        struct msghdr msg = {
+            .msg_control = buf,
+            .msg_controllen = sizeof buf,
+            .msg_iov = &count_vec,
+            .msg_iovlen = 1,
+        };
 
-		struct cmsghdr *cmsg;
-		int fd, share_fd, ret;
-		char *ptr;
-		/* parent */
-		if(_ion_alloc_test(&fd, &handle))
-			return;
-		ret = ion_share(fd, handle, &share_fd);
-		if (ret)
-			printf("share failed %s\n", strerror(errno));
-		ptr = mmap(NULL, len, prot, map_flags, share_fd, 0);
-		if (ptr == MAP_FAILED) {
-			return;
-		}
-		strcpy(ptr, "master");
-		cmsg = CMSG_FIRSTHDR(&msg);
-		cmsg->cmsg_level = SOL_SOCKET;
-		cmsg->cmsg_type = SCM_RIGHTS;
-		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
-		*(int *)CMSG_DATA(cmsg) = share_fd;
-		/* send the fd */
-		printf("master? [%10s] should be [master]\n", ptr);
-		printf("master sending msg 1\n");
-		sendmsg(sd[0], &msg, 0);
-		if (recvmsg(sd[0], &msg, 0) < 0)
-			perror("master recv msg 2");
-		printf("master? [%10s] should be [child]\n", ptr);
+        struct cmsghdr *cmsg;
+        int fd, share_fd, ret;
+        char *ptr;
+        /* parent */
+        if(_ion_alloc_test(&fd, &handle))
+            return;
+        ret = ion_share(fd, handle, &share_fd);
+        if (ret)
+            printf("share failed %s\n", strerror(errno));
+        ptr = mmap(NULL, len, prot, map_flags, share_fd, 0);
+        if (ptr == MAP_FAILED) {
+            return;
+        }
+        strcpy(ptr, "master");
+        cmsg = CMSG_FIRSTHDR(&msg);
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_type = SCM_RIGHTS;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+        *(int *)CMSG_DATA(cmsg) = share_fd;
+        /* send the fd */
+        printf("master? [%10s] should be [master]\n", ptr);
+        printf("master sending msg 1\n");
+        sendmsg(sd[0], &msg, 0);
+        if (recvmsg(sd[0], &msg, 0) < 0)
+            perror("master recv msg 2");
+        printf("master? [%10s] should be [child]\n", ptr);
 
-		/* send ping */
-		sendmsg(sd[0], &msg, 0);
-		printf("master->master? [%10s]\n", ptr);
-		if (recvmsg(sd[0], &msg, 0) < 0)
-			perror("master recv 1");
-	} else {
-		struct msghdr msg;
-		struct cmsghdr *cmsg;
-		char* ptr;
-		int fd, recv_fd;
-		char* child_buf[100];
-		/* child */
-		struct iovec count_vec = {
-			.iov_base = child_buf,
-			.iov_len = sizeof child_buf,
-		};
+        /* send ping */
+        sendmsg(sd[0], &msg, 0);
+        printf("master->master? [%10s]\n", ptr);
+        if (recvmsg(sd[0], &msg, 0) < 0)
+            perror("master recv 1");
+    } else {
+        struct msghdr msg;
+        struct cmsghdr *cmsg;
+        char* ptr;
+        int fd, recv_fd;
+        char* child_buf[100];
+        /* child */
+        struct iovec count_vec = {
+            .iov_base = child_buf,
+            .iov_len = sizeof child_buf,
+        };
 
-		struct msghdr child_msg = {
-			.msg_control = buf,
-			.msg_controllen = sizeof buf,
-			.msg_iov = &count_vec,
-			.msg_iovlen = 1,
-		};
+        struct msghdr child_msg = {
+            .msg_control = buf,
+            .msg_controllen = sizeof buf,
+            .msg_iov = &count_vec,
+            .msg_iovlen = 1,
+        };
 
-		if (recvmsg(sd[1], &child_msg, 0) < 0)
-			perror("child recv msg 1");
-		cmsg = CMSG_FIRSTHDR(&child_msg);
-		if (cmsg == NULL) {
-			printf("no cmsg rcvd in child");
-			return;
-		}
-		recv_fd = *(int*)CMSG_DATA(cmsg);
-		if (recv_fd < 0) {
-			printf("could not get recv_fd from socket");
-			return;
-		}
-		printf("child %d\n", recv_fd);
-		fd = ion_open();
-		ptr = mmap(NULL, len, prot, map_flags, recv_fd, 0);
-		if (ptr == MAP_FAILED) {
-			return;
-		}
-		printf("child? [%10s] should be [master]\n", ptr);
-		strcpy(ptr, "child");
-		printf("child sending msg 2\n");
-		sendmsg(sd[1], &child_msg, 0);
-	}
+        if (recvmsg(sd[1], &child_msg, 0) < 0)
+            perror("child recv msg 1");
+        cmsg = CMSG_FIRSTHDR(&child_msg);
+        if (cmsg == NULL) {
+            printf("no cmsg rcvd in child");
+            return;
+        }
+        recv_fd = *(int*)CMSG_DATA(cmsg);
+        if (recv_fd < 0) {
+            printf("could not get recv_fd from socket");
+            return;
+        }
+        printf("child %d\n", recv_fd);
+        fd = ion_open();
+        ptr = mmap(NULL, len, prot, map_flags, recv_fd, 0);
+        if (ptr == MAP_FAILED) {
+            return;
+        }
+        printf("child? [%10s] should be [master]\n", ptr);
+        strcpy(ptr, "child");
+        printf("child sending msg 2\n");
+        sendmsg(sd[1], &child_msg, 0);
+    }
 }
 
 int main(int argc, char* argv[]) {
-	int c;
-	enum tests {
-		ALLOC_TEST = 0, MAP_TEST, SHARE_TEST,
-	};
+    int c;
+    enum tests {
+        ALLOC_TEST = 0, MAP_TEST, SHARE_TEST,
+    };
 
-	while (1) {
-		static struct option opts[] = {
-			{"alloc", no_argument, 0, 'a'},
-			{"alloc_flags", required_argument, 0, 'f'},
-			{"heap_mask", required_argument, 0, 'h'},
-			{"map", no_argument, 0, 'm'},
-			{"share", no_argument, 0, 's'},
-			{"len", required_argument, 0, 'l'},
-			{"align", required_argument, 0, 'g'},
-			{"map_flags", required_argument, 0, 'z'},
-			{"prot", required_argument, 0, 'p'},
-		};
-		int i = 0;
-		c = getopt_long(argc, argv, "af:h:l:mr:st", opts, &i);
-		if (c == -1)
-			break;
+    while (1) {
+        static struct option opts[] = {
+            {"alloc", no_argument, 0, 'a'},
+            {"alloc_flags", required_argument, 0, 'f'},
+            {"heap_mask", required_argument, 0, 'h'},
+            {"map", no_argument, 0, 'm'},
+            {"share", no_argument, 0, 's'},
+            {"len", required_argument, 0, 'l'},
+            {"align", required_argument, 0, 'g'},
+            {"map_flags", required_argument, 0, 'z'},
+            {"prot", required_argument, 0, 'p'},
+        };
+        int i = 0;
+        c = getopt_long(argc, argv, "af:h:l:mr:st", opts, &i);
+        if (c == -1)
+            break;
 
-		switch (c) {
-		case 'l':
-			len = atol(optarg);
-			break;
-		case 'g':
-			align = atol(optarg);
-			break;
-		case 'z':
-			map_flags = 0;
-			map_flags |= strstr(optarg, "PROT_EXEC") ?
-				PROT_EXEC : 0;
-			map_flags |= strstr(optarg, "PROT_READ") ?
-				PROT_READ: 0;
-			map_flags |= strstr(optarg, "PROT_WRITE") ?
-				PROT_WRITE: 0;
-			map_flags |= strstr(optarg, "PROT_NONE") ?
-				PROT_NONE: 0;
-			break;
-		case 'p':
-			prot = 0;
-			prot |= strstr(optarg, "MAP_PRIVATE") ?
-				MAP_PRIVATE	 : 0;
-			prot |= strstr(optarg, "MAP_SHARED") ?
-				MAP_PRIVATE	 : 0;
-			break;
-		case 'f':
-			alloc_flags = atol(optarg);
-			break;
-		case 'h':
-			heap_mask = atol(optarg);
-			break;
-		case 'a':
-			test = ALLOC_TEST;
-			break;
-		case 'm':
-			test = MAP_TEST;
-			break;
-		case 's':
-			test = SHARE_TEST;
-			break;
-		}
-	}
-	printf("test %d, len %u, align %u, map_flags %d, prot %d, heap_mask %d,"
-	       " alloc_flags %d\n", test, len, align, map_flags, prot,
-	       heap_mask, alloc_flags);
-	switch (test) {
-		case ALLOC_TEST:
-			ion_alloc_test();
-			break;
-		case MAP_TEST:
-			ion_map_test();
-			break;
-		case SHARE_TEST:
-			ion_share_test();
-			break;
-		default:
-			printf("must specify a test (alloc, map, share)\n");
-	}
-	return 0;
+        switch (c) {
+        case 'l':
+            len = atol(optarg);
+            break;
+        case 'g':
+            align = atol(optarg);
+            break;
+        case 'z':
+            map_flags = 0;
+            map_flags |= strstr(optarg, "PROT_EXEC") ? PROT_EXEC : 0;
+            map_flags |= strstr(optarg, "PROT_READ") ? PROT_READ: 0;
+            map_flags |= strstr(optarg, "PROT_WRITE") ? PROT_WRITE: 0;
+            map_flags |= strstr(optarg, "PROT_NONE") ? PROT_NONE: 0;
+            break;
+        case 'p':
+            prot = 0;
+            prot |= strstr(optarg, "MAP_PRIVATE") ? MAP_PRIVATE : 0;
+            prot |= strstr(optarg, "MAP_SHARED") ? MAP_PRIVATE : 0;
+            break;
+        case 'f':
+            alloc_flags = atol(optarg);
+            break;
+        case 'h':
+            heap_mask = atol(optarg);
+            break;
+        case 'a':
+            test = ALLOC_TEST;
+            break;
+        case 'm':
+            test = MAP_TEST;
+            break;
+        case 's':
+            test = SHARE_TEST;
+            break;
+        }
+    }
+    printf("test %d, len %zu, align %zu, map_flags %d, prot %d, heap_mask %d,"
+           " alloc_flags %d\n", test, len, align, map_flags, prot,
+           heap_mask, alloc_flags);
+    switch (test) {
+        case ALLOC_TEST:
+            ion_alloc_test();
+            break;
+        case MAP_TEST:
+            ion_map_test();
+            break;
+        case SHARE_TEST:
+            ion_share_test();
+            break;
+        default:
+            printf("must specify a test (alloc, map, share)\n");
+    }
+    return 0;
 }
diff --git a/libion/kernel-headers/linux/ion.h b/libion/kernel-headers/linux/ion.h
new file mode 100644
index 0000000..5af39d0
--- /dev/null
+++ b/libion/kernel-headers/linux/ion.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_LINUX_ION_H
+#define _UAPI_LINUX_ION_H
+#include <linux/ioctl.h>
+#include <linux/types.h>
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+typedef int ion_user_handle_t;
+enum ion_heap_type {
+ ION_HEAP_TYPE_SYSTEM,
+ ION_HEAP_TYPE_SYSTEM_CONTIG,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ ION_HEAP_TYPE_CARVEOUT,
+ ION_HEAP_TYPE_CHUNK,
+ ION_HEAP_TYPE_DMA,
+ ION_HEAP_TYPE_CUSTOM,
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ ION_NUM_HEAPS = 16,
+};
+#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM)
+#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT)
+#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA)
+#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8
+#define ION_FLAG_CACHED 1
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ION_FLAG_CACHED_NEEDS_SYNC 2
+struct ion_allocation_data {
+ size_t len;
+ size_t align;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ unsigned int heap_id_mask;
+ unsigned int flags;
+ ion_user_handle_t handle;
+};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct ion_fd_data {
+ ion_user_handle_t handle;
+ int fd;
+};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct ion_handle_data {
+ ion_user_handle_t handle;
+};
+struct ion_custom_data {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ unsigned int cmd;
+ unsigned long arg;
+};
+#define ION_IOC_MAGIC 'I'
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0,   struct ion_allocation_data)
+#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
+#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)
+#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data)
+#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
+#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
+#endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
diff --git a/libion/kernel-headers/linux/ion_test.h b/libion/kernel-headers/linux/ion_test.h
new file mode 100644
index 0000000..6f3e2a7
--- /dev/null
+++ b/libion/kernel-headers/linux/ion_test.h
@@ -0,0 +1,38 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_LINUX_ION_TEST_H
+#define _UAPI_LINUX_ION_TEST_H
+#include <linux/ioctl.h>
+#include <linux/types.h>
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct ion_test_rw_data {
+ __u64 ptr;
+ __u64 offset;
+ __u64 size;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ int write;
+ int __padding;
+};
+#define ION_IOC_MAGIC 'I'
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ION_IOC_TEST_SET_FD   _IO(ION_IOC_MAGIC, 0xf0)
+#define ION_IOC_TEST_DMA_MAPPING   _IOW(ION_IOC_MAGIC, 0xf1, struct ion_test_rw_data)
+#define ION_IOC_TEST_KERNEL_MAPPING   _IOW(ION_IOC_MAGIC, 0xf2, struct ion_test_rw_data)
+#endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
diff --git a/libion/original-kernel-headers/linux/ion.h b/libion/original-kernel-headers/linux/ion.h
new file mode 100644
index 0000000..f09e7c1
--- /dev/null
+++ b/libion/original-kernel-headers/linux/ion.h
@@ -0,0 +1,196 @@
+/*
+ * drivers/staging/android/uapi/ion.h
+ *
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _UAPI_LINUX_ION_H
+#define _UAPI_LINUX_ION_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+typedef int ion_user_handle_t;
+
+/**
+ * enum ion_heap_types - list of all possible types of heaps
+ * @ION_HEAP_TYPE_SYSTEM:	 memory allocated via vmalloc
+ * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc
+ * @ION_HEAP_TYPE_CARVEOUT:	 memory allocated from a prereserved
+ * 				 carveout heap, allocations are physically
+ * 				 contiguous
+ * @ION_HEAP_TYPE_DMA:		 memory allocated via DMA API
+ * @ION_NUM_HEAPS:		 helper for iterating over heaps, a bit mask
+ * 				 is used to identify the heaps, so only 32
+ * 				 total heap types are supported
+ */
+enum ion_heap_type {
+	ION_HEAP_TYPE_SYSTEM,
+	ION_HEAP_TYPE_SYSTEM_CONTIG,
+	ION_HEAP_TYPE_CARVEOUT,
+	ION_HEAP_TYPE_CHUNK,
+	ION_HEAP_TYPE_DMA,
+	ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
+				 are at the end of this enum */
+	ION_NUM_HEAPS = 16,
+};
+
+#define ION_HEAP_SYSTEM_MASK		(1 << ION_HEAP_TYPE_SYSTEM)
+#define ION_HEAP_SYSTEM_CONTIG_MASK	(1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
+#define ION_HEAP_CARVEOUT_MASK		(1 << ION_HEAP_TYPE_CARVEOUT)
+#define ION_HEAP_TYPE_DMA_MASK		(1 << ION_HEAP_TYPE_DMA)
+
+#define ION_NUM_HEAP_IDS		sizeof(unsigned int) * 8
+
+/**
+ * allocation flags - the lower 16 bits are used by core ion, the upper 16
+ * bits are reserved for use by the heaps themselves.
+ */
+#define ION_FLAG_CACHED 1		/* mappings of this buffer should be
+					   cached, ion will do cache
+					   maintenance when the buffer is
+					   mapped for dma */
+#define ION_FLAG_CACHED_NEEDS_SYNC 2	/* mappings of this buffer will created
+					   at mmap time, if this is set
+					   caches must be managed manually */
+
+/**
+ * DOC: Ion Userspace API
+ *
+ * create a client by opening /dev/ion
+ * most operations handled via following ioctls
+ *
+ */
+
+/**
+ * struct ion_allocation_data - metadata passed from userspace for allocations
+ * @len:		size of the allocation
+ * @align:		required alignment of the allocation
+ * @heap_id_mask:	mask of heap ids to allocate from
+ * @flags:		flags passed to heap
+ * @handle:		pointer that will be populated with a cookie to use to 
+ *			refer to this allocation
+ *
+ * Provided by userspace as an argument to the ioctl
+ */
+struct ion_allocation_data {
+	size_t len;
+	size_t align;
+	unsigned int heap_id_mask;
+	unsigned int flags;
+	ion_user_handle_t handle;
+};
+
+/**
+ * struct ion_fd_data - metadata passed to/from userspace for a handle/fd pair
+ * @handle:	a handle
+ * @fd:		a file descriptor representing that handle
+ *
+ * For ION_IOC_SHARE or ION_IOC_MAP userspace populates the handle field with
+ * the handle returned from ion alloc, and the kernel returns the file
+ * descriptor to share or map in the fd field.  For ION_IOC_IMPORT, userspace
+ * provides the file descriptor and the kernel returns the handle.
+ */
+struct ion_fd_data {
+	ion_user_handle_t handle;
+	int fd;
+};
+
+/**
+ * struct ion_handle_data - a handle passed to/from the kernel
+ * @handle:	a handle
+ */
+struct ion_handle_data {
+	ion_user_handle_t handle;
+};
+
+/**
+ * struct ion_custom_data - metadata passed to/from userspace for a custom ioctl
+ * @cmd:	the custom ioctl function to call
+ * @arg:	additional data to pass to the custom ioctl, typically a user
+ *		pointer to a predefined structure
+ *
+ * This works just like the regular cmd and arg fields of an ioctl.
+ */
+struct ion_custom_data {
+	unsigned int cmd;
+	unsigned long arg;
+};
+
+#define ION_IOC_MAGIC		'I'
+
+/**
+ * DOC: ION_IOC_ALLOC - allocate memory
+ *
+ * Takes an ion_allocation_data struct and returns it with the handle field
+ * populated with the opaque handle for the allocation.
+ */
+#define ION_IOC_ALLOC		_IOWR(ION_IOC_MAGIC, 0, \
+				      struct ion_allocation_data)
+
+/**
+ * DOC: ION_IOC_FREE - free memory
+ *
+ * Takes an ion_handle_data struct and frees the handle.
+ */
+#define ION_IOC_FREE		_IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
+
+/**
+ * DOC: ION_IOC_MAP - get a file descriptor to mmap
+ *
+ * Takes an ion_fd_data struct with the handle field populated with a valid
+ * opaque handle.  Returns the struct with the fd field set to a file
+ * descriptor open in the current address space.  This file descriptor
+ * can then be used as an argument to mmap.
+ */
+#define ION_IOC_MAP		_IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)
+
+/**
+ * DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation
+ *
+ * Takes an ion_fd_data struct with the handle field populated with a valid
+ * opaque handle.  Returns the struct with the fd field set to a file
+ * descriptor open in the current address space.  This file descriptor
+ * can then be passed to another process.  The corresponding opaque handle can
+ * be retrieved via ION_IOC_IMPORT.
+ */
+#define ION_IOC_SHARE		_IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data)
+
+/**
+ * DOC: ION_IOC_IMPORT - imports a shared file descriptor
+ *
+ * Takes an ion_fd_data struct with the fd field populated with a valid file
+ * descriptor obtained from ION_IOC_SHARE and returns the struct with the handle
+ * filed set to the corresponding opaque handle.
+ */
+#define ION_IOC_IMPORT		_IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data)
+
+/**
+ * DOC: ION_IOC_SYNC - syncs a shared file descriptors to memory
+ *
+ * Deprecated in favor of using the dma_buf api's correctly (syncing
+ * will happend automatically when the buffer is mapped to a device).
+ * If necessary should be used after touching a cached buffer from the cpu,
+ * this will make the buffer in memory coherent.
+ */
+#define ION_IOC_SYNC		_IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
+
+/**
+ * DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl
+ *
+ * Takes the argument of the architecture specific ioctl to call and
+ * passes appropriate userdata for that ioctl
+ */
+#define ION_IOC_CUSTOM		_IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
+
+#endif /* _UAPI_LINUX_ION_H */
diff --git a/libion/original-kernel-headers/linux/ion_test.h b/libion/original-kernel-headers/linux/ion_test.h
new file mode 100644
index 0000000..ffef06f
--- /dev/null
+++ b/libion/original-kernel-headers/linux/ion_test.h
@@ -0,0 +1,70 @@
+/*
+ * drivers/staging/android/uapi/ion.h
+ *
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _UAPI_LINUX_ION_TEST_H
+#define _UAPI_LINUX_ION_TEST_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/**
+ * struct ion_test_rw_data - metadata passed to the kernel to read handle
+ * @ptr:	a pointer to an area at least as large as size
+ * @offset:	offset into the ion buffer to start reading
+ * @size:	size to read or write
+ * @write:	1 to write, 0 to read
+ */
+struct ion_test_rw_data {
+	__u64 ptr;
+	__u64 offset;
+	__u64 size;
+	int write;
+	int __padding;
+};
+
+#define ION_IOC_MAGIC		'I'
+
+/**
+ * DOC: ION_IOC_TEST_SET_DMA_BUF - attach a dma buf to the test driver
+ *
+ * Attaches a dma buf fd to the test driver.  Passing a second fd or -1 will
+ * release the first fd.
+ */
+#define ION_IOC_TEST_SET_FD \
+			_IO(ION_IOC_MAGIC, 0xf0)
+
+/**
+ * DOC: ION_IOC_TEST_DMA_MAPPING - read or write memory from a handle as DMA
+ *
+ * Reads or writes the memory from a handle using an uncached mapping.  Can be
+ * used by unit tests to emulate a DMA engine as close as possible.  Only
+ * expected to be used for debugging and testing, may not always be available.
+ */
+#define ION_IOC_TEST_DMA_MAPPING \
+			_IOW(ION_IOC_MAGIC, 0xf1, struct ion_test_rw_data)
+
+/**
+ * DOC: ION_IOC_TEST_KERNEL_MAPPING - read or write memory from a handle
+ *
+ * Reads or writes the memory from a handle using a kernel mapping.  Can be
+ * used by unit tests to test heap map_kernel functions.  Only expected to be
+ * used for debugging and testing, may not always be available.
+ */
+#define ION_IOC_TEST_KERNEL_MAPPING \
+			_IOW(ION_IOC_MAGIC, 0xf2, struct ion_test_rw_data)
+
+
+#endif /* _UAPI_LINUX_ION_H */
diff --git a/libion/tests/Android.mk b/libion/tests/Android.mk
new file mode 100644
index 0000000..8dc7f9d
--- /dev/null
+++ b/libion/tests/Android.mk
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := ion-unit-tests
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
+LOCAL_SHARED_LIBRARIES += libion
+LOCAL_STATIC_LIBRARIES += libgtest_main
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../kernel-headers
+LOCAL_SRC_FILES := \
+	ion_test_fixture.cpp \
+	allocate_test.cpp \
+	formerly_valid_handle_test.cpp \
+	invalid_values_test.cpp \
+	map_test.cpp \
+	device_test.cpp \
+	exit_test.cpp
+include $(BUILD_NATIVE_TEST)
diff --git a/libion/tests/allocate_test.cpp b/libion/tests/allocate_test.cpp
new file mode 100644
index 0000000..e26b302
--- /dev/null
+++ b/libion/tests/allocate_test.cpp
@@ -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 <sys/mman.h>
+
+#include <gtest/gtest.h>
+
+#include <ion/ion.h>
+#include "ion_test_fixture.h"
+
+class Allocate : public IonAllHeapsTest {
+};
+
+TEST_F(Allocate, Allocate)
+{
+    static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            ion_user_handle_t handle = 0;
+            ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, 0, &handle));
+            ASSERT_TRUE(handle != 0);
+            ASSERT_EQ(0, ion_free(m_ionFd, handle));
+        }
+    }
+}
+
+TEST_F(Allocate, AllocateCached)
+{
+    static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            ion_user_handle_t handle = 0;
+            ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED, &handle));
+            ASSERT_TRUE(handle != 0);
+            ASSERT_EQ(0, ion_free(m_ionFd, handle));
+        }
+    }
+}
+
+TEST_F(Allocate, AllocateCachedNeedsSync)
+{
+    static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            ion_user_handle_t handle = 0;
+            ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED_NEEDS_SYNC, &handle));
+            ASSERT_TRUE(handle != 0);
+            ASSERT_EQ(0, ion_free(m_ionFd, handle));
+        }
+    }
+}
+
+TEST_F(Allocate, RepeatedAllocate)
+{
+    static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            ion_user_handle_t handle = 0;
+
+            for (unsigned int i = 0; i < 1024; i++) {
+                SCOPED_TRACE(::testing::Message() << "iteration " << i);
+                ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, 0, &handle));
+                ASSERT_TRUE(handle != 0);
+                ASSERT_EQ(0, ion_free(m_ionFd, handle));
+            }
+        }
+    }
+}
+
+TEST_F(Allocate, Zeroed)
+{
+    void *zeroes = calloc(4096, 1);
+
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int fds[16];
+        for (unsigned int i = 0; i < 16; i++) {
+            int map_fd = -1;
+
+            ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, 0, &map_fd));
+            ASSERT_GE(map_fd, 0);
+
+            void *ptr = NULL;
+            ptr = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED, map_fd, 0);
+            ASSERT_TRUE(ptr != NULL);
+
+            memset(ptr, 0xaa, 4096);
+
+            ASSERT_EQ(0, munmap(ptr, 4096));
+            fds[i] = map_fd;
+        }
+
+        for (unsigned int i = 0; i < 16; i++) {
+            ASSERT_EQ(0, close(fds[i]));
+        }
+
+        int newIonFd = ion_open();
+        int map_fd = -1;
+
+        ASSERT_EQ(0, ion_alloc_fd(newIonFd, 4096, 0, heapMask, 0, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        void *ptr = NULL;
+        ptr = mmap(NULL, 4096, PROT_READ, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        ASSERT_EQ(0, memcmp(ptr, zeroes, 4096));
+
+        ASSERT_EQ(0, munmap(ptr, 4096));
+        ASSERT_EQ(0, close(map_fd));
+    }
+
+    free(zeroes);
+
+}
+
+TEST_F(Allocate, Large)
+{
+    for (unsigned int heapMask : m_allHeaps) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        ion_user_handle_t handle = 0;
+        ASSERT_EQ(-ENOMEM, ion_alloc(m_ionFd, 3UL*1024*1024*1024, 0, heapMask, 0, &handle));
+    }
+}
diff --git a/libion/tests/device_test.cpp b/libion/tests/device_test.cpp
new file mode 100644
index 0000000..6f6e1bd
--- /dev/null
+++ b/libion/tests/device_test.cpp
@@ -0,0 +1,568 @@
+/*
+ * 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 <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/ion_test.h>
+
+#include <gtest/gtest.h>
+
+#include <ion/ion.h>
+
+#include "ion_test_fixture.h"
+
+#define ALIGN(x,y) (((x) + ((y) - 1)) & ~((y) - 1))
+
+class Device : public IonAllHeapsTest {
+ public:
+    virtual void SetUp();
+    virtual void TearDown();
+    int m_deviceFd;
+    void readDMA(int fd, void *buf, size_t size);
+    void writeDMA(int fd, void *buf, size_t size);
+    void readKernel(int fd, void *buf, size_t size);
+    void writeKernel(int fd, void *buf, size_t size);
+    void blowCache();
+    void dirtyCache(void *ptr, size_t size);
+};
+
+void Device::SetUp()
+{
+    IonAllHeapsTest::SetUp();
+    m_deviceFd = open("/dev/ion-test", O_RDWR);
+    ASSERT_GE(m_deviceFd, 0);
+}
+
+void Device::TearDown()
+{
+    ASSERT_EQ(0, close(m_deviceFd));
+    IonAllHeapsTest::TearDown();
+}
+
+void Device::readDMA(int fd, void *buf, size_t size)
+{
+    ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, fd));
+    struct ion_test_rw_data ion_test_rw_data = {
+            .ptr = (uint64_t)buf,
+            .offset = 0,
+            .size = size,
+            .write = 0,
+    };
+
+    ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_DMA_MAPPING, &ion_test_rw_data));
+    ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, -1));
+}
+
+void Device::writeDMA(int fd, void *buf, size_t size)
+{
+    ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, fd));
+    struct ion_test_rw_data ion_test_rw_data = {
+            .ptr = (uint64_t)buf,
+            .offset = 0,
+            .size = size,
+            .write = 1,
+    };
+
+    ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_DMA_MAPPING, &ion_test_rw_data));
+    ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, -1));
+}
+
+void Device::readKernel(int fd, void *buf, size_t size)
+{
+    ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, fd));
+    struct ion_test_rw_data ion_test_rw_data = {
+            .ptr = (uint64_t)buf,
+            .offset = 0,
+            .size = size,
+            .write = 0,
+    };
+
+    ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_KERNEL_MAPPING, &ion_test_rw_data));
+    ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, -1));
+}
+
+void Device::writeKernel(int fd, void *buf, size_t size)
+{
+    ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, fd));
+    struct ion_test_rw_data ion_test_rw_data = {
+            .ptr = (uint64_t)buf,
+            .offset = 0,
+            .size = size,
+            .write = 1,
+    };
+
+    ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_KERNEL_MAPPING, &ion_test_rw_data));
+    ASSERT_EQ(0, ioctl(m_deviceFd, ION_IOC_TEST_SET_FD, -1));
+}
+
+void Device::blowCache()
+{
+    const size_t bigger_than_cache = 8*1024*1024;
+    void *buf1 = malloc(bigger_than_cache);
+    void *buf2 = malloc(bigger_than_cache);
+    memset(buf1, 0xaa, bigger_than_cache);
+    memcpy(buf2, buf1, bigger_than_cache);
+    free(buf1);
+    free(buf2);
+}
+
+void Device::dirtyCache(void *ptr, size_t size)
+{
+    /* try to dirty cache lines */
+    for (size_t i = size-1; i > 0; i--) {
+        ((volatile char *)ptr)[i];
+        ((char *)ptr)[i] = i;
+    }
+}
+
+TEST_F(Device, KernelReadCached)
+{
+    void *alloc = malloc(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int map_fd = -1;
+        unsigned int flags = ION_FLAG_CACHED;
+
+        ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        void *ptr;
+        ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        for (int i = 0; i < 4096; i++)
+            ((char *)ptr)[i] = i;
+
+        ((char*)buf)[4096] = 0x12;
+        readKernel(map_fd, buf, 4096);
+        ASSERT_EQ(((char*)buf)[4096], 0x12);
+
+        for (int i = 0; i < 4096; i++)
+            ASSERT_EQ((char)i, ((char *)buf)[i]);
+
+        ASSERT_EQ(0, munmap(ptr, 4096));
+        ASSERT_EQ(0, close(map_fd));
+    }
+
+    free(alloc);
+}
+
+TEST_F(Device, KernelWriteCached)
+{
+    void *alloc = malloc(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+    for (int i = 0; i < 4096; i++)
+        ((char *)buf)[i] = i;
+
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int map_fd = -1;
+        unsigned int flags = ION_FLAG_CACHED;
+
+        ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        void *ptr;
+        ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        dirtyCache(ptr, 4096);
+
+        writeKernel(map_fd, buf, 4096);
+
+        for (int i = 0; i < 4096; i++)
+            ASSERT_EQ((char)i, ((char *)ptr)[i]) << i;
+
+        ASSERT_EQ(0, munmap(ptr, 4096));
+        ASSERT_EQ(0, close(map_fd));
+    }
+
+    free(alloc);
+}
+
+TEST_F(Device, DMAReadCached)
+{
+    void *alloc = malloc(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int map_fd = -1;
+        unsigned int flags = ION_FLAG_CACHED;
+
+        ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        void *ptr;
+        ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        for (int i = 0; i < 4096; i++)
+            ((char *)ptr)[i] = i;
+
+        readDMA(map_fd, buf, 4096);
+
+        for (int i = 0; i < 4096; i++)
+            ASSERT_EQ((char)i, ((char *)buf)[i]);
+
+        ASSERT_EQ(0, munmap(ptr, 4096));
+        ASSERT_EQ(0, close(map_fd));
+    }
+
+    free(alloc);
+}
+
+TEST_F(Device, DMAWriteCached)
+{
+    void *alloc = malloc(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+    for (int i = 0; i < 4096; i++)
+        ((char *)buf)[i] = i;
+
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int map_fd = -1;
+        unsigned int flags = ION_FLAG_CACHED;
+
+        ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        void *ptr;
+        ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        dirtyCache(ptr, 4096);
+
+        writeDMA(map_fd, buf, 4096);
+
+        for (int i = 0; i < 4096; i++)
+            ASSERT_EQ((char)i, ((char *)ptr)[i]) << i;
+
+        ASSERT_EQ(0, munmap(ptr, 4096));
+        ASSERT_EQ(0, close(map_fd));
+    }
+
+    free(alloc);
+}
+
+TEST_F(Device, KernelReadCachedNeedsSync)
+{
+    void *alloc = malloc(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int map_fd = -1;
+        unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+        ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        void *ptr;
+        ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        for (int i = 0; i < 4096; i++)
+            ((char *)ptr)[i] = i;
+
+        ((char*)buf)[4096] = 0x12;
+        readKernel(map_fd, buf, 4096);
+        ASSERT_EQ(((char*)buf)[4096], 0x12);
+
+        for (int i = 0; i < 4096; i++)
+            ASSERT_EQ((char)i, ((char *)buf)[i]);
+
+        ASSERT_EQ(0, munmap(ptr, 4096));
+        ASSERT_EQ(0, close(map_fd));
+    }
+
+    free(alloc);
+}
+
+TEST_F(Device, KernelWriteCachedNeedsSync)
+{
+    void *alloc = malloc(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+    for (int i = 0; i < 4096; i++)
+        ((char *)buf)[i] = i;
+
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int map_fd = -1;
+        unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+        ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        void *ptr;
+        ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        dirtyCache(ptr, 4096);
+
+        writeKernel(map_fd, buf, 4096);
+
+        for (int i = 0; i < 4096; i++)
+            ASSERT_EQ((char)i, ((char *)ptr)[i]) << i;
+
+        ASSERT_EQ(0, munmap(ptr, 4096));
+        ASSERT_EQ(0, close(map_fd));
+    }
+
+    free(alloc);
+}
+
+TEST_F(Device, DMAReadCachedNeedsSync)
+{
+    void *alloc = malloc(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int map_fd = -1;
+        unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+        ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        void *ptr;
+        ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        for (int i = 0; i < 4096; i++)
+            ((char *)ptr)[i] = i;
+
+        ion_sync_fd(m_ionFd, map_fd);
+
+        readDMA(map_fd, buf, 4096);
+
+        for (int i = 0; i < 4096; i++)
+            ASSERT_EQ((char)i, ((char *)buf)[i]);
+
+        ASSERT_EQ(0, munmap(ptr, 4096));
+        ASSERT_EQ(0, close(map_fd));
+    }
+
+    free(alloc);
+}
+
+TEST_F(Device, DMAWriteCachedNeedsSync)
+{
+    void *alloc = malloc(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+    for (int i = 0; i < 4096; i++)
+        ((char *)buf)[i] = i;
+
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int map_fd = -1;
+        unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+        ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        void *ptr;
+        ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        dirtyCache(ptr, 4096);
+
+        writeDMA(map_fd, buf, 4096);
+
+        ion_sync_fd(m_ionFd, map_fd);
+
+        for (int i = 0; i < 4096; i++)
+            ASSERT_EQ((char)i, ((char *)ptr)[i]) << i;
+
+        ASSERT_EQ(0, munmap(ptr, 4096));
+        ASSERT_EQ(0, close(map_fd));
+    }
+
+    free(alloc);
+}
+TEST_F(Device, KernelRead)
+{
+    void *alloc = malloc(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int map_fd = -1;
+        unsigned int flags = 0;
+
+        ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        void *ptr;
+        ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        for (int i = 0; i < 4096; i++)
+            ((char *)ptr)[i] = i;
+
+        ((char*)buf)[4096] = 0x12;
+        readKernel(map_fd, buf, 4096);
+        ASSERT_EQ(((char*)buf)[4096], 0x12);
+
+        for (int i = 0; i < 4096; i++)
+            ASSERT_EQ((char)i, ((char *)buf)[i]);
+
+        ASSERT_EQ(0, munmap(ptr, 4096));
+        ASSERT_EQ(0, close(map_fd));
+    }
+
+    free(alloc);
+}
+
+TEST_F(Device, KernelWrite)
+{
+    void *alloc = malloc(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+    for (int i = 0; i < 4096; i++)
+        ((char *)buf)[i] = i;
+
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int map_fd = -1;
+        unsigned int flags = 0;
+
+        ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        void *ptr;
+        ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        dirtyCache(ptr, 4096);
+
+        writeKernel(map_fd, buf, 4096);
+
+        for (int i = 0; i < 4096; i++)
+            ASSERT_EQ((char)i, ((char *)ptr)[i]) << i;
+
+        ASSERT_EQ(0, munmap(ptr, 4096));
+        ASSERT_EQ(0, close(map_fd));
+    }
+
+    free(alloc);
+}
+
+TEST_F(Device, DMARead)
+{
+    void *alloc = malloc(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int map_fd = -1;
+        unsigned int flags = 0;
+
+        ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        void *ptr;
+        ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        for (int i = 0; i < 4096; i++)
+            ((char *)ptr)[i] = i;
+
+        readDMA(map_fd, buf, 4096);
+
+        for (int i = 0; i < 4096; i++)
+            ASSERT_EQ((char)i, ((char *)buf)[i]);
+
+        ASSERT_EQ(0, munmap(ptr, 4096));
+        ASSERT_EQ(0, close(map_fd));
+    }
+
+    free(alloc);
+}
+
+TEST_F(Device, DMAWrite)
+{
+    void *alloc = malloc(8192 + 1024);
+    void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+
+    for (int i = 0; i < 4096; i++)
+        ((char *)buf)[i] = i;
+
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int map_fd = -1;
+        unsigned int flags = 0;
+
+        ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        void *ptr;
+        ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        dirtyCache(ptr, 4096);
+
+        writeDMA(map_fd, buf, 4096);
+
+        for (int i = 0; i < 4096; i++)
+            ASSERT_EQ((char)i, ((char *)ptr)[i]) << i;
+
+        ASSERT_EQ(0, munmap(ptr, 4096));
+        ASSERT_EQ(0, close(map_fd));
+    }
+
+    free(alloc);
+}
+
+TEST_F(Device, IsCached)
+{
+    void *buf = malloc(4096);
+
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int map_fd = -1;
+        unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+        ASSERT_EQ(0, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, flags, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        void *ptr;
+        ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        dirtyCache(ptr, 4096);
+
+        readDMA(map_fd, buf, 4096);
+
+        bool same = true;
+        for (int i = 4096-16; i >= 0; i -= 16)
+            if (((char *)buf)[i] != i)
+                same = false;
+        ASSERT_FALSE(same);
+
+        ASSERT_EQ(0, munmap(ptr, 4096));
+        ASSERT_EQ(0, close(map_fd));
+    }
+}
diff --git a/libion/tests/exit_test.cpp b/libion/tests/exit_test.cpp
new file mode 100644
index 0000000..cdd3e27
--- /dev/null
+++ b/libion/tests/exit_test.cpp
@@ -0,0 +1,227 @@
+/*
+ * 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 <sys/mman.h>
+
+#include <gtest/gtest.h>
+
+#include <ion/ion.h>
+
+#include "ion_test_fixture.h"
+
+class Exit : public IonAllHeapsTest {
+};
+
+TEST_F(Exit, WithAlloc)
+{
+    static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            EXPECT_EXIT({
+                ion_user_handle_t handle = 0;
+
+                ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, 0, &handle));
+                ASSERT_TRUE(handle != 0);
+                exit(0);
+            }, ::testing::ExitedWithCode(0), "");
+        }
+    }
+}
+
+TEST_F(Exit, WithAllocFd)
+{
+    static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            EXPECT_EXIT({
+                int handle_fd = -1;
+
+                ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &handle_fd));
+                ASSERT_NE(-1, handle_fd);
+                exit(0);
+            }, ::testing::ExitedWithCode(0), "");
+        }
+    }
+}
+
+TEST_F(Exit, WithRepeatedAllocFd)
+{
+    static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            for (unsigned int i = 0; i < 1024; i++) {
+                SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+                SCOPED_TRACE(::testing::Message() << "size " << size);
+                ASSERT_EXIT({
+                    int handle_fd = -1;
+
+                    ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &handle_fd));
+                    ASSERT_NE(-1, handle_fd);
+                    exit(0);
+                }, ::testing::ExitedWithCode(0), "")
+                        << "failed on heap " << heapMask
+                        << " and size " << size
+                        << " on iteration " << i;
+            }
+        }
+    }
+}
+
+
+TEST_F(Exit, WithMapping)
+{
+    static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            EXPECT_EXIT({
+                int map_fd = -1;
+
+                ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &map_fd));
+                ASSERT_GE(map_fd, 0);
+
+                void *ptr;
+                ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+                ASSERT_TRUE(ptr != NULL);
+                exit(0);
+            }, ::testing::ExitedWithCode(0), "");
+        }
+    }
+
+}
+
+TEST_F(Exit, WithPartialMapping)
+{
+    static const size_t allocationSizes[] = {64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            EXPECT_EXIT({
+                int map_fd = -1;
+
+                ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &map_fd));
+                ASSERT_GE(map_fd, 0);
+
+                void *ptr;
+                ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+                ASSERT_TRUE(ptr != NULL);
+
+                ASSERT_EQ(0, munmap(ptr, size / 2));
+                exit(0);
+            }, ::testing::ExitedWithCode(0), "");
+        }
+    }
+}
+
+TEST_F(Exit, WithMappingCached)
+{
+    static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            EXPECT_EXIT({
+                int map_fd = -1;
+
+                ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED, &map_fd));
+                ASSERT_GE(map_fd, 0);
+
+                void *ptr;
+                ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+                ASSERT_TRUE(ptr != NULL);
+                exit(0);
+            }, ::testing::ExitedWithCode(0), "");
+        }
+    }
+
+}
+
+TEST_F(Exit, WithPartialMappingCached)
+{
+    static const size_t allocationSizes[] = {64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            EXPECT_EXIT({
+                int map_fd = -1;
+
+                ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED, &map_fd));
+                ASSERT_GE(map_fd, 0);
+
+                void *ptr;
+                ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+                ASSERT_TRUE(ptr != NULL);
+
+                ASSERT_EQ(0, munmap(ptr, size / 2));
+                exit(0);
+            }, ::testing::ExitedWithCode(0), "");
+        }
+    }
+}
+
+TEST_F(Exit, WithMappingNeedsSync)
+{
+    static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            EXPECT_EXIT({
+                int map_fd = -1;
+
+                ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC, &map_fd));
+                ASSERT_GE(map_fd, 0);
+
+                void *ptr;
+                ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+                ASSERT_TRUE(ptr != NULL);
+                exit(0);
+            }, ::testing::ExitedWithCode(0), "");
+        }
+    }
+
+}
+
+TEST_F(Exit, WithPartialMappingNeedsSync)
+{
+    static const size_t allocationSizes[] = {64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            EXPECT_EXIT({
+                int map_fd = -1;
+
+                ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC, &map_fd));
+                ASSERT_GE(map_fd, 0);
+
+                void *ptr;
+                ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+                ASSERT_TRUE(ptr != NULL);
+
+                ASSERT_EQ(0, munmap(ptr, size / 2));
+                exit(0);
+            }, ::testing::ExitedWithCode(0), "");
+        }
+    }
+}
diff --git a/libion/tests/formerly_valid_handle_test.cpp b/libion/tests/formerly_valid_handle_test.cpp
new file mode 100644
index 0000000..01ab8f3
--- /dev/null
+++ b/libion/tests/formerly_valid_handle_test.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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 <sys/mman.h>
+
+#include <gtest/gtest.h>
+
+#include <ion/ion.h>
+
+#include "ion_test_fixture.h"
+
+class FormerlyValidHandle : public IonTest {
+ public:
+    virtual void SetUp();
+    virtual void TearDown();
+    ion_user_handle_t m_handle;
+};
+
+void FormerlyValidHandle::SetUp()
+{
+    IonTest::SetUp();
+    ASSERT_EQ(0, ion_alloc(m_ionFd, 4096, 0, 1/* ion_env->m_firstHeap */, 0, &m_handle));
+    ASSERT_TRUE(m_handle != 0);
+    ASSERT_EQ(0, ion_free(m_ionFd, m_handle));
+}
+
+void FormerlyValidHandle::TearDown()
+{
+    m_handle = 0;
+}
+
+TEST_F(FormerlyValidHandle, free)
+{
+	ASSERT_EQ(-EINVAL, ion_free(m_ionFd, m_handle));
+}
+
+TEST_F(FormerlyValidHandle, map)
+{
+    int map_fd;
+    unsigned char *ptr;
+
+    ASSERT_EQ(-EINVAL, ion_map(m_ionFd, m_handle, 4096, PROT_READ, 0, 0, &ptr, &map_fd));
+}
+
+TEST_F(FormerlyValidHandle, share)
+{
+    int share_fd;
+
+    ASSERT_EQ(-EINVAL, ion_share(m_ionFd, m_handle, &share_fd));
+}
diff --git a/libion/tests/invalid_values_test.cpp b/libion/tests/invalid_values_test.cpp
new file mode 100644
index 0000000..77fea17
--- /dev/null
+++ b/libion/tests/invalid_values_test.cpp
@@ -0,0 +1,186 @@
+/*
+ * 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 <sys/mman.h>
+
+#include <gtest/gtest.h>
+
+#include <ion/ion.h>
+
+#include "ion_test_fixture.h"
+
+class InvalidValues : public IonAllHeapsTest {
+ public:
+    virtual void SetUp();
+    virtual void TearDown();
+    ion_user_handle_t m_validHandle;
+    int m_validShareFd;
+    ion_user_handle_t const m_badHandle = -1;
+};
+
+void InvalidValues::SetUp()
+{
+    IonAllHeapsTest::SetUp();
+    ASSERT_EQ(0, ion_alloc(m_ionFd, 4096, 0, m_firstHeap, 0, &m_validHandle))
+      << m_ionFd << " " << m_firstHeap;
+    ASSERT_TRUE(m_validHandle != 0);
+    ASSERT_EQ(0, ion_share(m_ionFd, m_validHandle, &m_validShareFd));
+}
+
+void InvalidValues::TearDown()
+{
+    ASSERT_EQ(0, ion_free(m_ionFd, m_validHandle));
+    ASSERT_EQ(0, close(m_validShareFd));
+    m_validHandle = 0;
+    IonAllHeapsTest::TearDown();
+}
+
+TEST_F(InvalidValues, ion_close)
+{
+    EXPECT_EQ(-EBADF, ion_close(-1));
+}
+
+TEST_F(InvalidValues, ion_alloc)
+{
+    ion_user_handle_t handle;
+    /* invalid ion_fd */
+    int ret = ion_alloc(0, 4096, 0, m_firstHeap, 0, &handle);
+    EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY);
+    /* invalid ion_fd */
+    EXPECT_EQ(-EBADF, ion_alloc(-1, 4096, 0, m_firstHeap, 0, &handle));
+    /* no heaps */
+    EXPECT_EQ(-ENODEV, ion_alloc(m_ionFd, 4096, 0, 0, 0, &handle));
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        /* zero size */
+        EXPECT_EQ(-EINVAL, ion_alloc(m_ionFd, 0, 0, heapMask, 0, &handle));
+        /* too large size */
+        EXPECT_EQ(-EINVAL, ion_alloc(m_ionFd, -1, 0, heapMask, 0, &handle));
+        /* bad alignment */
+        EXPECT_EQ(-EINVAL, ion_alloc(m_ionFd, 4096, -1, heapMask, 0, &handle));
+        /* NULL handle */
+        EXPECT_EQ(-EINVAL, ion_alloc(m_ionFd, 4096, 0, heapMask, 0, NULL));
+    }
+}
+
+TEST_F(InvalidValues, ion_alloc_fd)
+{
+    int fd;
+    /* invalid ion_fd */
+    int ret = ion_alloc_fd(0, 4096, 0, m_firstHeap, 0, &fd);
+    EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY);
+    /* invalid ion_fd */
+    EXPECT_EQ(-EBADF, ion_alloc_fd(-1, 4096, 0, m_firstHeap, 0, &fd));
+    /* no heaps */
+    EXPECT_EQ(-ENODEV, ion_alloc_fd(m_ionFd, 4096, 0, 0, 0, &fd));
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        /* zero size */
+        EXPECT_EQ(-EINVAL, ion_alloc_fd(m_ionFd, 0, 0, heapMask, 0, &fd));
+        /* too large size */
+        EXPECT_EQ(-EINVAL, ion_alloc_fd(m_ionFd, -1, 0, heapMask, 0, &fd));
+        /* bad alignment */
+        EXPECT_EQ(-EINVAL, ion_alloc_fd(m_ionFd, 4096, -1, heapMask, 0, &fd));
+        /* NULL handle */
+        EXPECT_EQ(-EINVAL, ion_alloc_fd(m_ionFd, 4096, 0, heapMask, 0, NULL));
+    }
+}
+
+TEST_F(InvalidValues, ion_free)
+{
+    /* invalid ion fd */
+    int ret = ion_free(0, m_validHandle);
+    EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY);
+    /* invalid ion fd */
+    EXPECT_EQ(-EBADF, ion_free(-1, m_validHandle));
+    /* zero handle */
+    EXPECT_EQ(-EINVAL, ion_free(m_ionFd, 0));
+    /* bad handle */
+    EXPECT_EQ(-EINVAL, ion_free(m_ionFd, m_badHandle));
+}
+
+TEST_F(InvalidValues, ion_map)
+{
+    int map_fd;
+    unsigned char *ptr;
+
+    /* invalid ion fd */
+    int ret = ion_map(0, m_validHandle, 4096, PROT_READ, 0, 0, &ptr, &map_fd);
+    EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY);
+    /* invalid ion fd */
+    EXPECT_EQ(-EBADF, ion_map(-1, m_validHandle, 4096, PROT_READ, 0, 0, &ptr, &map_fd));
+    /* zero handle */
+    EXPECT_EQ(-EINVAL, ion_map(m_ionFd, 0, 4096, PROT_READ, 0, 0, &ptr, &map_fd));
+    /* bad handle */
+    EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_badHandle, 4096, PROT_READ, 0, 0, &ptr, &map_fd));
+    /* zero length */
+    EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 0, PROT_READ, 0, 0, &ptr, &map_fd));
+    /* bad prot */
+    EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 4096, -1, 0, 0, &ptr, &map_fd));
+    /* bad offset */
+    EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 4096, PROT_READ, 0, -1, &ptr, &map_fd));
+    /* NULL ptr */
+    EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 4096, PROT_READ, 0, 0, NULL, &map_fd));
+    /* NULL map_fd */
+    EXPECT_EQ(-EINVAL, ion_map(m_ionFd, m_validHandle, 4096, PROT_READ, 0, 0, &ptr, NULL));
+}
+
+TEST_F(InvalidValues, ion_share)
+{
+    int share_fd;
+
+    /* invalid ion fd */
+    int ret = ion_share(0, m_validHandle, &share_fd);
+    EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY);
+    /* invalid ion fd */
+    EXPECT_EQ(-EBADF, ion_share(-1, m_validHandle, &share_fd));
+    /* zero handle */
+    EXPECT_EQ(-EINVAL, ion_share(m_ionFd, 0, &share_fd));
+    /* bad handle */
+    EXPECT_EQ(-EINVAL, ion_share(m_ionFd, m_badHandle, &share_fd));
+    /* NULL share_fd */
+    EXPECT_EQ(-EINVAL, ion_share(m_ionFd, m_validHandle, NULL));
+}
+
+TEST_F(InvalidValues, ion_import)
+{
+    ion_user_handle_t handle;
+
+    /* invalid ion fd */
+    int ret = ion_import(0, m_validShareFd, &handle);
+    EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY);
+    /* invalid ion fd */
+    EXPECT_EQ(-EBADF, ion_import(-1, m_validShareFd, &handle));
+    /* bad share_fd */
+    EXPECT_EQ(-EINVAL, ion_import(m_ionFd, 0, &handle));
+    /* invalid share_fd */
+    EXPECT_EQ(-EBADF, ion_import(m_ionFd, -1, &handle));
+    /* NULL handle */
+    EXPECT_EQ(-EINVAL, ion_import(m_ionFd, m_validShareFd, NULL));
+}
+
+TEST_F(InvalidValues, ion_sync_fd)
+{
+    /* invalid ion fd */
+    int ret = ion_sync_fd(0, m_validShareFd);
+    EXPECT_TRUE(ret == -EINVAL || ret == -ENOTTY);
+    /* invalid ion fd */
+    EXPECT_EQ(-EBADF, ion_sync_fd(-1, m_validShareFd));
+    /* bad share_fd */
+    EXPECT_EQ(-EINVAL, ion_sync_fd(m_ionFd, 0));
+    /* invalid share_fd */
+    EXPECT_EQ(-EBADF, ion_sync_fd(m_ionFd, -1));
+}
diff --git a/libion/tests/ion_test_fixture.cpp b/libion/tests/ion_test_fixture.cpp
new file mode 100644
index 0000000..e20c730
--- /dev/null
+++ b/libion/tests/ion_test_fixture.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <ion/ion.h>
+
+#include "ion_test_fixture.h"
+
+IonTest::IonTest() : m_ionFd(-1)
+{
+}
+
+void IonTest::SetUp() {
+    m_ionFd = ion_open();
+    ASSERT_GE(m_ionFd, 0);
+}
+
+void IonTest::TearDown() {
+    ion_close(m_ionFd);
+}
+
+IonAllHeapsTest::IonAllHeapsTest() :
+        m_firstHeap(0),
+        m_lastHeap(0),
+        m_allHeaps()
+{
+}
+
+void IonAllHeapsTest::SetUp() {
+    int fd = ion_open();
+    ASSERT_GE(fd, 0);
+
+    for (int i = 1; i != 0; i <<= 1) {
+        ion_user_handle_t handle = 0;
+        int ret;
+        ret = ion_alloc(fd, 4096, 0, i, 0, &handle);
+        if (ret == 0 && handle != 0) {
+            ion_free(fd, handle);
+            if (!m_firstHeap) {
+                m_firstHeap = i;
+            }
+            m_lastHeap = i;
+            m_allHeaps.push_back(i);
+        } else {
+            ASSERT_EQ(-ENODEV, ret);
+        }
+    }
+    ion_close(fd);
+
+    EXPECT_NE(0U, m_firstHeap);
+    EXPECT_NE(0U, m_lastHeap);
+
+    RecordProperty("Heaps", m_allHeaps.size());
+    IonTest::SetUp();
+}
+
+void IonAllHeapsTest::TearDown() {
+    IonTest::TearDown();
+}
diff --git a/libion/tests/ion_test_fixture.h b/libion/tests/ion_test_fixture.h
new file mode 100644
index 0000000..4098214
--- /dev/null
+++ b/libion/tests/ion_test_fixture.h
@@ -0,0 +1,46 @@
+/*
+ * 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 ION_TEST_FIXTURE_H_
+#define ION_TEST_FIXTURE_H_
+
+#include <gtest/gtest.h>
+
+using ::testing::Test;
+
+class IonTest : public virtual Test {
+ public:
+    IonTest();
+	virtual ~IonTest() {};
+	virtual void SetUp();
+	virtual void TearDown();
+	int m_ionFd;
+};
+
+class IonAllHeapsTest : public IonTest {
+ public:
+    IonAllHeapsTest();
+    virtual ~IonAllHeapsTest() {};
+    virtual void SetUp();
+    virtual void TearDown();
+
+    unsigned int m_firstHeap;
+    unsigned int m_lastHeap;
+
+    std::vector<unsigned int> m_allHeaps;
+};
+
+#endif /* ION_TEST_FIXTURE_H_ */
diff --git a/libion/tests/map_test.cpp b/libion/tests/map_test.cpp
new file mode 100644
index 0000000..c006dc8
--- /dev/null
+++ b/libion/tests/map_test.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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 <sys/mman.h>
+
+#include <gtest/gtest.h>
+
+#include <ion/ion.h>
+
+#include "ion_test_fixture.h"
+
+class Map : public IonAllHeapsTest {
+};
+
+TEST_F(Map, MapHandle)
+{
+    static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            ion_user_handle_t handle = 0;
+
+            ASSERT_EQ(0, ion_alloc(m_ionFd, size, 0, heapMask, 0, &handle));
+            ASSERT_TRUE(handle != 0);
+
+            int map_fd = -1;
+            unsigned char *ptr = NULL;
+            ASSERT_EQ(0, ion_map(m_ionFd, handle, size, PROT_READ | PROT_WRITE, MAP_SHARED, 0, &ptr, &map_fd));
+            ASSERT_TRUE(ptr != NULL);
+            ASSERT_GE(map_fd, 0);
+
+            ASSERT_EQ(0, close(map_fd));
+
+            ASSERT_EQ(0, ion_free(m_ionFd, handle));
+
+            memset(ptr, 0xaa, size);
+
+            ASSERT_EQ(0, munmap(ptr, size));
+        }
+    }
+}
+
+TEST_F(Map, MapFd)
+{
+    static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            int map_fd = -1;
+
+            ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, 0, &map_fd));
+            ASSERT_GE(map_fd, 0);
+
+            void *ptr;
+            ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+            ASSERT_TRUE(ptr != NULL);
+
+            ASSERT_EQ(0, close(map_fd));
+
+            memset(ptr, 0xaa, size);
+
+            ASSERT_EQ(0, munmap(ptr, size));
+        }
+    }
+}
+
+TEST_F(Map, MapOffset)
+{
+    for (unsigned int heapMask : m_allHeaps) {
+        SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+        int map_fd = -1;
+
+        ASSERT_EQ(0, ion_alloc_fd(m_ionFd, PAGE_SIZE * 2, 0, heapMask, 0, &map_fd));
+        ASSERT_GE(map_fd, 0);
+
+        unsigned char *ptr;
+        ptr = (unsigned char *)mmap(NULL, PAGE_SIZE * 2, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+        ASSERT_TRUE(ptr != NULL);
+
+        memset(ptr, 0, PAGE_SIZE);
+        memset(ptr + PAGE_SIZE, 0xaa, PAGE_SIZE);
+
+        ASSERT_EQ(0, munmap(ptr, PAGE_SIZE * 2));
+
+        ptr = (unsigned char *)mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, PAGE_SIZE);
+        ASSERT_TRUE(ptr != NULL);
+
+        ASSERT_EQ(ptr[0], 0xaa);
+        ASSERT_EQ(ptr[PAGE_SIZE - 1], 0xaa);
+
+        ASSERT_EQ(0, munmap(ptr, PAGE_SIZE));
+
+        ASSERT_EQ(0, close(map_fd));
+    }
+}
+
+TEST_F(Map, MapCached)
+{
+    static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            int map_fd = -1;
+            unsigned int flags = ION_FLAG_CACHED;
+
+            ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, flags, &map_fd));
+            ASSERT_GE(map_fd, 0);
+
+            void *ptr;
+            ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+            ASSERT_TRUE(ptr != NULL);
+
+            ASSERT_EQ(0, close(map_fd));
+
+            memset(ptr, 0xaa, size);
+
+            ASSERT_EQ(0, munmap(ptr, size));
+        }
+    }
+}
+
+TEST_F(Map, MapCachedNeedsSync)
+{
+    static const size_t allocationSizes[] = {4*1024, 64*1024, 1024*1024, 2*1024*1024};
+    for (unsigned int heapMask : m_allHeaps) {
+        for (size_t size : allocationSizes) {
+            SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
+            SCOPED_TRACE(::testing::Message() << "size " << size);
+            int map_fd = -1;
+            unsigned int flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+
+            ASSERT_EQ(0, ion_alloc_fd(m_ionFd, size, 0, heapMask, flags, &map_fd));
+            ASSERT_GE(map_fd, 0);
+
+            void *ptr;
+            ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0);
+            ASSERT_TRUE(ptr != NULL);
+
+            ASSERT_EQ(0, close(map_fd));
+
+            memset(ptr, 0xaa, size);
+
+            ASSERT_EQ(0, munmap(ptr, size));
+        }
+    }
+}
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/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 7f20e5b..0f502c0 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -9,13 +9,11 @@
 PIXELFLINGER_SRC_FILES:= \
     codeflinger/ARMAssemblerInterface.cpp \
     codeflinger/ARMAssemblerProxy.cpp \
-    codeflinger/ARMAssembler.cpp \
     codeflinger/CodeCache.cpp \
     codeflinger/GGLAssembler.cpp \
     codeflinger/load_store.cpp \
     codeflinger/blending.cpp \
     codeflinger/texturing.cpp \
-    codeflinger/disassem.c \
 	codeflinger/tinyutils/SharedBuffer.cpp \
 	codeflinger/tinyutils/VectorImpl.cpp \
 	fixed.cpp.arm \
@@ -39,6 +37,8 @@
 endif
 
 ifeq ($(TARGET_ARCH),arm)
+PIXELFLINGER_SRC_FILES += codeflinger/ARMAssembler.cpp
+PIXELFLINGER_SRC_FILES += codeflinger/disassem.c
 # special optimization flags for pixelflinger
 PIXELFLINGER_CFLAGS += -fstrict-aliasing -fomit-frame-pointer
 endif
@@ -52,6 +52,14 @@
 
 LOCAL_SHARED_LIBRARIES := libcutils liblog
 
+ifeq ($(TARGET_ARCH),aarch64)
+PIXELFLINGER_SRC_FILES += arch-aarch64/t32cb16blend.S
+PIXELFLINGER_SRC_FILES += arch-aarch64/col32cb16blend.S
+PIXELFLINGER_SRC_FILES += codeflinger/Aarch64Assembler.cpp
+PIXELFLINGER_SRC_FILES += codeflinger/Aarch64Disassembler.cpp
+PIXELFLINGER_CFLAGS += -fstrict-aliasing -fomit-frame-pointer
+endif
+
 #
 # Shared library
 #
diff --git a/libpixelflinger/arch-aarch64/col32cb16blend.S b/libpixelflinger/arch-aarch64/col32cb16blend.S
new file mode 100644
index 0000000..aa969a4
--- /dev/null
+++ b/libpixelflinger/arch-aarch64/col32cb16blend.S
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+    .text
+    .align
+
+    .global scanline_col32cb16blend_aarch64
+
+//
+// This function alpha blends a fixed color into a destination scanline, using
+// the formula:
+//
+//     d = s + (((a + (a >> 7)) * d) >> 8)
+//
+// where d is the destination pixel,
+//       s is the source color,
+//       a is the alpha channel of the source color.
+//
+
+// x0 = destination buffer pointer
+// w1 = color value
+// w2 = count
+
+
+scanline_col32cb16blend_aarch64:
+
+    lsr         w5, w1, #24                     // shift down alpha
+    mov         w9, #0xff                       // create mask
+    add         w5, w5, w5, lsr #7              // add in top bit
+    mov         w4, #256                        // create #0x100
+    sub         w5, w4, w5                      // invert alpha
+    and         w10, w1, #0xff                  // extract red
+    and         w12, w9, w1, lsr #8             // extract green
+    and         w4,  w9, w1, lsr #16            // extract blue
+    lsl         w10, w10, #5                    // prescale red
+    lsl         w12, w12, #6                    // prescale green
+    lsl         w4,  w4,  #5                    // prescale blue
+    lsr         w9,  w9,  #2                    // create dest green mask
+
+1:
+    ldrh        w8, [x0]                        // load dest pixel
+    subs        w2, w2, #1                      // decrement loop counter
+    lsr         w6, w8, #11                     // extract dest red
+    and         w7, w9, w8, lsr #5              // extract dest green
+    and         w8, w8, #0x1f                   // extract dest blue
+
+    madd        w6, w6, w5, w10                 // dest red * alpha + src red
+    madd        w7, w7, w5, w12                 // dest green * alpha + src green
+    madd        w8, w8, w5, w4                  // dest blue * alpha + src blue
+
+    lsr         w6, w6, #8                      // shift down red
+    lsr         w7, w7, #8                      // shift down green
+    lsl         w6, w6, #11                     // shift red into 565
+    orr         w6, w6, w7, lsl #5              // shift green into 565
+    orr         w6, w6, w8, lsr #8              // shift blue into 565
+
+    strh        w6, [x0], #2                    // store pixel to dest, update ptr
+    b.ne        1b                              // if count != 0, loop
+
+    ret
+
+
+
diff --git a/libpixelflinger/arch-aarch64/t32cb16blend.S b/libpixelflinger/arch-aarch64/t32cb16blend.S
new file mode 100644
index 0000000..b62ed36
--- /dev/null
+++ b/libpixelflinger/arch-aarch64/t32cb16blend.S
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+    .text
+    .align
+
+    .global scanline_t32cb16blend_aarch64
+
+/*
+ * .macro pixel
+ *
+ *  This macro alpha blends RGB565 original pixel located in either
+ *  top or bottom 16 bits of DREG register with SRC 32 bit pixel value
+ *  and writes the result to FB register
+ *
+ * \DREG is a 32-bit register containing *two* original destination RGB565
+ *       pixels, with the even one in the low-16 bits, and the odd one in the
+ *       high 16 bits.
+ *
+ * \SRC is a 32-bit 0xAABBGGRR pixel value, with pre-multiplied colors.
+ *
+ * \FB is a target register that will contain the blended pixel values.
+ *
+ * \ODD is either 0 or 1 and indicates if we're blending the lower or
+ *      upper 16-bit pixels in DREG into FB
+ *
+ *
+ * clobbered: w6, w7, w16, w17, w18
+ *
+ */
+
+.macro pixel,   DREG, SRC, FB, ODD
+
+    // SRC = 0xAABBGGRR
+    lsr     w7, \SRC, #24               // sA
+    add     w7, w7, w7, lsr #7          // sA + (sA >> 7)
+    mov     w6, #0x100
+    sub     w7, w6, w7                  // sA = 0x100 - (sA+(sA>>7))
+
+1:
+
+.if \ODD //Blending odd pixel present in top 16 bits of DREG register
+
+    // red
+    lsr     w16, \DREG, #(16 + 11)
+    mul     w16, w7, w16
+    lsr     w6, \SRC, #3
+    and     w6, w6, #0x1F
+    add     w16, w6, w16, lsr #8
+    cmp     w16, #0x1F
+    orr     w17, \FB, #(0x1F<<(16 + 11))
+    orr     w18, \FB, w16, lsl #(16 + 11)
+    csel    \FB, w17, w18, hi
+        // green
+        and     w6, \DREG, #(0x3F<<(16 + 5))
+        lsr     w17,w6,#(16+5)
+        mul     w6, w7, w17
+        lsr     w16, \SRC, #(8+2)
+        and     w16, w16, #0x3F
+        add     w6, w16, w6, lsr #8
+        cmp     w6, #0x3F
+        orr     w17, \FB, #(0x3F<<(16 + 5))
+        orr     w18, \FB, w6, lsl #(16 + 5)
+        csel    \FB, w17, w18, hi
+            // blue
+            and     w16, \DREG, #(0x1F << 16)
+            lsr     w17,w16,#16
+            mul     w16, w7, w17
+            lsr     w6, \SRC, #(8+8+3)
+            and     w6, w6, #0x1F
+            add     w16, w6, w16, lsr #8
+            cmp     w16, #0x1F
+            orr     w17, \FB, #(0x1F << 16)
+            orr     w18, \FB, w16, lsl #16
+            csel    \FB, w17, w18, hi
+
+.else //Blending even pixel present in bottom 16 bits of DREG register
+
+    // red
+    lsr     w16, \DREG, #11
+    and     w16, w16, #0x1F
+    mul     w16, w7, w16
+    lsr     w6, \SRC, #3
+    and     w6, w6, #0x1F
+    add     w16, w6, w16, lsr #8
+    cmp     w16, #0x1F
+    mov     w17, #(0x1F<<11)
+    lsl     w18, w16, #11
+    csel    \FB, w17, w18, hi
+
+
+        // green
+        and     w6, \DREG, #(0x3F<<5)
+        mul     w6, w7, w6
+        lsr     w16, \SRC, #(8+2)
+        and     w16, w16, #0x3F
+        add     w6, w16, w6, lsr #(5+8)
+        cmp     w6, #0x3F
+        orr     w17, \FB, #(0x3F<<5)
+        orr     w18, \FB, w6, lsl #5
+        csel    \FB, w17, w18, hi
+
+            // blue
+            and     w16, \DREG, #0x1F
+            mul     w16, w7, w16
+            lsr     w6, \SRC, #(8+8+3)
+            and     w6, w6, #0x1F
+            add     w16, w6, w16, lsr #8
+            cmp     w16, #0x1F
+            orr     w17, \FB, #0x1F
+            orr     w18, \FB, w16
+            csel    \FB, w17, w18, hi
+
+.endif // End of blending even pixel
+
+.endm // End of pixel macro
+
+
+// x0:  dst ptr
+// x1:  src ptr
+// w2:  count
+// w3:  d
+// w4:  s0
+// w5:  s1
+// w6:  pixel
+// w7:  pixel
+// w8:  free
+// w9:  free
+// w10: free
+// w11: free
+// w12: scratch
+// w14: pixel
+
+scanline_t32cb16blend_aarch64:
+
+    // align DST to 32 bits
+    tst     x0, #0x3
+    b.eq    aligned
+    subs    w2, w2, #1
+    b.lo    return
+
+last:
+    ldr     w4, [x1], #4
+    ldrh    w3, [x0]
+    pixel   w3, w4, w12, 0
+    strh    w12, [x0], #2
+
+aligned:
+    subs    w2, w2, #2
+    b.lo    9f
+
+    // The main loop is unrolled twice and processes 4 pixels
+8:
+    ldp   w4,w5, [x1], #8
+    add     x0, x0, #4
+    // it's all zero, skip this pixel
+    orr     w3, w4, w5
+    cbz     w3, 7f
+
+    // load the destination
+    ldr     w3, [x0, #-4]
+    // stream the destination
+    pixel   w3, w4, w12, 0
+    pixel   w3, w5, w12, 1
+    str     w12, [x0, #-4]
+
+    // 2nd iteration of the loop, don't stream anything
+    subs    w2, w2, #2
+    csel    w4, w5, w4, lt
+    blt     9f
+    ldp     w4,w5, [x1], #8
+    add     x0, x0, #4
+    orr     w3, w4, w5
+    cbz     w3, 7f
+    ldr     w3, [x0, #-4]
+    pixel   w3, w4, w12, 0
+    pixel   w3, w5, w12, 1
+    str     w12, [x0, #-4]
+
+7:  subs    w2, w2, #2
+    bhs     8b
+    mov     w4, w5
+
+9:  adds    w2, w2, #1
+    b.lo    return
+    b       last
+
+return:
+    ret
diff --git a/libpixelflinger/buffer.cpp b/libpixelflinger/buffer.cpp
index af7356b..cbdab5a 100644
--- a/libpixelflinger/buffer.cpp
+++ b/libpixelflinger/buffer.cpp
@@ -93,7 +93,7 @@
         gen.width   = s.width;
         gen.height  = s.height;
         gen.stride  = s.stride;
-        gen.data    = int32_t(s.data);
+        gen.data    = uintptr_t(s.data);
     }
 }
 
diff --git a/libpixelflinger/codeflinger/ARMAssembler.cpp b/libpixelflinger/codeflinger/ARMAssembler.cpp
index 607ed3c..92243da 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.cpp
+++ b/libpixelflinger/codeflinger/ARMAssembler.cpp
@@ -99,8 +99,8 @@
         if (comment >= 0) {
             printf("; %s\n", mComments.valueAt(comment));
         }
-        printf("%08x:    %08x    ", int(i), int(i[0]));
-        ::disassemble((u_int)i);
+        printf("%08x:    %08x    ", uintptr_t(i), int(i[0]));
+        ::disassemble((uintptr_t)i);
         i++;
     }
 }
@@ -186,7 +186,7 @@
 
 #if defined(WITH_LIB_HARDWARE)
     if (__builtin_expect(mQemuTracing, 0)) {
-        int err = qemu_add_mapping(int(base()), name);
+        int err = qemu_add_mapping(uintptr_t(base()), name);
         mQemuTracing = (err >= 0);
     }
 #endif
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
index 073633c..5041999 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
+++ b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
@@ -61,6 +61,29 @@
             ((W&1)<<21) | (((offset&0xF0)<<4)|(offset&0xF));
 }
 
+// The following four functions are required for address manipulation
+// These are virtual functions, which can be overridden by architectures
+// that need special handling of address values (e.g. 64-bit arch)
 
+void ARMAssemblerInterface::ADDR_LDR(int cc, int Rd,
+     int Rn, uint32_t offset)
+{
+    LDR(cc, Rd, Rn, offset);
+}
+void ARMAssemblerInterface::ADDR_STR(int cc, int Rd,
+     int Rn, uint32_t offset)
+{
+    STR(cc, Rd, Rn, offset);
+}
+void ARMAssemblerInterface::ADDR_ADD(int cc, int s,
+     int Rd, int Rn, uint32_t Op2)
+{
+    dataProcessing(opADD, cc, s, Rd, Rn, Op2);
+}
+void ARMAssemblerInterface::ADDR_SUB(int cc, int s,
+     int Rd, int Rn, uint32_t Op2)
+{
+    dataProcessing(opSUB, cc, s, Rd, Rn, Op2);
+}
 }; // namespace android
 
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.h b/libpixelflinger/codeflinger/ARMAssemblerInterface.h
index 9991980..6e0d7c6 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerInterface.h
+++ b/libpixelflinger/codeflinger/ARMAssemblerInterface.h
@@ -63,7 +63,7 @@
     };
 
     enum {
-        CODEGEN_ARCH_ARM = 1, CODEGEN_ARCH_MIPS
+        CODEGEN_ARCH_ARM = 1, CODEGEN_ARCH_MIPS, CODEGEN_ARCH_AARCH64
     };
 
     // -----------------------------------------------------------------------
@@ -331,6 +331,16 @@
     inline void
     SMLAWT(int cc, int Rd, int Rm, int Rs, int Rn) {
         SMLAW(cc, yT, Rd, Rm, Rs, Rn);    }
+
+    // Address loading/storing/manipulation
+    virtual void ADDR_LDR(int cc, int Rd,
+                int Rn, uint32_t offset = __immed12_pre(0));
+    virtual void ADDR_STR (int cc, int Rd,
+                int Rn, uint32_t offset = __immed12_pre(0));
+    virtual void ADDR_ADD(int cc, int s, int Rd,
+                int Rn, uint32_t Op2);
+    virtual void ADDR_SUB(int cc, int s, int Rd,
+                int Rn, uint32_t Op2);
 };
 
 }; // namespace android
diff --git a/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp b/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
index 1c7bc76..816de48 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
+++ b/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
@@ -294,5 +294,18 @@
     mTarget->UBFX(cc, Rd, Rn, lsb, width);
 }
 
+void ARMAssemblerProxy::ADDR_LDR(int cc, int Rd, int Rn, uint32_t offset) {
+     mTarget->ADDR_LDR(cc, Rd, Rn, offset);
+}
+void ARMAssemblerProxy::ADDR_STR(int cc, int Rd, int Rn, uint32_t offset) {
+     mTarget->ADDR_STR(cc, Rd, Rn, offset);
+}
+void ARMAssemblerProxy::ADDR_ADD(int cc, int s, int Rd, int Rn, uint32_t Op2){
+     mTarget->ADDR_ADD(cc, s, Rd, Rn, Op2);
+}
+void ARMAssemblerProxy::ADDR_SUB(int cc, int s, int Rd, int Rn, uint32_t Op2){
+     mTarget->ADDR_SUB(cc, s, Rd, Rn, Op2);
+}
+
 }; // namespace android
 
diff --git a/libpixelflinger/codeflinger/ARMAssemblerProxy.h b/libpixelflinger/codeflinger/ARMAssemblerProxy.h
index 70cb464..b852794 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerProxy.h
+++ b/libpixelflinger/codeflinger/ARMAssemblerProxy.h
@@ -146,6 +146,15 @@
     virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
     virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
 
+    virtual void ADDR_LDR(int cc, int Rd,
+                int Rn, uint32_t offset = __immed12_pre(0));
+    virtual void ADDR_STR (int cc, int Rd,
+                int Rn, uint32_t offset = __immed12_pre(0));
+    virtual void ADDR_ADD(int cc, int s, int Rd,
+                int Rn, uint32_t Op2);
+    virtual void ADDR_SUB(int cc, int s, int Rd,
+                int Rn, uint32_t Op2);
+
 private:
     ARMAssemblerInterface*  mTarget;
 };
diff --git a/libpixelflinger/codeflinger/Aarch64Assembler.cpp b/libpixelflinger/codeflinger/Aarch64Assembler.cpp
new file mode 100644
index 0000000..0e4f7df
--- /dev/null
+++ b/libpixelflinger/codeflinger/Aarch64Assembler.cpp
@@ -0,0 +1,1242 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+#define LOG_TAG "ArmToAarch64Assembler"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <private/pixelflinger/ggl_context.h>
+
+#include "codeflinger/Aarch64Assembler.h"
+#include "codeflinger/CodeCache.h"
+#include "codeflinger/Aarch64Disassembler.h"
+
+
+/*
+** --------------------------------------------
+** Support for Aarch64 in GGLAssembler JIT
+** --------------------------------------------
+**
+** Approach
+** - GGLAssembler and associated files are largely un-changed.
+** - A translator class maps ArmAssemblerInterface calls to
+**   generate AArch64 instructions.
+**
+** ----------------------
+** ArmToAarch64Assembler
+** ----------------------
+**
+** - Subclassed from ArmAssemblerInterface
+**
+** - Translates each ArmAssemblerInterface call to generate
+**   one or more Aarch64 instructions  as necessary.
+**
+** - Does not implement ArmAssemblerInterface portions unused by GGLAssembler
+**   It calls NOT_IMPLEMENTED() for such cases, which in turn logs
+**    a fatal message.
+**
+** - Uses A64_.. series of functions to generate instruction machine code
+**   for Aarch64 instructions. These functions also log the instruction
+**   to LOG, if AARCH64_ASM_DEBUG define is set to 1
+**
+** - Dumps machine code and eqvt assembly if "debug.pf.disasm" option is set
+**   It uses aarch64_disassemble to perform disassembly
+**
+** - Uses register 13 (SP in ARM), 15 (PC in ARM), 16, 17 for storing
+**   intermediate results. GGLAssembler does not use SP and PC as these
+**   registers are marked as reserved. The temporary registers are not
+**   saved/restored on stack as these are caller-saved registers in Aarch64
+**
+** - Uses CSEL instruction to support conditional execution. The result is
+**   stored in a temporary register and then copied to the target register
+**   if the condition is true.
+**
+** - In the case of conditional data transfer instructions, conditional
+**   branch is used to skip over instruction, if the condition is false
+**
+** - Wherever possible, immediate values are transferred to temporary
+**   register prior to processing. This simplifies overall implementation
+**   as instructions requiring immediate values are converted to
+**   move immediate instructions followed by register-register instruction.
+**
+** --------------------------------------------
+** ArmToAarch64Assembler unit test bench
+** --------------------------------------------
+**
+** - Tests ArmToAarch64Assembler interface for all the possible
+**   ways in which GGLAssembler uses ArmAssemblerInterface interface.
+**
+** - Uses test jacket (written in assembly) to set the registers,
+**   condition flags prior to calling generated instruction. It also
+**   copies registers and flags at the end of execution. Caller then
+**   checks if generated code performed correct operation based on
+**   output registers and flags.
+**
+** - Broadly contains three type of tests, (i) data operation tests
+**   (ii) data transfer tests and (iii) LDM/STM tests.
+**
+** ----------------------
+** Aarch64 disassembler
+** ----------------------
+** - This disassembler disassembles only those machine codes which can be
+**   generated by ArmToAarch64Assembler. It has a unit testbench which
+**   tests all the instructions supported by the disassembler.
+**
+** ------------------------------------------------------------------
+** ARMAssembler/ARMAssemblerInterface/ARMAssemblerProxy changes
+** ------------------------------------------------------------------
+**
+** - In existing code, addresses were being handled as 32 bit values at
+**   certain places.
+**
+** - Added a new set of functions for address load/store/manipulation.
+**   These are ADDR_LDR, ADDR_STR, ADDR_ADD, ADDR_SUB and they map to
+**   default 32 bit implementations in ARMAssemblerInterface.
+**
+** - ArmToAarch64Assembler maps these functions to appropriate 64 bit
+**   functions.
+**
+** ----------------------
+** GGLAssembler changes
+** ----------------------
+** - Since ArmToAarch64Assembler can generate 4 Aarch64 instructions for
+**   each call in worst case, the memory required is set to 4 times
+**   ARM memory
+**
+** - Address load/store/manipulation were changed to use new functions
+**   added in the ARMAssemblerInterface.
+**
+*/
+
+
+#define NOT_IMPLEMENTED()  LOG_FATAL("Arm instruction %s not yet implemented\n", __func__)
+
+#define AARCH64_ASM_DEBUG 0
+
+#if AARCH64_ASM_DEBUG
+    #define LOG_INSTR(...) ALOGD("\t" __VA_ARGS__)
+    #define LOG_LABEL(...) ALOGD(__VA_ARGS__)
+#else
+    #define LOG_INSTR(...) ((void)0)
+    #define LOG_LABEL(...) ((void)0)
+#endif
+
+namespace android {
+
+static const char* shift_codes[] =
+{
+    "LSL", "LSR", "ASR", "ROR"
+};
+static const char *cc_codes[] =
+{
+    "EQ", "NE", "CS", "CC", "MI",
+    "PL", "VS", "VC", "HI", "LS",
+    "GE", "LT", "GT", "LE", "AL", "NV"
+};
+
+ArmToAarch64Assembler::ArmToAarch64Assembler(const sp<Assembly>& assembly)
+    :   ARMAssemblerInterface(),
+        mAssembly(assembly)
+{
+    mBase = mPC = (uint32_t *)assembly->base();
+    mDuration = ggl_system_time();
+    mZeroReg = 13;
+    mTmpReg1 = 15;
+    mTmpReg2 = 16;
+    mTmpReg3 = 17;
+}
+
+ArmToAarch64Assembler::ArmToAarch64Assembler(void *base)
+    :   ARMAssemblerInterface(), mAssembly(NULL)
+{
+    mBase = mPC = (uint32_t *)base;
+    mDuration = ggl_system_time();
+    // Regs 13, 15, 16, 17 are used as temporary registers
+    mZeroReg = 13;
+    mTmpReg1 = 15;
+    mTmpReg2 = 16;
+    mTmpReg3 = 17;
+}
+
+ArmToAarch64Assembler::~ArmToAarch64Assembler()
+{
+}
+
+uint32_t* ArmToAarch64Assembler::pc() const
+{
+    return mPC;
+}
+
+uint32_t* ArmToAarch64Assembler::base() const
+{
+    return mBase;
+}
+
+void ArmToAarch64Assembler::reset()
+{
+    if(mAssembly == NULL)
+        mPC = mBase;
+    else
+        mBase = mPC = (uint32_t *)mAssembly->base();
+    mBranchTargets.clear();
+    mLabels.clear();
+    mLabelsInverseMapping.clear();
+    mComments.clear();
+#if AARCH64_ASM_DEBUG
+    ALOGI("RESET\n");
+#endif
+}
+
+int ArmToAarch64Assembler::getCodegenArch()
+{
+    return CODEGEN_ARCH_AARCH64;
+}
+
+// ----------------------------------------------------------------------------
+
+void ArmToAarch64Assembler::disassemble(const char* name)
+{
+    if(name)
+    {
+        printf("%s:\n", name);
+    }
+    size_t count = pc()-base();
+    uint32_t* i = base();
+    while (count--)
+    {
+        ssize_t label = mLabelsInverseMapping.indexOfKey(i);
+        if (label >= 0)
+        {
+            printf("%s:\n", mLabelsInverseMapping.valueAt(label));
+        }
+        ssize_t comment = mComments.indexOfKey(i);
+        if (comment >= 0)
+        {
+            printf("; %s\n", mComments.valueAt(comment));
+        }
+        printf("%p:    %08x    ", i, uint32_t(i[0]));
+        {
+            char instr[256];
+            ::aarch64_disassemble(*i, instr);
+            printf("%s\n", instr);
+        }
+        i++;
+    }
+}
+
+void ArmToAarch64Assembler::comment(const char* string)
+{
+    mComments.add(mPC, string);
+    LOG_INSTR("//%s\n", string);
+}
+
+void ArmToAarch64Assembler::label(const char* theLabel)
+{
+    mLabels.add(theLabel, mPC);
+    mLabelsInverseMapping.add(mPC, theLabel);
+    LOG_LABEL("%s:\n", theLabel);
+}
+
+void ArmToAarch64Assembler::B(int cc, const char* label)
+{
+    mBranchTargets.add(branch_target_t(label, mPC));
+    LOG_INSTR("B%s %s\n", cc_codes[cc], label );
+    *mPC++ = (0x54 << 24) | cc;
+}
+
+void ArmToAarch64Assembler::BL(int cc, const char* label)
+{
+    NOT_IMPLEMENTED(); //Not Required
+}
+
+// ----------------------------------------------------------------------------
+//Prolog/Epilog & Generate...
+// ----------------------------------------------------------------------------
+
+void ArmToAarch64Assembler::prolog()
+{
+    // write prolog code
+    mPrologPC = mPC;
+    *mPC++ = A64_MOVZ_X(mZeroReg,0,0);
+}
+
+void ArmToAarch64Assembler::epilog(uint32_t touched)
+{
+    // write epilog code
+    static const int XLR = 30;
+    *mPC++ = A64_RET(XLR);
+}
+
+int ArmToAarch64Assembler::generate(const char* name)
+{
+    // fixup all the branches
+    size_t count = mBranchTargets.size();
+    while (count--)
+    {
+        const branch_target_t& bt = mBranchTargets[count];
+        uint32_t* target_pc = mLabels.valueFor(bt.label);
+        LOG_ALWAYS_FATAL_IF(!target_pc,
+                "error resolving branch targets, target_pc is null");
+        int32_t offset = int32_t(target_pc - bt.pc);
+        *bt.pc |= (offset & 0x7FFFF) << 5;
+    }
+
+    if(mAssembly != NULL)
+        mAssembly->resize( int(pc()-base())*4 );
+
+    // the instruction cache is flushed by CodeCache
+    const int64_t duration = ggl_system_time() - mDuration;
+    const char * const format = "generated %s (%d ins) at [%p:%p] in %ld ns\n";
+    ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
+
+
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.pf.disasm", value, "0");
+    if (atoi(value) != 0)
+    {
+        printf(format, name, int(pc()-base()), base(), pc(), duration);
+        disassemble(name);
+    }
+    return NO_ERROR;
+}
+
+uint32_t* ArmToAarch64Assembler::pcForLabel(const char* label)
+{
+    return mLabels.valueFor(label);
+}
+
+// ----------------------------------------------------------------------------
+// Data Processing...
+// ----------------------------------------------------------------------------
+void ArmToAarch64Assembler::dataProcessingCommon(int opcode,
+        int s, int Rd, int Rn, uint32_t Op2)
+{
+    if(opcode != opSUB && s == 1)
+    {
+        NOT_IMPLEMENTED(); //Not required
+        return;
+    }
+
+    if(opcode != opSUB && opcode != opADD && opcode != opAND &&
+       opcode != opORR && opcode != opMVN)
+    {
+        NOT_IMPLEMENTED(); //Not required
+        return;
+    }
+
+    if(Op2 == OPERAND_REG_IMM && mAddrMode.reg_imm_shift > 31)
+        {
+        NOT_IMPLEMENTED();
+        return;
+    }
+
+    //Store immediate in temporary register and convert
+    //immediate operation into register operation
+    if(Op2 == OPERAND_IMM)
+    {
+        int imm = mAddrMode.immediate;
+        *mPC++ = A64_MOVZ_W(mTmpReg2, imm & 0x0000FFFF, 0);
+        *mPC++ = A64_MOVK_W(mTmpReg2, (imm >> 16) & 0x0000FFFF, 16);
+        Op2 = mTmpReg2;
+    }
+
+
+    {
+        uint32_t shift;
+        uint32_t amount;
+        uint32_t Rm;
+
+        if(Op2 == OPERAND_REG_IMM)
+        {
+            shift   = mAddrMode.reg_imm_type;
+            amount  = mAddrMode.reg_imm_shift;
+            Rm      = mAddrMode.reg_imm_Rm;
+        }
+        else if(Op2 < OPERAND_REG)
+        {
+            shift   = 0;
+            amount  = 0;
+            Rm      = Op2;
+        }
+        else
+        {
+            NOT_IMPLEMENTED(); //Not required
+            return;
+        }
+
+        switch(opcode)
+        {
+            case opADD: *mPC++ = A64_ADD_W(Rd, Rn, Rm, shift, amount); break;
+            case opAND: *mPC++ = A64_AND_W(Rd, Rn, Rm, shift, amount); break;
+            case opORR: *mPC++ = A64_ORR_W(Rd, Rn, Rm, shift, amount); break;
+            case opMVN: *mPC++ = A64_ORN_W(Rd, Rn, Rm, shift, amount); break;
+            case opSUB: *mPC++ = A64_SUB_W(Rd, Rn, Rm, shift, amount, s);break;
+        };
+
+    }
+}
+
+void ArmToAarch64Assembler::dataProcessing(int opcode, int cc,
+        int s, int Rd, int Rn, uint32_t Op2)
+{
+    uint32_t Wd;
+
+    if(cc != AL)
+        Wd = mTmpReg1;
+    else
+        Wd = Rd;
+
+    if(opcode == opADD || opcode == opAND || opcode == opORR ||opcode == opSUB)
+    {
+        dataProcessingCommon(opcode, s, Wd, Rn, Op2);
+    }
+    else if(opcode == opCMP)
+    {
+        dataProcessingCommon(opSUB, 1, mTmpReg3, Rn, Op2);
+    }
+    else if(opcode == opRSB)
+    {
+        dataProcessingCommon(opSUB, s, Wd, Rn, Op2);
+        dataProcessingCommon(opSUB, s, Wd, mZeroReg, Wd);
+    }
+    else if(opcode == opMOV)
+    {
+        dataProcessingCommon(opORR, 0, Wd, mZeroReg, Op2);
+        if(s == 1)
+        {
+            dataProcessingCommon(opSUB, 1, mTmpReg3, Wd, mZeroReg);
+        }
+    }
+    else if(opcode == opMVN)
+    {
+        dataProcessingCommon(opMVN, s, Wd, mZeroReg, Op2);
+    }
+    else if(opcode == opBIC)
+    {
+        dataProcessingCommon(opMVN, s, mTmpReg3, mZeroReg, Op2);
+        dataProcessingCommon(opAND, s, Wd, Rn, mTmpReg3);
+    }
+    else
+    {
+        NOT_IMPLEMENTED();
+        return;
+    }
+
+    if(cc != AL)
+    {
+        *mPC++ = A64_CSEL_W(Rd, mTmpReg1, Rd, cc);
+    }
+}
+// ----------------------------------------------------------------------------
+// Address Processing...
+// ----------------------------------------------------------------------------
+
+void ArmToAarch64Assembler::ADDR_ADD(int cc,
+        int s, int Rd, int Rn, uint32_t Op2)
+{
+    if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+    if(s  != 0) { NOT_IMPLEMENTED(); return;} //Not required
+
+
+    if(Op2 == OPERAND_REG_IMM && mAddrMode.reg_imm_type == LSL)
+    {
+        int Rm = mAddrMode.reg_imm_Rm;
+        int amount = mAddrMode.reg_imm_shift;
+        *mPC++ = A64_ADD_X_Wm_SXTW(Rd, Rn, Rm, amount);
+    }
+    else if(Op2 < OPERAND_REG)
+    {
+        int Rm = Op2;
+        int amount = 0;
+        *mPC++ = A64_ADD_X_Wm_SXTW(Rd, Rn, Rm, amount);
+    }
+    else if(Op2 == OPERAND_IMM)
+    {
+        int imm = mAddrMode.immediate;
+        *mPC++ = A64_MOVZ_W(mTmpReg1, imm & 0x0000FFFF, 0);
+        *mPC++ = A64_MOVK_W(mTmpReg1, (imm >> 16) & 0x0000FFFF, 16);
+
+        int Rm = mTmpReg1;
+        int amount = 0;
+        *mPC++ = A64_ADD_X_Wm_SXTW(Rd, Rn, Rm, amount);
+    }
+    else
+    {
+        NOT_IMPLEMENTED(); //Not required
+    }
+}
+
+void ArmToAarch64Assembler::ADDR_SUB(int cc,
+        int s, int Rd, int Rn, uint32_t Op2)
+{
+    if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+    if(s  != 0) { NOT_IMPLEMENTED(); return;} //Not required
+
+    if(Op2 == OPERAND_REG_IMM && mAddrMode.reg_imm_type == LSR)
+    {
+        *mPC++ = A64_ADD_W(mTmpReg1, mZeroReg, mAddrMode.reg_imm_Rm,
+                           LSR, mAddrMode.reg_imm_shift);
+        *mPC++ = A64_SUB_X_Wm_SXTW(Rd, Rn, mTmpReg1, 0);
+    }
+    else
+    {
+        NOT_IMPLEMENTED(); //Not required
+    }
+}
+
+// ----------------------------------------------------------------------------
+// multiply...
+// ----------------------------------------------------------------------------
+void ArmToAarch64Assembler::MLA(int cc, int s,int Rd, int Rm, int Rs, int Rn)
+{
+    if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+
+    *mPC++ = A64_MADD_W(Rd, Rm, Rs, Rn);
+    if(s == 1)
+        dataProcessingCommon(opSUB, 1, mTmpReg1, Rd, mZeroReg);
+}
+void ArmToAarch64Assembler::MUL(int cc, int s, int Rd, int Rm, int Rs)
+{
+    if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+    if(s  != 0) { NOT_IMPLEMENTED(); return;} //Not required
+    *mPC++ = A64_MADD_W(Rd, Rm, Rs, mZeroReg);
+}
+void ArmToAarch64Assembler::UMULL(int cc, int s,
+        int RdLo, int RdHi, int Rm, int Rs)
+{
+    NOT_IMPLEMENTED(); //Not required
+}
+void ArmToAarch64Assembler::UMUAL(int cc, int s,
+        int RdLo, int RdHi, int Rm, int Rs)
+{
+    NOT_IMPLEMENTED(); //Not required
+}
+void ArmToAarch64Assembler::SMULL(int cc, int s,
+        int RdLo, int RdHi, int Rm, int Rs)
+{
+    NOT_IMPLEMENTED(); //Not required
+}
+void ArmToAarch64Assembler::SMUAL(int cc, int s,
+        int RdLo, int RdHi, int Rm, int Rs)
+{
+    NOT_IMPLEMENTED(); //Not required
+}
+
+// ----------------------------------------------------------------------------
+// branches relative to PC...
+// ----------------------------------------------------------------------------
+void ArmToAarch64Assembler::B(int cc, uint32_t* pc){
+    NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToAarch64Assembler::BL(int cc, uint32_t* pc){
+    NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToAarch64Assembler::BX(int cc, int Rn){
+    NOT_IMPLEMENTED(); //Not required
+}
+
+// ----------------------------------------------------------------------------
+// data transfer...
+// ----------------------------------------------------------------------------
+enum dataTransferOp
+{
+    opLDR,opLDRB,opLDRH,opSTR,opSTRB,opSTRH
+};
+
+void ArmToAarch64Assembler::dataTransfer(int op, int cc,
+                            int Rd, int Rn, uint32_t op_type, uint32_t size)
+{
+    const int XSP = 31;
+    if(Rn == SP)
+        Rn = XSP;
+
+    if(op_type == OPERAND_IMM)
+    {
+        int addrReg;
+        int imm = mAddrMode.immediate;
+        if(imm >= 0 && imm < (1<<12))
+            *mPC++ = A64_ADD_IMM_X(mTmpReg1, mZeroReg, imm, 0);
+        else if(imm < 0 && -imm < (1<<12))
+            *mPC++ = A64_SUB_IMM_X(mTmpReg1, mZeroReg, -imm, 0);
+        else
+        {
+            NOT_IMPLEMENTED();
+            return;
+        }
+
+        addrReg = Rn;
+        if(mAddrMode.preindex == true || mAddrMode.postindex == true)
+        {
+            *mPC++ = A64_ADD_X(mTmpReg2, addrReg, mTmpReg1);
+            if(mAddrMode.preindex == true)
+                addrReg = mTmpReg2;
+        }
+
+        if(cc != AL)
+            *mPC++ = A64_B_COND(cc^1, 8);
+
+        *mPC++ = A64_LDRSTR_Wm_SXTW_0(op, size, Rd, addrReg, mZeroReg);
+
+        if(mAddrMode.writeback == true)
+            *mPC++ = A64_CSEL_X(Rn, mTmpReg2, Rn, cc);
+    }
+    else if(op_type == OPERAND_REG_OFFSET)
+    {
+        if(cc != AL)
+            *mPC++ = A64_B_COND(cc^1, 8);
+        *mPC++ = A64_LDRSTR_Wm_SXTW_0(op, size, Rd, Rn, mAddrMode.reg_offset);
+
+    }
+    else if(op_type > OPERAND_UNSUPPORTED)
+    {
+        if(cc != AL)
+            *mPC++ = A64_B_COND(cc^1, 8);
+        *mPC++ = A64_LDRSTR_Wm_SXTW_0(op, size, Rd, Rn, mZeroReg);
+    }
+    else
+    {
+        NOT_IMPLEMENTED(); // Not required
+    }
+    return;
+
+}
+void ArmToAarch64Assembler::ADDR_LDR(int cc, int Rd, int Rn, uint32_t op_type)
+{
+    return dataTransfer(opLDR, cc, Rd, Rn, op_type, 64);
+}
+void ArmToAarch64Assembler::ADDR_STR(int cc, int Rd, int Rn, uint32_t op_type)
+{
+    return dataTransfer(opSTR, cc, Rd, Rn, op_type, 64);
+}
+void ArmToAarch64Assembler::LDR(int cc, int Rd, int Rn, uint32_t op_type)
+{
+    return dataTransfer(opLDR, cc, Rd, Rn, op_type);
+}
+void ArmToAarch64Assembler::LDRB(int cc, int Rd, int Rn, uint32_t op_type)
+{
+    return dataTransfer(opLDRB, cc, Rd, Rn, op_type);
+}
+void ArmToAarch64Assembler::STR(int cc, int Rd, int Rn, uint32_t op_type)
+{
+    return dataTransfer(opSTR, cc, Rd, Rn, op_type);
+}
+
+void ArmToAarch64Assembler::STRB(int cc, int Rd, int Rn, uint32_t op_type)
+{
+    return dataTransfer(opSTRB, cc, Rd, Rn, op_type);
+}
+
+void ArmToAarch64Assembler::LDRH(int cc, int Rd, int Rn, uint32_t op_type)
+{
+    return dataTransfer(opLDRH, cc, Rd, Rn, op_type);
+}
+void ArmToAarch64Assembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset)
+{
+    NOT_IMPLEMENTED(); //Not required
+}
+void ArmToAarch64Assembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset)
+{
+    NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToAarch64Assembler::STRH(int cc, int Rd, int Rn, uint32_t op_type)
+{
+    return dataTransfer(opSTRH, cc, Rd, Rn, op_type);
+}
+
+// ----------------------------------------------------------------------------
+// block data transfer...
+// ----------------------------------------------------------------------------
+void ArmToAarch64Assembler::LDM(int cc, int dir,
+        int Rn, int W, uint32_t reg_list)
+{
+    const int XSP = 31;
+    if(cc != AL || dir != IA || W == 0 || Rn != SP)
+    {
+        NOT_IMPLEMENTED();
+        return;
+    }
+
+    for(int i = 0; i < 32; ++i)
+    {
+        if((reg_list & (1 << i)))
+        {
+            int reg = i;
+            int size = 16;
+            *mPC++ = A64_LDR_IMM_PostIndex(reg, XSP, size);
+        }
+    }
+}
+
+void ArmToAarch64Assembler::STM(int cc, int dir,
+        int Rn, int W, uint32_t reg_list)
+{
+    const int XSP = 31;
+    if(cc != AL || dir != DB || W == 0 || Rn != SP)
+    {
+        NOT_IMPLEMENTED();
+        return;
+    }
+
+    for(int i = 31; i >= 0; --i)
+    {
+        if((reg_list & (1 << i)))
+        {
+            int size = -16;
+            int reg  = i;
+            *mPC++ = A64_STR_IMM_PreIndex(reg, XSP, size);
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+// special...
+// ----------------------------------------------------------------------------
+void ArmToAarch64Assembler::SWP(int cc, int Rn, int Rd, int Rm)
+{
+    NOT_IMPLEMENTED(); //Not required
+}
+void ArmToAarch64Assembler::SWPB(int cc, int Rn, int Rd, int Rm)
+{
+    NOT_IMPLEMENTED(); //Not required
+}
+void ArmToAarch64Assembler::SWI(int cc, uint32_t comment)
+{
+    NOT_IMPLEMENTED(); //Not required
+}
+
+// ----------------------------------------------------------------------------
+// DSP instructions...
+// ----------------------------------------------------------------------------
+void ArmToAarch64Assembler::PLD(int Rn, uint32_t offset) {
+    NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToAarch64Assembler::CLZ(int cc, int Rd, int Rm)
+{
+    NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToAarch64Assembler::QADD(int cc,  int Rd, int Rm, int Rn)
+{
+    NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToAarch64Assembler::QDADD(int cc,  int Rd, int Rm, int Rn)
+{
+    NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToAarch64Assembler::QSUB(int cc,  int Rd, int Rm, int Rn)
+{
+    NOT_IMPLEMENTED(); //Not required
+}
+
+void ArmToAarch64Assembler::QDSUB(int cc,  int Rd, int Rm, int Rn)
+{
+    NOT_IMPLEMENTED(); //Not required
+}
+
+// ----------------------------------------------------------------------------
+// 16 x 16 multiplication
+// ----------------------------------------------------------------------------
+void ArmToAarch64Assembler::SMUL(int cc, int xy,
+                int Rd, int Rm, int Rs)
+{
+    if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+
+    if (xy & xyTB)
+        *mPC++ = A64_SBFM_W(mTmpReg1, Rm, 16, 31);
+    else
+        *mPC++ = A64_SBFM_W(mTmpReg1, Rm, 0, 15);
+
+    if (xy & xyBT)
+        *mPC++ = A64_SBFM_W(mTmpReg2, Rs, 16, 31);
+    else
+        *mPC++ = A64_SBFM_W(mTmpReg2, Rs, 0, 15);
+
+    *mPC++ = A64_MADD_W(Rd,mTmpReg1,mTmpReg2, mZeroReg);
+}
+// ----------------------------------------------------------------------------
+// 32 x 16 multiplication
+// ----------------------------------------------------------------------------
+void ArmToAarch64Assembler::SMULW(int cc, int y, int Rd, int Rm, int Rs)
+{
+    if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+
+    if (y & yT)
+        *mPC++ = A64_SBFM_W(mTmpReg1, Rs, 16, 31);
+    else
+        *mPC++ = A64_SBFM_W(mTmpReg1, Rs, 0, 15);
+
+    *mPC++ = A64_SBFM_W(mTmpReg2, Rm, 0, 31);
+    *mPC++ = A64_SMADDL(mTmpReg3,mTmpReg1,mTmpReg2, mZeroReg);
+    *mPC++ = A64_UBFM_X(Rd,mTmpReg3, 16, 47);
+}
+// ----------------------------------------------------------------------------
+// 16 x 16 multiplication and accumulate
+// ----------------------------------------------------------------------------
+void ArmToAarch64Assembler::SMLA(int cc, int xy, int Rd, int Rm, int Rs, int Rn)
+{
+    if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+    if(xy != xyBB) { NOT_IMPLEMENTED(); return;} //Not required
+
+    *mPC++ = A64_SBFM_W(mTmpReg1, Rm, 0, 15);
+    *mPC++ = A64_SBFM_W(mTmpReg2, Rs, 0, 15);
+    *mPC++ = A64_MADD_W(Rd, mTmpReg1, mTmpReg2, Rn);
+}
+
+void ArmToAarch64Assembler::SMLAL(int cc, int xy,
+                int RdHi, int RdLo, int Rs, int Rm)
+{
+    NOT_IMPLEMENTED(); //Not required
+    return;
+}
+
+void ArmToAarch64Assembler::SMLAW(int cc, int y,
+                int Rd, int Rm, int Rs, int Rn)
+{
+    NOT_IMPLEMENTED(); //Not required
+    return;
+}
+
+// ----------------------------------------------------------------------------
+// Byte/half word extract and extend
+// ----------------------------------------------------------------------------
+void ArmToAarch64Assembler::UXTB16(int cc, int Rd, int Rm, int rotate)
+{
+    if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+
+    *mPC++ = A64_EXTR_W(mTmpReg1, Rm, Rm, rotate * 8);
+
+    uint32_t imm = 0x00FF00FF;
+    *mPC++ = A64_MOVZ_W(mTmpReg2, imm & 0xFFFF, 0);
+    *mPC++ = A64_MOVK_W(mTmpReg2, (imm >> 16) & 0x0000FFFF, 16);
+    *mPC++ = A64_AND_W(Rd,mTmpReg1, mTmpReg2);
+}
+
+// ----------------------------------------------------------------------------
+// Bit manipulation
+// ----------------------------------------------------------------------------
+void ArmToAarch64Assembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
+{
+    if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
+    *mPC++ = A64_UBFM_W(Rd, Rn, lsb, lsb + width - 1);
+}
+// ----------------------------------------------------------------------------
+// Shifters...
+// ----------------------------------------------------------------------------
+int ArmToAarch64Assembler::buildImmediate(
+        uint32_t immediate, uint32_t& rot, uint32_t& imm)
+{
+    rot = 0;
+    imm = immediate;
+    return 0; // Always true
+}
+
+
+bool ArmToAarch64Assembler::isValidImmediate(uint32_t immediate)
+{
+    uint32_t rot, imm;
+    return buildImmediate(immediate, rot, imm) == 0;
+}
+
+uint32_t ArmToAarch64Assembler::imm(uint32_t immediate)
+{
+    mAddrMode.immediate = immediate;
+    mAddrMode.writeback = false;
+    mAddrMode.preindex  = false;
+    mAddrMode.postindex = false;
+    return OPERAND_IMM;
+
+}
+
+uint32_t ArmToAarch64Assembler::reg_imm(int Rm, int type, uint32_t shift)
+{
+    mAddrMode.reg_imm_Rm = Rm;
+    mAddrMode.reg_imm_type = type;
+    mAddrMode.reg_imm_shift = shift;
+    return OPERAND_REG_IMM;
+}
+
+uint32_t ArmToAarch64Assembler::reg_rrx(int Rm)
+{
+    NOT_IMPLEMENTED();
+    return OPERAND_UNSUPPORTED;
+}
+
+uint32_t ArmToAarch64Assembler::reg_reg(int Rm, int type, int Rs)
+{
+    NOT_IMPLEMENTED(); //Not required
+    return OPERAND_UNSUPPORTED;
+}
+// ----------------------------------------------------------------------------
+// Addressing modes...
+// ----------------------------------------------------------------------------
+uint32_t ArmToAarch64Assembler::immed12_pre(int32_t immed12, int W)
+{
+    mAddrMode.immediate = immed12;
+    mAddrMode.writeback = W;
+    mAddrMode.preindex  = true;
+    mAddrMode.postindex = false;
+    return OPERAND_IMM;
+}
+
+uint32_t ArmToAarch64Assembler::immed12_post(int32_t immed12)
+{
+    mAddrMode.immediate = immed12;
+    mAddrMode.writeback = true;
+    mAddrMode.preindex  = false;
+    mAddrMode.postindex = true;
+    return OPERAND_IMM;
+}
+
+uint32_t ArmToAarch64Assembler::reg_scale_pre(int Rm, int type,
+        uint32_t shift, int W)
+{
+    if(type != 0 || shift != 0 || W != 0)
+    {
+        NOT_IMPLEMENTED(); //Not required
+        return OPERAND_UNSUPPORTED;
+    }
+    else
+    {
+        mAddrMode.reg_offset = Rm;
+        return OPERAND_REG_OFFSET;
+    }
+}
+
+uint32_t ArmToAarch64Assembler::reg_scale_post(int Rm, int type, uint32_t shift)
+{
+    NOT_IMPLEMENTED(); //Not required
+    return OPERAND_UNSUPPORTED;
+}
+
+uint32_t ArmToAarch64Assembler::immed8_pre(int32_t immed8, int W)
+{
+    mAddrMode.immediate = immed8;
+    mAddrMode.writeback = W;
+    mAddrMode.preindex  = true;
+    mAddrMode.postindex = false;
+    return OPERAND_IMM;
+}
+
+uint32_t ArmToAarch64Assembler::immed8_post(int32_t immed8)
+{
+    mAddrMode.immediate = immed8;
+    mAddrMode.writeback = true;
+    mAddrMode.preindex  = false;
+    mAddrMode.postindex = true;
+    return OPERAND_IMM;
+}
+
+uint32_t ArmToAarch64Assembler::reg_pre(int Rm, int W)
+{
+    if(W != 0)
+    {
+        NOT_IMPLEMENTED(); //Not required
+        return OPERAND_UNSUPPORTED;
+    }
+    else
+    {
+        mAddrMode.reg_offset = Rm;
+        return OPERAND_REG_OFFSET;
+    }
+}
+
+uint32_t ArmToAarch64Assembler::reg_post(int Rm)
+{
+    NOT_IMPLEMENTED(); //Not required
+    return OPERAND_UNSUPPORTED;
+}
+
+// ----------------------------------------------------------------------------
+// A64 instructions
+// ----------------------------------------------------------------------------
+
+static const char * dataTransferOpName[] =
+{
+    "LDR","LDRB","LDRH","STR","STRB","STRH"
+};
+
+static const uint32_t dataTransferOpCode [] =
+{
+    ((0xB8u << 24) | (0x3 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11)),
+    ((0x38u << 24) | (0x3 << 21) | (0x6 << 13) | (0x1 << 12) |(0x1 << 11)),
+    ((0x78u << 24) | (0x3 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11)),
+    ((0xB8u << 24) | (0x1 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11)),
+    ((0x38u << 24) | (0x1 << 21) | (0x6 << 13) | (0x1 << 12) |(0x1 << 11)),
+    ((0x78u << 24) | (0x1 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11))
+};
+uint32_t ArmToAarch64Assembler::A64_LDRSTR_Wm_SXTW_0(uint32_t op,
+                            uint32_t size, uint32_t Rt,
+                            uint32_t Rn, uint32_t Rm)
+{
+    if(size == 32)
+    {
+        LOG_INSTR("%s W%d, [X%d, W%d, SXTW #0]\n",
+                   dataTransferOpName[op], Rt, Rn, Rm);
+        return(dataTransferOpCode[op] | (Rm << 16) | (Rn << 5) | Rt);
+    }
+    else
+    {
+        LOG_INSTR("%s X%d, [X%d, W%d, SXTW #0]\n",
+                  dataTransferOpName[op], Rt, Rn, Rm);
+        return(dataTransferOpCode[op] | (0x1<<30) | (Rm<<16) | (Rn<<5)|Rt);
+    }
+}
+
+uint32_t ArmToAarch64Assembler::A64_STR_IMM_PreIndex(uint32_t Rt,
+                            uint32_t Rn, int32_t simm)
+{
+    if(Rn == 31)
+        LOG_INSTR("STR W%d, [SP, #%d]!\n", Rt, simm);
+    else
+        LOG_INSTR("STR W%d, [X%d, #%d]!\n", Rt, Rn, simm);
+
+    uint32_t imm9 = (unsigned)(simm) & 0x01FF;
+    return (0xB8 << 24) | (imm9 << 12) | (0x3 << 10) | (Rn << 5) | Rt;
+}
+
+uint32_t ArmToAarch64Assembler::A64_LDR_IMM_PostIndex(uint32_t Rt,
+                            uint32_t Rn, int32_t simm)
+{
+    if(Rn == 31)
+        LOG_INSTR("LDR W%d, [SP], #%d\n",Rt,simm);
+    else
+        LOG_INSTR("LDR W%d, [X%d], #%d\n",Rt, Rn, simm);
+
+    uint32_t imm9 = (unsigned)(simm) & 0x01FF;
+    return (0xB8 << 24) | (0x1 << 22) |
+             (imm9 << 12) | (0x1 << 10) | (Rn << 5) | Rt;
+
+}
+uint32_t ArmToAarch64Assembler::A64_ADD_X_Wm_SXTW(uint32_t Rd,
+                               uint32_t Rn,
+                               uint32_t Rm,
+                               uint32_t amount)
+{
+    LOG_INSTR("ADD X%d, X%d, W%d, SXTW #%d\n", Rd, Rn, Rm, amount);
+    return ((0x8B << 24) | (0x1 << 21) |(Rm << 16) |
+              (0x6 << 13) | (amount << 10) | (Rn << 5) | Rd);
+
+}
+
+uint32_t ArmToAarch64Assembler::A64_SUB_X_Wm_SXTW(uint32_t Rd,
+                               uint32_t Rn,
+                               uint32_t Rm,
+                               uint32_t amount)
+{
+    LOG_INSTR("SUB X%d, X%d, W%d, SXTW #%d\n", Rd, Rn, Rm, amount);
+    return ((0xCB << 24) | (0x1 << 21) |(Rm << 16) |
+            (0x6 << 13) | (amount << 10) | (Rn << 5) | Rd);
+
+}
+
+uint32_t ArmToAarch64Assembler::A64_B_COND(uint32_t cc, uint32_t offset)
+{
+    LOG_INSTR("B.%s #.+%d\n", cc_codes[cc], offset);
+    return (0x54 << 24) | ((offset/4) << 5) | (cc);
+
+}
+uint32_t ArmToAarch64Assembler::A64_ADD_X(uint32_t Rd, uint32_t Rn,
+                                          uint32_t Rm, uint32_t shift,
+                                          uint32_t amount)
+{
+    LOG_INSTR("ADD X%d, X%d, X%d, %s #%d\n",
+               Rd, Rn, Rm, shift_codes[shift], amount);
+    return ((0x8B << 24) | (shift << 22) | ( Rm << 16) |
+            (amount << 10) |(Rn << 5) | Rd);
+}
+uint32_t ArmToAarch64Assembler::A64_ADD_IMM_X(uint32_t Rd, uint32_t Rn,
+                                          uint32_t imm, uint32_t shift)
+{
+    LOG_INSTR("ADD X%d, X%d, #%d, LSL #%d\n", Rd, Rn, imm, shift);
+    return (0x91 << 24) | ((shift/12) << 22) | (imm << 10) | (Rn << 5) | Rd;
+}
+
+uint32_t ArmToAarch64Assembler::A64_SUB_IMM_X(uint32_t Rd, uint32_t Rn,
+                                          uint32_t imm, uint32_t shift)
+{
+    LOG_INSTR("SUB X%d, X%d, #%d, LSL #%d\n", Rd, Rn, imm, shift);
+    return (0xD1 << 24) | ((shift/12) << 22) | (imm << 10) | (Rn << 5) | Rd;
+}
+
+uint32_t ArmToAarch64Assembler::A64_ADD_W(uint32_t Rd, uint32_t Rn,
+                                          uint32_t Rm, uint32_t shift,
+                                          uint32_t amount)
+{
+    LOG_INSTR("ADD W%d, W%d, W%d, %s #%d\n",
+               Rd, Rn, Rm, shift_codes[shift], amount);
+    return ((0x0B << 24) | (shift << 22) | ( Rm << 16) |
+            (amount << 10) |(Rn << 5) | Rd);
+}
+
+uint32_t ArmToAarch64Assembler::A64_SUB_W(uint32_t Rd, uint32_t Rn,
+                                          uint32_t Rm, uint32_t shift,
+                                          uint32_t amount,
+                                          uint32_t setflag)
+{
+    if(setflag == 0)
+    {
+        LOG_INSTR("SUB W%d, W%d, W%d, %s #%d\n",
+               Rd, Rn, Rm, shift_codes[shift], amount);
+        return ((0x4B << 24) | (shift << 22) | ( Rm << 16) |
+                (amount << 10) |(Rn << 5) | Rd);
+    }
+    else
+    {
+        LOG_INSTR("SUBS W%d, W%d, W%d, %s #%d\n",
+                   Rd, Rn, Rm, shift_codes[shift], amount);
+        return ((0x6B << 24) | (shift << 22) | ( Rm << 16) |
+                (amount << 10) |(Rn << 5) | Rd);
+    }
+}
+
+uint32_t ArmToAarch64Assembler::A64_AND_W(uint32_t Rd, uint32_t Rn,
+                                          uint32_t Rm, uint32_t shift,
+                                          uint32_t amount)
+{
+    LOG_INSTR("AND W%d, W%d, W%d, %s #%d\n",
+               Rd, Rn, Rm, shift_codes[shift], amount);
+    return ((0x0A << 24) | (shift << 22) | ( Rm << 16) |
+            (amount << 10) |(Rn << 5) | Rd);
+}
+
+uint32_t ArmToAarch64Assembler::A64_ORR_W(uint32_t Rd, uint32_t Rn,
+                                          uint32_t Rm, uint32_t shift,
+                                          uint32_t amount)
+{
+    LOG_INSTR("ORR W%d, W%d, W%d, %s #%d\n",
+               Rd, Rn, Rm, shift_codes[shift], amount);
+    return ((0x2A << 24) | (shift << 22) | ( Rm << 16) |
+            (amount << 10) |(Rn << 5) | Rd);
+}
+
+uint32_t ArmToAarch64Assembler::A64_ORN_W(uint32_t Rd, uint32_t Rn,
+                                          uint32_t Rm, uint32_t shift,
+                                          uint32_t amount)
+{
+    LOG_INSTR("ORN W%d, W%d, W%d, %s #%d\n",
+               Rd, Rn, Rm, shift_codes[shift], amount);
+    return ((0x2A << 24) | (shift << 22) | (0x1 << 21) | ( Rm << 16) |
+            (amount << 10) |(Rn << 5) | Rd);
+}
+
+uint32_t ArmToAarch64Assembler::A64_CSEL_X(uint32_t Rd, uint32_t Rn,
+                                           uint32_t Rm, uint32_t cond)
+{
+    LOG_INSTR("CSEL X%d, X%d, X%d, %s\n", Rd, Rn, Rm, cc_codes[cond]);
+    return ((0x9A << 24)|(0x1 << 23)|(Rm << 16) |(cond << 12)| (Rn << 5) | Rd);
+}
+
+uint32_t ArmToAarch64Assembler::A64_CSEL_W(uint32_t Rd, uint32_t Rn,
+                                           uint32_t Rm, uint32_t cond)
+{
+    LOG_INSTR("CSEL W%d, W%d, W%d, %s\n", Rd, Rn, Rm, cc_codes[cond]);
+    return ((0x1A << 24)|(0x1 << 23)|(Rm << 16) |(cond << 12)| (Rn << 5) | Rd);
+}
+
+uint32_t ArmToAarch64Assembler::A64_RET(uint32_t Rn)
+{
+    LOG_INSTR("RET X%d\n", Rn);
+    return ((0xD6 << 24) | (0x1 << 22) | (0x1F << 16) | (Rn << 5));
+}
+
+uint32_t ArmToAarch64Assembler::A64_MOVZ_X(uint32_t Rd, uint32_t imm,
+                                         uint32_t shift)
+{
+    LOG_INSTR("MOVZ X%d, #0x%x, LSL #%d\n", Rd, imm, shift);
+    return(0xD2 << 24) | (0x1 << 23) | ((shift/16) << 21) |  (imm << 5) | Rd;
+}
+
+uint32_t ArmToAarch64Assembler::A64_MOVK_W(uint32_t Rd, uint32_t imm,
+                                         uint32_t shift)
+{
+    LOG_INSTR("MOVK W%d, #0x%x, LSL #%d\n", Rd, imm, shift);
+    return (0x72 << 24) | (0x1 << 23) | ((shift/16) << 21) | (imm << 5) | Rd;
+}
+
+uint32_t ArmToAarch64Assembler::A64_MOVZ_W(uint32_t Rd, uint32_t imm,
+                                         uint32_t shift)
+{
+    LOG_INSTR("MOVZ W%d, #0x%x, LSL #%d\n", Rd, imm, shift);
+    return(0x52 << 24) | (0x1 << 23) | ((shift/16) << 21) |  (imm << 5) | Rd;
+}
+
+uint32_t ArmToAarch64Assembler::A64_SMADDL(uint32_t Rd, uint32_t Rn,
+                                           uint32_t Rm, uint32_t Ra)
+{
+    LOG_INSTR("SMADDL X%d, W%d, W%d, X%d\n",Rd, Rn, Rm, Ra);
+    return ((0x9B << 24) | (0x1 << 21) | (Rm << 16)|(Ra << 10)|(Rn << 5) | Rd);
+}
+
+uint32_t ArmToAarch64Assembler::A64_MADD_W(uint32_t Rd, uint32_t Rn,
+                                           uint32_t Rm, uint32_t Ra)
+{
+    LOG_INSTR("MADD W%d, W%d, W%d, W%d\n",Rd, Rn, Rm, Ra);
+    return ((0x1B << 24) | (Rm << 16) | (Ra << 10) |(Rn << 5) | Rd);
+}
+
+uint32_t ArmToAarch64Assembler::A64_SBFM_W(uint32_t Rd, uint32_t Rn,
+                                           uint32_t immr, uint32_t imms)
+{
+    LOG_INSTR("SBFM W%d, W%d, #%d, #%d\n", Rd, Rn, immr, imms);
+    return ((0x13 << 24) | (immr << 16) | (imms << 10) | (Rn << 5) | Rd);
+
+}
+uint32_t ArmToAarch64Assembler::A64_UBFM_W(uint32_t Rd, uint32_t Rn,
+                                           uint32_t immr, uint32_t imms)
+{
+    LOG_INSTR("UBFM W%d, W%d, #%d, #%d\n", Rd, Rn, immr, imms);
+    return ((0x53 << 24) | (immr << 16) | (imms << 10) | (Rn << 5) | Rd);
+
+}
+uint32_t ArmToAarch64Assembler::A64_UBFM_X(uint32_t Rd, uint32_t Rn,
+                                           uint32_t immr, uint32_t imms)
+{
+    LOG_INSTR("UBFM X%d, X%d, #%d, #%d\n", Rd, Rn, immr, imms);
+    return ((0xD3 << 24) | (0x1 << 22) |
+            (immr << 16) | (imms << 10) | (Rn << 5) | Rd);
+
+}
+uint32_t ArmToAarch64Assembler::A64_EXTR_W(uint32_t Rd, uint32_t Rn,
+                                           uint32_t Rm, uint32_t lsb)
+{
+    LOG_INSTR("EXTR W%d, W%d, W%d, #%d\n", Rd, Rn, Rm, lsb);
+    return (0x13 << 24)|(0x1 << 23) | (Rm << 16) | (lsb << 10)|(Rn << 5) | Rd;
+}
+
+}; // namespace android
+
diff --git a/libpixelflinger/codeflinger/Aarch64Assembler.h b/libpixelflinger/codeflinger/Aarch64Assembler.h
new file mode 100644
index 0000000..79c912b
--- /dev/null
+++ b/libpixelflinger/codeflinger/Aarch64Assembler.h
@@ -0,0 +1,290 @@
+/*
+ * 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.
+ *
+ * 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 ANDROID_ARMTOAARCH64ASSEMBLER_H
+#define ANDROID_ARMTOAARCH64ASSEMBLER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "tinyutils/Vector.h"
+#include "tinyutils/KeyedVector.h"
+#include "tinyutils/smartpointer.h"
+
+#include "tinyutils/smartpointer.h"
+#include "codeflinger/ARMAssemblerInterface.h"
+#include "codeflinger/CodeCache.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class ArmToAarch64Assembler : public ARMAssemblerInterface
+{
+public:
+                ArmToAarch64Assembler(const sp<Assembly>& assembly);
+                ArmToAarch64Assembler(void *base);
+    virtual     ~ArmToAarch64Assembler();
+
+    uint32_t*   base() const;
+    uint32_t*   pc() const;
+
+
+    void        disassemble(const char* name);
+
+    // ------------------------------------------------------------------------
+    // ARMAssemblerInterface...
+    // ------------------------------------------------------------------------
+
+    virtual void    reset();
+
+    virtual int     generate(const char* name);
+    virtual int     getCodegenArch();
+
+    virtual void    prolog();
+    virtual void    epilog(uint32_t touched);
+    virtual void    comment(const char* string);
+
+
+    // -----------------------------------------------------------------------
+    // shifters and addressing modes
+    // -----------------------------------------------------------------------
+
+    // shifters...
+    virtual bool        isValidImmediate(uint32_t immed);
+    virtual int         buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm);
+
+    virtual uint32_t    imm(uint32_t immediate);
+    virtual uint32_t    reg_imm(int Rm, int type, uint32_t shift);
+    virtual uint32_t    reg_rrx(int Rm);
+    virtual uint32_t    reg_reg(int Rm, int type, int Rs);
+
+    // addressing modes...
+    virtual uint32_t    immed12_pre(int32_t immed12, int W=0);
+    virtual uint32_t    immed12_post(int32_t immed12);
+    virtual uint32_t    reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0);
+    virtual uint32_t    reg_scale_post(int Rm, int type=0, uint32_t shift=0);
+    virtual uint32_t    immed8_pre(int32_t immed8, int W=0);
+    virtual uint32_t    immed8_post(int32_t immed8);
+    virtual uint32_t    reg_pre(int Rm, int W=0);
+    virtual uint32_t    reg_post(int Rm);
+
+
+    virtual void    dataProcessing(int opcode, int cc, int s,
+                                int Rd, int Rn,
+                                uint32_t Op2);
+    virtual void MLA(int cc, int s,
+                int Rd, int Rm, int Rs, int Rn);
+    virtual void MUL(int cc, int s,
+                int Rd, int Rm, int Rs);
+    virtual void UMULL(int cc, int s,
+                int RdLo, int RdHi, int Rm, int Rs);
+    virtual void UMUAL(int cc, int s,
+                int RdLo, int RdHi, int Rm, int Rs);
+    virtual void SMULL(int cc, int s,
+                int RdLo, int RdHi, int Rm, int Rs);
+    virtual void SMUAL(int cc, int s,
+                int RdLo, int RdHi, int Rm, int Rs);
+
+    virtual void B(int cc, uint32_t* pc);
+    virtual void BL(int cc, uint32_t* pc);
+    virtual void BX(int cc, int Rn);
+    virtual void label(const char* theLabel);
+    virtual void B(int cc, const char* label);
+    virtual void BL(int cc, const char* label);
+
+    virtual uint32_t* pcForLabel(const char* label);
+
+    virtual void ADDR_LDR(int cc, int Rd,
+                int Rn, uint32_t offset = 0);
+    virtual void ADDR_ADD(int cc, int s, int Rd,
+                int Rn, uint32_t Op2);
+    virtual void ADDR_SUB(int cc, int s, int Rd,
+                int Rn, uint32_t Op2);
+    virtual void ADDR_STR (int cc, int Rd,
+                int Rn, uint32_t offset = 0);
+
+    virtual void LDR (int cc, int Rd,
+                int Rn, uint32_t offset = 0);
+    virtual void LDRB(int cc, int Rd,
+                int Rn, uint32_t offset = 0);
+    virtual void STR (int cc, int Rd,
+                int Rn, uint32_t offset = 0);
+    virtual void STRB(int cc, int Rd,
+                int Rn, uint32_t offset = 0);
+    virtual void LDRH (int cc, int Rd,
+                int Rn, uint32_t offset = 0);
+    virtual void LDRSB(int cc, int Rd,
+                int Rn, uint32_t offset = 0);
+    virtual void LDRSH(int cc, int Rd,
+                int Rn, uint32_t offset = 0);
+    virtual void STRH (int cc, int Rd,
+                int Rn, uint32_t offset = 0);
+
+
+    virtual void LDM(int cc, int dir,
+                int Rn, int W, uint32_t reg_list);
+    virtual void STM(int cc, int dir,
+                int Rn, int W, uint32_t reg_list);
+
+    virtual void SWP(int cc, int Rn, int Rd, int Rm);
+    virtual void SWPB(int cc, int Rn, int Rd, int Rm);
+    virtual void SWI(int cc, uint32_t comment);
+
+    virtual void PLD(int Rn, uint32_t offset);
+    virtual void CLZ(int cc, int Rd, int Rm);
+    virtual void QADD(int cc, int Rd, int Rm, int Rn);
+    virtual void QDADD(int cc, int Rd, int Rm, int Rn);
+    virtual void QSUB(int cc, int Rd, int Rm, int Rn);
+    virtual void QDSUB(int cc, int Rd, int Rm, int Rn);
+    virtual void SMUL(int cc, int xy,
+                int Rd, int Rm, int Rs);
+    virtual void SMULW(int cc, int y,
+                int Rd, int Rm, int Rs);
+    virtual void SMLA(int cc, int xy,
+                int Rd, int Rm, int Rs, int Rn);
+    virtual void SMLAL(int cc, int xy,
+                int RdHi, int RdLo, int Rs, int Rm);
+    virtual void SMLAW(int cc, int y,
+                int Rd, int Rm, int Rs, int Rn);
+    virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
+    virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
+
+private:
+    ArmToAarch64Assembler(const ArmToAarch64Assembler& rhs);
+    ArmToAarch64Assembler& operator = (const ArmToAarch64Assembler& rhs);
+
+    // -----------------------------------------------------------------------
+    // helper functions
+    // -----------------------------------------------------------------------
+
+    void dataTransfer(int operation, int cc, int Rd, int Rn,
+                      uint32_t operand_type, uint32_t size = 32);
+    void dataProcessingCommon(int opcode, int s,
+                      int Rd, int Rn, uint32_t Op2);
+
+    // -----------------------------------------------------------------------
+    // Aarch64 instructions
+    // -----------------------------------------------------------------------
+    uint32_t A64_B_COND(uint32_t cc, uint32_t offset);
+    uint32_t A64_RET(uint32_t Rn);
+
+    uint32_t A64_LDRSTR_Wm_SXTW_0(uint32_t operation,
+                                uint32_t size, uint32_t Rt,
+                                uint32_t Rn, uint32_t Rm);
+
+    uint32_t A64_STR_IMM_PreIndex(uint32_t Rt, uint32_t Rn, int32_t simm);
+    uint32_t A64_LDR_IMM_PostIndex(uint32_t Rt,uint32_t Rn, int32_t simm);
+
+    uint32_t A64_ADD_X_Wm_SXTW(uint32_t Rd, uint32_t Rn, uint32_t Rm,
+                               uint32_t amount);
+    uint32_t A64_SUB_X_Wm_SXTW(uint32_t Rd, uint32_t Rn, uint32_t Rm,
+                               uint32_t amount);
+
+    uint32_t A64_ADD_IMM_X(uint32_t Rd, uint32_t Rn,
+                           uint32_t imm, uint32_t shift = 0);
+    uint32_t A64_SUB_IMM_X(uint32_t Rd, uint32_t Rn,
+                           uint32_t imm, uint32_t shift = 0);
+
+    uint32_t A64_ADD_X(uint32_t Rd, uint32_t Rn,
+                       uint32_t Rm, uint32_t shift = 0, uint32_t amount = 0);
+    uint32_t A64_ADD_W(uint32_t Rd, uint32_t Rn, uint32_t Rm,
+                       uint32_t shift = 0, uint32_t amount = 0);
+    uint32_t A64_SUB_W(uint32_t Rd, uint32_t Rn, uint32_t Rm,
+                       uint32_t shift = 0, uint32_t amount = 0,
+                       uint32_t setflag = 0);
+    uint32_t A64_AND_W(uint32_t Rd, uint32_t Rn,
+                       uint32_t Rm, uint32_t shift = 0, uint32_t amount = 0);
+    uint32_t A64_ORR_W(uint32_t Rd, uint32_t Rn,
+                       uint32_t Rm, uint32_t shift = 0, uint32_t amount = 0);
+    uint32_t A64_ORN_W(uint32_t Rd, uint32_t Rn,
+                       uint32_t Rm, uint32_t shift = 0, uint32_t amount = 0);
+
+    uint32_t A64_MOVZ_W(uint32_t Rd, uint32_t imm, uint32_t shift);
+    uint32_t A64_MOVZ_X(uint32_t Rd, uint32_t imm, uint32_t shift);
+    uint32_t A64_MOVK_W(uint32_t Rd, uint32_t imm, uint32_t shift);
+
+    uint32_t A64_SMADDL(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t Ra);
+    uint32_t A64_MADD_W(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t Ra);
+
+    uint32_t A64_SBFM_W(uint32_t Rd, uint32_t Rn,
+                        uint32_t immr, uint32_t imms);
+    uint32_t A64_UBFM_W(uint32_t Rd, uint32_t Rn,
+                        uint32_t immr, uint32_t imms);
+    uint32_t A64_UBFM_X(uint32_t Rd, uint32_t Rn,
+                        uint32_t immr, uint32_t imms);
+
+    uint32_t A64_EXTR_W(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t lsb);
+    uint32_t A64_CSEL_X(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t cond);
+    uint32_t A64_CSEL_W(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t cond);
+
+    uint32_t*       mBase;
+    uint32_t*       mPC;
+    uint32_t*       mPrologPC;
+    int64_t         mDuration;
+    uint32_t        mTmpReg1, mTmpReg2, mTmpReg3, mZeroReg;
+
+    struct branch_target_t {
+        inline branch_target_t() : label(0), pc(0) { }
+        inline branch_target_t(const char* l, uint32_t* p)
+            : label(l), pc(p) { }
+        const char* label;
+        uint32_t*   pc;
+    };
+
+    sp<Assembly>    mAssembly;
+    Vector<branch_target_t>                 mBranchTargets;
+    KeyedVector< const char*, uint32_t* >   mLabels;
+    KeyedVector< uint32_t*, const char* >   mLabelsInverseMapping;
+    KeyedVector< uint32_t*, const char* >   mComments;
+
+    enum operand_type_t
+    {
+        OPERAND_REG = 0x20,
+        OPERAND_IMM,
+        OPERAND_REG_IMM,
+        OPERAND_REG_OFFSET,
+        OPERAND_UNSUPPORTED
+    };
+
+    struct addr_mode_t {
+        int32_t         immediate;
+        bool            writeback;
+        bool            preindex;
+        bool            postindex;
+        int32_t         reg_imm_Rm;
+        int32_t         reg_imm_type;
+        uint32_t        reg_imm_shift;
+        int32_t         reg_offset;
+    } mAddrMode;
+
+};
+
+}; // namespace android
+
+#endif //ANDROID_AARCH64ASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/Aarch64Disassembler.cpp b/libpixelflinger/codeflinger/Aarch64Disassembler.cpp
new file mode 100644
index 0000000..4bb97b4
--- /dev/null
+++ b/libpixelflinger/codeflinger/Aarch64Disassembler.cpp
@@ -0,0 +1,316 @@
+/*
+ * 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.
+ *
+ * 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 <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+
+struct disasm_table_entry_t
+{
+    uint32_t       mask;
+    uint32_t       value;
+    const char*    instr_template;
+};
+
+
+static disasm_table_entry_t disasm_table[] =
+{
+    {0xff000000, 0x91000000, "add <xd|sp>, <xn|sp>, #<imm1>, <shift1>"},
+    {0xff000000, 0xd1000000, "sub <xd|sp>, <xn|sp>, #<imm1>, <shift1>"},
+    {0xff200000, 0x8b000000, "add <xd>, <xn>, <xm>, <shift2> #<amt1>"},
+    {0xff200000, 0x0b000000, "add <wd>, <wn>, <wm>, <shift2> #<amt1>"},
+    {0xff200000, 0x4b000000, "sub <wd>, <wn>, <wm>, <shift2> #<amt1>"},
+    {0xff200000, 0x6b000000, "subs <wd>, <wn>, <wm>, <shift2> #<amt1>"},
+    {0xff200000, 0x0a000000, "and <wd>, <wn>, <wm>, <shift2> #<amt1>"},
+    {0xff200000, 0x2a000000, "orr <wd>, <wn>, <wm>, <shift2> #<amt1>"},
+    {0xff200000, 0x2a200000, "orn <wd>, <wn>, <wm>, <shift2> #<amt1>"},
+    {0xff800000, 0x72800000, "movk <wd>, #<imm2>, lsl #<shift3>"},
+    {0xff800000, 0x52800000, "movz <wd>, #<imm2>, lsl #<shift3>"},
+    {0xff800000, 0xd2800000, "movz <xd>, #<imm2>, lsl #<shift3>"},
+    {0xffe00c00, 0x1a800000, "csel <wd>, <wn>, <wm>, <cond1>"},
+    {0xffe00c00, 0x9a800000, "csel <xd>, <xn>, <xm>, <cond1>"},
+    {0xffe00c00, 0x5a800000, "csinv <wd>, <wn>, <wm>, <cond1>"},
+    {0xffe08000, 0x1b000000, "madd <wd>, <wn>, <wm>, <wa>"},
+    {0xffe08000, 0x9b200000, "smaddl <xd>, <wn>, <wm>, <xa>"},
+    {0xffe04c00, 0xb8604800, "ldr <wt>, [<xn|sp>, <r1><m1>, <ext1> #<amt2>]"},
+    {0xffe04c00, 0xb8204800, "str <wt>, [<xn|sp>, <r1><m1>, <ext1> #<amt2>]"},
+    {0xffe04c00, 0xf8604800, "ldr <xt>, [<xn|sp>, <r1><m1>, <ext1> #<amt3>]"},
+    {0xffe04c00, 0xf8204800, "str <xt>, [<xn|sp>, <r1><m1>, <ext1> #<amt3>]"},
+    {0xffe04c00, 0x38604800, "ldrb <wt>, [<xn|sp>, <r1><m1>, <ext1> <amt5>]"},
+    {0xffe04c00, 0x38204800, "strb <wt>, [<xn|sp>, <r1><m1>, <ext1> <amt5>]"},
+    {0xffe04c00, 0x78604800, "ldrh <wt>, [<xn|sp>, <r1><m1>, <ext1> #<amt6>]"},
+    {0xffe04c00, 0x78204800, "strh <wt>, [<xn|sp>, <r1><m1>, <ext1> #<amt6>]"},
+    {0xffe00c00, 0xb8400400, "ldr <wt>, [<xn|sp>], #<simm1>"},
+    {0xffe00c00, 0xb8000c00, "str <wt>, [<xn|sp>, #<simm1>]!"},
+    {0xffc00000, 0x13000000, "sbfm <wd>, <wn>, #<immr1>, #<imms1>"},
+    {0xffc00000, 0x53000000, "ubfm <wd>, <wn>, #<immr1>, #<imms1>"},
+    {0xffc00000, 0xd3400000, "ubfm <xd>, <xn>, #<immr1>, #<imms1>"},
+    {0xffe00000, 0x13800000, "extr <wd>, <wn>, <wm>, #<lsb1>"},
+    {0xff000000, 0x54000000, "b.<cond2> <label1>"},
+    {0xfffffc1f, 0xd65f0000, "ret <xn>"},
+    {0xffe00000, 0x8b200000, "add <xd|sp>, <xn|sp>, <r2><m1>, <ext2> #<amt4>"},
+    {0xffe00000, 0xcb200000, "sub <xd|sp>, <xn|sp>, <r2><m1>, <ext2> #<amt4>"}
+};
+
+static int32_t bits_signed(uint32_t instr, uint32_t msb, uint32_t lsb)
+{
+    int32_t value;
+    value   = ((int32_t)instr) << (31 - msb);
+    value >>= (31 - msb);
+    value >>= lsb;
+    return value;
+}
+static uint32_t bits_unsigned(uint32_t instr, uint32_t msb, uint32_t lsb)
+{
+    uint32_t width = msb - lsb + 1;
+    uint32_t mask  = (1 << width) - 1;
+    return ((instr >> lsb) & mask);
+}
+
+static void get_token(const char *instr, uint32_t index, char *token)
+{
+    uint32_t i, j;
+    for(i = index, j = 0; i < strlen(instr); ++i)
+    {
+        if(instr[index] == '<' && instr[i] == '>')
+        {
+            token[j++] = instr[i];
+            break;
+        }
+        else if(instr[index] != '<' && instr[i] == '<')
+        {
+            break;
+        }
+        else
+        {
+            token[j++] = instr[i];
+        }
+    }
+    token[j] = '\0';
+    return;
+}
+
+
+static const char * token_cc_table[] =
+{
+    "eq", "ne", "cs", "cc", "mi",
+    "pl", "vs", "vc", "hi", "ls",
+    "ge", "lt", "gt", "le", "al", "nv"
+};
+
+static void decode_rx_zr_token(uint32_t reg, const char *prefix, char *instr_part)
+{
+    if(reg == 31)
+        sprintf(instr_part, "%s%s", prefix, "zr");
+    else
+        sprintf(instr_part, "%s%d", prefix, reg);
+}
+
+static void decode_token(uint32_t code, char *token, char *instr_part)
+{
+    if(strcmp(token, "<imm1>") == 0)
+        sprintf(instr_part, "0x%x", bits_unsigned(code, 21,10));
+    else if(strcmp(token, "<imm2>") == 0)
+        sprintf(instr_part, "0x%x", bits_unsigned(code, 20,5));
+    else if(strcmp(token, "<shift1>") == 0)
+        sprintf(instr_part, "lsl #%d", bits_unsigned(code, 23,22) * 12);
+    else if(strcmp(token, "<shift2>") == 0)
+    {
+        static const char * shift2_table[] = { "lsl", "lsr", "asr", "ror"};
+        sprintf(instr_part, "%s", shift2_table[bits_unsigned(code, 23,22)]);
+    }
+    else if(strcmp(token, "<shift3>") == 0)
+        sprintf(instr_part, "%d", bits_unsigned(code, 22,21) * 16);
+    else if(strcmp(token, "<amt1>") == 0)
+        sprintf(instr_part, "%d", bits_unsigned(code, 15,10));
+    else if(strcmp(token, "<amt2>") == 0)
+        sprintf(instr_part, "%d", bits_unsigned(code, 12,12) * 2);
+    else if(strcmp(token, "<amt3>") == 0)
+        sprintf(instr_part, "%d", bits_unsigned(code, 12,12) * 3);
+    else if(strcmp(token, "<amt4>") == 0)
+        sprintf(instr_part, "%d", bits_unsigned(code, 12,10));
+    else if(strcmp(token, "<amt5>") == 0)
+    {
+        static const char * amt5_table[] = {"", "#0"};
+        sprintf(instr_part, "%s", amt5_table[bits_unsigned(code, 12,12)]);
+    }
+    else if(strcmp(token, "<amt6>") == 0)
+        sprintf(instr_part, "%d", bits_unsigned(code, 12,12));
+    else if(strcmp(token, "<simm1>") == 0)
+        sprintf(instr_part, "%d", bits_signed(code, 20,12));
+    else if(strcmp(token, "<immr1>") == 0)
+        sprintf(instr_part, "%d", bits_unsigned(code, 21,16));
+    else if(strcmp(token, "<imms1>") == 0)
+        sprintf(instr_part, "%d", bits_unsigned(code, 15,10));
+    else if(strcmp(token, "<lsb1>") == 0)
+        sprintf(instr_part, "%d", bits_unsigned(code, 15,10));
+    else if(strcmp(token, "<cond1>") == 0)
+        sprintf(instr_part, "%s", token_cc_table[bits_unsigned(code, 15,12)]);
+    else if(strcmp(token, "<cond2>") == 0)
+        sprintf(instr_part, "%s", token_cc_table[bits_unsigned(code, 4,0)]);
+    else if(strcmp(token, "<r1>") == 0)
+    {
+        const char * token_r1_table[] =
+        {
+            "reserved", "reserved", "w", "x",
+            "reserved", "reserved", "w", "x"
+        };
+        sprintf(instr_part, "%s", token_r1_table[bits_unsigned(code, 15,13)]);
+    }
+    else if(strcmp(token, "<r2>") == 0)
+    {
+        static const char * token_r2_table[] =
+        {
+                "w","w","w", "x", "w", "w", "w", "x"
+        };
+        sprintf(instr_part, "%s", token_r2_table[bits_unsigned(code, 15,13)]);
+    }
+    else if(strcmp(token, "<m1>") == 0)
+    {
+        uint32_t reg = bits_unsigned(code, 20,16);
+        if(reg == 31)
+            sprintf(instr_part, "%s", "zr");
+        else
+            sprintf(instr_part, "%d", reg);
+    }
+    else if(strcmp(token, "<ext1>") == 0)
+    {
+        static const char * token_ext1_table[] =
+        {
+             "reserved","reserved","uxtw", "lsl",
+             "reserved","reserved", "sxtw", "sxtx"
+        };
+        sprintf(instr_part, "%s", token_ext1_table[bits_unsigned(code, 15,13)]);
+    }
+    else if(strcmp(token, "<ext2>") == 0)
+    {
+        static const char * token_ext2_table[] =
+        {
+                "uxtb","uxth","uxtw","uxtx",
+                "sxtb","sxth","sxtw","sxtx"
+        };
+        sprintf(instr_part, "%s", token_ext2_table[bits_unsigned(code, 15,13)]);
+    }
+    else if (strcmp(token, "<label1>") == 0)
+    {
+        int32_t offset = bits_signed(code, 23,5) * 4;
+        if(offset > 0)
+            sprintf(instr_part, "#.+%d", offset);
+        else
+            sprintf(instr_part, "#.-%d", -offset);
+    }
+    else if (strcmp(token, "<xn|sp>") == 0)
+    {
+        uint32_t reg = bits_unsigned(code, 9, 5);
+        if(reg == 31)
+            sprintf(instr_part, "%s", "sp");
+        else
+            sprintf(instr_part, "x%d", reg);
+    }
+    else if (strcmp(token, "<xd|sp>") == 0)
+    {
+        uint32_t reg = bits_unsigned(code, 4, 0);
+        if(reg == 31)
+            sprintf(instr_part, "%s", "sp");
+        else
+            sprintf(instr_part, "x%d", reg);
+    }
+    else if (strcmp(token, "<xn>") == 0)
+        decode_rx_zr_token(bits_unsigned(code, 9, 5), "x", instr_part);
+    else if (strcmp(token, "<xd>") == 0)
+        decode_rx_zr_token(bits_unsigned(code, 4, 0), "x", instr_part);
+    else if (strcmp(token, "<xm>") == 0)
+        decode_rx_zr_token(bits_unsigned(code, 20, 16), "x", instr_part);
+    else if (strcmp(token, "<xa>") == 0)
+        decode_rx_zr_token(bits_unsigned(code, 14, 10), "x", instr_part);
+    else if (strcmp(token, "<xt>") == 0)
+        decode_rx_zr_token(bits_unsigned(code, 4, 0), "x", instr_part);
+    else if (strcmp(token, "<wn>") == 0)
+        decode_rx_zr_token(bits_unsigned(code, 9, 5), "w", instr_part);
+    else if (strcmp(token, "<wd>") == 0)
+        decode_rx_zr_token(bits_unsigned(code, 4, 0), "w", instr_part);
+    else if (strcmp(token, "<wm>") == 0)
+        decode_rx_zr_token(bits_unsigned(code, 20, 16), "w", instr_part);
+    else if (strcmp(token, "<wa>") == 0)
+        decode_rx_zr_token(bits_unsigned(code, 14, 10), "w", instr_part);
+    else if (strcmp(token, "<wt>") == 0)
+        decode_rx_zr_token(bits_unsigned(code, 4, 0), "w", instr_part);
+    else
+    {
+        sprintf(instr_part, "error");
+    }
+    return;
+}
+
+int aarch64_disassemble(uint32_t code, char* instr)
+{
+    uint32_t i;
+    char token[256];
+    char instr_part[256];
+
+    if(instr == NULL)
+        return -1;
+
+    bool matched = false;
+    disasm_table_entry_t *entry = NULL;
+    for(i = 0; i < sizeof(disasm_table)/sizeof(disasm_table_entry_t); ++i)
+    {
+        entry = &disasm_table[i];
+        if((code & entry->mask) == entry->value)
+        {
+            matched = true;
+            break;
+        }
+    }
+    if(matched == false)
+    {
+        strcpy(instr, "Unknown Instruction");
+        return -1;
+    }
+    else
+    {
+        uint32_t index = 0;
+        uint32_t length = strlen(entry->instr_template);
+        instr[0] = '\0';
+        do
+        {
+            get_token(entry->instr_template, index, token);
+            if(token[0] == '<')
+            {
+                decode_token(code, token, instr_part);
+                strcat(instr, instr_part);
+            }
+            else
+            {
+                strcat(instr, token);
+            }
+            index += strlen(token);
+        }while(index < length);
+        return 0;
+    }
+}
diff --git a/libpixelflinger/codeflinger/Aarch64Disassembler.h b/libpixelflinger/codeflinger/Aarch64Disassembler.h
new file mode 100644
index 0000000..177d692
--- /dev/null
+++ b/libpixelflinger/codeflinger/Aarch64Disassembler.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * 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 ANDROID_AARCH64DISASSEMBLER_H
+#define ANDROID_AARCH64DISASSEMBLER_H
+
+#include <inttypes.h>
+int aarch64_disassemble(uint32_t code, char* instr);
+
+#endif //ANDROID_AARCH64ASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
index 58fde7e..4fe30d9 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -34,7 +34,7 @@
 
 // ----------------------------------------------------------------------------
 
-#if defined(__arm__)
+#if defined(__arm__) || defined(__aarch64__)
 #include <unistd.h>
 #include <errno.h>
 #endif
@@ -201,7 +201,7 @@
         mCacheInUse += assemblySize;
         mWhen++;
         // synchronize caches...
-#if defined(__arm__) || defined(__mips__)
+#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
         const long base = long(assembly->base());
         const long curr = base + long(assembly->size());
         err = cacheflush(base, curr, 0);
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
index 0cb042e..7f088db 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ b/libpixelflinger/codeflinger/GGLAssembler.cpp
@@ -263,7 +263,7 @@
                 const int mask = GGL_DITHER_SIZE-1;
                 parts.dither = reg_t(regs.obtain());
                 AND(AL, 0, parts.dither.reg, parts.count.reg, imm(mask));
-                ADD(AL, 0, parts.dither.reg, parts.dither.reg, ctxtReg);
+                ADDR_ADD(AL, 0, parts.dither.reg, ctxtReg, parts.dither.reg);
                 LDRB(AL, parts.dither.reg, parts.dither.reg,
                         immed12_pre(GGL_OFFSETOF(ditherMatrix)));
             }
@@ -336,7 +336,7 @@
         build_iterate_z(parts);
         build_iterate_f(parts);
         if (!mAllMasked) {
-            ADD(AL, 0, parts.cbPtr.reg, parts.cbPtr.reg, imm(parts.cbPtr.size>>3));
+            ADDR_ADD(AL, 0, parts.cbPtr.reg, parts.cbPtr.reg, imm(parts.cbPtr.size>>3));
         }
         SUB(AL, S, parts.count.reg, parts.count.reg, imm(1<<16));
         B(PL, "fragment_loop");
@@ -392,7 +392,7 @@
         int Rs = scratches.obtain();
         parts.cbPtr.setTo(obtainReg(), cb_bits);
         CONTEXT_LOAD(Rs, state.buffers.color.stride);
-        CONTEXT_LOAD(parts.cbPtr.reg, state.buffers.color.data);
+        CONTEXT_ADDR_LOAD(parts.cbPtr.reg, state.buffers.color.data);
         SMLABB(AL, Rs, Ry, Rs, Rx);  // Rs = Rx + Ry*Rs
         base_offset(parts.cbPtr, parts.cbPtr, Rs);
         scratches.recycle(Rs);
@@ -428,11 +428,11 @@
         int Rs = dzdx;
         int zbase = scratches.obtain();
         CONTEXT_LOAD(Rs, state.buffers.depth.stride);
-        CONTEXT_LOAD(zbase, state.buffers.depth.data);
+        CONTEXT_ADDR_LOAD(zbase, state.buffers.depth.data);
         SMLABB(AL, Rs, Ry, Rs, Rx);
         ADD(AL, 0, Rs, Rs, reg_imm(parts.count.reg, LSR, 16));
-        ADD(AL, 0, zbase, zbase, reg_imm(Rs, LSL, 1));
-        CONTEXT_STORE(zbase, generated_vars.zbase);
+        ADDR_ADD(AL, 0, zbase, zbase, reg_imm(Rs, LSL, 1));
+        CONTEXT_ADDR_STORE(zbase, generated_vars.zbase);
     }
 
     // init texture coordinates
@@ -445,8 +445,8 @@
     // init coverage factor application (anti-aliasing)
     if (mAA) {
         parts.covPtr.setTo(obtainReg(), 16);
-        CONTEXT_LOAD(parts.covPtr.reg, state.buffers.coverage);
-        ADD(AL, 0, parts.covPtr.reg, parts.covPtr.reg, reg_imm(Rx, LSL, 1));
+        CONTEXT_ADDR_LOAD(parts.covPtr.reg, state.buffers.coverage);
+        ADDR_ADD(AL, 0, parts.covPtr.reg, parts.covPtr.reg, reg_imm(Rx, LSL, 1));
     }
 }
 
@@ -765,8 +765,8 @@
         int depth = scratches.obtain();
         int z = parts.z.reg;
         
-        CONTEXT_LOAD(zbase, generated_vars.zbase);  // stall
-        SUB(AL, 0, zbase, zbase, reg_imm(parts.count.reg, LSR, 15));
+        CONTEXT_ADDR_LOAD(zbase, generated_vars.zbase);  // stall
+        ADDR_SUB(AL, 0, zbase, zbase, reg_imm(parts.count.reg, LSR, 15));
             // above does zbase = zbase + ((count >> 16) << 1)
 
         if (mask & Z_TEST) {
@@ -901,6 +901,10 @@
         AND( AL, 0, d, s, imm(mask) );
         return;
     }
+    else if (getCodegenArch() == CODEGEN_ARCH_AARCH64) {
+        AND( AL, 0, d, s, imm(mask) );
+        return;
+    }
 
     int negative_logic = !isValidImmediate(mask);
     if (negative_logic) {
@@ -990,22 +994,22 @@
 {
     switch (b.size) {
     case 32:
-        ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 2));
+        ADDR_ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 2));
         break;
     case 24:
         if (d.reg == b.reg) {
-            ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 1));
-            ADD(AL, 0, d.reg, d.reg, o.reg);
+            ADDR_ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 1));
+            ADDR_ADD(AL, 0, d.reg, d.reg, o.reg);
         } else {
-            ADD(AL, 0, d.reg, o.reg, reg_imm(o.reg, LSL, 1));
-            ADD(AL, 0, d.reg, d.reg, b.reg);
+            ADDR_ADD(AL, 0, d.reg, o.reg, reg_imm(o.reg, LSL, 1));
+            ADDR_ADD(AL, 0, d.reg, d.reg, b.reg);
         }
         break;
     case 16:
-        ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 1));
+        ADDR_ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 1));
         break;
     case 8:
-        ADD(AL, 0, d.reg, b.reg, o.reg);
+        ADDR_ADD(AL, 0, d.reg, b.reg, o.reg);
         break;
     }
 }
diff --git a/libpixelflinger/codeflinger/GGLAssembler.h b/libpixelflinger/codeflinger/GGLAssembler.h
index d993684..9db20df 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.h
+++ b/libpixelflinger/codeflinger/GGLAssembler.h
@@ -31,6 +31,12 @@
 
 // ----------------------------------------------------------------------------
 
+#define CONTEXT_ADDR_LOAD(REG, FIELD) \
+    ADDR_LDR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
+
+#define CONTEXT_ADDR_STORE(REG, FIELD) \
+    ADDR_STR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
+
 #define CONTEXT_LOAD(REG, FIELD) \
     LDR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
 
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
index 9e3d217..b2cfbb3 100644
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ b/libpixelflinger/codeflinger/texturing.cpp
@@ -356,7 +356,7 @@
             // merge base & offset
             CONTEXT_LOAD(txPtr.reg, generated_vars.texture[i].stride);
             SMLABB(AL, Rx, Ry, txPtr.reg, Rx);               // x+y*stride
-            CONTEXT_LOAD(txPtr.reg, generated_vars.texture[i].data);
+            CONTEXT_ADDR_LOAD(txPtr.reg, generated_vars.texture[i].data);
             base_offset(txPtr, txPtr, Rx);
         } else {
             Scratch scratches(registerFile());
@@ -629,7 +629,7 @@
                 return;
 
             CONTEXT_LOAD(stride,    generated_vars.texture[i].stride);
-            CONTEXT_LOAD(txPtr.reg, generated_vars.texture[i].data);
+            CONTEXT_ADDR_LOAD(txPtr.reg, generated_vars.texture[i].data);
             SMLABB(AL, u, v, stride, u);    // u+v*stride 
             base_offset(txPtr, txPtr, u);
 
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index a5d28b2..bc774f3 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -31,8 +31,11 @@
 
 #include "codeflinger/CodeCache.h"
 #include "codeflinger/GGLAssembler.h"
+#if defined(__arm__)
 #include "codeflinger/ARMAssembler.h"
-#if defined(__mips__)
+#elif defined(__aarch64__)
+#include "codeflinger/Aarch64Assembler.h"
+#elif defined(__mips__)
 #include "codeflinger/MIPSAssembler.h"
 #endif
 //#include "codeflinger/ARMAssemblerOptimizer.h"
@@ -52,7 +55,7 @@
 #   define ANDROID_CODEGEN      ANDROID_CODEGEN_GENERATED
 #endif
 
-#if defined(__arm__) || defined(__mips__)
+#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
 #   define ANDROID_ARM_CODEGEN  1
 #else
 #   define ANDROID_ARM_CODEGEN  0
@@ -68,6 +71,8 @@
 
 #ifdef __mips__
 #define ASSEMBLY_SCRATCH_SIZE   4096
+#elif defined(__aarch64__)
+#define ASSEMBLY_SCRATCH_SIZE   8192
 #else
 #define ASSEMBLY_SCRATCH_SIZE   2048
 #endif
@@ -122,6 +127,9 @@
 extern "C" void scanline_t32cb16_arm(uint16_t *dst, uint32_t *src, size_t ct);
 extern "C" void scanline_col32cb16blend_neon(uint16_t *dst, uint32_t *col, size_t ct);
 extern "C" void scanline_col32cb16blend_arm(uint16_t *dst, uint32_t col, size_t ct);
+#elif defined(__aarch64__)
+extern "C" void scanline_t32cb16blend_aarch64(uint16_t*, uint32_t*, size_t);
+extern "C" void scanline_col32cb16blend_aarch64(uint16_t *dst, uint32_t col, size_t ct);
 #elif defined(__mips__)
 extern "C" void scanline_t32cb16blend_mips(uint16_t*, uint32_t*, size_t);
 #endif
@@ -276,6 +284,8 @@
 
 #if defined(__mips__)
 static CodeCache gCodeCache(32 * 1024);
+#elif defined(__aarch64__)
+static CodeCache gCodeCache(48 * 1024);
 #else
 static CodeCache gCodeCache(12 * 1024);
 #endif
@@ -394,6 +404,8 @@
 #endif
 #if defined(__mips__)
         GGLAssembler assembler( new ArmToMipsAssembler(a) );
+#elif defined(__aarch64__)
+        GGLAssembler assembler( new ArmToAarch64Assembler(a) );
 #endif
         // generate the scanline code for the given needs
         int err = assembler.scanline(c->state.needs, c);
@@ -1717,7 +1729,7 @@
             gen.width   = t.surface.width;
             gen.height  = t.surface.height;
             gen.stride  = t.surface.stride;
-            gen.data    = int32_t(t.surface.data);
+            gen.data    = uintptr_t(t.surface.data);
             gen.dsdx = ti.dsdx;
             gen.dtdx = ti.dtdx;
         }
@@ -1877,7 +1889,7 @@
             struct {
                 int32_t s, sq;
                 int32_t t, tq;
-            };
+            } sqtq;
             struct {
                 int32_t v, q;
             } st[2];
@@ -1916,10 +1928,10 @@
         int32_t t =   tmu.shade.it0 +
                      (tmu.shade.idtdy * ys) + (tmu.shade.idtdx * xs) +
                      ((tmu.shade.idtdx + tmu.shade.idtdy)>>1);
-        tc[i].s  = s;
-        tc[i].t  = t;
-        tc[i].sq = gglMulx(s, q0, iwscale);
-        tc[i].tq = gglMulx(t, q0, iwscale);
+        tc[i].sqtq.s  = s;
+        tc[i].sqtq.t  = t;
+        tc[i].sqtq.sq = gglMulx(s, q0, iwscale);
+        tc[i].sqtq.tq = gglMulx(t, q0, iwscale);
     }
 
     int32_t span = 0;
@@ -2085,6 +2097,8 @@
 #else  // defined(__ARM_HAVE_NEON) && BYTE_ORDER == LITTLE_ENDIAN
     scanline_col32cb16blend_arm(dst, GGL_RGBA_TO_HOST(c->packed8888), ct);
 #endif // defined(__ARM_HAVE_NEON) && BYTE_ORDER == LITTLE_ENDIAN
+#elif ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && defined(__aarch64__))
+    scanline_col32cb16blend_aarch64(dst, GGL_RGBA_TO_HOST(c->packed8888), ct);
 #else
     uint32_t s = GGL_RGBA_TO_HOST(c->packed8888);
     int sA = (s>>24);
@@ -2125,7 +2139,7 @@
     int sR, sG, sB;
     uint32_t s, d;
 
-    if (ct==1 || uint32_t(dst)&2) {
+    if (ct==1 || uintptr_t(dst)&2) {
 last_one:
         s = GGL_RGBA_TO_HOST( *src++ );
         *dst++ = convertAbgr8888ToRgb565(s);
@@ -2157,7 +2171,7 @@
 
 void scanline_t32cb16blend(context_t* c)
 {
-#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || defined(__mips)))
+#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || defined(__mips__) || defined(__aarch64__)))
     int32_t x = c->iterators.xl;
     size_t ct = c->iterators.xr - x;
     int32_t y = c->iterators.y;
@@ -2171,7 +2185,9 @@
 
 #ifdef __arm__
     scanline_t32cb16blend_arm(dst, src, ct);
-#else
+#elif defined(__aarch64__)
+    scanline_t32cb16blend_aarch64(dst, src, ct);
+#elif defined(__mips__)
     scanline_t32cb16blend_mips(dst, src, ct);
 #endif
 #else
diff --git a/libpixelflinger/tests/arch-aarch64/Android.mk b/libpixelflinger/tests/arch-aarch64/Android.mk
new file mode 100644
index 0000000..f096491
--- /dev/null
+++ b/libpixelflinger/tests/arch-aarch64/Android.mk
@@ -0,0 +1,3 @@
+ifeq ($(TARGET_ARCH),aarch64)
+include $(all-subdir-makefiles)
+endif
diff --git a/libpixelflinger/tests/arch-aarch64/assembler/Android.mk b/libpixelflinger/tests/arch-aarch64/assembler/Android.mk
new file mode 100644
index 0000000..10e06c4
--- /dev/null
+++ b/libpixelflinger/tests/arch-aarch64/assembler/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    aarch64_assembler_test.cpp\
+    asm_test_jacket.S
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libpixelflinger
+
+LOCAL_C_INCLUDES := \
+    system/core/libpixelflinger
+
+LOCAL_MODULE:= test-pixelflinger-aarch64-assembler-test
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libpixelflinger/tests/arch-aarch64/assembler/aarch64_assembler_test.cpp b/libpixelflinger/tests/arch-aarch64/assembler/aarch64_assembler_test.cpp
new file mode 100644
index 0000000..d3e57b3
--- /dev/null
+++ b/libpixelflinger/tests/arch-aarch64/assembler/aarch64_assembler_test.cpp
@@ -0,0 +1,782 @@
+/*
+ * 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.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/mman.h>
+#include <cutils/ashmem.h>
+#include <cutils/atomic.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include "codeflinger/ARMAssemblerInterface.h"
+#include "codeflinger/Aarch64Assembler.h"
+using namespace android;
+
+#define TESTS_DATAOP_ENABLE             1
+#define TESTS_DATATRANSFER_ENABLE       1
+#define TESTS_LDMSTM_ENABLE             1
+#define TESTS_REG_CORRUPTION_ENABLE     0
+
+void *instrMem;
+uint32_t  instrMemSize = 128 * 1024;
+char     dataMem[8192];
+
+typedef void (*asm_function_t)();
+extern "C" void asm_test_jacket(asm_function_t function,
+                                int64_t regs[], int32_t flags[]);
+
+#define MAX_32BIT (uint32_t)(((uint64_t)1 << 32) - 1)
+const uint32_t NA = 0;
+const uint32_t NUM_REGS = 32;
+const uint32_t NUM_FLAGS = 16;
+
+enum instr_t
+{
+    INSTR_ADD,
+    INSTR_SUB,
+    INSTR_AND,
+    INSTR_ORR,
+    INSTR_RSB,
+    INSTR_BIC,
+    INSTR_CMP,
+    INSTR_MOV,
+    INSTR_MVN,
+    INSTR_MUL,
+    INSTR_MLA,
+    INSTR_SMULBB,
+    INSTR_SMULBT,
+    INSTR_SMULTB,
+    INSTR_SMULTT,
+    INSTR_SMULWB,
+    INSTR_SMULWT,
+    INSTR_SMLABB,
+    INSTR_UXTB16,
+    INSTR_UBFX,
+    INSTR_ADDR_ADD,
+    INSTR_ADDR_SUB,
+    INSTR_LDR,
+    INSTR_LDRB,
+    INSTR_LDRH,
+    INSTR_ADDR_LDR,
+    INSTR_LDM,
+    INSTR_STR,
+    INSTR_STRB,
+    INSTR_STRH,
+    INSTR_ADDR_STR,
+    INSTR_STM
+};
+
+enum shift_t
+{
+    SHIFT_LSL,
+    SHIFT_LSR,
+    SHIFT_ASR,
+    SHIFT_ROR,
+    SHIFT_NONE
+};
+
+enum offset_t
+{
+    REG_SCALE_OFFSET,
+    REG_OFFSET,
+    IMM8_OFFSET,
+    IMM12_OFFSET,
+    NO_OFFSET
+};
+
+enum cond_t
+{
+    EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV,
+    HS = CS,
+    LO = CC
+};
+
+const char * cc_code[] =
+{
+    "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC",
+    "HI", "LS","GE","LT", "GT", "LE", "AL", "NV"
+};
+
+
+struct dataOpTest_t
+{
+    uint32_t id;
+    instr_t  op;
+    uint32_t preFlag;
+    cond_t   cond;
+    bool     setFlags;
+    uint64_t RnValue;
+    uint64_t RsValue;
+    bool     immediate;
+    uint32_t immValue;
+    uint64_t RmValue;
+    uint32_t shiftMode;
+    uint32_t shiftAmount;
+    uint64_t RdValue;
+    bool     checkRd;
+    uint64_t postRdValue;
+    bool     checkFlag;
+    uint32_t postFlag;
+};
+
+struct dataTransferTest_t
+{
+    uint32_t id;
+    instr_t op;
+    uint32_t preFlag;
+    cond_t   cond;
+    bool     setMem;
+    uint64_t memOffset;
+    uint64_t memValue;
+    uint64_t RnValue;
+    offset_t offsetType;
+    uint64_t RmValue;
+    uint32_t immValue;
+    bool     writeBack;
+    bool     preIndex;
+    bool     postIndex;
+    uint64_t RdValue;
+    uint64_t postRdValue;
+    uint64_t postRnValue;
+    bool     checkMem;
+    uint64_t postMemOffset;
+    uint32_t postMemLength;
+    uint64_t postMemValue;
+};
+
+
+dataOpTest_t dataOpTests [] =
+{
+     {0xA000,INSTR_ADD,AL,AL,0,1,NA,1,MAX_32BIT ,NA,NA,NA,NA,1,0,0,0},
+     {0xA001,INSTR_ADD,AL,AL,0,1,NA,1,MAX_32BIT -1,NA,NA,NA,NA,1,MAX_32BIT,0,0},
+     {0xA002,INSTR_ADD,AL,AL,0,1,NA,0,NA,MAX_32BIT ,NA,NA,NA,1,0,0,0},
+     {0xA003,INSTR_ADD,AL,AL,0,1,NA,0,NA,MAX_32BIT -1,NA,NA,NA,1,MAX_32BIT,0,0},
+     {0xA004,INSTR_ADD,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSL,0,NA,1,0,0,0},
+     {0xA005,INSTR_ADD,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSL,31,NA,1,0x80000001,0,0},
+     {0xA006,INSTR_ADD,AL,AL,0,1,NA,0,0,3,SHIFT_LSR,1,NA,1,2,0,0},
+     {0xA007,INSTR_ADD,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSR,31,NA,1,2,0,0},
+     {0xA008,INSTR_ADD,AL,AL,0,0,NA,0,0,3,SHIFT_ASR,1,NA,1,1,0,0},
+     {0xA009,INSTR_ADD,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_ASR,31,NA,1,0,0,0},
+     {0xA010,INSTR_AND,AL,AL,0,1,NA,1,MAX_32BIT ,0,0,0,NA,1,1,0,0},
+     {0xA011,INSTR_AND,AL,AL,0,1,NA,1,MAX_32BIT -1,0,0,0,NA,1,0,0,0},
+     {0xA012,INSTR_AND,AL,AL,0,1,NA,0,0,MAX_32BIT ,0,0,NA,1,1,0,0},
+     {0xA013,INSTR_AND,AL,AL,0,1,NA,0,0,MAX_32BIT -1,0,0,NA,1,0,0,0},
+     {0xA014,INSTR_AND,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSL,0,NA,1,1,0,0},
+     {0xA015,INSTR_AND,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSL,31,NA,1,0,0,0},
+     {0xA016,INSTR_AND,AL,AL,0,1,NA,0,0,3,SHIFT_LSR,1,NA,1,1,0,0},
+     {0xA017,INSTR_AND,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSR,31,NA,1,1,0,0},
+     {0xA018,INSTR_AND,AL,AL,0,0,NA,0,0,3,SHIFT_ASR,1,NA,1,0,0,0},
+     {0xA019,INSTR_AND,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_ASR,31,NA,1,1,0,0},
+     {0xA020,INSTR_ORR,AL,AL,0,3,NA,1,MAX_32BIT ,0,0,0,NA,1,MAX_32BIT,0,0},
+     {0xA021,INSTR_ORR,AL,AL,0,2,NA,1,MAX_32BIT -1,0,0,0,NA,1,MAX_32BIT-1,0,0},
+     {0xA022,INSTR_ORR,AL,AL,0,3,NA,0,0,MAX_32BIT ,0,0,NA,1,MAX_32BIT,0,0},
+     {0xA023,INSTR_ORR,AL,AL,0,2,NA,0,0,MAX_32BIT -1,0,0,NA,1,MAX_32BIT-1,0,0},
+     {0xA024,INSTR_ORR,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSL,0,NA,1,MAX_32BIT,0,0},
+     {0xA025,INSTR_ORR,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSL,31,NA,1,0x80000001,0,0},
+     {0xA026,INSTR_ORR,AL,AL,0,1,NA,0,0,3,SHIFT_LSR,1,NA,1,1,0,0},
+     {0xA027,INSTR_ORR,AL,AL,0,0,NA,0,0,MAX_32BIT ,SHIFT_LSR,31,NA,1,1,0,0},
+     {0xA028,INSTR_ORR,AL,AL,0,0,NA,0,0,3,SHIFT_ASR,1,NA,1,1,0,0},
+     {0xA029,INSTR_ORR,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_ASR,31,NA,1,MAX_32BIT ,0,0},
+     {0xA030,INSTR_CMP,AL,AL,1,0x10000,NA,1,0x10000,0,0,0,NA,0,0,1,HS},
+     {0xA031,INSTR_CMP,AL,AL,1,0x00000,NA,1,0x10000,0,0,0,NA,0,0,1,CC},
+     {0xA032,INSTR_CMP,AL,AL,1,0x00000,NA,0,0,0x10000,0,0,NA,0,0,1,LT},
+     {0xA033,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x10000,0,0,NA,0,0,1,EQ},
+     {0xA034,INSTR_CMP,AL,AL,1,0x00000,NA,0,0,0x10000,0,0,NA,0,0,1,LS},
+     {0xA035,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x10000,0,0,NA,0,0,1,LS},
+     {0xA036,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x00000,0,0,NA,0,0,1,HI},
+     {0xA037,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x10000,0,0,NA,0,0,1,HS},
+     {0xA038,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x00000,0,0,NA,0,0,1,HS},
+     {0xA039,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x00000,0,0,NA,0,0,1,NE},
+     {0xA040,INSTR_CMP,AL,AL,1,0,NA,0,0,MAX_32BIT ,SHIFT_LSR,1,NA,0,0,1,LT},
+     {0xA041,INSTR_CMP,AL,AL,1,1,NA,0,0,MAX_32BIT ,SHIFT_LSR,31,NA,0,0,1,EQ},
+     {0xA042,INSTR_CMP,AL,AL,1,0,NA,0,0,0x10000,SHIFT_LSR,31,NA,0,0,1,LS},
+     {0xA043,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x30000,SHIFT_LSR,1,NA,0,0,1,LS},
+     {0xA044,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x00000,SHIFT_LSR,31,NA,0,0,1,HI},
+     {0xA045,INSTR_CMP,AL,AL,1,1,NA,0,0,MAX_32BIT ,SHIFT_LSR,31,NA,0,0,1,HS},
+     {0xA046,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x2000,SHIFT_LSR,1,NA,0,0,1,HS},
+     {0xA047,INSTR_CMP,AL,AL,1,0,NA,0,0,MAX_32BIT ,SHIFT_LSR,1,NA,0,0,1,NE},
+     {0xA048,INSTR_CMP,AL,AL,1,0,NA,0,0,0x10000,SHIFT_ASR,2,NA,0,0,1,LT},
+     {0xA049,INSTR_CMP,AL,AL,1,MAX_32BIT ,NA,0,0,MAX_32BIT ,SHIFT_ASR,1,NA,0,0,1,EQ},
+     {0xA050,INSTR_CMP,AL,AL,1,MAX_32BIT ,NA,0,0,MAX_32BIT ,SHIFT_ASR,31,NA,0,0,1,LS},
+     {0xA051,INSTR_CMP,AL,AL,1,0,NA,0,0,0x10000,SHIFT_ASR,1,NA,0,0,1,LS},
+     {0xA052,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x10000,SHIFT_ASR,1,NA,0,0,1,HI},
+     {0xA053,INSTR_CMP,AL,AL,1,1,NA,0,0,0x10000,SHIFT_ASR,31,NA,0,0,1,HS},
+     {0xA054,INSTR_CMP,AL,AL,1,1,NA,0,0,0x10000,SHIFT_ASR,16,NA,0,0,1,HS},
+     {0xA055,INSTR_CMP,AL,AL,1,1,NA,0,0,MAX_32BIT ,SHIFT_ASR,1,NA,0,0,1,NE},
+     {0xA056,INSTR_MUL,AL,AL,0,0,0x10000,0,0,0x10000,0,0,NA,1,0,0,0},
+     {0xA057,INSTR_MUL,AL,AL,0,0,0x1000,0,0,0x10000,0,0,NA,1,0x10000000,0,0},
+     {0xA058,INSTR_MUL,AL,AL,0,0,MAX_32BIT ,0,0,1,0,0,NA,1,MAX_32BIT ,0,0},
+     {0xA059,INSTR_MLA,AL,AL,0,0x10000,0x10000,0,0,0x10000,0,0,NA,1,0x10000,0,0},
+     {0xA060,INSTR_MLA,AL,AL,0,0x10000,0x1000,0,0,0x10000,0,0,NA,1,0x10010000,0,0},
+     {0xA061,INSTR_MLA,AL,AL,1,1,MAX_32BIT ,0,0,1,0,0,NA,1,0,1,PL},
+     {0xA062,INSTR_MLA,AL,AL,1,0,MAX_32BIT ,0,0,1,0,0,NA,1,MAX_32BIT ,1,MI},
+     {0xA063,INSTR_SUB,AL,AL,1,1 << 16,NA,1,1 << 16,NA,NA,NA,NA,1,0,1,PL},
+     {0xA064,INSTR_SUB,AL,AL,1,(1 << 16) + 1,NA,1,1 << 16,NA,NA,NA,NA,1,1,1,PL},
+     {0xA065,INSTR_SUB,AL,AL,1,0,NA,1,1 << 16,NA,NA,NA,NA,1,(uint32_t)(0 - (1<<16)),1,MI},
+     {0xA066,INSTR_SUB,MI,MI,0,2,NA,0,NA,1,NA,NA,2,1,1,0,NA},
+     {0xA067,INSTR_SUB,EQ,MI,0,2,NA,0,NA,1,NA,NA,2,1,2,0,NA},
+     {0xA068,INSTR_SUB,GT,GE,0,2,NA,1,1,NA,NA,NA,2,1,1,0,NA},
+     {0xA069,INSTR_SUB,LT,GE,0,2,NA,1,1,NA,NA,NA,2,1,2,0,NA},
+     {0xA070,INSTR_SUB,CS,HS,0,2,NA,1,1,NA,NA,NA,2,1,1,0,NA},
+     {0xA071,INSTR_SUB,CC,HS,0,2,NA,1,1,NA,NA,NA,2,1,2,0,NA},
+     {0xA072,INSTR_SUB,AL,AL,0,1,NA,1,1 << 16,0,0,0,NA,1,(uint32_t)(1 - (1 << 16)),0,NA},
+     {0xA073,INSTR_SUB,AL,AL,0,MAX_32BIT,NA,1,1,0,0,0,NA,1,MAX_32BIT  - 1,0,NA},
+     {0xA074,INSTR_SUB,AL,AL,0,1,NA,1,1,0,0,0,NA,1,0,0,NA},
+     {0xA075,INSTR_SUB,AL,AL,0,1,NA,0,NA,1 << 16,0,0,NA,1,(uint32_t)(1 - (1 << 16)),0,NA},
+     {0xA076,INSTR_SUB,AL,AL,0,MAX_32BIT,NA,0,NA,1,0,0,NA,1,MAX_32BIT  - 1,0,NA},
+     {0xA077,INSTR_SUB,AL,AL,0,1,NA,0,NA,1,0,0,NA,1,0,0,NA},
+     {0xA078,INSTR_SUB,AL,AL,0,1,NA,0,NA,1,SHIFT_LSL,16,NA,1,(uint32_t)(1 - (1 << 16)),0,NA},
+     {0xA079,INSTR_SUB,AL,AL,0,0x80000001,NA,0,NA,MAX_32BIT ,SHIFT_LSL,31,NA,1,1,0,NA},
+     {0xA080,INSTR_SUB,AL,AL,0,1,NA,0,NA,3,SHIFT_LSR,1,NA,1,0,0,NA},
+     {0xA081,INSTR_SUB,AL,AL,0,1,NA,0,NA,MAX_32BIT ,SHIFT_LSR,31,NA,1,0,0,NA},
+     {0xA082,INSTR_RSB,GT,GE,0,2,NA,1,0,NA,NA,NA,2,1,(uint32_t)-2,0,NA},
+     {0xA083,INSTR_RSB,LT,GE,0,2,NA,1,0,NA,NA,NA,2,1,2,0,NA},
+     {0xA084,INSTR_RSB,AL,AL,0,1,NA,1,1 << 16,NA,NA,NA,NA,1,(1 << 16) - 1,0,NA},
+     {0xA085,INSTR_RSB,AL,AL,0,MAX_32BIT,NA,1,1,NA,NA,NA,NA,1,(uint32_t) (1 - MAX_32BIT),0,NA},
+     {0xA086,INSTR_RSB,AL,AL,0,1,NA,1,1,NA,NA,NA,NA,1,0,0,NA},
+     {0xA087,INSTR_RSB,AL,AL,0,1,NA,0,NA,1 << 16,0,0,NA,1,(1 << 16) - 1,0,NA},
+     {0xA088,INSTR_RSB,AL,AL,0,MAX_32BIT,NA,0,NA,1,0,0,NA,1,(uint32_t) (1 - MAX_32BIT),0,NA},
+     {0xA089,INSTR_RSB,AL,AL,0,1,NA,0,NA,1,0,0,NA,1,0,0,NA},
+     {0xA090,INSTR_RSB,AL,AL,0,1,NA,0,NA,1,SHIFT_LSL,16,NA,1,(1 << 16) - 1,0,NA},
+     {0xA091,INSTR_RSB,AL,AL,0,0x80000001,NA,0,NA,MAX_32BIT ,SHIFT_LSL,31,NA,1,(uint32_t)-1,0,NA},
+     {0xA092,INSTR_RSB,AL,AL,0,1,NA,0,NA,3,SHIFT_LSR,1,NA,1,0,0,NA},
+     {0xA093,INSTR_RSB,AL,AL,0,1,NA,0,NA,MAX_32BIT ,SHIFT_LSR,31,NA,1,0,0,NA},
+     {0xA094,INSTR_MOV,AL,AL,0,NA,NA,1,0x80000001,NA,NA,NA,NA,1,0x80000001,0,0},
+     {0xA095,INSTR_MOV,AL,AL,0,NA,NA,0,0,0x80000001,0,0,NA,1,0x80000001,0,0},
+     {0xA096,INSTR_MOV,AL,AL,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,NA,1,MAX_32BIT -1,0,0},
+     {0xA097,INSTR_MOV,AL,AL,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,31,NA,1,0x80000000,0,0},
+     {0xA098,INSTR_MOV,AL,AL,0,NA,NA,0,0,3,SHIFT_LSR,1,NA,1,1,0,0},
+     {0xA099,INSTR_MOV,AL,AL,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSR,31,NA,1,1,0,0},
+     {0xA100,INSTR_MOV,AL,AL,0,NA,NA,0,0,3,SHIFT_ASR,1,NA,1,1,0,0},
+     {0xA101,INSTR_MOV,AL,AL,0,NA,NA,0,0,MAX_32BIT ,SHIFT_ASR,31,NA,1,MAX_32BIT ,0,0},
+     {0xA102,INSTR_MOV,AL,AL,0,NA,NA,0,0,3,SHIFT_ROR,1,NA,1,0x80000001,0,0},
+     {0xA103,INSTR_MOV,AL,AL,0,NA,NA,0,0,0x80000001,SHIFT_ROR,31,NA,1,3,0,0},
+     {0xA104,INSTR_MOV,AL,AL,1,NA,NA,0,0,MAX_32BIT -1,SHIFT_ASR,1,NA,1,MAX_32BIT,1,MI},
+     {0xA105,INSTR_MOV,AL,AL,1,NA,NA,0,0,3,SHIFT_ASR,1,NA,1,1,1,PL},
+     {0xA106,INSTR_MOV,PL,MI,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2,0,0},
+     {0xA107,INSTR_MOV,MI,MI,0,NA,NA,0,0,0x80000001,0,0,2,1,0x80000001,0,0},
+     {0xA108,INSTR_MOV,EQ,LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2,0,0},
+     {0xA109,INSTR_MOV,LT,LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0x80000001,0,0},
+     {0xA110,INSTR_MOV,GT,GE,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,MAX_32BIT -1,0,0},
+     {0xA111,INSTR_MOV,EQ,GE,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,31,2,1,0x80000000,0,0},
+     {0xA112,INSTR_MOV,LT,GE,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,31,2,1,2,0,0},
+     {0xA113,INSTR_MOV,GT,LE,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,2,0,0},
+     {0xA114,INSTR_MOV,EQ,LE,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0x80000001,0,0},
+     {0xA115,INSTR_MOV,LT,LE,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,31,2,1,0x80000000,0,0},
+     {0xA116,INSTR_MOV,EQ,GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2,0,0},
+     {0xA117,INSTR_MOV,GT,GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0x80000001,0,0},
+     {0xA118,INSTR_MOV,LE,GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2,0,0},
+     {0xA119,INSTR_MOV,EQ,GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2,0,0},
+     {0xA120,INSTR_MOV,GT,GT,0,NA,NA,0,0,0x80000001,0,0,2,1,0x80000001,0,0},
+     {0xA121,INSTR_MOV,LE,GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2,0,0},
+     {0xA122,INSTR_MOV,EQ,GT,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,2,0,0},
+     {0xA123,INSTR_MOV,GT,GT,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,MAX_32BIT -1,0,0},
+     {0xA124,INSTR_MOV,LE,GT,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,2,0,0},
+     {0xA125,INSTR_MOV,LO,HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2,0,0},
+     {0xA126,INSTR_MOV,HS,HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0x80000001,0,0},
+     {0xA127,INSTR_MVN,LO,HS,0,NA,NA,1,MAX_32BIT -1,NA,NA,NA,2,1,2,0,0},
+     {0xA128,INSTR_MVN,HS,HS,0,NA,NA,1,MAX_32BIT -1,NA,NA,NA,2,1,1,0,0},
+     {0xA129,INSTR_MVN,AL,AL,0,NA,NA,1,0,NA,NA,NA,2,1,MAX_32BIT,0,NA},
+     {0xA130,INSTR_MVN,AL,AL,0,NA,NA,0,NA,MAX_32BIT -1,NA,0,2,1,1,0,NA},
+     {0xA131,INSTR_MVN,AL,AL,0,NA,NA,0,NA,0x80000001,NA,0,2,1,0x7FFFFFFE,0,NA},
+     {0xA132,INSTR_BIC,AL,AL,0,1,NA,1,MAX_32BIT ,NA,NA,NA,NA,1,0,0,0},
+     {0xA133,INSTR_BIC,AL,AL,0,1,NA,1,MAX_32BIT -1,NA,NA,NA,NA,1,1,0,0},
+     {0xA134,INSTR_BIC,AL,AL,0,1,NA,0,0,MAX_32BIT ,0,0,NA,1,0,0,0},
+     {0xA135,INSTR_BIC,AL,AL,0,1,NA,0,0,MAX_32BIT -1,0,0,NA,1,1,0,0},
+     {0xA136,INSTR_BIC,AL,AL,0,0xF0,NA,0,0,3,SHIFT_ASR,1,NA,1,0xF0,0,0},
+     {0xA137,INSTR_BIC,AL,AL,0,0xF0,NA,0,0,MAX_32BIT ,SHIFT_ASR,31,NA,1,0,0,0},
+     {0xA138,INSTR_SMULBB,AL,AL,0,NA,0xABCDFFFF,0,NA,0xABCD0001,NA,NA,NA,1,0xFFFFFFFF,0,0},
+     {0xA139,INSTR_SMULBB,AL,AL,0,NA,0xABCD0001,0,NA,0xABCD0FFF,NA,NA,NA,1,0x00000FFF,0,0},
+     {0xA140,INSTR_SMULBB,AL,AL,0,NA,0xABCD0001,0,NA,0xABCDFFFF,NA,NA,NA,1,0xFFFFFFFF,0,0},
+     {0xA141,INSTR_SMULBB,AL,AL,0,NA,0xABCDFFFF,0,NA,0xABCDFFFF,NA,NA,NA,1,1,0,0},
+     {0xA142,INSTR_SMULBT,AL,AL,0,NA,0xFFFFABCD,0,NA,0xABCD0001,NA,NA,NA,1,0xFFFFFFFF,0,0},
+     {0xA143,INSTR_SMULBT,AL,AL,0,NA,0x0001ABCD,0,NA,0xABCD0FFF,NA,NA,NA,1,0x00000FFF,0,0},
+     {0xA144,INSTR_SMULBT,AL,AL,0,NA,0x0001ABCD,0,NA,0xABCDFFFF,NA,NA,NA,1,0xFFFFFFFF,0,0},
+     {0xA145,INSTR_SMULBT,AL,AL,0,NA,0xFFFFABCD,0,NA,0xABCDFFFF,NA,NA,NA,1,1,0,0},
+     {0xA146,INSTR_SMULTB,AL,AL,0,NA,0xABCDFFFF,0,NA,0x0001ABCD,NA,NA,NA,1,0xFFFFFFFF,0,0},
+     {0xA147,INSTR_SMULTB,AL,AL,0,NA,0xABCD0001,0,NA,0x0FFFABCD,NA,NA,NA,1,0x00000FFF,0,0},
+     {0xA148,INSTR_SMULTB,AL,AL,0,NA,0xABCD0001,0,NA,0xFFFFABCD,NA,NA,NA,1,0xFFFFFFFF,0,0},
+     {0xA149,INSTR_SMULTB,AL,AL,0,NA,0xABCDFFFF,0,NA,0xFFFFABCD,NA,NA,NA,1,1,0,0},
+     {0xA150,INSTR_SMULTT,AL,AL,0,NA,0xFFFFABCD,0,NA,0x0001ABCD,NA,NA,NA,1,0xFFFFFFFF,0,0},
+     {0xA151,INSTR_SMULTT,AL,AL,0,NA,0x0001ABCD,0,NA,0x0FFFABCD,NA,NA,NA,1,0x00000FFF,0,0},
+     {0xA152,INSTR_SMULTT,AL,AL,0,NA,0x0001ABCD,0,NA,0xFFFFABCD,NA,NA,NA,1,0xFFFFFFFF,0,0},
+     {0xA153,INSTR_SMULTT,AL,AL,0,NA,0xFFFFABCD,0,NA,0xFFFFABCD,NA,NA,NA,1,1,0,0},
+     {0xA154,INSTR_SMULWB,AL,AL,0,NA,0xABCDFFFF,0,NA,0x0001ABCD,NA,NA,NA,1,0xFFFFFFFE,0,0},
+     {0xA155,INSTR_SMULWB,AL,AL,0,NA,0xABCD0001,0,NA,0x0FFFABCD,NA,NA,NA,1,0x00000FFF,0,0},
+     {0xA156,INSTR_SMULWB,AL,AL,0,NA,0xABCD0001,0,NA,0xFFFFABCD,NA,NA,NA,1,0xFFFFFFFF,0,0},
+     {0xA157,INSTR_SMULWB,AL,AL,0,NA,0xABCDFFFF,0,NA,0xFFFFABCD,NA,NA,NA,1,0,0,0},
+     {0xA158,INSTR_SMULWT,AL,AL,0,NA,0xFFFFABCD,0,NA,0x0001ABCD,NA,NA,NA,1,0xFFFFFFFE,0,0},
+     {0xA159,INSTR_SMULWT,AL,AL,0,NA,0x0001ABCD,0,NA,0x0FFFABCD,NA,NA,NA,1,0x00000FFF,0,0},
+     {0xA160,INSTR_SMULWT,AL,AL,0,NA,0x0001ABCD,0,NA,0xFFFFABCD,NA,NA,NA,1,0xFFFFFFFF,0,0},
+     {0xA161,INSTR_SMULWT,AL,AL,0,NA,0xFFFFABCD,0,NA,0xFFFFABCD,NA,NA,NA,1,0,0,0},
+     {0xA162,INSTR_SMLABB,AL,AL,0,1,0xABCDFFFF,0,NA,0xABCD0001,NA,NA,NA,1,0,0,0},
+     {0xA163,INSTR_SMLABB,AL,AL,0,1,0xABCD0001,0,NA,0xABCD0FFF,NA,NA,NA,1,0x00001000,0,0},
+     {0xA164,INSTR_SMLABB,AL,AL,0,0xFFFFFFFF,0xABCD0001,0,NA,0xABCDFFFF,NA,NA,NA,1,0xFFFFFFFE,0,0},
+     {0xA165,INSTR_SMLABB,AL,AL,0,0xFFFFFFFF,0xABCDFFFF,0,NA,0xABCDFFFF,NA,NA,NA,1,0,0,0},
+     {0xA166,INSTR_UXTB16,AL,AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,0,NA,1,0x00CD0001,0,0},
+     {0xA167,INSTR_UXTB16,AL,AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,1,NA,1,0x00AB00EF,0,0},
+     {0xA168,INSTR_UXTB16,AL,AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,2,NA,1,0x000100CD,0,0},
+     {0xA169,INSTR_UXTB16,AL,AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,3,NA,1,0x00EF00AB,0,0},
+     {0xA170,INSTR_UBFX,AL,AL,0,0xABCDEF01,4,0,NA,24,NA,NA,NA,1,0x00BCDEF0,0,0},
+     {0xA171,INSTR_UBFX,AL,AL,0,0xABCDEF01,1,0,NA,2,NA,NA,NA,1,0,0,0},
+     {0xA172,INSTR_UBFX,AL,AL,0,0xABCDEF01,16,0,NA,8,NA,NA,NA,1,0xCD,0,0},
+     {0xA173,INSTR_UBFX,AL,AL,0,0xABCDEF01,31,0,NA,1,NA,NA,NA,1,1,0,0},
+     {0xA174,INSTR_ADDR_ADD,AL,AL,0,0xCFFFFFFFF,NA,0,NA,0x1,SHIFT_LSL,1,NA,1,0xD00000001,0,0},
+     {0xA175,INSTR_ADDR_ADD,AL,AL,0,0x01,NA,0,NA,0x1,SHIFT_LSL,2,NA,1,0x5,0,0},
+     {0xA176,INSTR_ADDR_ADD,AL,AL,0,0xCFFFFFFFF,NA,0,NA,0x1,NA,0,NA,1,0xD00000000,0,0},
+     {0xA177,INSTR_ADDR_SUB,AL,AL,0,0xD00000001,NA,0,NA,0x010000,SHIFT_LSR,15,NA,1,0xCFFFFFFFF,0,0},
+     {0xA178,INSTR_ADDR_SUB,AL,AL,0,0xCFFFFFFFF,NA,0,NA,0x020000,SHIFT_LSR,15,NA,1,0xCFFFFFFFB,0,0},
+     {0xA179,INSTR_ADDR_SUB,AL,AL,0,3,NA,0,NA,0x010000,SHIFT_LSR,15,NA,1,1,0,0},
+};
+
+dataTransferTest_t dataTransferTests [] =
+{
+    {0xB000,INSTR_LDR,AL,AL,1,24,0xABCDEF0123456789,0,REG_SCALE_OFFSET,24,NA,NA,NA,NA,NA,0x23456789,0,0,NA,NA,NA},
+    {0xB001,INSTR_LDR,AL,AL,1,4064,0xABCDEF0123456789,0,IMM12_OFFSET,NA,4068,0,1,0,NA,0xABCDEF01,0,0,NA,NA,NA},
+    {0xB002,INSTR_LDR,AL,AL,1,0,0xABCDEF0123456789,0,IMM12_OFFSET,NA,4,1,0,1,NA,0x23456789,4,0,NA,NA,NA},
+    {0xB003,INSTR_LDR,AL,AL,1,0,0xABCDEF0123456789,0,NO_OFFSET,NA,NA,0,0,0,NA,0x23456789,0,0,NA,NA,NA},
+    {0xB004,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,0,REG_SCALE_OFFSET,4064,NA,NA,NA,NA,NA,0x89,0,0,NA,NA,NA},
+    {0xB005,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,0,IMM12_OFFSET,NA,4065,0,1,0,NA,0x67,0,0,NA,NA,NA},
+    {0xB006,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,0,0,1,0,NA,0x67,4065,0,NA,NA,NA},
+    {0xB007,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,1,0,1,0,NA,0x45,4065,0,NA,NA,NA},
+    {0xB008,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,2,0,1,0,NA,0x23,4065,0,NA,NA,NA},
+    {0xB009,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,1,1,0,1,NA,0x67,4066,0,NA,NA,NA},
+    {0xB010,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,0,NO_OFFSET,NA,NA,0,0,0,NA,0x89,0,0,NA,NA,NA},
+    {0xB011,INSTR_LDRH,AL,AL,1,0,0xABCDEF0123456789,0,IMM8_OFFSET,NA,2,1,0,1,NA,0x6789,2,0,NA,NA,NA},
+    {0xB012,INSTR_LDRH,AL,AL,1,4064,0xABCDEF0123456789,0,REG_OFFSET,4064,0,0,1,0,NA,0x6789,0,0,NA,NA,NA},
+    {0xB013,INSTR_LDRH,AL,AL,1,4064,0xABCDEF0123456789,0,REG_OFFSET,4066,0,0,1,0,NA,0x2345,0,0,NA,NA,NA},
+    {0xB014,INSTR_LDRH,AL,AL,1,0,0xABCDEF0123456789,0,NO_OFFSET,NA,0,0,0,0,NA,0x6789,0,0,NA,NA,NA},
+    {0xB015,INSTR_LDRH,AL,AL,1,0,0xABCDEF0123456789,2,NO_OFFSET,NA,0,0,0,0,NA,0x2345,2,0,NA,NA,NA},
+    {0xB016,INSTR_ADDR_LDR,AL,AL,1,4064,0xABCDEF0123456789,0,IMM12_OFFSET,NA,4064,0,1,0,NA,0xABCDEF0123456789,0,0,NA,NA,NA},
+    {0xB017,INSTR_STR,AL,AL,1,2,0xDEADBEEFDEADBEEF,4,IMM12_OFFSET,NA,4,1,0,1,0xABCDEF0123456789,0xABCDEF0123456789,8,1,2,8,0xDEAD23456789BEEF},
+    {0xB018,INSTR_STR,AL,AL,1,2,0xDEADBEEFDEADBEEF,4,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4,1,2,8,0xDEAD23456789BEEF},
+    {0xB019,INSTR_STR,AL,AL,1,4066,0xDEADBEEFDEADBEEF,4,IMM12_OFFSET,NA,4064,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,4,1,4066,8,0xDEAD23456789BEEF},
+    {0xB020,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,0,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEFDEAD89EF},
+    {0xB021,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,1,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEFDE89BEEF},
+    {0xB022,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,2,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEF89ADBEEF},
+    {0xB023,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,4,1,0,1,0xABCDEF0123456789,0xABCDEF0123456789,5,1,0,8,0xDEADBEEFDEAD89EF},
+    {0xB024,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEFDEAD89EF},
+    {0xB025,INSTR_STRH,AL,AL,1,4066,0xDEADBEEFDEADBEEF,4070,IMM12_OFFSET,NA,2,1,0,1,0xABCDEF0123456789,0xABCDEF0123456789,4072,1,4066,8,0xDEAD6789DEADBEEF},
+    {0xB026,INSTR_STRH,AL,AL,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
+    {0xB027,INSTR_STRH,EQ,NE,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEADBEEFDEADBEEF},
+    {0xB028,INSTR_STRH,NE,NE,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
+    {0xB029,INSTR_STRH,NE,EQ,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEADBEEFDEADBEEF},
+    {0xB030,INSTR_STRH,EQ,EQ,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
+    {0xB031,INSTR_STRH,HI,LS,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEADBEEFDEADBEEF},
+    {0xB032,INSTR_STRH,LS,LS,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
+    {0xB033,INSTR_STRH,LS,HI,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEADBEEFDEADBEEF},
+    {0xB034,INSTR_STRH,HI,HI,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
+    {0xB035,INSTR_STRH,CC,HS,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEADBEEFDEADBEEF},
+    {0xB036,INSTR_STRH,CS,HS,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
+    {0xB037,INSTR_STRH,GE,LT,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEADBEEFDEADBEEF},
+    {0xB038,INSTR_STRH,LT,LT,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
+    {0xB039,INSTR_ADDR_STR,AL,AL,1,4064,0xDEADBEEFDEADBEEF,4,IMM12_OFFSET,NA,4060,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,4,1,4064,8,0xABCDEF0123456789},
+};
+
+
+int flushcache()
+{
+    const long base = long(instrMem);
+    const long curr = base + long(instrMemSize);
+    return cacheflush(base, curr, 0);
+}
+void dataOpTest(dataOpTest_t test, ARMAssemblerInterface *a64asm, uint32_t Rd = 0,
+                uint32_t Rn = 1, uint32_t Rm = 2, uint32_t Rs = 3)
+{
+    int64_t  regs[NUM_REGS] = {0};
+    int32_t  flags[NUM_FLAGS] = {0};
+    int64_t  savedRegs[NUM_REGS] = {0};
+    uint32_t i;
+    uint32_t op2;
+
+    for(i = 0; i < NUM_REGS; ++i)
+    {
+        regs[i] = i;
+    }
+
+    regs[Rd] = test.RdValue;
+    regs[Rn] = test.RnValue;
+    regs[Rs] = test.RsValue;
+    flags[test.preFlag] = 1;
+    a64asm->reset();
+    a64asm->prolog();
+    if(test.immediate == true)
+    {
+        op2 = a64asm->imm(test.immValue);
+    }
+    else if(test.immediate == false && test.shiftAmount == 0)
+    {
+        op2 = Rm;
+        regs[Rm] = test.RmValue;
+    }
+    else
+    {
+        op2 = a64asm->reg_imm(Rm, test.shiftMode, test.shiftAmount);
+        regs[Rm] = test.RmValue;
+    }
+    switch(test.op)
+    {
+    case INSTR_ADD: a64asm->ADD(test.cond, test.setFlags, Rd,Rn,op2); break;
+    case INSTR_SUB: a64asm->SUB(test.cond, test.setFlags, Rd,Rn,op2); break;
+    case INSTR_RSB: a64asm->RSB(test.cond, test.setFlags, Rd,Rn,op2); break;
+    case INSTR_AND: a64asm->AND(test.cond, test.setFlags, Rd,Rn,op2); break;
+    case INSTR_ORR: a64asm->ORR(test.cond, test.setFlags, Rd,Rn,op2); break;
+    case INSTR_BIC: a64asm->BIC(test.cond, test.setFlags, Rd,Rn,op2); break;
+    case INSTR_MUL: a64asm->MUL(test.cond, test.setFlags, Rd,Rm,Rs); break;
+    case INSTR_MLA: a64asm->MLA(test.cond, test.setFlags, Rd,Rm,Rs,Rn); break;
+    case INSTR_CMP: a64asm->CMP(test.cond, Rn,op2); break;
+    case INSTR_MOV: a64asm->MOV(test.cond, test.setFlags,Rd,op2); break;
+    case INSTR_MVN: a64asm->MVN(test.cond, test.setFlags,Rd,op2); break;
+    case INSTR_SMULBB:a64asm->SMULBB(test.cond, Rd,Rm,Rs); break;
+    case INSTR_SMULBT:a64asm->SMULBT(test.cond, Rd,Rm,Rs); break;
+    case INSTR_SMULTB:a64asm->SMULTB(test.cond, Rd,Rm,Rs); break;
+    case INSTR_SMULTT:a64asm->SMULTT(test.cond, Rd,Rm,Rs); break;
+    case INSTR_SMULWB:a64asm->SMULWB(test.cond, Rd,Rm,Rs); break;
+    case INSTR_SMULWT:a64asm->SMULWT(test.cond, Rd,Rm,Rs); break;
+    case INSTR_SMLABB:a64asm->SMLABB(test.cond, Rd,Rm,Rs,Rn); break;
+    case INSTR_UXTB16:a64asm->UXTB16(test.cond, Rd,Rm,test.shiftAmount); break;
+    case INSTR_UBFX:
+    {
+        int32_t lsb   = test.RsValue;
+        int32_t width = test.RmValue;
+        a64asm->UBFX(test.cond, Rd,Rn,lsb, width);
+        break;
+    }
+    case INSTR_ADDR_ADD: a64asm->ADDR_ADD(test.cond, test.setFlags, Rd,Rn,op2); break;
+    case INSTR_ADDR_SUB: a64asm->ADDR_SUB(test.cond, test.setFlags, Rd,Rn,op2); break;
+    default: printf("Error"); return;
+    }
+    a64asm->epilog(0);
+    flushcache();
+
+    asm_function_t asm_function = (asm_function_t)(instrMem);
+
+    for(i = 0; i < NUM_REGS; ++i)
+        savedRegs[i] = regs[i];
+
+    asm_test_jacket(asm_function, regs, flags);
+
+    /* Check if all regs except Rd is same */
+    for(i = 0; i < NUM_REGS; ++i)
+    {
+        if(i == Rd) continue;
+        if(regs[i] != savedRegs[i])
+        {
+            printf("Test %x failed Reg(%d) tampered Expected(0x%"PRIx64"),"
+                   "Actual(0x%"PRIx64") t\n", test.id, i, savedRegs[i], regs[i]);
+            return;
+        }
+    }
+
+    if(test.checkRd == 1 && (uint64_t)regs[Rd] != test.postRdValue)
+    {
+        printf("Test %x failed, Expected(%"PRIx64"), Actual(%"PRIx64")\n",
+                test.id, test.postRdValue, regs[Rd]);
+    }
+    else if(test.checkFlag == 1 && flags[test.postFlag] == 0)
+    {
+        printf("Test %x failed Flag(%s) NOT set\n",
+                test.id,cc_code[test.postFlag]);
+    }
+    else
+    {
+        printf("Test %x passed\n", test.id);
+    }
+}
+
+
+void dataTransferTest(dataTransferTest_t test, ARMAssemblerInterface *a64asm,
+                      uint32_t Rd = 0, uint32_t Rn = 1,uint32_t Rm = 2)
+{
+    int64_t regs[NUM_REGS] = {0};
+    int64_t savedRegs[NUM_REGS] = {0};
+    int32_t flags[NUM_FLAGS] = {0};
+    uint32_t i;
+    for(i = 0; i < NUM_REGS; ++i)
+    {
+        regs[i] = i;
+    }
+
+    uint32_t op2;
+
+    regs[Rd] = test.RdValue;
+    regs[Rn] = (uint64_t)(&dataMem[test.RnValue]);
+    regs[Rm] = test.RmValue;
+    flags[test.preFlag] = 1;
+
+    if(test.setMem == true)
+    {
+        unsigned char *mem = (unsigned char *)&dataMem[test.memOffset];
+        uint64_t value = test.memValue;
+        for(int j = 0; j < 8; ++j)
+        {
+            mem[j] = value & 0x00FF;
+            value >>= 8;
+        }
+    }
+    a64asm->reset();
+    a64asm->prolog();
+    if(test.offsetType == REG_SCALE_OFFSET)
+    {
+        op2 = a64asm->reg_scale_pre(Rm);
+    }
+    else if(test.offsetType == REG_OFFSET)
+    {
+        op2 = a64asm->reg_pre(Rm);
+    }
+    else if(test.offsetType == IMM12_OFFSET && test.preIndex == true)
+    {
+        op2 = a64asm->immed12_pre(test.immValue, test.writeBack);
+    }
+    else if(test.offsetType == IMM12_OFFSET && test.postIndex == true)
+    {
+        op2 = a64asm->immed12_post(test.immValue);
+    }
+    else if(test.offsetType == IMM8_OFFSET && test.preIndex == true)
+    {
+        op2 = a64asm->immed8_pre(test.immValue, test.writeBack);
+    }
+    else if(test.offsetType == IMM8_OFFSET && test.postIndex == true)
+    {
+        op2 = a64asm->immed8_post(test.immValue);
+    }
+    else if(test.offsetType == NO_OFFSET)
+    {
+        op2 = a64asm->__immed12_pre(0);
+    }
+    else
+    {
+        printf("Error - Unknown offset\n"); return;
+    }
+
+    switch(test.op)
+    {
+    case INSTR_LDR:  a64asm->LDR(test.cond, Rd,Rn,op2); break;
+    case INSTR_LDRB: a64asm->LDRB(test.cond, Rd,Rn,op2); break;
+    case INSTR_LDRH: a64asm->LDRH(test.cond, Rd,Rn,op2); break;
+    case INSTR_ADDR_LDR: a64asm->ADDR_LDR(test.cond, Rd,Rn,op2); break;
+    case INSTR_STR:  a64asm->STR(test.cond, Rd,Rn,op2); break;
+    case INSTR_STRB: a64asm->STRB(test.cond, Rd,Rn,op2); break;
+    case INSTR_STRH: a64asm->STRH(test.cond, Rd,Rn,op2); break;
+    case INSTR_ADDR_STR: a64asm->ADDR_STR(test.cond, Rd,Rn,op2); break;
+    default: printf("Error"); return;
+    }
+    a64asm->epilog(0);
+    flushcache();
+
+    asm_function_t asm_function = (asm_function_t)(instrMem);
+
+    for(i = 0; i < NUM_REGS; ++i)
+        savedRegs[i] = regs[i];
+
+
+    asm_test_jacket(asm_function, regs, flags);
+
+    /* Check if all regs except Rd/Rn are same */
+    for(i = 0; i < NUM_REGS; ++i)
+    {
+        if(i == Rd || i == Rn) continue;
+        if(regs[i] != savedRegs[i])
+        {
+            printf("Test %x failed Reg(%d) tampered"
+                   " Expected(0x%"PRIx64"), Actual(0x%"PRIx64") t\n",
+                   test.id, i, savedRegs[i], regs[i]);
+            return;
+        }
+    }
+
+    if((uint64_t)regs[Rd] != test.postRdValue)
+    {
+        printf("Test %x failed, "
+               "Expected in Rd(0x%"PRIx64"), Actual(0x%"PRIx64")\n",
+               test.id, test.postRdValue, regs[Rd]);
+    }
+    else if((uint64_t)regs[Rn] != (uint64_t)(&dataMem[test.postRnValue]))
+    {
+        printf("Test %x failed, "
+               "Expected in Rn(0x%"PRIx64"), Actual(0x%"PRIx64")\n",
+               test.id, test.postRnValue, regs[Rn] - (uint64_t)dataMem);
+    }
+    else if(test.checkMem == true)
+    {
+        unsigned char *addr = (unsigned char *)&dataMem[test.postMemOffset];
+        uint64_t value;
+        value = 0;
+        for(uint32_t j = 0; j < test.postMemLength; ++j)
+            value = (value << 8) | addr[test.postMemLength-j-1];
+        if(value != test.postMemValue)
+        {
+            printf("Test %x failed, "
+                   "Expected in Mem(0x%"PRIx64"), Actual(0x%"PRIx64")\n",
+                   test.id, test.postMemValue, value);
+        }
+        else
+        {
+            printf("Test %x passed\n", test.id);
+        }
+    }
+    else
+    {
+        printf("Test %x passed\n", test.id);
+    }
+}
+
+void dataTransferLDMSTM(ARMAssemblerInterface *a64asm)
+{
+    int64_t regs[NUM_REGS] = {0};
+    int32_t flags[NUM_FLAGS] = {0};
+    const uint32_t numArmv7Regs = 16;
+
+    uint32_t Rn = ARMAssemblerInterface::SP;
+
+    uint32_t patterns[] =
+    {
+        0x5A03,
+        0x4CF0,
+        0x1EA6,
+        0x0DBF,
+    };
+
+    uint32_t i, j;
+    for(i = 0; i < sizeof(patterns)/sizeof(uint32_t); ++i)
+    {
+        for(j = 0; j < NUM_REGS; ++j)
+        {
+            regs[j] = j;
+        }
+        a64asm->reset();
+        a64asm->prolog();
+        a64asm->STM(AL,ARMAssemblerInterface::DB,Rn,1,patterns[i]);
+        for(j = 0; j < numArmv7Regs; ++j)
+        {
+            uint32_t op2 = a64asm->imm(0x31);
+            a64asm->MOV(AL, 0,j,op2);
+        }
+        a64asm->LDM(AL,ARMAssemblerInterface::IA,Rn,1,patterns[i]);
+        a64asm->epilog(0);
+        flushcache();
+
+        asm_function_t asm_function = (asm_function_t)(instrMem);
+        asm_test_jacket(asm_function, regs, flags);
+
+        for(j = 0; j < numArmv7Regs; ++j)
+        {
+            if((1 << j) & patterns[i])
+            {
+                if(regs[j] != j)
+                {
+                    printf("LDM/STM Test %x failed "
+                           "Reg%d expected(0x%x) Actual(0x%"PRIx64") \n",
+                            patterns[i],j,j,regs[j]);
+                    break;
+                }
+            }
+        }
+        if(j == numArmv7Regs)
+            printf("LDM/STM Test %x passed\n", patterns[i]);
+    }
+}
+
+int main(void)
+{
+    uint32_t i;
+
+    /* Allocate memory to store instructions generated by ArmToAarch64Assembler */
+    {
+        int fd = ashmem_create_region("code cache", instrMemSize);
+        if(fd < 0)
+            printf("Creating code cache, ashmem_create_region "
+                                "failed with error '%s'", strerror(errno));
+        instrMem = mmap(NULL, instrMemSize,
+                                    PROT_READ | PROT_WRITE | PROT_EXEC,
+                                MAP_PRIVATE, fd, 0);
+    }
+
+    ArmToAarch64Assembler a64asm(instrMem);
+
+    if(TESTS_DATAOP_ENABLE)
+    {
+        printf("Running data processing tests\n");
+        for(i = 0; i < sizeof(dataOpTests)/sizeof(dataOpTest_t); ++i)
+            dataOpTest(dataOpTests[i], &a64asm);
+    }
+
+    if(TESTS_DATATRANSFER_ENABLE)
+    {
+        printf("Running data transfer tests\n");
+        for(i = 0; i < sizeof(dataTransferTests)/sizeof(dataTransferTest_t); ++i)
+            dataTransferTest(dataTransferTests[i], &a64asm);
+    }
+
+    if(TESTS_LDMSTM_ENABLE)
+    {
+        printf("Running LDM/STM tests\n");
+        dataTransferLDMSTM(&a64asm);
+    }
+
+
+    if(TESTS_REG_CORRUPTION_ENABLE)
+    {
+        uint32_t reg_list[] = {0,1,12,14};
+        uint32_t Rd, Rm, Rs, Rn;
+        uint32_t i;
+        uint32_t numRegs = sizeof(reg_list)/sizeof(uint32_t);
+
+        printf("Running Register corruption tests\n");
+        for(i = 0; i < sizeof(dataOpTests)/sizeof(dataOpTest_t); ++i)
+        {
+            for(Rd = 0; Rd < numRegs; ++Rd)
+            {
+                for(Rn = 0; Rn < numRegs; ++Rn)
+                {
+                    for(Rm = 0; Rm < numRegs; ++Rm)
+                    {
+                        for(Rs = 0; Rs < numRegs;++Rs)
+                        {
+                            if(Rd == Rn || Rd == Rm || Rd == Rs) continue;
+                            if(Rn == Rm || Rn == Rs) continue;
+                            if(Rm == Rs) continue;
+                            printf("Testing combination Rd(%d), Rn(%d),"
+                                   " Rm(%d), Rs(%d): ",
+                                   reg_list[Rd], reg_list[Rn], reg_list[Rm], reg_list[Rs]);
+                            dataOpTest(dataOpTests[i], &a64asm, reg_list[Rd],
+                                       reg_list[Rn], reg_list[Rm], reg_list[Rs]);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return 0;
+}
diff --git a/libpixelflinger/tests/arch-aarch64/assembler/asm_test_jacket.S b/libpixelflinger/tests/arch-aarch64/assembler/asm_test_jacket.S
new file mode 100644
index 0000000..a1392c2
--- /dev/null
+++ b/libpixelflinger/tests/arch-aarch64/assembler/asm_test_jacket.S
@@ -0,0 +1,221 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+    .text
+    .align
+
+    .global asm_test_jacket
+
+    // Set the register and flag values
+    // Calls the asm function
+    // Reads the register/flag values to output register
+
+    // Parameters
+    // X0 - Function to jump
+    // X1 - register values array
+    // X2 - flag values array
+asm_test_jacket:
+    // Save registers to stack
+    stp    x29, x30, [sp,#-16]!
+    stp    x27, x28, [sp,#-16]!
+
+    mov x30, x0
+    mov x28, x1
+    mov x27, x2
+
+    //Set the flags based on flag array
+    //EQ
+    ldr w0, [x27,#0]
+    cmp w0, #1
+    b.ne bt_aeq
+    cmp w0,#1
+    b bt_end
+bt_aeq:
+
+    //NE
+    ldr w0, [x27,#4]
+    cmp w0, #1
+    b.ne bt_ane
+    cmp w0,#2
+    b bt_end
+bt_ane:
+
+    //CS
+    ldr w0, [x27,#8]
+    cmp w0, #1
+    b.ne bt_acs
+    cmp w0,#0
+    b bt_end
+bt_acs:
+
+    //CC
+    ldr w0, [x27,#12]
+    cmp w0, #1
+    b.ne bt_acc
+    cmp w0,#2
+    b bt_end
+bt_acc:
+
+    //MI
+    ldr w0, [x27,#16]
+    cmp w0, #1
+    b.ne bt_ami
+    subs w0,w0,#2
+    b bt_end
+bt_ami:
+
+    //PL
+    ldr w0, [x27,#20]
+    cmp w0, #1
+    b.ne bt_apl
+    subs w0,w0,#0
+    b bt_end
+bt_apl:
+    //HI - (C==1) && (Z==0)
+    ldr w0, [x27,#32]
+    cmp w0, #1
+    b.ne bt_ahi
+    cmp w0,#0
+    b bt_end
+bt_ahi:
+
+    //LS - (C==0) || (Z==1)
+    ldr w0, [x27,#36]
+    cmp w0, #1
+    b.ne bt_als
+    cmp w0,#1
+    b bt_end
+bt_als:
+
+    //GE
+    ldr w0, [x27,#40]
+    cmp w0, #1
+    b.ne bt_age
+    cmp w0,#0
+    b bt_end
+bt_age:
+
+    //LT
+    ldr w0, [x27,#44]
+    cmp w0, #1
+    b.ne bt_alt
+    cmp w0,#2
+    b bt_end
+bt_alt:
+
+    //GT
+    ldr w0, [x27,#48]
+    cmp w0, #1
+    b.ne bt_agt
+    cmp w0,#0
+    b bt_end
+bt_agt:
+
+    //LE
+    ldr w0, [x27,#52]
+    cmp w0, #1
+    b.ne bt_ale
+    cmp w0,#2
+    b bt_end
+bt_ale:
+
+
+bt_end:
+
+    // Load the registers from reg array
+    ldr x0, [x28,#0]
+    ldr x1, [x28,#8]
+    ldr x2, [x28,#16]
+    ldr x3, [x28,#24]
+    ldr x4, [x28,#32]
+    ldr x5, [x28,#40]
+    ldr x6, [x28,#48]
+    ldr x7, [x28,#56]
+    ldr x8, [x28,#64]
+    ldr x9, [x28,#72]
+    ldr x10, [x28,#80]
+    ldr x11, [x28,#88]
+    ldr x12, [x28,#96]
+    ldr x14, [x28,#112]
+
+    // Call the function
+    blr X30
+
+    // Save the registers to reg array
+    str x0, [x28,#0]
+    str x1, [x28,#8]
+    str x2, [x28,#16]
+    str x3, [x28,#24]
+    str x4, [x28,#32]
+    str x5, [x28,#40]
+    str x6, [x28,#48]
+    str x7, [x28,#56]
+    str x8, [x28,#64]
+    str x9, [x28,#72]
+    str x10, [x28,#80]
+    str x11, [x28,#88]
+    str x12, [x28,#96]
+    str x14, [x28,#112]
+
+    //Set the flags array based on result flags
+    movz w0, #0
+    movz w1, #1
+    csel w2, w1, w0, EQ
+    str w2, [x27,#0]
+    csel w2, w1, w0, NE
+    str w2, [x27,#4]
+    csel w2, w1, w0, CS
+    str w2, [x27,#8]
+    csel w2, w1, w0, CC
+    str w2, [x27,#12]
+    csel w2, w1, w0, MI
+    str w2, [x27,#16]
+    csel w2, w1, w0, PL
+    str w2, [x27,#20]
+    csel w2, w1, w0, VS
+    str w2, [x27,#24]
+    csel w2, w1, w0, VC
+    str w2, [x27,#28]
+    csel w2, w1, w0, HI
+    str w2, [x27,#32]
+    csel w2, w1, w0, LS
+    str w2, [x27,#36]
+    csel w2, w1, w0, GE
+    str w2, [x27,#40]
+    csel w2, w1, w0, LT
+    str w2, [x27,#44]
+    csel w2, w1, w0, GT
+    str w2, [x27,#48]
+    csel w2, w1, w0, LE
+    str w2, [x27,#52]
+
+    // Restore registers from stack
+    ldp    x27, x28, [sp],#16
+    ldp    x29, x30, [sp],#16
+    ret
+
diff --git a/libpixelflinger/tests/arch-aarch64/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-aarch64/col32cb16blend/Android.mk
new file mode 100644
index 0000000..7445fc8
--- /dev/null
+++ b/libpixelflinger/tests/arch-aarch64/col32cb16blend/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    col32cb16blend_test.c \
+    ../../../arch-aarch64/col32cb16blend.S
+
+LOCAL_SHARED_LIBRARIES :=
+
+LOCAL_C_INCLUDES :=
+
+LOCAL_MODULE:= test-pixelflinger-aarch64-col32cb16blend
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libpixelflinger/tests/arch-aarch64/col32cb16blend/col32cb16blend_test.c b/libpixelflinger/tests/arch-aarch64/col32cb16blend/col32cb16blend_test.c
new file mode 100644
index 0000000..f057884
--- /dev/null
+++ b/libpixelflinger/tests/arch-aarch64/col32cb16blend/col32cb16blend_test.c
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ *
+ * 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 <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+
+#define ARGB_8888_MAX   0xFFFFFFFF
+#define ARGB_8888_MIN   0x00000000
+#define RGB_565_MAX 0xFFFF
+#define RGB_565_MIN 0x0000
+
+struct test_t
+{
+    char name[256];
+    uint32_t dst_color;
+    uint32_t src_color;
+    size_t count;
+};
+
+struct test_t tests[] =
+{
+    {"Count 1, Src=Max, Dst=Min", ARGB_8888_MAX, RGB_565_MIN, 1},
+    {"Count 2, Src=Min, Dst=Max", ARGB_8888_MIN, RGB_565_MAX, 2},
+    {"Count 3, Src=Max, Dst=Max", ARGB_8888_MAX, RGB_565_MAX, 3},
+    {"Count 4, Src=Min, Dst=Min", ARGB_8888_MAX, RGB_565_MAX, 4},
+    {"Count 1, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 1},
+    {"Count 2, Src=Rand, Dst=Rand", 0xABCDEF12, 0x2345, 2},
+    {"Count 3, Src=Rand, Dst=Rand", 0x11111111, 0xEDFE, 3},
+    {"Count 4, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 4},
+    {"Count 5, Src=Rand, Dst=Rand", 0xEFEFFEFE, 0xFACC, 5},
+    {"Count 10, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 10}
+};
+
+void scanline_col32cb16blend_aarch64(uint16_t *dst, int32_t src, size_t count);
+void scanline_col32cb16blend_c(uint16_t * dst, int32_t src, size_t count)
+{
+    int srcAlpha = (src>>24);
+    int f = 0x100 - (srcAlpha + (srcAlpha>>7));
+    while (count--)
+    {
+        uint16_t d = *dst;
+        int dstR = (d>>11)&0x1f;
+        int dstG = (d>>5)&0x3f;
+        int dstB = (d)&0x1f;
+        int srcR = (src >> (   3))&0x1F;
+        int srcG = (src >> ( 8+2))&0x3F;
+        int srcB = (src >> (16+3))&0x1F;
+        srcR += (f*dstR)>>8;
+        srcG += (f*dstG)>>8;
+        srcB += (f*dstB)>>8;
+        *dst++ = (uint16_t)((srcR<<11)|(srcG<<5)|srcB);
+    }
+}
+
+void scanline_col32cb16blend_test()
+{
+    uint16_t dst_c[16], dst_asm[16];
+    uint32_t i, j;
+
+    for(i = 0; i < sizeof(tests)/sizeof(struct test_t); ++i)
+    {
+        struct test_t test = tests[i];
+
+        printf("Testing - %s:",test.name);
+
+        memset(dst_c, 0, sizeof(dst_c));
+        memset(dst_asm, 0, sizeof(dst_asm));
+
+        for(j = 0; j < test.count; ++j)
+        {
+            dst_c[j]   = test.dst_color;
+            dst_asm[j] = test.dst_color;
+        }
+
+
+        scanline_col32cb16blend_c(dst_c, test.src_color, test.count);
+        scanline_col32cb16blend_aarch64(dst_asm, test.src_color, test.count);
+
+
+        if(memcmp(dst_c, dst_asm, sizeof(dst_c)) == 0)
+            printf("Passed\n");
+        else
+            printf("Failed\n");
+
+        for(j = 0; j < test.count; ++j)
+        {
+            printf("dst_c[%d] = %x, dst_asm[%d] = %x \n", j, dst_c[j], j, dst_asm[j]);
+        }
+    }
+}
+
+int main()
+{
+    scanline_col32cb16blend_test();
+    return 0;
+}
diff --git a/libpixelflinger/tests/arch-aarch64/disassembler/Android.mk b/libpixelflinger/tests/arch-aarch64/disassembler/Android.mk
new file mode 100644
index 0000000..376c3b7
--- /dev/null
+++ b/libpixelflinger/tests/arch-aarch64/disassembler/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    aarch64_diassembler_test.cpp \
+    ../../../codeflinger/Aarch64Disassembler.cpp
+
+LOCAL_SHARED_LIBRARIES :=
+
+LOCAL_C_INCLUDES := \
+    system/core/libpixelflinger/codeflinger
+
+LOCAL_MODULE:= test-pixelflinger-aarch64-disassembler-test
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libpixelflinger/tests/arch-aarch64/disassembler/aarch64_diassembler_test.cpp b/libpixelflinger/tests/arch-aarch64/disassembler/aarch64_diassembler_test.cpp
new file mode 100644
index 0000000..17caee1
--- /dev/null
+++ b/libpixelflinger/tests/arch-aarch64/disassembler/aarch64_diassembler_test.cpp
@@ -0,0 +1,321 @@
+/*
+ * 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.
+ *
+ * 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 <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+
+int aarch64_disassemble(uint32_t code, char* instr);
+
+struct test_table_entry_t
+{
+     uint32_t code;
+     const char *instr;
+};
+static test_table_entry_t test_table [] =
+{
+    { 0x91000240, "add x0, x18, #0x0, lsl #0"         },
+    { 0x9140041f, "add sp, x0, #0x1, lsl #12"         },
+    { 0x917ffff2, "add x18, sp, #0xfff, lsl #12"      },
+
+    { 0xd13ffe40, "sub x0, x18, #0xfff, lsl #0"       },
+    { 0xd140001f, "sub sp, x0, #0x0, lsl #12"         },
+    { 0xd14007f2, "sub x18, sp, #0x1, lsl #12"        },
+
+    { 0x8b1e0200, "add x0, x16, x30, lsl #0"          },
+    { 0x8b507fdf, "add xzr, x30, x16, lsr #31"        },
+    { 0x8b8043f0, "add x16, xzr, x0, asr #16"         },
+    { 0x8b5f401e, "add x30, x0, xzr, lsr #16"         },
+
+
+    { 0x4b1e0200, "sub w0, w16, w30, lsl #0"          },
+    { 0x4b507fdf, "sub wzr, w30, w16, lsr #31"        },
+    { 0x4b8043f0, "sub w16, wzr, w0, asr #16"         },
+    { 0x4b5f401e, "sub w30, w0, wzr, lsr #16"         },
+
+    { 0x6b1e0200, "subs w0, w16, w30, lsl #0"         },
+    { 0x6b507fdf, "subs wzr, w30, w16, lsr #31"       },
+    { 0x6b8043f0, "subs w16, wzr, w0, asr #16"        },
+    { 0x6b5f401e, "subs w30, w0, wzr, lsr #16"        },
+
+    { 0x0a1e0200, "and w0, w16, w30, lsl #0"          },
+    { 0x0a507fdf, "and wzr, w30, w16, lsr #31"        },
+    { 0x0a8043f0, "and w16, wzr, w0, asr #16"         },
+    { 0x0adf401e, "and w30, w0, wzr, ror #16"         },
+
+    { 0x2a1e0200, "orr w0, w16, w30, lsl #0"          },
+    { 0x2a507fdf, "orr wzr, w30, w16, lsr #31"        },
+    { 0x2a8043f0, "orr w16, wzr, w0, asr #16"         },
+    { 0x2adf401e, "orr w30, w0, wzr, ror #16"         },
+
+    { 0x2a3e0200, "orn w0, w16, w30, lsl #0"          },
+    { 0x2a707fdf, "orn wzr, w30, w16, lsr #31"        },
+    { 0x2aa043f0, "orn w16, wzr, w0, asr #16"         },
+    { 0x2aff401e, "orn w30, w0, wzr, ror #16"         },
+
+    { 0x729fffe0, "movk w0, #0xffff, lsl #0"          },
+    { 0x72a0000f, "movk w15, #0x0, lsl #16"           },
+    { 0x7281fffe, "movk w30, #0xfff, lsl #0"          },
+    { 0x72a0003f, "movk wzr, #0x1, lsl #16"           },
+
+    { 0x529fffe0, "movz w0, #0xffff, lsl #0"          },
+    { 0x52a0000f, "movz w15, #0x0, lsl #16"           },
+    { 0x5281fffe, "movz w30, #0xfff, lsl #0"          },
+    { 0x52a0003f, "movz wzr, #0x1, lsl #16"           },
+
+    { 0xd29fffe0, "movz x0, #0xffff, lsl #0"          },
+    { 0xd2a0000f, "movz x15, #0x0, lsl #16"           },
+    { 0xd2c1fffe, "movz x30, #0xfff, lsl #32"         },
+    { 0xd2e0003f, "movz xzr, #0x1, lsl #48"           },
+
+    { 0x1a8003e0, "csel w0, wzr, w0, eq"              },
+    { 0x1a831001, "csel w1, w0, w3, ne"               },
+    { 0x1a9e2022, "csel w2, w1, w30, cs"              },
+    { 0x1a8a3083, "csel w3, w4, w10, cc"              },
+    { 0x1a8b40e4, "csel w4, w7, w11, mi"              },
+    { 0x1a9b5105, "csel w5, w8, w27, pl"              },
+    { 0x1a846167, "csel w7, w11, w4, vs"              },
+    { 0x1a8671c8, "csel w8, w14, w6, vc"              },
+    { 0x1a878289, "csel w9, w20, w7, hi"              },
+    { 0x1a8c92aa, "csel w10, w21, w12, ls"            },
+    { 0x1a8ea2ce, "csel w14, w22, w14, ge"            },
+    { 0x1a9fb3b2, "csel w18, w29, wzr, lt"            },
+    { 0x1a9fc3d8, "csel w24, w30, wzr, gt"            },
+    { 0x1a82d17e, "csel w30, w11, w2, le"             },
+    { 0x1a81e19f, "csel wzr, w12, w1, al"             },
+
+    { 0x9a8003e0, "csel x0, xzr, x0, eq"              },
+    { 0x9a831001, "csel x1, x0, x3, ne"               },
+    { 0x9a9e2022, "csel x2, x1, x30, cs"              },
+    { 0x9a8a3083, "csel x3, x4, x10, cc"              },
+    { 0x9a8b40e4, "csel x4, x7, x11, mi"              },
+    { 0x9a9b5105, "csel x5, x8, x27, pl"              },
+    { 0x9a846167, "csel x7, x11, x4, vs"              },
+    { 0x9a8671c8, "csel x8, x14, x6, vc"              },
+    { 0x9a878289, "csel x9, x20, x7, hi"              },
+    { 0x9a8c92aa, "csel x10, x21, x12, ls"            },
+    { 0x9a8ea2ce, "csel x14, x22, x14, ge"            },
+    { 0x9a9fb3b2, "csel x18, x29, xzr, lt"            },
+    { 0x9a9fc3d8, "csel x24, x30, xzr, gt"            },
+    { 0x9a82d17e, "csel x30, x11, x2, le"             },
+    { 0x9a81e19f, "csel xzr, x12, x1, al"             },
+
+    { 0x5a8003e0, "csinv w0, wzr, w0, eq"             },
+    { 0x5a831001, "csinv w1, w0, w3, ne"              },
+    { 0x5a9e2022, "csinv w2, w1, w30, cs"             },
+    { 0x5a8a3083, "csinv w3, w4, w10, cc"             },
+    { 0x5a8b40e4, "csinv w4, w7, w11, mi"             },
+    { 0x5a9b5105, "csinv w5, w8, w27, pl"             },
+    { 0x5a846167, "csinv w7, w11, w4, vs"             },
+    { 0x5a8671c8, "csinv w8, w14, w6, vc"             },
+    { 0x5a878289, "csinv w9, w20, w7, hi"             },
+    { 0x5a8c92aa, "csinv w10, w21, w12, ls"           },
+    { 0x5a8ea2ce, "csinv w14, w22, w14, ge"           },
+    { 0x5a9fb3b2, "csinv w18, w29, wzr, lt"           },
+    { 0x5a9fc3d8, "csinv w24, w30, wzr, gt"           },
+    { 0x5a82d17e, "csinv w30, w11, w2, le"            },
+    { 0x5a81e19f, "csinv wzr, w12, w1, al"            },
+
+    { 0x1b1f3fc0, "madd w0, w30, wzr, w15"            },
+    { 0x1b0079ef, "madd w15, w15, w0, w30"            },
+    { 0x1b0f7ffe, "madd w30, wzr, w15, wzr"           },
+    { 0x1b1e001f, "madd wzr, w0, w30, w0"             },
+
+    { 0x9b3f3fc0, "smaddl x0, w30, wzr, x15"          },
+    { 0x9b2079ef, "smaddl x15, w15, w0, x30"          },
+    { 0x9b2f7ffe, "smaddl x30, wzr, w15, xzr"         },
+    { 0x9b3e001f, "smaddl xzr, w0, w30, x0"           },
+
+    { 0xd65f0000, "ret x0"                            },
+    { 0xd65f01e0, "ret x15"                           },
+    { 0xd65f03c0, "ret x30"                           },
+    { 0xd65f03e0, "ret xzr"                           },
+
+    { 0xb87f4be0, "ldr w0, [sp, wzr, uxtw #0]"        },
+    { 0xb87ed80f, "ldr w15, [x0, w30, sxtw #2]"       },
+    { 0xb86fc9fe, "ldr w30, [x15, w15, sxtw #0]"      },
+    { 0xb8605bdf, "ldr wzr, [x30, w0, uxtw #2]"       },
+    { 0xb87febe0, "ldr w0, [sp, xzr, sxtx #0]"        },
+    { 0xb87e780f, "ldr w15, [x0, x30, lsl #2]"        },
+    { 0xb86f69fe, "ldr w30, [x15, x15, lsl #0]"       },
+    { 0xb860fbdf, "ldr wzr, [x30, x0, sxtx #2]"       },
+
+    { 0xb83f4be0, "str w0, [sp, wzr, uxtw #0]"        },
+    { 0xb83ed80f, "str w15, [x0, w30, sxtw #2]"       },
+    { 0xb82fc9fe, "str w30, [x15, w15, sxtw #0]"      },
+    { 0xb8205bdf, "str wzr, [x30, w0, uxtw #2]"       },
+    { 0xb83febe0, "str w0, [sp, xzr, sxtx #0]"        },
+    { 0xb83e780f, "str w15, [x0, x30, lsl #2]"        },
+    { 0xb82f69fe, "str w30, [x15, x15, lsl #0]"       },
+    { 0xb820fbdf, "str wzr, [x30, x0, sxtx #2]"       },
+
+    { 0x787f4be0, "ldrh w0, [sp, wzr, uxtw #0]"       },
+    { 0x787ed80f, "ldrh w15, [x0, w30, sxtw #1]"      },
+    { 0x786fc9fe, "ldrh w30, [x15, w15, sxtw #0]"     },
+    { 0x78605bdf, "ldrh wzr, [x30, w0, uxtw #1]"      },
+    { 0x787febe0, "ldrh w0, [sp, xzr, sxtx #0]"       },
+    { 0x787e780f, "ldrh w15, [x0, x30, lsl #1]"       },
+    { 0x786f69fe, "ldrh w30, [x15, x15, lsl #0]"      },
+    { 0x7860fbdf, "ldrh wzr, [x30, x0, sxtx #1]"      },
+
+    { 0x783f4be0, "strh w0, [sp, wzr, uxtw #0]"       },
+    { 0x783ed80f, "strh w15, [x0, w30, sxtw #1]"      },
+    { 0x782fc9fe, "strh w30, [x15, w15, sxtw #0]"     },
+    { 0x78205bdf, "strh wzr, [x30, w0, uxtw #1]"      },
+    { 0x783febe0, "strh w0, [sp, xzr, sxtx #0]"       },
+    { 0x783e780f, "strh w15, [x0, x30, lsl #1]"       },
+    { 0x782f69fe, "strh w30, [x15, x15, lsl #0]"      },
+    { 0x7820fbdf, "strh wzr, [x30, x0, sxtx #1]"      },
+
+    { 0x387f5be0, "ldrb w0, [sp, wzr, uxtw #0]"       },
+    { 0x387ec80f, "ldrb w15, [x0, w30, sxtw ]"        },
+    { 0x386fd9fe, "ldrb w30, [x15, w15, sxtw #0]"     },
+    { 0x38604bdf, "ldrb wzr, [x30, w0, uxtw ]"        },
+    { 0x387ffbe0, "ldrb w0, [sp, xzr, sxtx #0]"       },
+    { 0x387e780f, "ldrb w15, [x0, x30, lsl #0]"       },
+    { 0x386f79fe, "ldrb w30, [x15, x15, lsl #0]"      },
+    { 0x3860ebdf, "ldrb wzr, [x30, x0, sxtx ]"        },
+
+    { 0x383f5be0, "strb w0, [sp, wzr, uxtw #0]"       },
+    { 0x383ec80f, "strb w15, [x0, w30, sxtw ]"        },
+    { 0x382fd9fe, "strb w30, [x15, w15, sxtw #0]"     },
+    { 0x38204bdf, "strb wzr, [x30, w0, uxtw ]"        },
+    { 0x383ffbe0, "strb w0, [sp, xzr, sxtx #0]"       },
+    { 0x383e780f, "strb w15, [x0, x30, lsl #0]"       },
+    { 0x382f79fe, "strb w30, [x15, x15, lsl #0]"      },
+    { 0x3820ebdf, "strb wzr, [x30, x0, sxtx ]"        },
+
+    { 0xf87f4be0, "ldr x0, [sp, wzr, uxtw #0]"        },
+    { 0xf87ed80f, "ldr x15, [x0, w30, sxtw #3]"       },
+    { 0xf86fc9fe, "ldr x30, [x15, w15, sxtw #0]"      },
+    { 0xf8605bdf, "ldr xzr, [x30, w0, uxtw #3]"       },
+    { 0xf87febe0, "ldr x0, [sp, xzr, sxtx #0]"        },
+    { 0xf87e780f, "ldr x15, [x0, x30, lsl #3]"        },
+    { 0xf86f69fe, "ldr x30, [x15, x15, lsl #0]"       },
+    { 0xf860fbdf, "ldr xzr, [x30, x0, sxtx #3]"       },
+
+    { 0xf83f4be0, "str x0, [sp, wzr, uxtw #0]"        },
+    { 0xf83ed80f, "str x15, [x0, w30, sxtw #3]"       },
+    { 0xf82fc9fe, "str x30, [x15, w15, sxtw #0]"      },
+    { 0xf8205bdf, "str xzr, [x30, w0, uxtw #3]"       },
+    { 0xf83febe0, "str x0, [sp, xzr, sxtx #0]"        },
+    { 0xf83e780f, "str x15, [x0, x30, lsl #3]"        },
+    { 0xf82f69fe, "str x30, [x15, x15, lsl #0]"       },
+    { 0xf820fbdf, "str xzr, [x30, x0, sxtx #3]"       },
+
+    { 0xb85007e0, "ldr w0, [sp], #-256"               },
+    { 0xb840040f, "ldr w15, [x0], #0"                 },
+    { 0xb84015fe, "ldr w30, [x15], #1"                },
+    { 0xb84ff7df, "ldr wzr, [x30], #255"              },
+    { 0xb8100fe0, "str w0, [sp, #-256]!"              },
+    { 0xb8000c0f, "str w15, [x0, #0]!"                },
+    { 0xb8001dfe, "str w30, [x15, #1]!"               },
+    { 0xb80fffdf, "str wzr, [x30, #255]!"             },
+
+    { 0x13017be0, "sbfm w0, wzr, #1, #30"             },
+    { 0x131e7fcf, "sbfm w15, w30, #30, #31"           },
+    { 0x131f01fe, "sbfm w30, w15, #31, #0"            },
+    { 0x1300041f, "sbfm wzr, w0, #0, #1"              },
+
+    { 0x53017be0, "ubfm w0, wzr, #1, #30"             },
+    { 0x531e7fcf, "ubfm w15, w30, #30, #31"           },
+    { 0x531f01fe, "ubfm w30, w15, #31, #0"            },
+    { 0x5300041f, "ubfm wzr, w0, #0, #1"              },
+    { 0xd3417fe0, "ubfm x0, xzr, #1, #31"             },
+    { 0xd35fffcf, "ubfm x15, x30, #31, #63"           },
+    { 0xd35f01fe, "ubfm x30, x15, #31, #0"            },
+    { 0xd340041f, "ubfm xzr, x0, #0, #1"              },
+
+    { 0x139e7be0, "extr w0, wzr, w30, #30"            },
+    { 0x138f7fcf, "extr w15, w30, w15, #31"           },
+    { 0x138001fe, "extr w30, w15, w0, #0"             },
+    { 0x139f041f, "extr wzr, w0, wzr, #1"             },
+
+    { 0x54000020, "b.eq #.+4"                         },
+    { 0x54000201, "b.ne #.+64"                        },
+    { 0x54000802, "b.cs #.+256"                       },
+    { 0x54002003, "b.cc #.+1024"                      },
+    { 0x54008004, "b.mi #.+4096"                      },
+    { 0x54ffffe5, "b.pl #.-4"                         },
+    { 0x54ffff06, "b.vs #.-32"                        },
+    { 0x54fffc07, "b.vc #.-128"                       },
+    { 0x54fff008, "b.hi #.-512"                       },
+    { 0x54000049, "b.ls #.+8"                         },
+    { 0x5400006a, "b.ge #.+12"                        },
+    { 0x5400008b, "b.lt #.+16"                        },
+    { 0x54ffffcc, "b.gt #.-8"                         },
+    { 0x54ffffad, "b.le #.-12"                        },
+    { 0x54ffff8e, "b.al #.-16"                        },
+
+    { 0x8b2001e0, "add x0, x15, w0, uxtb #0"          },
+    { 0x8b2f27cf, "add x15, x30, w15, uxth #1"        },
+    { 0x8b3e4bfe, "add x30, sp, w30, uxtw #2"         },
+    { 0x8b3f6c1f, "add sp, x0, xzr, uxtx #3"          },
+    { 0x8b2091e0, "add x0, x15, w0, sxtb #4"          },
+    { 0x8b2fa3cf, "add x15, x30, w15, sxth #0"        },
+    { 0x8b3ec7fe, "add x30, sp, w30, sxtw #1"         },
+    { 0x8b3fe81f, "add sp, x0, xzr, sxtx #2"          },
+
+    { 0xcb2001e0, "sub x0, x15, w0, uxtb #0"          },
+    { 0xcb2f27cf, "sub x15, x30, w15, uxth #1"        },
+    { 0xcb3e4bfe, "sub x30, sp, w30, uxtw #2"         },
+    { 0xcb3f6c1f, "sub sp, x0, xzr, uxtx #3"          },
+    { 0xcb2091e0, "sub x0, x15, w0, sxtb #4"          },
+    { 0xcb2fa3cf, "sub x15, x30, w15, sxth #0"        },
+    { 0xcb3ec7fe, "sub x30, sp, w30, sxtw #1"         },
+    { 0xcb3fe81f, "sub sp, x0, xzr, sxtx #2"          }
+};
+
+int main()
+{
+    char instr[256];
+    uint32_t failed = 0;
+    for(uint32_t i = 0; i < sizeof(test_table)/sizeof(test_table_entry_t); ++i)
+    {
+        test_table_entry_t *test;
+        test = &test_table[i];
+        aarch64_disassemble(test->code, instr);
+        if(strcmp(instr, test->instr) != 0)
+        {
+            printf("Test Failed \n"
+                   "Code     : 0x%0x\n"
+                   "Expected : %s\n"
+                   "Actual   : %s\n", test->code, test->instr, instr);
+            failed++;
+        }
+    }
+    if(failed == 0)
+    {
+        printf("All tests PASSED\n");
+        return 0;
+    }
+    else
+    {
+        printf("%d tests FAILED\n", failed);
+        return -1;
+    }
+}
diff --git a/libpixelflinger/tests/arch-aarch64/t32cb16blend/Android.mk b/libpixelflinger/tests/arch-aarch64/t32cb16blend/Android.mk
new file mode 100644
index 0000000..a67f0e3
--- /dev/null
+++ b/libpixelflinger/tests/arch-aarch64/t32cb16blend/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    t32cb16blend_test.c \
+    ../../../arch-aarch64/t32cb16blend.S
+
+LOCAL_SHARED_LIBRARIES :=
+
+LOCAL_C_INCLUDES :=
+
+LOCAL_MODULE:= test-pixelflinger-aarch64-t32cb16blend
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libpixelflinger/tests/arch-aarch64/t32cb16blend/t32cb16blend_test.c b/libpixelflinger/tests/arch-aarch64/t32cb16blend/t32cb16blend_test.c
new file mode 100644
index 0000000..bcde3e6
--- /dev/null
+++ b/libpixelflinger/tests/arch-aarch64/t32cb16blend/t32cb16blend_test.c
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ *
+ * 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 <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#define ARGB_8888_MAX   0xFFFFFFFF
+#define ARGB_8888_MIN   0x00000000
+#define RGB_565_MAX     0xFFFF
+#define RGB_565_MIN     0x0000
+
+struct test_t
+{
+    char name[256];
+    uint32_t src_color;
+    uint16_t dst_color;
+    size_t count;
+};
+
+struct test_t tests[] =
+{
+    {"Count 0", 0, 0, 0},
+    {"Count 1, Src=Max, Dst=Min", ARGB_8888_MAX, RGB_565_MIN, 1},
+    {"Count 2, Src=Min, Dst=Max", ARGB_8888_MIN, RGB_565_MAX, 2},
+    {"Count 3, Src=Max, Dst=Max", ARGB_8888_MAX, RGB_565_MAX, 3},
+    {"Count 4, Src=Min, Dst=Min", ARGB_8888_MAX, RGB_565_MAX, 4},
+    {"Count 1, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 1},
+    {"Count 2, Src=Rand, Dst=Rand", 0xABCDEF12, 0x2345, 2},
+    {"Count 3, Src=Rand, Dst=Rand", 0x11111111, 0xEDFE, 3},
+    {"Count 4, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 4},
+    {"Count 5, Src=Rand, Dst=Rand", 0xEFEFFEFE, 0xFACC, 5},
+    {"Count 10, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 10}
+
+};
+
+void scanline_t32cb16blend_aarch64(uint16_t*, uint32_t*, size_t);
+void scanline_t32cb16blend_c(uint16_t * dst, uint32_t* src, size_t count)
+{
+    while (count--)
+    {
+        uint16_t d = *dst;
+        uint32_t s = *src++;
+        int dstR = (d>>11)&0x1f;
+        int dstG = (d>>5)&0x3f;
+        int dstB = (d)&0x1f;
+        int srcR = (s >> (   3))&0x1F;
+        int srcG = (s >> ( 8+2))&0x3F;
+        int srcB = (s >> (16+3))&0x1F;
+        int srcAlpha = (s>>24) & 0xFF;
+
+
+        int f = 0x100 - (srcAlpha + ((srcAlpha>>7) & 0x1));
+        srcR += (f*dstR)>>8;
+        srcG += (f*dstG)>>8;
+        srcB += (f*dstB)>>8;
+        srcR = srcR > 0x1F? 0x1F: srcR;
+        srcG = srcG > 0x3F? 0x3F: srcG;
+        srcB = srcB > 0x1F? 0x1F: srcB;
+        *dst++ = (uint16_t)((srcR<<11)|(srcG<<5)|srcB);
+    }
+}
+
+void scanline_t32cb16blend_test()
+{
+    uint16_t dst_c[16], dst_asm[16];
+    uint32_t src[16];
+    uint32_t i;
+    uint32_t  j;
+
+    for(i = 0; i < sizeof(tests)/sizeof(struct test_t); ++i)
+    {
+        struct test_t test = tests[i];
+
+        printf("Testing - %s:",test.name);
+
+        memset(dst_c, 0, sizeof(dst_c));
+        memset(dst_asm, 0, sizeof(dst_asm));
+
+        for(j = 0; j < test.count; ++j)
+        {
+            dst_c[j]   = test.dst_color;
+            dst_asm[j] = test.dst_color;
+            src[j] = test.src_color;
+        }
+
+        scanline_t32cb16blend_c(dst_c,src,test.count);
+        scanline_t32cb16blend_aarch64(dst_asm,src,test.count);
+
+
+        if(memcmp(dst_c, dst_asm, sizeof(dst_c)) == 0)
+            printf("Passed\n");
+        else
+            printf("Failed\n");
+
+        for(j = 0; j < test.count; ++j)
+        {
+            printf("dst_c[%d] = %x, dst_asm[%d] = %x \n", j, dst_c[j], j, dst_asm[j]);
+        }
+    }
+}
+
+int main()
+{
+    scanline_t32cb16blend_test();
+    return 0;
+}
diff --git a/libpixelflinger/tests/codegen/codegen.cpp b/libpixelflinger/tests/codegen/codegen.cpp
index 3d5a040..e8a4f5e 100644
--- a/libpixelflinger/tests/codegen/codegen.cpp
+++ b/libpixelflinger/tests/codegen/codegen.cpp
@@ -10,8 +10,9 @@
 #include "codeflinger/GGLAssembler.h"
 #include "codeflinger/ARMAssembler.h"
 #include "codeflinger/MIPSAssembler.h"
+#include "codeflinger/Aarch64Assembler.h"
 
-#if defined(__arm__) || defined(__mips__)
+#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
 #   define ANDROID_ARM_CODEGEN  1
 #else
 #   define ANDROID_ARM_CODEGEN  0
@@ -19,6 +20,8 @@
 
 #if defined (__mips__)
 #define ASSEMBLY_SCRATCH_SIZE   4096
+#elif defined(__aarch64__)
+#define ASSEMBLY_SCRATCH_SIZE   8192
 #else
 #define ASSEMBLY_SCRATCH_SIZE   2048
 #endif
@@ -53,13 +56,17 @@
     GGLAssembler assembler( new ArmToMipsAssembler(a) );
 #endif
 
+#if defined(__aarch64__)
+    GGLAssembler assembler( new ArmToAarch64Assembler(a) );
+#endif
+
     int err = assembler.scanline(needs, (context_t*)c);
     if (err != 0) {
         printf("error %08x (%s)\n", err, strerror(-err));
     }
     gglUninit(c);
 #else
-    printf("This test runs only on ARM or MIPS\n");
+    printf("This test runs only on ARM, Aarch64 or MIPS\n");
 #endif
 }
 
diff --git a/libpixelflinger/tests/gglmul/Android.mk b/libpixelflinger/tests/gglmul/Android.mk
new file mode 100644
index 0000000..64f88b7
--- /dev/null
+++ b/libpixelflinger/tests/gglmul/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	gglmul_test.cpp
+
+LOCAL_SHARED_LIBRARIES :=
+
+LOCAL_C_INCLUDES := \
+	system/core/libpixelflinger
+
+LOCAL_MODULE:= test-pixelflinger-gglmul
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libpixelflinger/tests/gglmul/gglmul_test.cpp b/libpixelflinger/tests/gglmul/gglmul_test.cpp
new file mode 100644
index 0000000..103e4e9
--- /dev/null
+++ b/libpixelflinger/tests/gglmul/gglmul_test.cpp
@@ -0,0 +1,279 @@
+/*
+ * 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.
+ *
+ * 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 <stdio.h>
+#include <stdint.h>
+
+#include "private/pixelflinger/ggl_fixed.h"
+
+// gglClampx() tests
+struct gglClampx_test_t
+{
+    GGLfixed input;
+    GGLfixed output;
+};
+
+gglClampx_test_t gglClampx_tests[] =
+{
+    {FIXED_ONE + 1, FIXED_ONE},
+    {FIXED_ONE, FIXED_ONE},
+    {FIXED_ONE - 1, FIXED_ONE - 1},
+    {1, 1},
+    {0, 0},
+    {FIXED_MIN,0}
+};
+
+void gglClampx_test()
+{
+    uint32_t i;
+
+    printf("Testing gglClampx\n");
+    for(i = 0; i < sizeof(gglClampx_tests)/sizeof(gglClampx_test_t); ++i)
+    {
+        gglClampx_test_t *test = &gglClampx_tests[i];
+        printf("Test input=0x%08x output=0x%08x :",
+                test->input, test->output);
+        if(gglClampx(test->input) == test->output)
+            printf("Passed\n");
+        else
+            printf("Failed\n");
+    }
+}
+
+// gglClz() tests
+struct gglClz_test_t
+{
+    GGLfixed input;
+    GGLfixed output;
+};
+
+gglClz_test_t gglClz_tests[] =
+{
+    {0, 32},
+    {1, 31},
+    {-1,0}
+};
+
+void gglClz_test()
+{
+    uint32_t i;
+
+    printf("Testing gglClz\n");
+    for(i = 0; i < sizeof(gglClz_tests)/sizeof(gglClz_test_t); ++i)
+    {
+        gglClz_test_t *test = &gglClz_tests[i];
+        printf("Test input=0x%08x output=%2d :", test->input, test->output);
+        if(gglClz(test->input) == test->output)
+            printf("Passed\n");
+        else
+            printf("Failed\n");
+    }
+}
+
+// gglMulx() tests
+struct gglMulx_test_t
+{
+    GGLfixed x;
+    GGLfixed y;
+    int      shift;
+};
+
+gglMulx_test_t gglMulx_tests[] =
+{
+    {1,1,1},
+    {0,1,1},
+    {FIXED_ONE,FIXED_ONE,16},
+    {FIXED_MIN,FIXED_MAX,16},
+    {FIXED_MAX,FIXED_MAX,16},
+    {FIXED_MIN,FIXED_MIN,16},
+    {FIXED_HALF,FIXED_ONE,16},
+    {FIXED_MAX,FIXED_MAX,31},
+    {FIXED_ONE,FIXED_MAX,31}
+};
+
+void gglMulx_test()
+{
+    uint32_t i;
+    GGLfixed actual, expected;
+
+    printf("Testing gglMulx\n");
+    for(i = 0; i < sizeof(gglMulx_tests)/sizeof(gglMulx_test_t); ++i)
+    {
+        gglMulx_test_t *test = &gglMulx_tests[i];
+        printf("Test x=0x%08x y=0x%08x shift=%2d :",
+                test->x, test->y, test->shift);
+        actual = gglMulx(test->x, test->y, test->shift);
+        expected =
+          ((int64_t)test->x * test->y + (1 << (test->shift-1))) >> test->shift;
+    if(actual == expected)
+        printf(" Passed\n");
+    else
+        printf(" Failed Actual(0x%08x) Expected(0x%08x)\n",
+               actual, expected);
+    }
+}
+// gglMulAddx() tests
+struct gglMulAddx_test_t
+{
+    GGLfixed x;
+    GGLfixed y;
+    int      shift;
+    GGLfixed a;
+};
+
+gglMulAddx_test_t gglMulAddx_tests[] =
+{
+    {1,2,1,1},
+    {0,1,1,1},
+    {FIXED_ONE,FIXED_ONE,16, 0},
+    {FIXED_MIN,FIXED_MAX,16, FIXED_HALF},
+    {FIXED_MAX,FIXED_MAX,16, FIXED_MIN},
+    {FIXED_MIN,FIXED_MIN,16, FIXED_MAX},
+    {FIXED_HALF,FIXED_ONE,16,FIXED_ONE},
+    {FIXED_MAX,FIXED_MAX,31, FIXED_HALF},
+    {FIXED_ONE,FIXED_MAX,31, FIXED_HALF}
+};
+
+void gglMulAddx_test()
+{
+    uint32_t i;
+    GGLfixed actual, expected;
+
+    printf("Testing gglMulAddx\n");
+    for(i = 0; i < sizeof(gglMulAddx_tests)/sizeof(gglMulAddx_test_t); ++i)
+    {
+        gglMulAddx_test_t *test = &gglMulAddx_tests[i];
+        printf("Test x=0x%08x y=0x%08x shift=%2d a=0x%08x :",
+                test->x, test->y, test->shift, test->a);
+        actual = gglMulAddx(test->x, test->y,test->a, test->shift);
+        expected = (((int64_t)test->x * test->y) >> test->shift) + test->a;
+
+        if(actual == expected)
+            printf(" Passed\n");
+        else
+            printf(" Failed Actual(0x%08x) Expected(0x%08x)\n",
+                    actual, expected);
+    }
+}
+// gglMulSubx() tests
+struct gglMulSubx_test_t
+{
+    GGLfixed x;
+    GGLfixed y;
+    int      shift;
+    GGLfixed a;
+};
+
+gglMulSubx_test_t gglMulSubx_tests[] =
+{
+    {1,2,1,1},
+    {0,1,1,1},
+    {FIXED_ONE,FIXED_ONE,16, 0},
+    {FIXED_MIN,FIXED_MAX,16, FIXED_HALF},
+    {FIXED_MAX,FIXED_MAX,16, FIXED_MIN},
+    {FIXED_MIN,FIXED_MIN,16, FIXED_MAX},
+    {FIXED_HALF,FIXED_ONE,16,FIXED_ONE},
+    {FIXED_MAX,FIXED_MAX,31, FIXED_HALF},
+    {FIXED_ONE,FIXED_MAX,31, FIXED_HALF}
+};
+
+void gglMulSubx_test()
+{
+    uint32_t i;
+    GGLfixed actual, expected;
+
+    printf("Testing gglMulSubx\n");
+    for(i = 0; i < sizeof(gglMulSubx_tests)/sizeof(gglMulSubx_test_t); ++i)
+    {
+        gglMulSubx_test_t *test = &gglMulSubx_tests[i];
+        printf("Test x=0x%08x y=0x%08x shift=%2d a=0x%08x :",
+                test->x, test->y, test->shift, test->a);
+        actual = gglMulSubx(test->x, test->y, test->a, test->shift);
+        expected = (((int64_t)test->x * test->y) >> test->shift) - test->a;
+
+        if(actual == expected)
+            printf(" Passed\n");
+        else
+            printf(" Failed Actual(0x%08x) Expected(0x%08x)\n",
+                actual, expected);
+    }
+}
+
+// gglMulii() tests
+const int32_t INT32_MAX = 0x7FFFFFFF;
+const int32_t INT32_MIN = 0x80000000;
+
+struct gglMulii_test_t
+{
+    int32_t x;
+    int32_t y;
+};
+
+gglMulii_test_t gglMulii_tests[] =
+{
+    {1,INT32_MIN},
+    {1,INT32_MAX},
+    {0,INT32_MIN},
+    {0,INT32_MAX},
+    {INT32_MIN, INT32_MAX},
+    {INT32_MAX, INT32_MIN},
+    {INT32_MIN, INT32_MIN},
+    {INT32_MAX, INT32_MAX}
+};
+
+void gglMulii_test()
+{
+    uint32_t i;
+    int64_t actual, expected;
+
+    printf("Testing gglMulii\n");
+    for(i = 0; i < sizeof(gglMulii_tests)/sizeof(gglMulii_test_t); ++i)
+    {
+        gglMulii_test_t *test = &gglMulii_tests[i];
+        printf("Test x=0x%08x y=0x%08x :", test->x, test->y);
+        actual = gglMulii(test->x, test->y);
+        expected = ((int64_t)test->x * test->y);
+
+        if(actual == expected)
+            printf(" Passed\n");
+        else
+            printf(" Failed Actual(%ld) Expected(%ld)\n",
+                    actual, expected);
+    }
+}
+
+int main(int argc, char** argv)
+{
+    gglClampx_test();
+    gglClz_test();
+    gglMulx_test();
+    gglMulAddx_test();
+    gglMulSubx_test();
+    gglMulii_test();
+    return 0;
+}
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 4beebb7..34f2016 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -23,6 +23,11 @@
 
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+
 #include <linux/if.h>
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter_ipv4/ipt_ULOG.h>
@@ -38,6 +43,9 @@
 const int NetlinkEvent::NlActionChange = 3;
 const int NetlinkEvent::NlActionLinkUp = 4;
 const int NetlinkEvent::NlActionLinkDown = 5;
+const int NetlinkEvent::NlActionAddressUpdated = 6;
+const int NetlinkEvent::NlActionAddressRemoved = 7;
+const int NetlinkEvent::NlActionRdnss = 8;
 
 NetlinkEvent::NetlinkEvent() {
     mAction = NlActionUnknown;
@@ -70,13 +78,209 @@
 }
 
 /*
- * Parse an binary message from a NETLINK_ROUTE netlink socket.
+ * Parse a RTM_NEWADDR or RTM_DELADDR message.
+ */
+bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr,
+                                      int rtasize) {
+    struct rtattr *rta;
+    struct ifa_cacheinfo *cacheinfo = NULL;
+    char addrstr[INET6_ADDRSTRLEN] = "";
+
+    // Sanity check.
+    if (type != RTM_NEWADDR && type != RTM_DELADDR) {
+        SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type);
+        return false;
+    }
+
+    // For log messages.
+    const char *msgtype = (type == RTM_NEWADDR) ? "RTM_NEWADDR" : "RTM_DELADDR";
+
+    for (rta = IFA_RTA(ifaddr); RTA_OK(rta, rtasize);
+         rta = RTA_NEXT(rta, rtasize)) {
+        if (rta->rta_type == IFA_ADDRESS) {
+            // Only look at the first address, because we only support notifying
+            // one change at a time.
+            if (*addrstr != '\0') {
+                SLOGE("Multiple IFA_ADDRESSes in %s, ignoring\n", msgtype);
+                continue;
+            }
+
+            // Convert the IP address to a string.
+            if (ifaddr->ifa_family == AF_INET) {
+                struct in_addr *addr4 = (struct in_addr *) RTA_DATA(rta);
+                if (RTA_PAYLOAD(rta) < sizeof(*addr4)) {
+                    SLOGE("Short IPv4 address (%d bytes) in %s",
+                          RTA_PAYLOAD(rta), msgtype);
+                    continue;
+                }
+                inet_ntop(AF_INET, addr4, addrstr, sizeof(addrstr));
+            } else if (ifaddr->ifa_family == AF_INET6) {
+                struct in6_addr *addr6 = (struct in6_addr *) RTA_DATA(rta);
+                if (RTA_PAYLOAD(rta) < sizeof(*addr6)) {
+                    SLOGE("Short IPv6 address (%d bytes) in %s",
+                          RTA_PAYLOAD(rta), msgtype);
+                    continue;
+                }
+                inet_ntop(AF_INET6, addr6, addrstr, sizeof(addrstr));
+            } else {
+                SLOGE("Unknown address family %d\n", ifaddr->ifa_family);
+                continue;
+            }
+
+            // Find the interface name.
+            char ifname[IFNAMSIZ + 1];
+            if (!if_indextoname(ifaddr->ifa_index, ifname)) {
+                SLOGE("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype);
+                return false;
+            }
+
+            // Fill in interface information.
+            mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated :
+                                              NlActionAddressRemoved;
+            mSubsystem = strdup("net");
+            asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
+                     ifaddr->ifa_prefixlen);
+            asprintf(&mParams[1], "INTERFACE=%s", ifname);
+            asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
+            asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
+        } else if (rta->rta_type == IFA_CACHEINFO) {
+            // Address lifetime information.
+            if (cacheinfo) {
+                // We only support one address.
+                SLOGE("Multiple IFA_CACHEINFOs in %s, ignoring\n", msgtype);
+                continue;
+            }
+
+            if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) {
+                SLOGE("Short IFA_CACHEINFO (%d vs. %d bytes) in %s",
+                      RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype);
+                continue;
+            }
+
+            cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta);
+            asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
+            asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
+            asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
+            asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
+        }
+    }
+
+    if (addrstr[0] == '\0') {
+        SLOGE("No IFA_ADDRESS in %s\n", msgtype);
+        return false;
+    }
+
+    return true;
+}
+
+/*
+<<<<<<< HEAD
+ * Parse a RTM_NEWNDUSEROPT message.
+ */
+bool NetlinkEvent::parseNdUserOptMessage(struct nduseroptmsg *msg, int len) {
+    // Check the length is valid.
+    if (msg->nduseropt_opts_len > len) {
+        SLOGE("RTM_NEWNDUSEROPT invalid length %d > %d\n",
+              msg->nduseropt_opts_len, len);
+        return false;
+    }
+    len = msg->nduseropt_opts_len;
+
+    // Check address family and packet type.
+    if (msg->nduseropt_family != AF_INET6) {
+        SLOGE("RTM_NEWNDUSEROPT message for unknown family %d\n",
+              msg->nduseropt_family);
+        return false;
+    }
+
+    if (msg->nduseropt_icmp_type != ND_ROUTER_ADVERT ||
+        msg->nduseropt_icmp_code != 0) {
+        SLOGE("RTM_NEWNDUSEROPT message for unknown ICMPv6 type/code %d/%d\n",
+              msg->nduseropt_icmp_type, msg->nduseropt_icmp_code);
+        return false;
+    }
+
+    // Find the interface name.
+    char ifname[IFNAMSIZ + 1];
+    if (!if_indextoname(msg->nduseropt_ifindex, ifname)) {
+        SLOGE("RTM_NEWNDUSEROPT on unknown ifindex %d\n",
+              msg->nduseropt_ifindex);
+        return false;
+    }
+
+    // The kernel sends a separate netlink message for each ND option in the RA.
+    // So only parse the first ND option in the message.
+    struct nd_opt_hdr *opthdr = (struct nd_opt_hdr *) (msg + 1);
+
+    // The length is in multiples of 8 octets.
+    uint16_t optlen = opthdr->nd_opt_len;
+    if (optlen * 8 > len) {
+        SLOGE("Invalid option length %d > %d for ND option %d\n",
+              optlen * 8, len, opthdr->nd_opt_type);
+        return false;
+    }
+
+    if (opthdr->nd_opt_type == ND_OPT_RDNSS) {
+        // DNS Servers (RFC 6106).
+        // Each address takes up 2*8 octets, and the header takes up 8 octets.
+        // So for a valid option with one or more addresses, optlen must be
+        // odd and greater than 1.
+        if ((optlen < 3) || !(optlen & 0x1)) {
+            SLOGE("Invalid optlen %d for RDNSS option\n", optlen);
+            return false;
+        }
+        int numaddrs = (optlen - 1) / 2;
+
+        // Find the lifetime.
+        struct nd_opt_rdnss *rndss_opt = (struct nd_opt_rdnss *) opthdr;
+        uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime);
+
+        // Construct "SERVERS=<comma-separated string of DNS addresses>".
+        // Reserve (INET6_ADDRSTRLEN + 1) chars for each address: all but the
+        // the last address are followed by ','; the last is followed by '\0'.
+        static const char kServerTag[] = "SERVERS=";
+        static const int kTagLength = sizeof(kServerTag) - 1;
+        int bufsize = kTagLength + numaddrs * (INET6_ADDRSTRLEN + 1);
+        char *buf = (char *) malloc(bufsize);
+        if (!buf) {
+            SLOGE("RDNSS option: out of memory\n");
+            return false;
+        }
+        strcpy(buf, kServerTag);
+        int pos = kTagLength;
+
+        struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1);
+        for (int i = 0; i < numaddrs; i++) {
+            if (i > 0) {
+                buf[pos++] = ',';
+            }
+            inet_ntop(AF_INET6, addrs + i, buf + pos, bufsize - pos);
+            pos += strlen(buf + pos);
+        }
+        buf[pos] = '\0';
+
+        mAction = NlActionRdnss;
+        mSubsystem = strdup("net");
+        asprintf(&mParams[0], "INTERFACE=%s", ifname);
+        asprintf(&mParams[1], "LIFETIME=%u", lifetime);
+        mParams[2] = buf;
+    } else {
+        SLOGD("Unknown ND option type %d\n", opthdr->nd_opt_type);
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Parse a binary message from a NETLINK_ROUTE netlink socket.
  */
 bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
-    size_t sz = size;
-    const struct nlmsghdr *nh = (struct nlmsghdr *) buffer;
+    const struct nlmsghdr *nh;
 
-    while (NLMSG_OK(nh, sz) && (nh->nlmsg_type != NLMSG_DONE)) {
+    for (nh = (struct nlmsghdr *) buffer;
+         NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE);
+         nh = NLMSG_NEXT(nh, size)) {
 
         if (nh->nlmsg_type == RTM_NEWLINK) {
             int len = nh->nlmsg_len - sizeof(*nh);
@@ -127,10 +331,41 @@
             mSubsystem = strdup("qlog");
             mAction = NlActionChange;
 
+        } else if (nh->nlmsg_type == RTM_NEWADDR ||
+                   nh->nlmsg_type == RTM_DELADDR) {
+            int len = nh->nlmsg_len - sizeof(*nh);
+            struct ifaddrmsg *ifa;
+
+            if (sizeof(*ifa) > (size_t) len) {
+                SLOGE("Got a short RTM_xxxADDR message\n");
+                continue;
+            }
+
+            ifa = (ifaddrmsg *)NLMSG_DATA(nh);
+            size_t rtasize = IFA_PAYLOAD(nh);
+            if (!parseIfAddrMessage(nh->nlmsg_type, ifa, rtasize)) {
+                continue;
+            }
+
+        } else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) {
+            int len = nh->nlmsg_len - sizeof(*nh);
+            struct nduseroptmsg *ndmsg = (struct nduseroptmsg *) NLMSG_DATA(nh);
+
+            if (sizeof(*ndmsg) > (size_t) len) {
+                SLOGE("Got a short RTM_NEWNDUSEROPT message\n");
+                continue;
+            }
+
+            size_t optsize = NLMSG_PAYLOAD(nh, sizeof(*ndmsg));
+            if (!parseNdUserOptMessage(ndmsg, optsize)) {
+                continue;
+            }
+
+
         } else {
-                SLOGD("Unexpected netlink message. type=0x%x\n", nh->nlmsg_type);
+                SLOGD("Unexpected netlink message. type=0x%x\n",
+                      nh->nlmsg_type);
         }
-        nh = NLMSG_NEXT(nh, size);
     }
 
     return true;
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..9a2dd6c
--- /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(Looper_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 & 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 "
+                "LOOPER_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 = 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 = POLL_ERROR;
+        goto Done;
+    }
+
+    // Check for poll timeout.
+    if (eventCount == 0) {
+#if DEBUG_POLL_AND_WAKE
+        ALOGD("%p ~ pollOnce - timeout", this);
+#endif
+        result = 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 |= EVENT_INPUT;
+                if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
+                if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
+                if (epollEvents & EPOLLHUP) events |= 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 = 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 == 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 = 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 == 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 != POLL_CALLBACK) {
+                return result;
+            }
+
+            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+            timeoutMillis = toMillisecondTimeoutDelay(now, endTime);
+            if (timeoutMillis == 0) {
+                return 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, Looper_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 = POLL_CALLBACK;
+    }
+
+    int epollEvents = 0;
+    if (events & EVENT_INPUT) epollEvents |= EPOLLIN;
+    if (events & 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..413250f
--- /dev/null
+++ b/libutils/SystemClock.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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
+
+    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;
+    }
+
+    // /dev/alarm doesn't exist, fallback to CLOCK_BOOTTIME
+    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;
+    }
+
+    // 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..00077e6
--- /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(Looper::POLL_TIMEOUT, result)
+            << "pollOnce result should be LOOPER_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(Looper::POLL_WAKE, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_WAKE, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_TIMEOUT, result)
+            << "pollOnce result should be Looper::POLL_TIMEOUT";
+}
+
+TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    handler.setCallback(mLooper, pipe.receiveFd, Looper::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(Looper::POLL_TIMEOUT, result)
+            << "pollOnce result should be Looper::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, Looper::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(Looper::POLL_CALLBACK, result)
+            << "pollOnce result should be Looper::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(Looper::EVENT_INPUT, handler.events)
+            << "callback should have received Looper::EVENT_INPUT as events";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNoSignalledFDs_WaitsForTimeoutAndReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    handler.setCallback(mLooper, pipe.receiveFd, Looper::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(Looper::POLL_TIMEOUT, result)
+            << "pollOnce result should be Looper::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, Looper::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(Looper::POLL_CALLBACK, result)
+            << "pollOnce result should be Looper::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(Looper::EVENT_INPUT, handler.events)
+            << "callback should have received Looper::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, Looper::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(Looper::POLL_CALLBACK, result)
+            << "pollOnce result should be Looper::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(Looper::EVENT_INPUT, handler.events)
+            << "callback should have received Looper::EVENT_INPUT as events";
+}
+
+TEST_F(LooperTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeInvoked) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    handler.setCallback(mLooper, pipe.receiveFd, Looper::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(Looper::POLL_TIMEOUT, result)
+            << "pollOnce result should be Looper::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, Looper::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(Looper::POLL_CALLBACK, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_TIMEOUT, result)
+            << "pollOnce result should be Looper::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, Looper::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(Looper::EVENT_INPUT, events)
+            << "pollOnce should have returned Looper::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, Looper::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, Looper::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, Looper::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, Looper::EVENT_INPUT);
+    handler2.setCallback(mLooper, pipe.receiveFd, Looper::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(Looper::POLL_CALLBACK, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_CALLBACK, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_CALLBACK, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_WAKE, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_CALLBACK, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_TIMEOUT, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_CALLBACK, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_CALLBACK, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_WAKE, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_CALLBACK, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_TIMEOUT, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_CALLBACK, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_CALLBACK, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_WAKE, result)
+            << "pollOnce result should be Looper::POLL_WAKE because looper was awoken";
+    EXPECT_EQ(size_t(0), handler->messages.size())
+            << "no messages to handle";
+
+    result = mLooper->pollOnce(0);
+
+    EXPECT_EQ(Looper::POLL_TIMEOUT, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_CALLBACK, result)
+            << "pollOnce result should be Looper::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(Looper::POLL_TIMEOUT, result)
+            << "pollOnce result should be Looper::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/libziparchive/Android.mk b/libziparchive/Android.mk
new file mode 100644
index 0000000..5d836a1
--- /dev/null
+++ b/libziparchive/Android.mk
@@ -0,0 +1,69 @@
+#
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+source_files := \
+	zip_archive.h \
+	zip_archive.cc
+
+includes := external/zlib
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := ${source_files}
+
+LOCAL_STATIC_LIBRARIES := libz
+LOCAL_SHARED_LIBRARIES := libutils
+LOCAL_MODULE:= libziparchive
+
+LOCAL_C_INCLUDES += ${includes}
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libziparchive
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := ${source_files}
+LOCAL_C_INCLUDES += ${includes}
+
+LOCAL_STATIC_LIBRARIES := libz libutils
+LOCAL_MODULE:= libziparchive-host
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := ziparchive-tests
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_CFLAGS += \
+    -DGTEST_OS_LINUX_ANDROID \
+    -DGTEST_HAS_STD_STRING
+LOCAL_SRC_FILES := zip_archive_test.cc
+LOCAL_LDFLAGS := -llog
+LOCAL_STATIC_LIBRARIES := libziparchive libz libgtest libgtest_main libutils
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := ziparchive-tests-host
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_CFLAGS += \
+    -DGTEST_OS_LINUX \
+    -DGTEST_HAS_STD_STRING
+LOCAL_SRC_FILES := zip_archive_test.cc
+LOCAL_STATIC_LIBRARIES := libziparchive-host \
+	libz \
+	libgtest_host \
+	libgtest_main_host \
+	liblog \
+	libutils
+include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libziparchive/testdata/valid.zip b/libziparchive/testdata/valid.zip
new file mode 100644
index 0000000..9e7cb78
--- /dev/null
+++ b/libziparchive/testdata/valid.zip
Binary files differ
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
new file mode 100644
index 0000000..2b827b3
--- /dev/null
+++ b/libziparchive/zip_archive.cc
@@ -0,0 +1,1048 @@
+/*
+ * 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.
+ */
+
+/*
+ * Read-only access to Zip archives, with minimal heap allocation.
+ */
+#include "ziparchive/zip_archive.h"
+
+#include <zlib.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <log/log.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utils/FileMap.h>
+
+#include <JNIHelp.h>  // TEMP_FAILURE_RETRY may or may not be in unistd
+
+// This is for windows. If we don't open a file in binary mode, weirds
+// things will happen.
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/*
+ * Zip file constants.
+ */
+static const uint32_t kEOCDSignature    = 0x06054b50;
+static const uint32_t kEOCDLen          = 2;
+static const uint32_t kEOCDNumEntries   = 8;              // offset to #of entries in file
+static const uint32_t kEOCDSize         = 12;             // size of the central directory
+static const uint32_t kEOCDFileOffset   = 16;             // offset to central directory
+
+static const uint32_t kMaxCommentLen    = 65535;          // longest possible in ushort
+static const uint32_t kMaxEOCDSearch    = (kMaxCommentLen + kEOCDLen);
+
+static const uint32_t kLFHSignature     = 0x04034b50;
+static const uint32_t kLFHLen           = 30;             // excluding variable-len fields
+static const uint32_t kLFHGPBFlags      = 6;              // general purpose bit flags
+static const uint32_t kLFHCRC           = 14;             // offset to CRC
+static const uint32_t kLFHCompLen       = 18;             // offset to compressed length
+static const uint32_t kLFHUncompLen     = 22;             // offset to uncompressed length
+static const uint32_t kLFHNameLen       = 26;             // offset to filename length
+static const uint32_t kLFHExtraLen      = 28;             // offset to extra length
+
+static const uint32_t kCDESignature     = 0x02014b50;
+static const uint32_t kCDELen           = 46;             // excluding variable-len fields
+static const uint32_t kCDEMethod        = 10;             // offset to compression method
+static const uint32_t kCDEModWhen       = 12;             // offset to modification timestamp
+static const uint32_t kCDECRC           = 16;             // offset to entry CRC
+static const uint32_t kCDECompLen       = 20;             // offset to compressed length
+static const uint32_t kCDEUncompLen     = 24;             // offset to uncompressed length
+static const uint32_t kCDENameLen       = 28;             // offset to filename length
+static const uint32_t kCDEExtraLen      = 30;             // offset to extra length
+static const uint32_t kCDECommentLen    = 32;             // offset to comment length
+static const uint32_t kCDELocalOffset   = 42;             // offset to local hdr
+
+static const uint32_t kDDOptSignature   = 0x08074b50;     // *OPTIONAL* data descriptor signature
+static const uint32_t kDDSignatureLen   = 4;
+static const uint32_t kDDLen            = 12;
+static const uint32_t kDDMaxLen         = 16;             // max of 16 bytes with a signature, 12 bytes without
+static const uint32_t kDDCrc32          = 0;              // offset to crc32
+static const uint32_t kDDCompLen        = 4;              // offset to compressed length
+static const uint32_t kDDUncompLen      = 8;              // offset to uncompressed length
+
+static const uint32_t kGPBDDFlagMask    = 0x0008;         // mask value that signifies that the entry has a DD
+
+static const uint32_t kMaxErrorLen = 1024;
+
+static const char* kErrorMessages[] = {
+  "Unknown return code.",
+  "Iteration ended",
+  "Zlib error",
+  "Invalid file",
+  "Invalid handle",
+  "Duplicate entries in archive",
+  "Empty archive",
+  "Entry not found",
+  "Invalid offset",
+  "Inconsistent information",
+  "Invalid entry name",
+  "I/O Error",
+  "File mapping failed"
+};
+
+static const int32_t kErrorMessageUpperBound = 0;
+
+static const int32_t kIterationEnd = -1;
+
+// We encountered a Zlib error when inflating a stream from this file.
+// Usually indicates file corruption.
+static const int32_t kZlibError = -2;
+
+// The input file cannot be processed as a zip archive. Usually because
+// it's too small, too large or does not have a valid signature.
+static const int32_t kInvalidFile = -3;
+
+// An invalid iteration / ziparchive handle was passed in as an input
+// argument.
+static const int32_t kInvalidHandle = -4;
+
+// The zip archive contained two (or possibly more) entries with the same
+// name.
+static const int32_t kDuplicateEntry = -5;
+
+// The zip archive contains no entries.
+static const int32_t kEmptyArchive = -6;
+
+// The specified entry was not found in the archive.
+static const int32_t kEntryNotFound = -7;
+
+// The zip archive contained an invalid local file header pointer.
+static const int32_t kInvalidOffset = -8;
+
+// The zip archive contained inconsistent entry information. This could
+// be because the central directory & local file header did not agree, or
+// if the actual uncompressed length or crc32 do not match their declared
+// values.
+static const int32_t kInconsistentInformation = -9;
+
+// An invalid entry name was encountered.
+static const int32_t kInvalidEntryName = -10;
+
+// An I/O related system call (read, lseek, ftruncate, map) failed.
+static const int32_t kIoError = -11;
+
+// We were not able to mmap the central directory or entry contents.
+static const int32_t kMmapFailed = -12;
+
+static const int32_t kErrorMessageLowerBound = -13;
+
+static const char kTempMappingFileName[] = "zip: ExtractFileToFile";
+
+/*
+ * A Read-only Zip archive.
+ *
+ * We want "open" and "find entry by name" to be fast operations, and
+ * we want to use as little memory as possible.  We memory-map the zip
+ * central directory, and load a hash table with pointers to the filenames
+ * (which aren't null-terminated).  The other fields are at a fixed offset
+ * from the filename, so we don't need to extract those (but we do need
+ * to byte-read and endian-swap them every time we want them).
+ *
+ * It's possible that somebody has handed us a massive (~1GB) zip archive,
+ * so we can't expect to mmap the entire file.
+ *
+ * To speed comparisons when doing a lookup by name, we could make the mapping
+ * "private" (copy-on-write) and null-terminate the filenames after verifying
+ * the record structure.  However, this requires a private mapping of
+ * every page that the Central Directory touches.  Easier to tuck a copy
+ * of the string length into the hash table entry.
+ */
+struct ZipArchive {
+  /* open Zip archive */
+  int fd;
+
+  /* mapped central directory area */
+  off64_t directory_offset;
+  android::FileMap* directory_map;
+
+  /* number of entries in the Zip archive */
+  uint16_t num_entries;
+
+  /*
+   * We know how many entries are in the Zip archive, so we can have a
+   * fixed-size hash table. We define a load factor of 0.75 and overallocat
+   * so the maximum number entries can never be higher than
+   * ((4 * UINT16_MAX) / 3 + 1) which can safely fit into a uint32_t.
+   */
+  uint32_t hash_table_size;
+  ZipEntryName* hash_table;
+};
+
+// Returns 0 on success and negative values on failure.
+static android::FileMap* MapFileSegment(const int fd, const off64_t start,
+                                        const size_t length, const bool read_only,
+                                        const char* debug_file_name) {
+  android::FileMap* file_map = new android::FileMap;
+  const bool success = file_map->create(debug_file_name, fd, start, length, read_only);
+  if (!success) {
+    file_map->release();
+    return NULL;
+  }
+
+  return file_map;
+}
+
+static int32_t CopyFileToFile(int fd, uint8_t* begin, const uint32_t length, uint64_t *crc_out) {
+  static const uint32_t kBufSize = 32768;
+  uint8_t buf[kBufSize];
+
+  uint32_t count = 0;
+  uint64_t crc = 0;
+  while (count < length) {
+    uint32_t remaining = length - count;
+
+    // Safe conversion because kBufSize is narrow enough for a 32 bit signed
+    // value.
+    ssize_t get_size = (remaining > kBufSize) ? kBufSize : remaining;
+    ssize_t actual = TEMP_FAILURE_RETRY(read(fd, buf, get_size));
+
+    if (actual != get_size) {
+      ALOGW("CopyFileToFile: copy read failed (%d vs %zd)",
+          (int) actual, get_size);
+      return kIoError;
+    }
+
+    memcpy(begin + count, buf, get_size);
+    crc = crc32(crc, buf, get_size);
+    count += get_size;
+  }
+
+  *crc_out = crc;
+
+  return 0;
+}
+
+/*
+ * Round up to the next highest power of 2.
+ *
+ * Found on http://graphics.stanford.edu/~seander/bithacks.html.
+ */
+static uint32_t RoundUpPower2(uint32_t val) {
+  val--;
+  val |= val >> 1;
+  val |= val >> 2;
+  val |= val >> 4;
+  val |= val >> 8;
+  val |= val >> 16;
+  val++;
+
+  return val;
+}
+
+static uint32_t ComputeHash(const char* str, uint16_t len) {
+  uint32_t hash = 0;
+
+  while (len--) {
+    hash = hash * 31 + *str++;
+  }
+
+  return hash;
+}
+
+/*
+ * Convert a ZipEntry to a hash table index, verifying that it's in a
+ * valid range.
+ */
+static int64_t EntryToIndex(const ZipEntryName* hash_table,
+                            const uint32_t hash_table_size,
+                            const char* name, uint16_t length) {
+  const uint32_t hash = ComputeHash(name, length);
+
+  // NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
+  uint32_t ent = hash & (hash_table_size - 1);
+  while (hash_table[ent].name != NULL) {
+    if (hash_table[ent].name_length == length &&
+        memcmp(hash_table[ent].name, name, length) == 0) {
+      return ent;
+    }
+
+    ent = (ent + 1) & (hash_table_size - 1);
+  }
+
+  ALOGV("Zip: Unable to find entry %.*s", name_length, name);
+  return kEntryNotFound;
+}
+
+/*
+ * Add a new entry to the hash table.
+ */
+static int32_t AddToHash(ZipEntryName *hash_table, const uint64_t hash_table_size,
+                         const char* name, uint16_t length) {
+  const uint64_t hash = ComputeHash(name, length);
+  uint32_t ent = hash & (hash_table_size - 1);
+
+  /*
+   * We over-allocated the table, so we're guaranteed to find an empty slot.
+   * Further, we guarantee that the hashtable size is not 0.
+   */
+  while (hash_table[ent].name != NULL) {
+    if (hash_table[ent].name_length == length &&
+        memcmp(hash_table[ent].name, name, length) == 0) {
+      // We've found a duplicate entry. We don't accept it
+      ALOGW("Zip: Found duplicate entry %.*s", length, name);
+      return kDuplicateEntry;
+    }
+    ent = (ent + 1) & (hash_table_size - 1);
+  }
+
+  hash_table[ent].name = name;
+  hash_table[ent].name_length = length;
+  return 0;
+}
+
+/*
+ * Get 2 little-endian bytes.
+ */
+static uint16_t get2LE(const uint8_t* src) {
+  return src[0] | (src[1] << 8);
+}
+
+/*
+ * Get 4 little-endian bytes.
+ */
+static uint32_t get4LE(const uint8_t* src) {
+  uint32_t result;
+
+  result = src[0];
+  result |= src[1] << 8;
+  result |= src[2] << 16;
+  result |= src[3] << 24;
+
+  return result;
+}
+
+static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
+                                    ZipArchive* archive, off64_t file_length,
+                                    uint32_t read_amount, uint8_t* scan_buffer) {
+  const off64_t search_start = file_length - read_amount;
+
+  if (lseek64(fd, search_start, SEEK_SET) != search_start) {
+    ALOGW("Zip: seek %lld failed: %s", search_start, strerror(errno));
+    return kIoError;
+  }
+  ssize_t actual = TEMP_FAILURE_RETRY(read(fd, scan_buffer, read_amount));
+  if (actual != (ssize_t) read_amount) {
+    ALOGW("Zip: read %zd failed: %s", read_amount, strerror(errno));
+    return kIoError;
+  }
+
+  /*
+   * Scan backward for the EOCD magic.  In an archive without a trailing
+   * comment, we'll find it on the first try.  (We may want to consider
+   * doing an initial minimal read; if we don't find it, retry with a
+   * second read as above.)
+   */
+  int i;
+  for (i = read_amount - kEOCDLen; i >= 0; i--) {
+    if (scan_buffer[i] == 0x50 && get4LE(&scan_buffer[i]) == kEOCDSignature) {
+      ALOGV("+++ Found EOCD at buf+%d", i);
+      break;
+    }
+  }
+  if (i < 0) {
+    ALOGD("Zip: EOCD not found, %s is not zip", debug_file_name);
+    return kInvalidFile;
+  }
+
+  const off64_t eocd_offset = search_start + i;
+  const uint8_t* eocd_ptr = scan_buffer + i;
+
+  assert(eocd_offset < file_length);
+
+  /*
+   * Grab the CD offset and size, and the number of entries in the
+   * archive.  Verify that they look reasonable. Widen dir_size and
+   * dir_offset to the file offset type.
+   */
+  const uint16_t num_entries = get2LE(eocd_ptr + kEOCDNumEntries);
+  const off64_t dir_size = get4LE(eocd_ptr + kEOCDSize);
+  const off64_t dir_offset = get4LE(eocd_ptr + kEOCDFileOffset);
+
+  if (dir_offset + dir_size > eocd_offset) {
+    ALOGW("Zip: bad offsets (dir %lld, size %lld, eocd %lld)",
+        dir_offset, dir_size, eocd_offset);
+    return kInvalidOffset;
+  }
+  if (num_entries == 0) {
+    ALOGW("Zip: empty archive?");
+    return kEmptyArchive;
+  }
+
+  ALOGV("+++ num_entries=%d dir_size=%d dir_offset=%d", num_entries, dir_size,
+      dir_offset);
+
+  /*
+   * It all looks good.  Create a mapping for the CD, and set the fields
+   * in archive.
+   */
+  android::FileMap* map = MapFileSegment(fd, dir_offset, dir_size,
+                                         true /* read only */, debug_file_name);
+  if (map == NULL) {
+    archive->directory_map = NULL;
+    return kMmapFailed;
+  }
+
+  archive->directory_map = map;
+  archive->num_entries = num_entries;
+  archive->directory_offset = dir_offset;
+
+  return 0;
+}
+
+/*
+ * Find the zip Central Directory and memory-map it.
+ *
+ * On success, returns 0 after populating fields from the EOCD area:
+ *   directory_offset
+ *   directory_map
+ *   num_entries
+ */
+static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
+                                   ZipArchive* archive) {
+
+  // Test file length. We use lseek64 to make sure the file
+  // is small enough to be a zip file (Its size must be less than
+  // 0xffffffff bytes).
+  off64_t file_length = lseek64(fd, 0, SEEK_END);
+  if (file_length == -1) {
+    ALOGV("Zip: lseek on fd %d failed", fd);
+    return kInvalidFile;
+  }
+
+  if (file_length > (off64_t) 0xffffffff) {
+    ALOGV("Zip: zip file too long %d", file_length);
+    return kInvalidFile;
+  }
+
+  if (file_length < (int64_t) kEOCDLen) {
+    ALOGV("Zip: length %ld is too small to be zip", file_length);
+    return kInvalidFile;
+  }
+
+  /*
+   * Perform the traditional EOCD snipe hunt.
+   *
+   * We're searching for the End of Central Directory magic number,
+   * which appears at the start of the EOCD block.  It's followed by
+   * 18 bytes of EOCD stuff and up to 64KB of archive comment.  We
+   * need to read the last part of the file into a buffer, dig through
+   * it to find the magic number, parse some values out, and use those
+   * to determine the extent of the CD.
+   *
+   * We start by pulling in the last part of the file.
+   */
+  uint32_t read_amount = kMaxEOCDSearch;
+  if (file_length < (off64_t) read_amount) {
+    read_amount = file_length;
+  }
+
+  uint8_t* scan_buffer = (uint8_t*) malloc(read_amount);
+  int32_t result = MapCentralDirectory0(fd, debug_file_name, archive,
+                                        file_length, read_amount, scan_buffer);
+
+  free(scan_buffer);
+  return result;
+}
+
+/*
+ * Parses the Zip archive's Central Directory.  Allocates and populates the
+ * hash table.
+ *
+ * Returns 0 on success.
+ */
+static int32_t ParseZipArchive(ZipArchive* archive) {
+  int32_t result = -1;
+  const uint8_t* cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
+  size_t cd_length = archive->directory_map->getDataLength();
+  uint16_t num_entries = archive->num_entries;
+
+  /*
+   * Create hash table.  We have a minimum 75% load factor, possibly as
+   * low as 50% after we round off to a power of 2.  There must be at
+   * least one unused entry to avoid an infinite loop during creation.
+   */
+  archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
+  archive->hash_table = (ZipEntryName*) calloc(archive->hash_table_size,
+      sizeof(ZipEntryName));
+
+  /*
+   * Walk through the central directory, adding entries to the hash
+   * table and verifying values.
+   */
+  const uint8_t* ptr = cd_ptr;
+  for (uint16_t i = 0; i < num_entries; i++) {
+    if (get4LE(ptr) != kCDESignature) {
+      ALOGW("Zip: missed a central dir sig (at %d)", i);
+      goto bail;
+    }
+
+    if (ptr + kCDELen > cd_ptr + cd_length) {
+      ALOGW("Zip: ran off the end (at %d)", i);
+      goto bail;
+    }
+
+    const off64_t local_header_offset = get4LE(ptr + kCDELocalOffset);
+    if (local_header_offset >= archive->directory_offset) {
+      ALOGW("Zip: bad LFH offset %lld at entry %d", local_header_offset, i);
+      goto bail;
+    }
+
+    const uint16_t file_name_length = get2LE(ptr + kCDENameLen);
+    const uint16_t extra_length = get2LE(ptr + kCDEExtraLen);
+    const uint16_t comment_length = get2LE(ptr + kCDECommentLen);
+
+    /* add the CDE filename to the hash table */
+    const int add_result = AddToHash(archive->hash_table,
+        archive->hash_table_size, (const char*) ptr + kCDELen, file_name_length);
+    if (add_result) {
+      ALOGW("Zip: Error adding entry to hash table %d", add_result);
+      result = add_result;
+      goto bail;
+    }
+
+    ptr += kCDELen + file_name_length + extra_length + comment_length;
+    if ((size_t)(ptr - cd_ptr) > cd_length) {
+      ALOGW("Zip: bad CD advance (%d vs %zd) at entry %d",
+        (int) (ptr - cd_ptr), cd_length, i);
+      goto bail;
+    }
+  }
+  ALOGV("+++ zip good scan %d entries", num_entries);
+
+  result = 0;
+
+bail:
+  return result;
+}
+
+static int32_t OpenArchiveInternal(ZipArchive* archive,
+                                   const char* debug_file_name) {
+  int32_t result = -1;
+  if ((result = MapCentralDirectory(archive->fd, debug_file_name, archive))) {
+    return result;
+  }
+
+  if ((result = ParseZipArchive(archive))) {
+    return result;
+  }
+
+  return 0;
+}
+
+int32_t OpenArchiveFd(int fd, const char* debug_file_name,
+                      ZipArchiveHandle* handle) {
+  ZipArchive* archive = (ZipArchive*) malloc(sizeof(ZipArchive));
+  memset(archive, 0, sizeof(*archive));
+  *handle = archive;
+
+  archive->fd = fd;
+
+  return OpenArchiveInternal(archive, debug_file_name);
+}
+
+int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
+  ZipArchive* archive = (ZipArchive*) malloc(sizeof(ZipArchive));
+  memset(archive, 0, sizeof(*archive));
+  *handle = archive;
+
+  const int fd = open(fileName, O_RDONLY | O_BINARY, 0);
+  if (fd < 0) {
+    ALOGW("Unable to open '%s': %s", fileName, strerror(errno));
+    return kIoError;
+  } else {
+    archive->fd = fd;
+  }
+
+  return OpenArchiveInternal(archive, fileName);
+}
+
+/*
+ * Close a ZipArchive, closing the file and freeing the contents.
+ */
+void CloseArchive(ZipArchiveHandle handle) {
+  ZipArchive* archive = (ZipArchive*) handle;
+  ALOGV("Closing archive %p", archive);
+
+  if (archive->fd >= 0) {
+    close(archive->fd);
+  }
+
+  if (archive->directory_map != NULL) {
+    archive->directory_map->release();
+  }
+  free(archive->hash_table);
+
+  /* ensure nobody tries to use the ZipArchive after it's closed */
+  archive->directory_offset = -1;
+  archive->fd = -1;
+  archive->num_entries = -1;
+  archive->hash_table_size = -1;
+  archive->hash_table = NULL;
+}
+
+static int32_t UpdateEntryFromDataDescriptor(int fd,
+                                             ZipEntry *entry) {
+  uint8_t ddBuf[kDDMaxLen];
+  ssize_t actual = TEMP_FAILURE_RETRY(read(fd, ddBuf, sizeof(ddBuf)));
+  if (actual != sizeof(ddBuf)) {
+    return kIoError;
+  }
+
+  const uint32_t ddSignature = get4LE(ddBuf);
+  uint16_t ddOffset = 0;
+  if (ddSignature == kDDOptSignature) {
+    ddOffset = 4;
+  }
+
+  entry->crc32 = get4LE(ddBuf + ddOffset + kDDCrc32);
+  entry->compressed_length = get4LE(ddBuf + ddOffset + kDDCompLen);
+  entry->uncompressed_length = get4LE(ddBuf + ddOffset + kDDUncompLen);
+
+  return 0;
+}
+
+// Attempts to read |len| bytes into |buf| at offset |off|.
+//
+// This method uses pread64 on platforms that support it and
+// lseek64 + read on platforms that don't. This implies that
+// callers should not rely on the |fd| offset being incremented
+// as a side effect of this call.
+static inline ssize_t ReadAtOffset(int fd, uint8_t* buf, size_t len,
+                                   off64_t off) {
+#ifdef HAVE_PREAD
+  return TEMP_FAILURE_RETRY(pread64(fd, buf, len, off));
+#else
+  // The only supported platform that doesn't support pread at the moment
+  // is Windows. Only recent versions of windows support unix like forks,
+  // and even there the semantics are quite different.
+  if (lseek64(fd, off, SEEK_SET) != off) {
+    ALOGW("Zip: failed seek to offset %lld", off);
+    return kIoError;
+  }
+
+  return TEMP_FAILURE_RETRY(read(fd, buf, len));
+#endif  // HAVE_PREAD
+}
+
+static int32_t FindEntry(const ZipArchive* archive, const int ent,
+                         ZipEntry* data) {
+  const uint16_t nameLen = archive->hash_table[ent].name_length;
+  const char* name = archive->hash_table[ent].name;
+
+  // Recover the start of the central directory entry from the filename
+  // pointer.  The filename is the first entry past the fixed-size data,
+  // so we can just subtract back from that.
+  const unsigned char* ptr = (const unsigned char*) name;
+  ptr -= kCDELen;
+
+  // This is the base of our mmapped region, we have to sanity check that
+  // the name that's in the hash table is a pointer to a location within
+  // this mapped region.
+  const unsigned char* base_ptr = (const unsigned char*)
+    archive->directory_map->getDataPtr();
+  if (ptr < base_ptr || ptr > base_ptr + archive->directory_map->getDataLength()) {
+    ALOGW("Zip: Invalid entry pointer");
+    return kInvalidOffset;
+  }
+
+  // The offset of the start of the central directory in the zipfile.
+  // We keep this lying around so that we can sanity check all our lengths
+  // and our per-file structures.
+  const off64_t cd_offset = archive->directory_offset;
+
+  // Fill out the compression method, modification time, crc32
+  // and other interesting attributes from the central directory. These
+  // will later be compared against values from the local file header.
+  data->method = get2LE(ptr + kCDEMethod);
+  data->mod_time = get4LE(ptr + kCDEModWhen);
+  data->crc32 = get4LE(ptr + kCDECRC);
+  data->compressed_length = get4LE(ptr + kCDECompLen);
+  data->uncompressed_length = get4LE(ptr + kCDEUncompLen);
+
+  // Figure out the local header offset from the central directory. The
+  // actual file data will begin after the local header and the name /
+  // extra comments.
+  const off64_t local_header_offset = get4LE(ptr + kCDELocalOffset);
+  if (local_header_offset + (off64_t) kLFHLen >= cd_offset) {
+    ALOGW("Zip: bad local hdr offset in zip");
+    return kInvalidOffset;
+  }
+
+  uint8_t lfh_buf[kLFHLen];
+  ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf),
+                                 local_header_offset);
+  if (actual != sizeof(lfh_buf)) {
+    ALOGW("Zip: failed reading lfh name from offset %lld", local_header_offset);
+    return kIoError;
+  }
+
+  if (get4LE(lfh_buf) != kLFHSignature) {
+    ALOGW("Zip: didn't find signature at start of lfh, offset=%lld",
+        local_header_offset);
+    return kInvalidOffset;
+  }
+
+  // Paranoia: Match the values specified in the local file header
+  // to those specified in the central directory.
+  const uint16_t lfhGpbFlags = get2LE(lfh_buf + kLFHGPBFlags);
+  const uint16_t lfhNameLen = get2LE(lfh_buf + kLFHNameLen);
+  const uint16_t lfhExtraLen = get2LE(lfh_buf + kLFHExtraLen);
+
+  if ((lfhGpbFlags & kGPBDDFlagMask) == 0) {
+    const uint32_t lfhCrc = get4LE(lfh_buf + kLFHCRC);
+    const uint32_t lfhCompLen = get4LE(lfh_buf + kLFHCompLen);
+    const uint32_t lfhUncompLen = get4LE(lfh_buf + kLFHUncompLen);
+
+    data->has_data_descriptor = 0;
+    if (data->compressed_length != lfhCompLen || data->uncompressed_length != lfhUncompLen
+        || data->crc32 != lfhCrc) {
+      ALOGW("Zip: size/crc32 mismatch. expected {%d, %d, %x}, was {%d, %d, %x}",
+        data->compressed_length, data->uncompressed_length, data->crc32,
+        lfhCompLen, lfhUncompLen, lfhCrc);
+      return kInconsistentInformation;
+    }
+  } else {
+    data->has_data_descriptor = 1;
+  }
+
+  // Check that the local file header name matches the declared
+  // name in the central directory.
+  if (lfhNameLen == nameLen) {
+    const off64_t name_offset = local_header_offset + kLFHLen;
+    if (name_offset + lfhNameLen >= cd_offset) {
+      ALOGW("Zip: Invalid declared length");
+      return kInvalidOffset;
+    }
+
+    uint8_t* name_buf = (uint8_t*) malloc(nameLen);
+    ssize_t actual = ReadAtOffset(archive->fd, name_buf, nameLen,
+                                  name_offset);
+
+    if (actual != nameLen) {
+      ALOGW("Zip: failed reading lfh name from offset %lld", name_offset);
+      free(name_buf);
+      return kIoError;
+    }
+
+    if (memcmp(name, name_buf, nameLen)) {
+      free(name_buf);
+      return kInconsistentInformation;
+    }
+
+    free(name_buf);
+  } else {
+    ALOGW("Zip: lfh name did not match central directory.");
+    return kInconsistentInformation;
+  }
+
+  const off64_t data_offset = local_header_offset + kLFHLen + lfhNameLen + lfhExtraLen;
+  if (data_offset >= cd_offset) {
+    ALOGW("Zip: bad data offset %lld in zip", (off64_t) data_offset);
+    return kInvalidOffset;
+  }
+
+  if ((off64_t)(data_offset + data->compressed_length) > cd_offset) {
+    ALOGW("Zip: bad compressed length in zip (%lld + %zd > %lld)",
+      data_offset, data->compressed_length, cd_offset);
+    return kInvalidOffset;
+  }
+
+  if (data->method == kCompressStored &&
+    (off64_t)(data_offset + data->uncompressed_length) > cd_offset) {
+     ALOGW("Zip: bad uncompressed length in zip (%lld + %zd > %lld)",
+       data_offset, data->uncompressed_length, cd_offset);
+     return kInvalidOffset;
+  }
+
+  data->offset = data_offset;
+  return 0;
+}
+
+struct IterationHandle {
+  uint32_t position;
+  const char* prefix;
+  uint16_t prefix_len;
+  ZipArchive* archive;
+};
+
+int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, const char* prefix) {
+  ZipArchive* archive = (ZipArchive *) handle;
+
+  if (archive == NULL || archive->hash_table == NULL) {
+    ALOGW("Zip: Invalid ZipArchiveHandle");
+    return kInvalidHandle;
+  }
+
+  IterationHandle* cookie = (IterationHandle*) malloc(sizeof(IterationHandle));
+  cookie->position = 0;
+  cookie->prefix = prefix;
+  cookie->archive = archive;
+  if (prefix != NULL) {
+    cookie->prefix_len = strlen(prefix);
+  }
+
+  *cookie_ptr = cookie ;
+  return 0;
+}
+
+int32_t FindEntry(const ZipArchiveHandle handle, const char* entryName,
+                  ZipEntry* data) {
+  const ZipArchive* archive = (ZipArchive*) handle;
+  const int nameLen = strlen(entryName);
+  if (nameLen == 0 || nameLen > 65535) {
+    ALOGW("Zip: Invalid filename %s", entryName);
+    return kInvalidEntryName;
+  }
+
+  const int64_t ent = EntryToIndex(archive->hash_table,
+    archive->hash_table_size, entryName, nameLen);
+
+  if (ent < 0) {
+    ALOGD("Zip: Could not find entry %.*s", nameLen, entryName);
+    return ent;
+  }
+
+  return FindEntry(archive, ent, data);
+}
+
+int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) {
+  IterationHandle* handle = (IterationHandle *) cookie;
+  if (handle == NULL) {
+    return kInvalidHandle;
+  }
+
+  ZipArchive* archive = handle->archive;
+  if (archive == NULL || archive->hash_table == NULL) {
+    ALOGW("Zip: Invalid ZipArchiveHandle");
+    return kInvalidHandle;
+  }
+
+  const uint32_t currentOffset = handle->position;
+  const uint32_t hash_table_length = archive->hash_table_size;
+  const ZipEntryName *hash_table = archive->hash_table;
+
+  for (uint32_t i = currentOffset; i < hash_table_length; ++i) {
+    if (hash_table[i].name != NULL &&
+        (handle->prefix == NULL ||
+         (memcmp(handle->prefix, hash_table[i].name, handle->prefix_len) == 0))) {
+      handle->position = (i + 1);
+      const int error = FindEntry(archive, i, data);
+      if (!error) {
+        name->name = hash_table[i].name;
+        name->name_length = hash_table[i].name_length;
+      }
+
+      return error;
+    }
+  }
+
+  handle->position = 0;
+  return kIterationEnd;
+}
+
+static int32_t InflateToFile(int fd, const ZipEntry* entry,
+                             uint8_t* begin, uint32_t length,
+                             uint64_t* crc_out) {
+  int32_t result = -1;
+  const uint32_t kBufSize = 32768;
+  uint8_t read_buf[kBufSize];
+  uint8_t write_buf[kBufSize];
+  z_stream zstream;
+  int zerr;
+
+  /*
+   * Initialize the zlib stream struct.
+   */
+  memset(&zstream, 0, sizeof(zstream));
+  zstream.zalloc = Z_NULL;
+  zstream.zfree = Z_NULL;
+  zstream.opaque = Z_NULL;
+  zstream.next_in = NULL;
+  zstream.avail_in = 0;
+  zstream.next_out = (Bytef*) write_buf;
+  zstream.avail_out = kBufSize;
+  zstream.data_type = Z_UNKNOWN;
+
+  /*
+   * Use the undocumented "negative window bits" feature to tell zlib
+   * that there's no zlib header waiting for it.
+   */
+  zerr = inflateInit2(&zstream, -MAX_WBITS);
+  if (zerr != Z_OK) {
+    if (zerr == Z_VERSION_ERROR) {
+      ALOGE("Installed zlib is not compatible with linked version (%s)",
+        ZLIB_VERSION);
+    } else {
+      ALOGW("Call to inflateInit2 failed (zerr=%d)", zerr);
+    }
+
+    return kZlibError;
+  }
+
+  const uint32_t uncompressed_length = entry->uncompressed_length;
+
+  uint32_t compressed_length = entry->compressed_length;
+  uint32_t write_count = 0;
+  do {
+    /* read as much as we can */
+    if (zstream.avail_in == 0) {
+      const ssize_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
+      const ssize_t actual = TEMP_FAILURE_RETRY(read(fd, read_buf, getSize));
+      if (actual != getSize) {
+        ALOGW("Zip: inflate read failed (%d vs %zd)", actual, getSize);
+        result = kIoError;
+        goto z_bail;
+      }
+
+      compressed_length -= getSize;
+
+      zstream.next_in = read_buf;
+      zstream.avail_in = getSize;
+    }
+
+    /* uncompress the data */
+    zerr = inflate(&zstream, Z_NO_FLUSH);
+    if (zerr != Z_OK && zerr != Z_STREAM_END) {
+      ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
+          zerr, zstream.next_in, zstream.avail_in,
+          zstream.next_out, zstream.avail_out);
+      result = kZlibError;
+      goto z_bail;
+    }
+
+    /* write when we're full or when we're done */
+    if (zstream.avail_out == 0 ||
+      (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
+      const size_t write_size = zstream.next_out - write_buf;
+      // The file might have declared a bogus length.
+      if (write_size + write_count > length) {
+        goto z_bail;
+      }
+      memcpy(begin + write_count, write_buf, write_size);
+      write_count += write_size;
+
+      zstream.next_out = write_buf;
+      zstream.avail_out = kBufSize;
+    }
+  } while (zerr == Z_OK);
+
+  assert(zerr == Z_STREAM_END);     /* other errors should've been caught */
+
+  // stream.adler holds the crc32 value for such streams.
+  *crc_out = zstream.adler;
+
+  if (zstream.total_out != uncompressed_length || compressed_length != 0) {
+    ALOGW("Zip: size mismatch on inflated file (%ld vs %zd)",
+        zstream.total_out, uncompressed_length);
+    result = kInconsistentInformation;
+    goto z_bail;
+  }
+
+  result = 0;
+
+z_bail:
+  inflateEnd(&zstream);    /* free up any allocated structures */
+
+  return result;
+}
+
+int32_t ExtractToMemory(ZipArchiveHandle handle,
+                        ZipEntry* entry, uint8_t* begin, uint32_t size) {
+  ZipArchive* archive = (ZipArchive*) handle;
+  const uint16_t method = entry->method;
+  off64_t data_offset = entry->offset;
+
+  if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
+    ALOGW("Zip: lseek to data at %lld failed", (off64_t) data_offset);
+    return kIoError;
+  }
+
+  // this should default to kUnknownCompressionMethod.
+  int32_t return_value = -1;
+  uint64_t crc = 0;
+  if (method == kCompressStored) {
+    return_value = CopyFileToFile(archive->fd, begin, size, &crc);
+  } else if (method == kCompressDeflated) {
+    return_value = InflateToFile(archive->fd, entry, begin, size, &crc);
+  }
+
+  if (!return_value && entry->has_data_descriptor) {
+    return_value = UpdateEntryFromDataDescriptor(archive->fd, entry);
+    if (return_value) {
+      return return_value;
+    }
+  }
+
+  // TODO: Fix this check by passing the right flags to inflate2 so that
+  // it calculates the CRC for us.
+  if (entry->crc32 != crc && false) {
+    ALOGW("Zip: crc mismatch: expected %u, was %llu", entry->crc32, crc);
+    return kInconsistentInformation;
+  }
+
+  return return_value;
+}
+
+int32_t ExtractEntryToFile(ZipArchiveHandle handle,
+                           ZipEntry* entry, int fd) {
+  const int32_t declared_length = entry->uncompressed_length;
+
+  const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
+  if (current_offset == -1) {
+    ALOGW("Zip: unable to seek to current location on fd %d: %s", fd,
+          strerror(errno));
+    return kIoError;
+  }
+
+  int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
+  if (result == -1) {
+    ALOGW("Zip: unable to truncate file to %lld: %s", declared_length + current_offset,
+          strerror(errno));
+    return kIoError;
+  }
+
+  android::FileMap* map  = MapFileSegment(fd, current_offset, declared_length,
+                                          false, kTempMappingFileName);
+  if (map == NULL) {
+    return kMmapFailed;
+  }
+
+  const int32_t error = ExtractToMemory(handle, entry,
+                                        reinterpret_cast<uint8_t*>(map->getDataPtr()),
+                                        map->getDataLength());
+  map->release();
+  return error;
+}
+
+const char* ErrorCodeString(int32_t error_code) {
+  if (error_code > kErrorMessageLowerBound && error_code < kErrorMessageUpperBound) {
+    return kErrorMessages[error_code * -1];
+  }
+
+  return kErrorMessages[0];
+}
+
+int GetFileDescriptor(const ZipArchiveHandle handle) {
+  return ((ZipArchive*) handle)->fd;
+}
+
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
new file mode 100644
index 0000000..022be5b
--- /dev/null
+++ b/libziparchive/zip_archive_test.cc
@@ -0,0 +1,213 @@
+/*
+ * 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 "ziparchive/zip_archive.h"
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+static std::string test_data_dir;
+
+static const std::string kValidZip = "valid.zip";
+
+static const uint8_t kATxtContents[] = {
+  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+  '\n'
+};
+
+static const uint8_t kBTxtContents[] = {
+  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+  '\n'
+};
+
+static int32_t OpenArchiveWrapper(const std::string& name,
+                                  ZipArchiveHandle* handle) {
+  const std::string abs_path = test_data_dir + "/" + name;
+  return OpenArchive(abs_path.c_str(), handle);
+}
+
+static void AssertNameEquals(const std::string& name_str,
+                             const ZipEntryName& name) {
+  ASSERT_EQ(name_str.size(), name.name_length);
+  ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length));
+}
+
+TEST(ziparchive, Open) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, Iteration) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  void* iteration_cookie;
+  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL));
+
+  ZipEntry data;
+  ZipEntryName name;
+
+  // b/c.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b/c.txt", name);
+
+  // b/d.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b/d.txt", name);
+
+  // a.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("a.txt", name);
+
+  // b.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b.txt", name);
+
+  // b/
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b/", name);
+
+  // End of iteration.
+  ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
+
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, FindEntry) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  ZipEntry data;
+  ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
+
+  // Known facts about a.txt, from zipinfo -v.
+  ASSERT_EQ(63, data.offset);
+  ASSERT_EQ(kCompressDeflated, data.method);
+  ASSERT_EQ(static_cast<uint32_t>(17), data.uncompressed_length);
+  ASSERT_EQ(static_cast<uint32_t>(13), data.compressed_length);
+  ASSERT_EQ(0x950821c5, data.crc32);
+
+  // An entry that doesn't exist. Should be a negative return code.
+  ASSERT_LT(FindEntry(handle, "nonexistent.txt", &data), 0);
+
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, ExtractToMemory) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  // An entry that's deflated.
+  ZipEntry data;
+  ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
+  const uint32_t a_size = data.uncompressed_length;
+  ASSERT_EQ(a_size, sizeof(kATxtContents));
+  uint8_t* buffer = new uint8_t[a_size];
+  ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
+  ASSERT_EQ(0, memcmp(buffer, kATxtContents, a_size));
+  delete[] buffer;
+
+  // An entry that's stored.
+  ASSERT_EQ(0, FindEntry(handle, "b.txt", &data));
+  const uint32_t b_size = data.uncompressed_length;
+  ASSERT_EQ(b_size, sizeof(kBTxtContents));
+  buffer = new uint8_t[b_size];
+  ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
+  ASSERT_EQ(0, memcmp(buffer, kBTxtContents, b_size));
+  delete[] buffer;
+
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, ExtractToFile) {
+  char kTempFilePattern[] = "zip_archive_test_XXXXXX";
+  int fd = mkstemp(kTempFilePattern);
+  ASSERT_NE(-1, fd);
+  const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
+  const ssize_t data_size = sizeof(data);
+
+  ASSERT_EQ(data_size, TEMP_FAILURE_RETRY(write(fd, data, data_size)));
+
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  ZipEntry entry;
+  ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));
+  ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, fd));
+
+
+  // Assert that the first 8 bytes of the file haven't been clobbered.
+  uint8_t read_buffer[data_size];
+  ASSERT_EQ(0, lseek64(fd, 0, SEEK_SET));
+  ASSERT_EQ(data_size, TEMP_FAILURE_RETRY(read(fd, read_buffer, data_size)));
+  ASSERT_EQ(0, memcmp(read_buffer, data, data_size));
+
+  // Assert that the remainder of the file contains the incompressed data.
+  std::vector<uint8_t> uncompressed_data(entry.uncompressed_length);
+  ASSERT_EQ(static_cast<ssize_t>(entry.uncompressed_length),
+            TEMP_FAILURE_RETRY(
+                read(fd, &uncompressed_data[0], entry.uncompressed_length)));
+  ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents,
+                      sizeof(kATxtContents)));
+
+  // Assert that the total length of the file is sane
+  ASSERT_EQ(data_size + sizeof(kATxtContents), lseek64(fd, 0, SEEK_END));
+
+  close(fd);
+}
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+
+  static struct option options[] = {
+    { "test_data_dir", required_argument, NULL, 't' },
+    { NULL, 0, NULL, 0 }
+  };
+
+  while (true) {
+    int option_index;
+    const int c = getopt_long_only(argc, argv, "", options, &option_index);
+    if (c == -1) {
+      break;
+    }
+
+    if (c == 't') {
+      test_data_dir = optarg;
+    }
+  }
+
+  if (test_data_dir.size() == 0) {
+    printf("Test data flag (--test_data_dir) required\n\n");
+    return -1;
+  }
+
+  if (test_data_dir[0] != '/') {
+    printf("Test data must be an absolute path, was %s\n\n",
+           test_data_dir.c_str());
+    return -2;
+  }
+
+  return RUN_ALL_TESTS();
+}
+
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..db6cb4c 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/wait.h>
@@ -80,7 +81,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 0d53ae1..56e0d92 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.
@@ -201,8 +208,10 @@
     mkdir /data/misc/bluetooth 0770 system system
     mkdir /data/misc/keystore 0700 keystore keystore
     mkdir /data/misc/keychain 0771 system system
+    mkdir /data/misc/radio 0770 system radio
     mkdir /data/misc/sms 0770 system radio
     mkdir /data/misc/zoneinfo 0775 system system
+    restorecon_recursive /data/misc/zoneinfo
     mkdir /data/misc/vpn 0770 system vpn
     mkdir /data/misc/systemkeys 0700 system system
     # give system access to wpa_supplicant.conf for backup and restore
@@ -348,25 +357,20 @@
     chown system system /sys/kernel/ipv4/tcp_rmem_max
     chown root radio /proc/cmdline
 
-# Set these so we can remotely update SELinux policy
-    chown system system /sys/fs/selinux/enforce
-
 # Define TCP buffer sizes for various networks
 #   ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
-    setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208
-    setprop net.tcp.buffersize.wifi    524288,1048576,2097152,262144,524288,1048576
-    setprop net.tcp.buffersize.lte     524288,1048576,2097152,262144,524288,1048576
-    setprop net.tcp.buffersize.umts    4094,87380,110208,4096,16384,110208
-    setprop net.tcp.buffersize.hspa    4094,87380,262144,4096,16384,262144
-    setprop net.tcp.buffersize.hsupa   4094,87380,262144,4096,16384,262144
-    setprop net.tcp.buffersize.hsdpa   4094,87380,262144,4096,16384,262144
-    setprop net.tcp.buffersize.hspap   4094,87380,1220608,4096,16384,1220608
-    setprop net.tcp.buffersize.edge    4093,26280,35040,4096,16384,35040
-    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
+    setprop net.tcp.buffersize.default  4096,87380,110208,4096,16384,110208
+    setprop net.tcp.buffersize.wifi     524288,1048576,2097152,262144,524288,1048576
+    setprop net.tcp.buffersize.ethernet 524288,1048576,3145728,524288,1048576,2097152
+    setprop net.tcp.buffersize.lte      524288,1048576,2097152,262144,524288,1048576
+    setprop net.tcp.buffersize.umts     4094,87380,110208,4096,16384,110208
+    setprop net.tcp.buffersize.hspa     4094,87380,262144,4096,16384,262144
+    setprop net.tcp.buffersize.hsupa    4094,87380,262144,4096,16384,262144
+    setprop net.tcp.buffersize.hsdpa    4094,87380,262144,4096,16384,262144
+    setprop net.tcp.buffersize.hspap    4094,87380,1220608,4096,16384,1220608
+    setprop net.tcp.buffersize.edge     4093,26280,35040,4096,16384,35040
+    setprop net.tcp.buffersize.gprs     4092,8760,11680,4096,8760,11680
+    setprop net.tcp.buffersize.evdo     4094,87380,262144,4096,16384,262144
 
     class_start core
     class_start main
@@ -397,6 +401,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
@@ -404,12 +415,23 @@
     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
     disabled
     user shell
     group log
+    seclabel u:r:shell:s0
 
 on property:ro.debuggable=1
     start console
@@ -430,6 +452,7 @@
     user system
     group system
     critical
+    onrestart restart healthd
     onrestart restart zygote
     onrestart restart media
     onrestart restart surfaceflinger
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index a60cfc5..9bf17e2 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -1,3 +1,6 @@
+subsystem adf
+	devname uevent_devname
+
 /dev/null                 0666   root       root
 /dev/zero                 0666   root       root
 /dev/full                 0666   root       root
@@ -32,6 +35,7 @@
 /dev/uhid                 0660   system     net_bt_stack
 /dev/uinput               0660   system     net_bt_stack
 /dev/alarm                0664   system     radio
+/dev/rtc0                 0664   system     radio
 /dev/tty0                 0660   root       system
 /dev/graphics/*           0660   root       graphics
 /dev/msm_hw3dm            0660   system     graphics
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/date.c b/toolbox/date.c
index 35ef846..ed307c0 100644
--- a/toolbox/date.c
+++ b/toolbox/date.c
@@ -6,15 +6,87 @@
 #include <errno.h>
 #include <time.h>
 #include <linux/android_alarm.h>
+#include <linux/rtc.h>
 #include <sys/ioctl.h>
 
+static int settime_alarm(struct timespec *ts) {
+    int fd, ret;
+
+    fd = open("/dev/alarm", O_RDWR);
+    if (fd < 0)
+        return fd;
+
+    ret = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
+    close(fd);
+    return ret;
+}
+
+static int settime_alarm_tm(struct tm *tm) {
+    time_t t;
+    struct timespec ts;
+
+    t = mktime(tm);
+    ts.tv_sec = t;
+    ts.tv_nsec = 0;
+    return settime_alarm(&ts);
+}
+
+static int settime_alarm_timeval(struct timeval *tv) {
+    struct timespec ts;
+
+    ts.tv_sec = tv->tv_sec;
+    ts.tv_nsec = tv->tv_usec * 1000;
+    return settime_alarm(&ts);
+}
+
+static int settime_rtc_tm(struct tm *tm) {
+    int fd, ret;
+    struct timeval tv;
+    struct rtc_time rtc;
+
+    fd = open("/dev/rtc0", O_RDWR);
+    if (fd < 0)
+        return fd;
+
+    tv.tv_sec = mktime(tm);
+    tv.tv_usec = 0;
+
+    ret = settimeofday(&tv, NULL);
+    if (ret < 0)
+        goto done;
+
+    memset(&rtc, 0, sizeof(rtc));
+    rtc.tm_sec = tm->tm_sec;
+    rtc.tm_min = tm->tm_min;
+    rtc.tm_hour = tm->tm_hour;
+    rtc.tm_mday = tm->tm_mday;
+    rtc.tm_mon = tm->tm_mon;
+    rtc.tm_year = tm->tm_year;
+    rtc.tm_wday = tm->tm_wday;
+    rtc.tm_yday = tm->tm_yday;
+    rtc.tm_isdst = tm->tm_isdst;
+
+    ret = ioctl(fd, RTC_SET_TIME, rtc);
+done:
+    close(fd);
+    return ret;
+}
+
+static int settime_rtc_timeval(struct timeval *tv) {
+    struct tm tm, *err;
+    time_t t = tv->tv_sec;
+
+    err = gmtime_r(&t, &tm);
+    if (!err)
+        return -1;
+
+    return settime_rtc_tm(&tm);
+}
+
 static void settime(char *s) {
     struct tm tm;
     int day = atoi(s);
     int hour;
-    time_t t;
-    int fd;
-    struct timespec ts;
 
     while (*s && *s != '.')
         s++;
@@ -32,12 +104,8 @@
     tm.tm_sec = (hour % 100);
     tm.tm_isdst = -1;
 
-    t = mktime(&tm);
-    
-    fd = open("/dev/alarm", O_RDWR);
-    ts.tv_sec = t;
-    ts.tv_nsec = 0;
-    ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
+    if (settime_alarm_tm(&tm) < 0)
+        settime_rtc_tm(&tm);
 }
 
 int date_main(int argc, char *argv[])
@@ -114,12 +182,10 @@
         //tv.tv_sec = mktime(&tm);
         //tv.tv_usec = 0;
         strtotimeval(argv[optind], &tv);
-        printf("time %s -> %d.%d\n", argv[optind], tv.tv_sec, tv.tv_usec);
-        fd = open("/dev/alarm", O_RDWR);
-        ts.tv_sec = tv.tv_sec;
-        ts.tv_nsec = tv.tv_usec * 1000;
-        res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
-        //res = settimeofday(&tv, NULL);
+        printf("time %s -> %lu.%lu\n", argv[optind], tv.tv_sec, tv.tv_usec);
+        res = settime_alarm_timeval(&tv);
+        if (res < 0)
+            res = settime_rtc_timeval(&tv);
         if(res < 0) {
             fprintf(stderr,"settimeofday failed %s\n", strerror(errno));
             return 1;
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/ls.c b/toolbox/ls.c
index 5324511..8467628 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -75,23 +75,23 @@
     *out = 0;
 }
 
-static void user2str(unsigned uid, char *out)
+static void user2str(uid_t uid, char *out, size_t out_size)
 {
     struct passwd *pw = getpwuid(uid);
     if(pw) {
-        strcpy(out, pw->pw_name);
+        strlcpy(out, pw->pw_name, out_size);
     } else {
-        sprintf(out, "%d", uid);
+        snprintf(out, out_size, "%d", uid);
     }
 }
 
-static void group2str(unsigned gid, char *out)
+static void group2str(gid_t gid, char *out, size_t out_size)
 {
     struct group *gr = getgrgid(gid);
     if(gr) {
-        strcpy(out, gr->gr_name);
+        strlcpy(out, gr->gr_name, out_size);
     } else {
-        sprintf(out, "%d", gid);
+        snprintf(out, out_size, "%d", gid);
     }
 }
 
@@ -164,8 +164,8 @@
 {
     char date[32];
     char mode[16];
-    char user[16];
-    char group[16];
+    char user[32];
+    char group[32];
     const char *name;
 
     if(!s || !path) {
@@ -182,11 +182,11 @@
 
     mode2str(s->st_mode, mode);
     if (flags & LIST_LONG_NUMERIC) {
-        sprintf(user, "%ld", s->st_uid);
-        sprintf(group, "%ld", s->st_gid);
+        snprintf(user, sizeof(user), "%ld", s->st_uid);
+        snprintf(group, sizeof(group), "%ld", s->st_gid);
     } else {
-        user2str(s->st_uid, user);
-        group2str(s->st_gid, group);
+        user2str(s->st_uid, user, sizeof(user));
+        group2str(s->st_gid, group, sizeof(group));
     }
 
     strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s->st_mtime));
@@ -209,7 +209,7 @@
         break;
     case S_IFLNK: {
         char linkto[256];
-        int len;
+        ssize_t len;
 
         len = readlink(path, linkto, 256);
         if(len < 0) return -1;
@@ -235,11 +235,11 @@
     return 0;
 }
 
-static int listfile_maclabel(const char *path, struct stat *s, int flags)
+static int listfile_maclabel(const char *path, struct stat *s)
 {
     char mode[16];
-    char user[16];
-    char group[16];
+    char user[32];
+    char group[32];
     char *maclabel = NULL;
     const char *name;
 
@@ -261,8 +261,8 @@
     }
 
     mode2str(s->st_mode, mode);
-    user2str(s->st_uid, user);
-    group2str(s->st_gid, group);
+    user2str(s->st_uid, user, sizeof(user));
+    group2str(s->st_gid, group, sizeof(group));
 
     switch(s->st_mode & S_IFMT) {
     case S_IFLNK: {
@@ -324,7 +324,7 @@
     }
 
     if ((flags & LIST_MACLABEL) != 0) {
-        return listfile_maclabel(pathname, &s, flags);
+        return listfile_maclabel(pathname, &s);
     } else if ((flags & LIST_LONG) != 0) {
         return listfile_long(pathname, &s, flags);
     } else /*((flags & LIST_SIZE) != 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;
diff --git a/toolbox/uptime.c b/toolbox/uptime.c
index 1c312b0..3fb4606 100644
--- a/toolbox/uptime.c
+++ b/toolbox/uptime.c
@@ -54,24 +54,35 @@
         sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
 }
 
-int64_t elapsedRealtime()
+static int elapsedRealtimeAlarm(struct timespec *ts)
 {
-    struct timespec ts;
     int fd, result;
 
     fd = open("/dev/alarm", O_RDONLY);
     if (fd < 0)
         return fd;
 
-   result = ioctl(fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts);
-   close(fd);
+    result = ioctl(fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), ts);
+    close(fd);
+
+    return result;
+}
+
+int64_t elapsedRealtime()
+{
+    struct timespec ts;
+
+    int result = elapsedRealtimeAlarm(&ts);
+    if (result < 0)
+        result = clock_gettime(CLOCK_BOOTTIME, &ts);
 
     if (result == 0)
         return ts.tv_sec;
     return -1;
 }
 
-int uptime_main(int argc, char *argv[])
+int uptime_main(int argc __attribute__((unused)),
+        char *argv[] __attribute__((unused)))
 {
     float up_time, idle_time;
     char up_string[100], idle_string[100], sleep_string[100];